U-BOOT启动过程分析 经典文章汇集
发布时间:2020-12-15 18:46:19 所属栏目:百科 来源:网络整理
导读:U-Boot启动过程 尽管有了调试跟踪手段,甚至也可以通过串口打印信息了,但是不一定能够判断出错原因。如果能够充分理解代码的启动流程,那么对准确地解决和分析问题很有帮助。 开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。函数调用
U-Boot启动过程
尽管有了调试跟踪手段,甚至也可以通过串口打印信息了,但是不一定能够判断出错原因。如果能够充分理解代码的启动流程,那么对准确地解决和分析问题很有帮助。
开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。函数调用顺序如图6.3所示。
看一下board/smsk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。下面详细分析一下程序跳转和函数的调用关系以及函数实现。
1.cpu/arm920t/start.S
这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。
图6.3? U-Boot启动代码流程图
?
_start: b?????? reset??????? //复位向量
?????? ldr?? pc,_undefined_instruction
…
?/* the actual reset code ?*/
reset: ???????? //复位启动子程序
?????? /* 设置CPU为SVC32模式 */
?????? mrs?? r0,cpsr
?????? bic?? r0,r0,#0x1f
?????? orr?? r0,#0xd3
?????? msr?? cpsr,r0
/* 关闭看门狗 */
?
/* 这些初始化代码在系统重起的时候执行,运行时热复位从RAM中启动不执行 */
#ifdef CONFIG_INIT_CRITICAL
?????? bl??? cpu_init_crit
#endif
relocate:?????????????? ??????? /* 把U-Boot重新定位到RAM */
?????? adr?? r0,_start????? ??? /* r0是代码的当前位置 */
?????? ldr?? r1,_TEXT_BASE????? /* 测试判断是从Flash启动,还是RAM */
?????? cmp???? r0,r1?????? ?? /* 比较r0和r1,调试的时候不要执行重定位 */
?????? beq???? stack_setup??? /* 如果r0等于r1,跳过重定位代码 */
?????? /* 准备重新定位代码 */
?????? ldr?? r2,_armboot_start
?????? ldr?? r3,_bss_start
?????? sub?? r2,r3,r2????? ??? /* r2 得到armboot的大小?? */
?????? add?? r2,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,#CFG_MALLOC_LEN???? /* 向下是内存分配空间 */
#ifdef CONFIG_USE_IRQ
?????? sub?? sp,#12???? /* 为abort-stack预留3个字 */
clear_bss:
?????? mov ? r2,#0x00000000???? /* 清零 */
clbss_l:str r2,[r0]??????? /* bss段地址空间清零循环...? */
?????? add?? r0,#4
?????? bne?? clbss_l
?????? /* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */
_start_armboot: .word start_armboot???? //start_armboot
函数在
lib_arm/board.c
中实现
/* 关键的初始化子程序 */
cpu_init_crit:
……? //初始化CACHE,关闭MMU等操作指令
?????? /* 初始化RAM时钟。
???????
*?
因为内存时钟是依赖开发板硬件的,所以在
board
的相应目录下可以找到
memsetup.S
文件。
?????? */
?????? mov?? ip,lr
?????? bl??? memsetup
????????
//memsetup
子程序在
board/smdk2410/memsetup.S
中实现
?????? mov?? lr,ip
?????? mov?? pc,51); font-family:Arial; font-size:14px; line-height:26px; text-align:left">
2.lib_arm/board.c
start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
?
?
void start_armboot (void)
{
?????? DECLARE_GLOBAL_DATA_PTR;
?????? ulong size;
?????? init_fnc_t **init_fnc_ptr;
?????? char *s;
?????? /* Pointer is writable since we allocated a register for it */
?????? gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
?????? /* compiler optimization barrier needed for GCC >= 3.4 */
?????? __asm__ __volatile__("": : :"memory");
?????? memset ((void*)gd,sizeof (gd_t));
?????? gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
?????? memset (gd->bd,sizeof (bd_t));
?????? monitor_flash_len = _bss_start - _armboot_start;
?????? /* 顺序执行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 */
?????? /* NOTREACHED - no way out of command loop except booting */
}
?
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,
};
?
U-BOOT start_armboot浅析
?
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |