第 3 章 嵌入式系统的 BOOTLOADER
3.3 基于 S3C2410 开发板的 B OOT L OADER 实现
3.3.2 U-Boot 分析与移植
3.3.2.1 U-Boot Stage1 分析
|-- board
|-- common
|-- cpu
|-- disk
|-- doc
|-- drivers
|-- dtt
|-- examples
|-- fs
|-- include
|-- lib_arm
|-- lib_avr32
|-- lib_blackfin
|-- lib_generic
|-- lib_i386
|-- lib_m68k
|-- lib_microblaze
|-- lib_mips
|-- lib_nios
|-- lib_nios2
|-- lib_ppc
|-- nand_spl
|-- net
|-- post
|-- rtc
`-- tools
26 directories
大多数 BootLoader 都包含“启动加载”模式和“下载”模式,U-Boot 作为一款强大的 BootLoader 也支持这两种工作模式,并且常常允许用户在这两种模式之间切换。同时 U-Boot 也分为 Stage1 和 Stage2 两个阶段。其中依赖于 CPU 体系结构的代码通常都放在 Stage1 里,
并且通常用汇编语言实现。Stage2 通常用 C 语言实现,可以实现更复杂的功能,并且有更 好的移植性和可读性。
3.3.2.1 U-Boot Stage1 分析
U-Boot 的 Stage1 通常是在 start.S 文件中实现,并且都是用汇编语言编写。一个可执行
性 image 文件必须有一个入口点,并且只能有一个全局入口点,通常这个入口点的地址放在 ROM(Flash)0x0 位置,因此必须使编译器知道这个入口地址,该过程通常修改连接器的 脚本文件来完成。此处以三星的 smdk2410 开发板为例,该开发板的 U-Boot 实现代码已经 包含在里面。打开 board/smdk2410/ u-boot.lds 文件,该脚本文件的内容如下所示:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm)
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) } _end = .;
}
其中,ENTRY(_start)定义了入口点在 cpu/arm920t/start.S 文件,入口地址为 0x00000000。
在 cpu/arm920t/config.mk 文件中定义了代码区基地址:TEXT_BASE = 0x33F80000。接下来 分析 U-Boot 的 Stage1 的核心文件 start.S。
Ø 设置异常向量表
对于 ARM 处理器一般包括复位、未定义指令、SWI、预取终止、数据终止、IRQ、
FIQ 等异常,关于 ARM 处理器这些异常在后面会有专门的介绍,其中 U-Boot 中关于异 常向量的定义如下,当发生异常时执行 cpu/arm920t/ interrupts.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 不同的物理寄存器,当使用 fiq 模式时,访问寄存器 R8_fiq~R12_fiq;当使 用除 fiq 模式以外的其他模式时,访问寄存器 R8_usr~R12_usr。 对于 R13、
Program Status Register 的缩写,即备份程序状态寄存器,当异常发生时,SPSR 用于 到 MCU(Micro Controller Unit,多点控制单元)的 RST 端(复位端),MCU 正常 工作的时候,每隔一段时间输出一个信号到喂狗端,给 WDT(watchdog timer 的简 写)清零,如果超过规定的时间不喂狗,一般在程序跑飞时 WDT 定时超过,就会给 出一个复位信号到 MCU,然后 MCU 复位。看门狗的作用就是防止程序发生死循环,
或者说程序跑飞。根据 S3C2410 的用户手册,关闭看门狗的具体实现如下:
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) ldr r0, =pWTCON
mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0]
# if defined(CONFIG_S3C2410) ldr r1, =0x3ff
ldr r0, =INTSUBMSK str r1, [r0]
# endif
Ø 设置 CPU 的频率
S3C2410 的用户手册推荐 FCLK:HCLK:PCLK = 1:2:4,其中 FCLK 默认是 120MHz,
通常 FCLK 用于 CPU,HCLK 用于 AHB 总线,PCLK 用于 APB 总线。 定对 MMU 的操作。设置 CP15 寄存器的目的是失效 ICache(指令 Cache)和 DCache
(数据 Cache),然后禁止 MMU 和 Cache。
/* 禁止 MMU 和 Caches*/ 中的设置文件是 board/smdk2400/lowlevel_init.S,该文件包含 lowlevel_init 程序段用 于内存控制配置。在 start.S 中的相关实现如下:
mov ip, lr
bl lowlevel_init mov lr, ip
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
Ø BSS 段清零
BSS(Block Started by Symbol 的简称)段是可执行性文件中的一种数据段。通常 ARM 编译器生成的可执行性文件由两部分数据组成,分别是代码段和数据段。代码段又分 VIVI 源代码的实现,利用 copy_myself 函数实现,具体实现将在 U-Boot 移植一节中 详细介绍。
Ø 进入 C 代码
进入 C 代码的实现很简单,利用 ldr 指令实现到 C 代码地址的装载,具体实现如下:
ldr pc, _start_armboot
_start_armboot: .word start_armboot
到这里已经介绍完了 U-Boot Stage1 的所有主要实现,接下来讲述 U-Boot Stage2 实现 的内容。