设置 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_START和FIQ_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。
感谢作者这么优秀的资料: