来源:Linux社区  作者:xiaojiang1025  : http://www.linuxidc.com/Linux/2017-02/141019.htm

经过了上一篇的配置,我们已经执行make就可以编译出一个uboot.bin,但这还不够,首先,此时的uboot并不符合三星芯片对bootloader的格式要求,其次,此时的uboot.bin也没有结合我们的开发板进行配置,还无法使用。而要进行这样的个性化配置,前提条件就是对uboot开机流程和编译系统有所了解,本文主要讨论前者。uboot是一个两阶段bootloader,第一阶段主要做硬件直接相关的初始化,使用汇编编写;第二阶段主要为操作系统的运行准备环境,主要用C编写,这里以ARM平台为例分析其启动流程。下面是启动过程中主要涉及的文件

arch/arm/cpu/armv7/start.S
board/samsung/myboard/lowlevel_init.S
arch/arm/lib/crt0.S
arch/arm/lib/board.c
arch/samsung/myboard/myboard.c

第一阶段

第一阶段的主要文件和任务如下

arch/arm/cpu/armv7/start.S
        1. 设置CPU为SVC模式
        2. 关闭中断,MMU,Cache
board/samsung/origen/lowlevel_init.S
        3. 关闭看门狗
        4. 初始化内存,串口
        5. 设置栈
        6. 代码自搬移
        7. 清BSS
        8. 跳转到C入口????

start.S

 39 .globl _start40 _start: b       reset 41 ldr pc, _undefined_instruction 42 ldr pc, _software_interrupt 43 ldr pc, _prefetch_abort 44 ldr pc, _data_abort 45 ldr pc, _not_used 46 ldr pc, _irq 47 ldr pc, _fiq

--40--> 异常向量表设置

126 reset:
127         bl      save_boot_params
131         mrs     r0, cpsr
132 bic r0, r0, #0x1f 133 orr r0, r0, #0xd3 134 msr cpsr,r0

--126-->设置CPU为SVC模式

下面这三行代码非常重要,是整个uboot启动过程的交叉点

154         bl      cpu_init_cp15
155         bl      cpu_init_crit
158         bl      _main

--154-->跳转执行cpu_init_cp15,即初始化CP15协处理器
--155-->跳转执行cpu_init_crit,
--158-->跳转执行_main,即第二阶段

287 ENTRY(cpu_init_cp15)
291         mov     r0, #0                  @ set up for MCR
292 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs 293 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 294 mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array 295 mcr p15, 0, r0, c7, c10, 4 @ DSB 296 mcr p15, 0, r0, c7, c5, 4 @ ISB 297 301 mrc p15, 0, r0, c1, c0, 0 302 bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 303 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) 304 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align 305 orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB 307 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache 311 mcr p15, 0, r0, c1, c0, 0 312 mov pc, lr @ back to my caller 313 ENDPROC(cpu_init_cp15)

--291-->关闭Cache
--301-->关闭MMU

324 ENTRY(cpu_init_crit)
331         b       lowlevel_init           @ go setup pll,mux,memory
332 ENDPROC(cpu_init_crit)

--331-->跳转到lowlevel_init,位于board/samsung/origen/lowlevel_init.S,进行板级相关的设置。

lowlevel_init.S

这是位于目录的初始化文件,主要完成特定开发板的初始化工作,包括时钟、内存和串口等。

 82         bl system_clock_init85         bl mem_ctrl_asm_init87 1:88 /* for UART */ 89 bl uart_asm_init 90 bl tzpc_init 91 pop {pc} 114 system_clock_init: 329 uart_asm_init: 357 tzpc_init:

--82-->初始化系统时钟,即跳转到114行
--85-->初始化系统内存
--89-->初始化UART串口,即跳转到329行
--90-->初始化TrustZoneProtectorController,即跳转到357行

执行完lowlevel_init.S,依据上面那三行代码,执行流程就该回到start.S执行156行跳转到_main,开始执行第二阶段。

第二阶段

从start.S跳转到_main ,标致着uboot启动过程的第二阶段的开始。在第二阶段,核心文件是crt0.S,但我们最关心的是其中回调板级C程序的入口位置。第二阶段的流程如下:

arch/arm/lib/crt0.S
        1. 初始化C运行环境,调用board_init_f()
arch/arm/lib/board.c
        1. board_init_f对全局信息GD结构体进行填充
arch/arm/lib/crt0.S
        1. 代码重定位
        2. 代码自搬移
        3. 执行超循环
arch/arm/lib/board.c
        1. board_init_r()是进入定制板目录的入口

