start.S详解学习(一):设置 CPU 模式

简介: start.S详解学习(一):设置 CPU 模式

设置 CPU 模式

0-前置

/*
* armboot - Startup Code for ARM920 CPU-core
*
* Copyright (c) 2001 Marius Gr鰃er <mag@sysgo.de>
* Copyright (c) 2002 Alex Z黳ke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <version.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start

1、globl关键字

globl是个关键字,对应含义为:

所以,意思很简单,就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全

局的,外部可以访问,所以,你可以看到:

u-boot-master\arch\arm\cpu\u-boot.lds

中,有用到此变量:

ENTRY(_start)

即指定入口为_start,而由下面的_start的含义可以得知,_start就是整个start.S的最开始,即整个uboot的代码的开始。

_start: b reset

_start后面加上一个冒号‘:‘,表示其是一个标号Label,类似于C语言goto后面的标号。

而同时,_start的值,也就是这个代码的位置了,此处即为代码的最开始,相对的0的位置。

而此处最开始的相对的0位置,在程序开始运行的时候,如果是从NorFlash启动,那么其地址

是0,

_stat=0

如果是重新relocate代码之后,就是我们定义的值了,即,在

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\config.mk

中的:

TEXT_BASE = 0x33D00000

表示是代码段的基地址,即_start=TEXT_BASE=0x33D00000

标签写为符号,后跟冒号“:”。然后,该符号表示活动位置计数器的当前值,例如,它是一个合适的指令操作数。如果使用相同的符号表示两个不同的位置,则会发出警告:第一个定义将替代任何其他定义。

2、ldr指令

而_start标号后面的:

b reset

就是跳转到对应的标号为reset的位置。

ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

LDR指令的格式为:

LDR 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。

举个例子:

ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。

比如想把数据从内存中某处读取到寄存器中,只能使用ldr

比如:

ldr r0, 0x12345678

就是把0x12345678这个地址中的值存放到r0中。

3、word

上面那些ldr的作用,以第一个_undefined_instruction为例,就是将地址为_undefined_instruction中的一个word的值,赋值给pc。

.word .word expr {,expr}… 分配一段字内存单元,并用expr初始化字内存单元(32bit)

所以上面的含义,以_undefined_instruction为例,就是,此处分配了一个word=32bit=4字节的地址空间,里面存放的值是undefined_instruction。

而此处_undefined_instruction也就是该地址空间的地址了。用C语言来表达就是:

_undefined_instruction = &undefined_instruction

*_undefined_instruction = undefined_instruction

在后面的代码,我们可以看到,undefined_instruction也是一个标号,即一个地址值,对应着就是在发生“未定义指令”的时候,系统所要去执行的代码。

(其他几个对应的“软件中断”,“预取指错误”,“数据错误”,“未定义”,“(普通)中断”,“快速中断”,也是同样的做法,跳转到对应的位置执行对应的代码。)

所以:

ldr pc, 标号1
。。。
标号1:.word 标号2
标号2:
  。。。(具体要执行的代码)

的意思就是,将地址为标号1中内容载入到pc,而地址为标号1中的内容,正好装的是标号2。

用C语言表达其实很简单:

PC = *(标号1) = 标号2

对PC赋值,即是实现代码跳转,所以整个这段汇编代码的意思就是:

跳转到标号2的位置,执行对应的代码。

4、balignl

.balignl 16,0xdeadbeef

balignl这个标号的语法及含义:

意思就是,接下来的代码,都要16字节对齐,不足之处,用0xdeadbeef填充。

其中0xdeadbeef其实没啥特别意思,就是要填充的内容,你把其换成其他的也行,当然最好也

和0xdeadbeef一样是4个字节。

/*
*********************************************************************
****
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*********************************************************************
****
*/
_TEXT_BASE:
  .word TEXT_BASE

此处和上面的类似,_TEXT_BASE是一个标号地址,此地址中是一个word类型的变量,变量名是TEXT_BASE,此值见名知意,是text的base,即代码的基地址,可以在

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\config.mk

中找到其定义:

TEXT_BASE = 0x33D00000
.globl  _armboot_start
_armboot_start:
  .word  _start

同理,此含义可用C语言表示为:

*(_armboot_start) = _start

关于_bss_start和_bss_end都只是两个标号,对应着此处的地址。

而两个地址里面分别存放的值是__bss_start和_end,这两个的值,根据注释所说,是定义在

