Makefile分析完成后,发现0bj 第一个文件时start.o,我们找到start.s进行分析。
_start: b reset //0
ldr pc, _undefined_instruction //0x4
ldr pc, _software_interrupt //0x8
ldr pc, _prefetch_abort //0xc
ldr pc, _data_abort //0x0
ldr pc, _not_used //0x14
ldr pc, _irq //0x18
ldr pc, _fiq //0x1c
_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
irq:
sub lr, lr, #4 @ the return address
ldr sp, IRQ_STACK_START @ the stack for irq
stmdb sp!, { r0-r12,lr } @ save registers
ldr lr, =int_return @ set the return addr
ldr pc, =IRQ_Handle @ call the isr
int_return:
ldmia sp!, { r0-r12,pc }^ @ return from interrupt
就以irq为例,如果发生中断就会跳转到 irq(0x14地址上面),然后取出irq中保存的函数地址,跳转到该函数执行。跳转该函数之前,做了哪些操作呢?
1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址
2. SPSR_irq保存有被中断模式的CPSR
3. CPSR中的M4-M0被设置为10010, 进入到irq模式
4. 跳到0x14的地方执行程序
然后从0x14中取出函数地址赋给PC,跳转到该函数执行,具体可以看一眼反汇编更清楚:
跳转到该函数后,
1.设置返回地址
2.设置栈sp寄存器。
3.保存r0-r12到栈中,为了中断函数执行完成后可以恢复现场。
4.跳转到中断函数里面执行。执行完成后跳转到lr。
5.恢复现场,会把lr_irq的地址赋给pc,恢复栈中保存的r0-r12寄存器,并把spsr中的值赋给cpsr。
2.1 设置为SVC32模式,系统模式可以访问相关IO寄存器等。
mrs r0,cpsr //修改程序状态寄存器为系统模式。将程序状态寄存器传给通用寄存器。
bic r0,r0,#0x1f//清0寄存器。0x1f = 011111b,将r0[0-4]清0,
orr r0,r0,#0xd3//或运算。设置为系统模式,关fiq中断。
msr cpsr,r0 //将运算后的r0寄存器传给cpsr。
2.2关闭看门狗,防止没有喂狗程序reset。
ldr r0, =pWTCON //伪指令,实际和mov一样,不是arm体系架构提供的ldr.
mov r1, #0x0
str r1, [r0]//和ldr相反,将寄存器数据写入到存储器中。*r0 = r1.[r0]为存储器地址。
2.3关闭中断
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]//INTMSK=#0xfffffff
2.4 调用c函数之前必须设置栈和内存分布图
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
sub sp, r0, #12 /* leave 3 words for abort-stack */
2.5设置时钟
bl clock_init //c函数设置 Mpll,初始化fclk,hclk,pclk
2.6代码重定位
函数里面判断是nand启动还是nor启动,根据lds里面的设置,确定运行地址和加载地址。将加载地址(flash中的内容)拷贝到运行地址中(sdram)。
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
2.7清bss
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
2.8跳转到uboot的第二阶段
ldr pc, _start_armboot //绝对跳转,不是相对跳转
_start_armboot: .word start_armboot