• 沒有找到結果。

第 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 实现 的内容。