UBOOT特点:
用于多种CPU
用于多种操作系统
查看一下board/smdk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm","elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start) //脚本命令,指定程序入口点
SECTIONS
{
. = 0x00000000;
. = ALIGN(4); //伪操作,4字节对齐
.text :
{
cpu/arm920t/start.o (.text) //指定程序的执行代码段,即start.o文件,
*(.text) //则在最先执行的程序应该是start.s
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd)}
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss (NOLOAD) : { *(.bss) }
_end = .;
}
下面分析cpu/arm920t/start.s文件:
ENTRY(_start)指定了从_start开始执行,
这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。
_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 //中断向量
…
/* the actual reset code */
reset: //复位启动子程序
/* 设置CPU为SVC32模式 */
mrs r0,cpsr /*修改cpsr时,通过将其拷贝到通用寄存器修改*/
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/* 关闭看门狗 */
…… ……
relocate: /* 把U-Boot重新定位到RAM */
adr r0, _start /* r0是代码的当前位置 */
ldr r1, _TEXT_BASE /*_TEXT_BASE是RAM中的地址 */
cmp r0, r1 /* 比较r0和r1,判断当前是从Flash启动,还是RAM */
beq stack_setup /* 如果r0等于r1,跳过重定位代码 */
/* 准备重新定位代码 */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 得到armboot的大小 */
add r2, r0, r2 /* r2 得到要复制代码的末尾地址 */
copy_loop: /* 重新定位代码 */
ldmia r0!,{r3-r10} /*从源地址[r0]复制 */
stmia r1!,{r3-r10} /* 复制到目的地址[r1]*/
cmp r0, r2 /* 复制数据块直到源数据末尾地址[r2] */
ble copy_loop
/* 初始化堆栈等 */
stack_setup:
ldr r0, _TEXT_BASE /* 上面是128 KiB重定位的u-boot */
sub r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */
sub r0, r0, #CFG_GBL_DATA_SIZE /* 然后是bdinfo结构体地址空间 */
#ifdefCONFIG_USE_IRQ
sub r0, r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* 为abort-stack预留3个字 */
clear_bss:
ldr r0, _bss_start /* 找到bss段起始地址 */
ldr r1, _bss_end /* bss段末尾地址 */
mov r2, #0x00000000 /* 清零 */
clbss_l:str r2,[r0]
/* bss段地址空间清零循环... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */
ldr pc, _start_armboot
_start_armboot:.word start_armboot //start_armboot函数在lib_arm/board.c中实现
第二阶段
2.lib_arm/board.c
start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
3.init_sequence[]
init_sequence[]数组保存着基本的初始化函数指针。
init_fnc_t*init_sequence[] = {
cpu_init, /* 基本的处理器相关配置 --cpu/arm920t/cpu.c */
board_init, /* 基本的板级相关配置 --board/smdk2410/smdk2410.c */
interrupt_init, /* 初始化中断处理 --cpu/arm920t/s3c24x0/interrupt.c */
env_init, /* 初始化环境变量 --common/cmd_flash.c */
init_baudrate, /* 初始化波特率设置 --lib_arm/board.c */
serial_init, /* 串口通讯设置 --cpu/arm920t/s3c24x0/serial.c */
console_init_f, /* 控制台初始化阶段1 --common/console.c */
display_banner, /* 打印u-boot信息 --lib_arm/board.c */
dram_init, /* 配置可用的RAM --board/smdk2410/smdk2410.c */
display_dram_config, /* 显示RAM的配置大小 --lib_arm/board.c */
NULL,
};
voidstart_armboot (void)
{
/* 顺序执行init_sequence数组中的初始化函数 */
for (init_fnc_ptr = init_sequence;*init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/*配置可用的Flash */
size = flash_init ();
display_flash_config (size);
/* _armboot_start 在u-boot.lds链接脚本中定义 */
mem_malloc_init (_armboot_start -CFG_MALLOC_LEN);
/* 配置环境变量*/
env_relocate ();
/* 从环境变量中获取IP地址 */
gd->bd->bi_ip_addr= getenv_IPaddr ("ipaddr");
/* 以太网接口MAC 地址 */
……
devices_init (); /* 获取列表中的设备 */
jumptable_init ();
console_init_r (); /* 完整地初始化控制台设备 */
enable_interrupts (); /* 使能中断处理 */
/* 通过环境变量初始化 */
if ((s = getenv ("loadaddr"))!= NULL) {
load_addr = simple_strtoul (s,NULL, 16);
}
/* main_loop()循环不断执行 */
for (;;)
{
main_loop (); /* 主循环函数处理执行用户命令-- common/main.c */
}
注:参考国嵌视频