crt0.S

进入第二阶段是首要任务就是准备C语言运行的环境:

 96 _main:
102 #if defined(CONFIG_NAND_SPL)
103 /* deprecated, use instead CONFIG_SPL_BUILD */ 104 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 105 #elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) 106 ldr sp, =(CONFIG_SPL_STACK) 107 #else 108 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 109 #endif 110 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 111 sub sp, #GD_SIZE /* allocate one GD above SP */ 112 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 113 mov r8, sp /* GD is above SP */ 114 mov r0, #0 115 bl board_init_f

_main
--104-->初始化SP,为C语言做准备
--110-->保存128B放GD结构体来存放全局信息,
--111-->GD的地址放在r8中,
--115-->跳转到board_init_f(),这个整个初始化过程中第一次执行的C代码

board.c

下面这个函数就是uboot初始化过程中执行的第一个C函数,可以看作这个文件的入口函数。函数比较长,我就不逐句分析了,这个函数主要的作用就是执行一些高等级的初始化。其中最重要的就是准备全局信息GD结构体

209 typedef int (init_fnc_t) (void); 243 init_fnc_t *init_sequence[] = { 244 arch_cpu_init, /* basic arch cpu dependent setup */ 245 mark_bootstage, 246 #ifdef CONFIG_OF_CONTROL 247 fdtdec_check_fdt, ... 277 void board_init_f(ulong bootflag) 278 { ... 291 gd->mon_len = _bss_end_ofs; 292 #ifdef CONFIG_OF_EMBED 293 /* Get a pointer to the FDT */ 294 gd->fdt_blob = _binary_dt_dtb_start; 295 #elif defined CONFIG_OF_SEPARATE 296 /* FDT is at end of image */ 297 gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); 298 #endif 299 /* Allow the early environment to override the fdt address */ 300 gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, 301 (uintptr_t)gd->fdt_blob); 302 303 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { 304 if ((*init_fnc_ptr)() != 0) { 305 hang (); 306 } 307 } ...

board_init_f()
--243--> 全局的函数指针数组,每个指针都是int (*ptr)(void)型的。
--291-->mon_len 通过链接脚本可以知道存放的是 uboot 代码大小;
--294-->fdt_blob 存放设备数地址;
--303--遍历函数指针数组init_sequence中的每一个成员,就是将数组中的每一个初始化函数都执行一次,这种写法可以借鉴

crt0.S

函数board_init_f()返回后,继续执行crt0.S中115行之后的部分,主要的工作是执行代码自搬移,代码重定位等工作,执行完这些之后,我们我们找到了最感兴趣的下面这几句

163         /* call board_init_r(gd_t *id, ulong dest_addr) */
164         mov     r0, r8                  /* gd_t */
165         ldr     r1, [r8, #GD_RELOCADDR] /* dest_addr */
166 /* call board_init_r */ 167 ldr pc, =board_init_r /* this is auto-relocated! */

--167-->跳转到board_init_r函数执行,这次跳出去这个文件的语句就执行完毕了,不会再回来了

board.c

这也是最后一次跳转到这个文件了,执行额函数如下

519 void board_init_r(gd_t *id, ulong dest_addr) 520 { 521 ulong malloc_start; 522 #if !defined(CONFIG_SYS_NO_FLASH) 523 ulong flash_size; 524 #endif 525 526 gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ 527 bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); 528 529 monitor_flash_len = _end_ofs; 530 531 /* Enable caches */ 532 enable_caches(); 533 534 debug("monitor flash len: %08lX\n", monitor_flash_len); 535 board_init(); /* Setup chipselects */ ... 650 /* set up exceptions */ 651 interrupt_init(); 652 /* enable exceptions */ 653 enable_interrupts(); 667 eth_initialize(gd->bd); ... 701 /* main_loop() can return to retry autoboot, if so just run it again. */ 702 for (;;) { 703 main_loop(); 704 } 705

board_init_r()
--532-->很多紧急工作都做完了,可以打开cache了
--535-->关键!!!这个就是我们苦苦寻找的板级定制文件的xxx.c的入口函数!!!
--651-->中断初始化
--653-->使能中断
--667-->网卡初始化,函数的实现在net/eth.c,会回调板级xxx.c中的board_eth_init()
--703-->执行超循环,主要功能是处理环境变量,解析命令,也就是uboot中和我们交互的命令的解析工作都在这里执行!!!

main_loop()与启动内核

main_loop()的实现在common/main.c,它的主要功能就是循环检测输入的命令并执行,其中一个环境变量bootdelay(自启动)的设置决定了是否启动内核,如果延时大于等于零,并且没有在延时过程中接收到按键,则引导内核。ootloader 要想启动内核,可以直接跳到内核的第一个指令处,即内核的起始地址,这样便可以完成内核的启动工作了。但是要想启动内核还需要满足下面的一些条件,这些条件在Linux内核文档"/Documentation/kernel-parameters.txt"中有说明,
1、cpu 寄存器设置

* R0 = 0
* R1 = 机器类型 id
* R2 = 启动参数在内存中的起始地址

2、cpu 模式

* 禁止所有中断
* 必须为 SVC(超级用户)模式

3、Cache、MMU

* 关闭 MMU
* 指令 Cache 可以开启或者关闭
* 数据 Cache 必须关闭

4、设备

* DMA 设备应当停止工作

5、PC 为内核的起始地址

关于uboot的启动分析,本文只是冰山一角的一丢丢,不过希望通过我的这一堆废话下来,能帮助你对uboot的启动流程有一个整体的认识,当然,如果文中有错误,欢迎批评指正^-^

转载于:https://www.cnblogs.com/icefree/p/8491270.html

从0移植uboot (二) _启动流程分析相关推荐

  1. 从0移植uboot (二) _uboot启动流程分析

    经过了上一篇的配置,我们已经执行make就可以编译出一个uboot.bin,但这还不够,首先,此时的uboot并不符合三星芯片对bootloader的格式要求,同时,此时的uboot.bin也没有结合 ...

  2. SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext

    SpringBoot版本:2.1.1      ==>启动流程分析汇总 接上篇博客Spring Boot 2.1.1(十一)启动流程分析之设置系统属性spring.beaninfo.ignore ...

  3. Uboot 2017.01 启动流程分析

    前言 2017.01 UBoot包含两个阶段的启动,一个是SPL启动,一个是正常的启动我们称为第二阶段Uboot.当然,我们也可以选择使用SPL和不使用. 在编译的过程中,是先编译第二阶段Uboot, ...

  4. mini2440 u-boot linux 内核启动,u-boot.2012.10——mini2440(二、启动流程分析)

    参考资料:https://blog.csdn.net/suiyuan19840208/article/details/7239949 https://blog.csdn.net/pugu12/arti ...

  5. u-boot v2018.01 启动流程分析

    make smdkc100_defconfig 以被默认支持的smdkc100单板为背景分析u-boot v2018.01 参考图1可知uboot code链接顺序:                  ...

  6. Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

    uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...

  7. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的"board->machine->arc ...

  8. GEF入门实例_总结_04_Eclipse插件启动流程分析

    一.前言 本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏 注意到app目录下的6个类文件. 这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们 ...

  9. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

最新文章

  1. 喵哈哈村的魔法考试 Round #1 (Div.2) 题解源码(A.水+暴力,B.dp+栈)
  2. webpack 使用别名(resolve.alias)解决scss @import相对路径导致的问题
  3. windows下部署redis
  4. Spring的事件发布机制
  5. 第三方提权之serv-u提权
  6. raid5坏了一块盘怎么办_机械硬盘的坏道处理——屏蔽之
  7. lingo入门(数据部分)
  8. windows安全模式_Windows 安全模式的功能和作用
  9. python爬虫网络出错怎么办_python爬虫之headers处理、网络超时问题处理
  10. grayscale实现全站及局部变黑的效果 – 兼容IE/FF等浏览器
  11. 面试准备——springboot相关
  12. Java程序员集合框架面试题
  13. Django根据现有数据库建立model
  14. html如何做幻灯片效果,超酷的CSS3幻灯片效果
  15. 梯度下降与支持向量机
  16. Flask蓝本创建名称错误导致的werkzeug.routing.BuildError
  17. 【随笔记】NDK 编译开源库 SQLite3
  18. Excel如何一键删除重复行?Leo老师告诉你
  19. HDU - 1242
  20. 计算(输入计算式得出结果)

热门文章

  1. 20135302魏静静——linux课程第三周实验及总结
  2. mac下安装sublime text2插件less2css
  3. java web 三层架构
  4. 非寻常实习记Ⅱ:改变中的快乐成长
  5. Android 自动化测试框架简介
  6. 06-06 Jenkins 邮件报警机制
  7. tableau两个不同的图合并_【书稿摘要】Tableau地图函数(下)
  8. ai面试的优缺点_面试也能开“外挂”?领英AI做了什么
  9. idea中出现Please, configure Web Facet first问题
  10. java se ee me都有什么区别?