开发板相关的链接脚本里面的,我们此处的开发板相关的链接脚本是:

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\u-boot.lds

其中可以找到__bss_start和_end的定义:

而关于_bss_start和_bss_end定义为.glogl即全局变量,是因为uboot的其他源码中要用到这两个变量,详情请自己去搜索源码。

关于FREE_RAM_END和FREE_RAM_SIZE,这里只是两个标号,之所以也是声明为全局变量,是因为uboot的源码中会用到这两个变量。

但是这里有点特别的是,这两个变量,将在本源码start.S中的后面要用到,而在后面用到这两个变量之前,uboot的C源码中,会先去修改这两个值,具体的逻辑是:

本文件start.S中,后面有这两句:

ldr pc, _start_armboot
_start_armboot: .word start_armboot

意思很明显,就是去调用start_armboot函数。

1-start_armboot函数

而start_armboot函数是在:

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\lib_arm\board.c中:

即在start_armboot去调用了cpu_init。

2-cpu_init函数

cpu_init函数是在:

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\cpu\arm920t\cpu.c中

在cpu_init中,根据我们的一些定义,比如堆栈大小等等,去修改了IRQ_STACK_START ,FIQ_STACK_START ,FREE_RAM_END和FREE_RAM_SIZE的值。

至于为何这么修改,后面遇到的时候会具体再解释。

同上,IRQ_STACK_STARTFIQ_STACK_START,也是在cpu_init中用到了。

不过此处,是只有当定义了宏CONFIG_USE_IRQ的时候,才用到这两个变量,其含义也很明显,

只有用到了中断IRQ,才会用到中断的堆栈,才有中断堆栈的起始地址。快速中断FIQ,同理。

1-CPSR

  • CPSR 是当前的程序状态寄存器(Current Program Status Register),
  • SPSR 是保存的程序状态寄存器(Saved Program Status Register)。



2-MRS

MRS - Move From Status Register

程序状态寄存器访问指令

/*
* the actual reset code
*/
reset:
  /*
  * set the cpu to SVC32 mode
  */
  mrs r0,cpsr

3-bic

bic r0,r0,#0x1f

bic指令的语法是:

4-orr

orr r0,r0,#0xd3

5-msr

MSR - Move to Status Register

msr cpsr,r0

此行汇编代码含义为,将r0的值赋给CPSR。

感谢作者这么优秀的资料:

目录
相关文章
|
25天前
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
18 0
|
2月前
|
存储 SQL 缓存
手写操作系统(5)——CPU工作模式与虚拟地址(下)
手写操作系统(5)——CPU工作模式与虚拟地址
19 0
|
2月前
|
存储 缓存 Linux
手写操作系统(5)——CPU工作模式与虚拟地址(上)
手写操作系统(5)——CPU工作模式与虚拟地址
33 0
|
2月前
|
安全 编译器 程序员
CPU处理器模式与异常
CPU处理器模式与异常
93 0
|
9月前
|
监控 数据挖掘 虚拟化
VMWare 虚拟机 CPU 设置里针对 CPU 的 虚拟化 CPU 性能计数器(U) 选项功能介绍
VMWare 虚拟机 CPU 设置里针对 CPU 的 虚拟化 CPU 性能计数器(U) 选项功能介绍
|
9月前
|
安全 虚拟化
VMWare 虚拟机 CPU 设置里针对 CPU 的虚拟化 IOMMU(IO 内存管理单元) 选项功能介绍
VMWare 虚拟机 CPU 设置里针对 CPU 的虚拟化 IOMMU(IO 内存管理单元) 选项功能介绍
|
2月前
|
Unix 应用服务中间件 Linux
nginx的CPU亲和性设置和优先级设置
nginx的CPU亲和性设置和优先级设置
|
2月前
|
Nacos
nacos 2.2.3集群模式下,leader节点,CPU打满
nacos 2.2.3集群模式下,leader节点,CPU打满
51 1
|
2月前
|
Nacos
nacos 2.2.3集群模式下,leader节点,CPU打满,是什么原因?
nacos 2.2.3集群模式下,leader节点,CPU打满,是什么原因?
104 5
|
2月前
|
存储 缓存 Linux
关于S3学习所涉及到的知识(一):per-CPU变量&kernel syscore
关于S3学习所涉及到的知识(一):per-CPU变量&kernel syscore
45 0