前面分析了启动脚本、Makefile、mkconfig,接下来就是uboot的start.S这个启动代码了,下面是本章的平台介绍:
单板:迅为4412开发板(Exynos 4412)
SDRAM:1G
EMMC:4G
Exynos 4412的启动过程可以在数据手册的Booting Sequence找到,下面只截取关键部分:
Exynos 4412 has 64 KB ROM (iROM) and 256 KB SRAM (iRAM) as internal memory.
You can select the booting device from the following list:
1. General NAND flash memory
2. SD/MMC memory card
3. eMMC memory
4. USB deviceAt the system reset, the program execution starts at iROM. The system reset may be asserted not
only on booting time, but also on wakeup from low power modes. Therefore, the boot loader code executes appropriate processes according to the reset status. Refer to Figure 5-1 for more information.The boot loader is comprises the first and the second boot loaders. The characteristics of these boot loaders are:
1. iROM: It is a small and simple code to initiate SOC. It is implemented on internal ROM of SOC.
2. First boot loader (BL1): It is chip-specific and stored in external memory device.
3. Second boot loader (BL2): It is platform-specific and stored in external memory device. User should build and store this in an external memory device. It is not provided by Samsung.
从文字和图片可以总结出如下几点:
BL0:这段是固化的代码放置在 64K 的 iROM 里面,负责初始化基本的系统功能比如时钟和栈,并且加载 BL1 到内部 256KB 的 SRAM。
BL1:这段代码由三星提供,也更改不了,BL0 会根据 OM 引脚来判断当前 booting 设备是哪个,可以是 NAND_FLASH、SD卡、EMMC、USB设备,从选定好的设备中加载 BL1,BL1 主要负责初始化系统时钟和 DRAM 控制器,然后从 booting 设备中加载 OS 到 DRAM 中去运行,这里的 OS 其实就是指 BL2,DRAM 指的则是外部的 SDRAM。
BL2:BL2 的主要功能是去加载我们的 UBOOT 代码,此后 UBOOT 运行在 DRAM上, 同样加载的时候也需要校验,这里需要将 uboot.bin 合并(merge)进BL2里面,在迅为的启动脚本里面有描述,如下:
cat E4412.S.BL1.SSCR.EVT1.1.bin E4412.BL2.TZ.SSCR.EVT1.1.bin all00_padding.bin u-boot.bin E4412.TZ.SSCR.EVT1.1.bin > u-boot-iTOP-4412.bin
做好了一切准备以后就开始执行 start.S 了,这里标题指的第一阶段基本上都是用汇编去实现的,主要负责硬件的初始化,第二阶段都是C代码,实现一些比较复杂的内容,下一章节描述。
以 start.S 的代码开始描述:
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
/*
globl就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局的,外部可以访问
指定入口为_start
u-boot.lds里面定义了ENTRY(_start),即指定入口为_start
*/
.globl _start
/* 跳转到reset,这里的代码地址是00000010 */
_start: b reset
/*
ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
比如想把数据从内存中某处读取到寄存器中,只能使用ldr
将_undefined_instruction这个地址处的word(一字节)定义的值赋给pc。
ARM体系结构规定在上电复位的起始位置必须有8条连续的跳转指令,
通过硬件来实现。它们就是异常向量表。ARM在上电复位后是从0x0开始启动,
如果bootloader存在,则是从_start开始执行上面的跳转没有执行。
设置异常向量表的作用是识别bootloader,以后每当系统有异常出现时,
cpu会根据异常号从内存0x0处开始查找并做相应的处理
下面8条即设置异常中断向量表
*/
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
/*
当有异常出现ARM会自动执行以下步骤:
1 将下一条指令的地址存放在连接寄存器LR(通常是R14).---保存位置
2 将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中
3 根据异常类型,强制设置CPSR运行模式位
4 强制PC从相应异常向量地址取出下一条指令执行,从而跳转到异常处理函数中执行
*/
_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//快速中断
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
/* 接下来的代码,都要16字节对齐,不足之处,用0xdeadbeef填充 */
.balignl 16,0xdeadbeef
_TEXT_BASE:
/* _TEXT_BASE是一个标号地址,在board\samsung\smdkc210中定义,通过反汇编或路径可得知为"0xc3e00000" */
.word TEXT_BASE
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE /* 反汇编得知为:43e00000 */
.globl _armboot_start
_armboot_start:
/* 此含义可用C语言表示为:*(_armboot_start) = _start */
.word _start
/* 以下这些地址跟u-boot.lds一一对应,声明地址标号 */
.globl _bss_start
_bss_start:
/* bss段的起始地址 */
.word __bss_start
.globl _bss_end
_bss_end:
/* bss段的结束地址 */
.word _end
/* 相当于一个无参数的宏cache_invalidate_dcache_v7,也就相当于一个函数了,似乎和cache有关,暂不细究 */
.macro cache_invalidate_dcache_v7
MRC p15, 1, r0, c0, c0, 1 @ read Cache Level ID register (clidr)
ANDS r3, r0, #0x7000000 @ extract level of coherency from clidr
MOV r3, r3,