本文所有资料来至互联网,笔者加以整理和归纳,仅供以后复习
对于uboot的start.S,主要做的事情就是系统的各个方面的初始化。
从大的方面分,可以分成这几个部分:
- 设置CPU模式
- 关闭看门狗
- 关闭中断
- 设置堆栈sp指针
- 清除bss段
- 异常中断处理
1、分析.globl _start
Directive | Description | Syntax | Example |
---|---|---|---|
.global | Makes symbol visible to the linker | .global symbol | .global MyAsmFunc |
.globl | Same as .global | .globl symbol | .globl MyOtherAsmFunc |
所以,意思很简单,就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局的,外部可以访问
所以,你可以看到
board\开发板名\u-boot.lds
中,有用到此变量:
ENTRY(_start)
即指定入口为_start,而由下面的_start的含义可以得知,_start就是整个start.S的最开始,即整个uboot的代码的开始。
2、分析 _start: b reset
start的值,也就是这个代码的位置了,此处即为代码的最开始,相对的0的位置。
在程序开始运行的时候,如果是从NorFlash或NandFlash启动,那么其地址是0,
_start=0
如果是重新relocate代码之后,就是我们定义的值了,即,在
board\
开发板名
\config.mk
中的:
TEXT_BASE = 0x33D00000
表示是代码段的基地址,即
_start=TEXT_BASE=0x33D00000
2、分析 LDR
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 R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2]! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8]! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
3、分析 .word
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
表 1.2. .word的语法
Directive Description Syntax Example .word Define word expr (32bit numbers) .word expr {, …} .word 144511, 0x11223
所以上面的含义,以_undefined_instruction为例,就是,此处分配了一个word=32bit=4字节的地址空间,里面存放的值是undefined_instruction。
而此处_undefined_instruction也就是该地址空间的地址了。用C语言来表达就是:
_undefined_instruction = &undefined_instruction
或
*_undefined_instruction = undefined_instruction
在后面的代码,我们可以看到,undefined_instruction也是一个标号,即一个地址值,对应着就是在发生“未定义指令”的时候,系统所要去执行的代码。
(其他几个对应的“软件中断”,“预取指错误”,“数据错误”,“未定义”,“(普通)中断”,“快速中断”,也是同样的做法,跳转到对应的位置执行对应的代码。)
3、分析 .balignl
.balignl 16,0xdeadbeef
表 1.3. balignl的语法
Directive Description Syntax Example .balignl Word align the following code to alignment byte boundary (default=4). Fill skipped words with fill (default=0 or NOP). If the number of bytes skipped is greater than max, then don't align (default=alignment ). .balignl {alignment} {, fill} {, max} .balignl
所以意思就是,接下来的代码,都要16字节对齐,不足之处,用0xdeadbeef填充。
其中关于所要填充的内容0xdeadbeef,此处0xdeadbeef本身没有真正的意义,但是很明显,字面上的意思是,(坏)死的牛肉。
虽然其本身没有实际意义,但是其是在十六进制下,能表示出来的,为数不多的,可读的单词之一了。
另外一个相对常见的是:0xbadc0de,意思是bad code,坏的代码,注意其中的o是0,因为十六进制中是没有o的。
这些“单词”,相对的作用是,使得读代码的人,以及在查看程序运行结果时,容易看懂,便于引起注意。
4、分析 _TEXT_BASE 和_armboot_start
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
/* 此处的<pre name="code" class="objc">CFG_PHY_UBOOT_BASE应该在某处定义
*/
_TEXT_PHY_BASE: .word CFG_PHY_UBOOT_BASE.globl _armboot_start_armboot_start: .word _start
TEXT_BASE在\board\开发板名\config.mk
中定义
同理,此含义可用C语言表示为:
*(_armboot_start) = _start
5、分析 bss_start和_bss_end
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
关于_bss_start和_bss_end都只是两个标号,对应着此处的地址。
而两个地址里面分别存放的值是__bss_start和_end,这两个的值,根据注释所说,是定义在开发板相关的链接脚本里面的,我们此处的开发板相关的链接脚本是:
board\开发板名\
u-boot.lds
__bss_start = .;
.bss : { *(.bss) }
_end = .;
详细解析参考博客:http://www.crifan.com/about/me/