Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解)Uboot启动分析笔记-----Stage1(start.S与lowlevel_init.S详解)1 u-boot.lds首先了解uboot的链接脚本board/my2410/u-boot.lds,它定义了目标程序各部分的链接顺序。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*指定输出可执行文件为ELF格式,32为,ARM小端*/OUTPUT_ARCH(arm)/*指定输出可执行文件为ARM平台*/ENTRY(_start)/*起始代码段为_start*/SECTIONS{/* 指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置*、. = 0x00000000;从0x0位置开始. = ALIGN(4); 4字节对齐.text :{cpu/arm920t/start.o (.text)board/my2440/lowlevel_init.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : { *(.data) } /* 只读数据段,所有的只读数据段都放在这个位置*/. = ALIGN(4);.got : { *(.got) } /*指定got段, got段式是uboot自定义的一个段, 非标准段*/. = .;__u_boot_cmd_start = .; /*把__u_boot_cmd_start赋值为当前位置, 即起始位置*/.u_boot_cmd : { *(.u_boot_cmd) }/* u_boot_cmd段,所有的u-boot命令相关的定义都放在这个位置,因为每个命令定义等长,所以只要以__u_boot_cmd_start为起始地址进行查找就可以很快查找到某一个命令的定义,并依据定义的命令指针调用相应的函数进行处理用户的任务*/__u_boot_cmd_end = .;/* u_boot_cmd段结束位置,由此可以看出,这段空间的长度并没有严格限制,用户可以添加一些u-boot的命令,最终都会在连接是存放在这个位置。
*/. = ALIGN(4);__bss_start = .; /*把__bss_start赋值为当前位置,即bss段的开始位置*/.bss (NOLOAD) : { *(.bss) . = ALIGN(4); } /*指定bss段,这里NOLOAD的意思是这段不需装载,仅在执行域中才会有这段*/_end = .; /*把_end赋值为当前位置,即bss段的结束位置*/}第一个链接的是cpu/board/start.o,也即Uboot的入口指令在start中,下面详细分析程序的跳转和函数调用关系。
2 Stage1 : cpu/arm920t/start.S这个汇编程序时UBoot的入口程序,以复位向量开头。
reset↓cpu_init_crit↓relocate↓stack_setup↓start_armboot()↓init_sequence[]↓getenv()↓main_loop()其中前面4步为Stage1下面来详细分析一下cpu/arm920t/start.S这里以ARM9 2410为例,2440移植时需要修改一些配置,具体的再后面的移植中介绍. /* 这段代码的主要作用:进入SVC模式关闭看门狗屏蔽所有IRG掩码设置时钟频率 FCLK HCLK PCLK清楚I/D Cache禁止MMU和CACHE配置memory control重定位:如果代码不在指定的地址上需要把uboot从当前位置copy到RAM指定位置上建立堆栈,为进入C函数做准备清0 .bss段跳入start_armboot函数进入stage2(lib_arm/board.c)*/.globl _start_start: /* 系统复位位置, 各个异常向量对应的跳转代码 */b 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 /* 快速中断异常向量 */_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.balignl 16,0xdeadbeef/**ARM9支持7种异常。
下面是异常的响应过程*第一个复位异常,它放在0x0的位置,一上电就执行它,而且我们的程序总是从复位异常处理程序* 开始执行的,因此复位异常处理程序不需要返回。
*其他异常处理的如下:*当一个异常出现以后,ARM会自动执行以下几个步骤:*(1) 把下一条指令的地址放到连接寄存器LR(通常是R14),这样就能够在处理异常返回时从正确的位置继续执行。
*(2) 将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中。
从异常退出的时候,就可以由SPSR来恢复CPSR。
*(3) 根据异常类型,强制设置CPSR的运行模式位。
*(4) PC(程序计数器)被强制成相关异常向量处理函数地址,从而跳转到相应的异常处理程序中。
* 当异常处理完毕后,ARM会执行以下几步操作从异常返回:*(1)将连接寄存器LR的值减去相应的偏移量后送到PC中*(2) 将SPSR复制回CPSR中*(3) 若在进入异常处理时设置了中断禁止位,要在此清除** ARM规定了异常向量的地址:* b reset ;复位 0x0* ldr pc, _undefined_instruction ;未定义的指令异常 0x4* ldr pc, _software_interrupt ;软件中断异常 0x8* ldr pc, _prefetch_abort ;预取指令 0xc* ldr pc, _data_abort ;数据 0x10* ldr pc, _not_used ;未使用 0x14* ldr pc, _irq ;慢速中断异常 0x18* ldr pc, _fiq ;快速中断异常 0x1c* 当处理器碰到异常时,PC会被强制设置为对应的异常向量,从而跳转到* 相应的处理程序,然后再返回到主程序继续执行。
* .balignl 16,0xdeadbeef, 将地址对齐到16的倍数,如果地址寄存器的值(PC)跳过4个字节才是16的倍数,* 则使用0xdeadbeef填充这4个字节,如果它跳过1、2、3个字节,则填充值不确定。
如果地址寄存器的值(PC)是16的倍数,则无需移动。
********************//************************************************************************** Startup Code (reset vector) ………………….*************************************************************************/ /* 保存变量的数据区 */_TEXT_BASE:.word TEXT_BASE ;定义一个字并分配空间 4bytes.globl _armboot_start_armboot_start:.word _start ;声明一个全局的,并用 _start 初始化它, 在u-boot.lds中定义/* These are defined in the board-specific linker script.*/.globl _bss_start_bss_start:.word __bss_start.globl _bss_end_bss_end:.word _end#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word 0x0badc0de/* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de#endif/* the actual reset code*//* 系统的复位代码。
系统一上电,就跳到这里运行 */reset:mrs r0,cpsr /* 取得当前程序状态寄存器cpsr到r0 */bic r0,r0,#0x1f /* 这里使用位清除指令,把中断全部清除,只置位模式控制位为中断提供服务通常是 OS设备驱动程序的责任,因此在 Boot Loader 的执行全过程中可以不必响应任何中断*/orr r0,r0,#0xd3 /* 计算为超级保护模式,并disable IRQ和FIQ */msr cpsr,r0 /* 设置cpsr为超级保护模式 *//******************CPSR 的底8位为I F T M4 M3 M2 M1 M0 IRQdisable FIQdisable StateBitSVC[M4~M0] = 10011StateBit = set:THUMB state, others:ARM state* 设置cpu运行在SVC32模式。
ARM9共有7种模式:* 用户模式(usr): arm处理器正常的程序执行状态* 快速中断模式(fiq):用于高速数据传输或通道处理* 外部中断模式(irq):用于通用的中断处理* 超级保护模式(svc):操作系统使用的保护模式* 数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护* 系统模式(sys):运行具有特权的操作系统任务* 未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真* 通过设置ARM的CPSR寄存器,让CPU运行在操作系统保护模式,为后面进行其它操作作好准备了。