一、概述

uboot 的启动流程在网上有很多大佬记录,但是了对于像我这样的新手就有些困难了,而我也不做 uboot 相关的工作,所以没必去研究代码,这里我特意整理了一下,以流程图的形式展现代码执行的流程,方便快速了解 uboot 是怎么启动的,此笔记就不进行代码分析了,主要记录 uboot 启动流程中所执行的函数已经函数所在的文件,需要了解函数中的代码实现,可以结合 uboot 源码和正点原子的开发手册或者其他博客。

注意: uboot 运行过程中都是以单线程执行的,所以分析启动流程的时候相对多线程好理解。流程中有些函数名和文件位置可能不一样,但是不要慌,就这样慢慢的找下去就可以快速了解到自己的工程是怎么启动的了

二、SOC 启动流程

uboot 只是一个启动引导向,最终的目的是启动 linux 那么即使不使用 uboot 也可以用其他的引导向,但是目前主流都是使用的 uboot,所以这里对uboot的执行函数进行了整理,方便大家好阅读 uboot 的工程源码,在了解uboot之前,需要了解一下芯片的都做啥了。

看到这个笔记的小伙伴们,应该都知道,系统的启动方式有很多种,比如 SD、mmc、norflash、nandflash等,那么我们 uboot 就可以存在其中一个硬件设备中,芯片是怎么知道 uboot 在那里又是怎么去执行 uboot 代码的?

半导体厂商在制作芯片的时候,会在芯片内部的 ROM 中植入一小段程序,上电后芯片会先执行内部的代码,然后判断我们是以什么方式启动,并在对应的设备中找到 uboot 程序,最终启动 linux 系统,当然芯片内部的这段代码还是比较麻烦的,并且厂家也不会公布这段代码,这里我就不做过多介绍了,需要的小伙伴可以去了解一下。

芯片内部的 SRAM 是比较小的,不足以跑复杂的程序,所以当芯片找到 uboot 程序后,会执行 uboot 的一小段程序,这小段程序叫做uboot SPL,他的主要目的就是初始化芯片使用的外部 RAM 然后将剩余的 uboot 放到外部的内存中运行,提高芯片的运行能力,具体可以了解这位大佬的博客:u-boot (3) —— spl

到这里差不多了,接下来可以了解 uboot 的启动流程了。

三、uboot 入口

在分析程序之前,都会从入口函数开始,从上图可知uboot 的入口是 u-boot.lds 链接脚本开始的。可能会有小伙变怎有疑问,我是怎么知道最先执行的 u-boot.lds 链接脚本,其实在了解一个工程之前,会先从 makefile 开始,只是我 uboot 中的makefile 比较复杂,我还有些不了明白,这里就不献丑了,有需要的小伙伴可以先看大佬的分析,所以从makefile文件中知道,最先执行的是 u-boot.lds 链接脚本。

  1. u-boot.lds

    分析 uboot 顶层 Makefile 时,得知 uboot 的启动是从链接脚本 u-boot.lds 文件开始的,所以我们需要找到 u-boot.lds 的文件位置,如果没有编译的话,最初的链接脚本在 arch/arm/cpu/ 路径下,但是这个不是最终使用的链接脚本,在编译时会在 uboot 的根目录下生成 u-boot.lds 文件,所以在编译过程中使用的是根目录下的连接脚本。

    链接脚本中描述了 uboot 的段的内存使用地址,以及中断向量表的地址,可以结合 uboot 根目录下的 u-boot.map 文件进行分析,这里就不详细介绍了。

  2. _start

    打开链接脚本后,会看到 ENTRY(_start) 声明的入口函数 _start ,而函数 _start 在 arch/arm/lib/vectors.S 文件中,此函数的作用是声明一些中断函数,当上电启动时会跳转到 reset 复位函数。

  3. reset

    reset 函数在文件 arch/arm/cpu/armv7/start.S 文件中,不同的芯片文件位置不同,我使用的芯片是armv7架构的,在 reset 函数中有 save_boot_params 、cpu_init_cp15 、 cpu_init_crit 、 _main 函数

    • save_boot_params 也在 start.S 文件中,主要是设置 CPU 的为SVC模式。
    • cpu_init_cp15 也在文件 start.S 中,主要作用是设置 CP15 相关的内容,比如关闭 MMU 啥的。
    • cpu_init_crit 也在文件 start.S 中,cpu_init_crit 内部仅仅是调用了函数 lowlevel_init。
  4. lowlevel_init

    lowlevel_init函数在文件 arch/arm/cpu/armv7/lowlevel_init.S 中,主要用于设置堆栈以调用C函数执行进一步的初始化,lowlevel_init 函数中调用了 s_init 函数。

  5. s_init

    s_init 函数在 arch/arm/cpu/armv7/xxx/soc.c 文件中,有的芯片型号中没有 soc.c 文件,而 s_init 函数没有什么作用,就可以不用了解了 。

三、uboot 外设初始化

此流程主要是完成 uboot 工作的基本条件,并初始一些外设,代码很多,初次学习最好不要直接对函数进行具体的分析,先了解框架。

  1. _main

    _main 函数定义在文件 arch/arm/lib/crt0.S 中,在 _main 函数主要有 board_init_f 、 relocate_code 、relocate_vectors 、 c_runtime_cpu_setup 、 board_init_r 函数

  2. board_init_f

    board_init_f 函数在文件 common/board_f.c 中,如下图所示:

    board_init_f 函数中会执行 init_sequence_f 表中的函数,主要有两个工作

    • 初始化一系列外设,比如串口、定时器,或者打印一些消息等。
    • 初始化 gd 的各个成员变量,uboot 会将自己重定位到 DRAM 最后面的地址区域,也就是将自己拷贝到 DRAM 最后面的内存区域中。

    其中 serial_init 函数初始串口后,我们就可以使用 printf 函数打印日志,打印后便会在控制台中看到相应的信息,和C语言中的用法一样,

    display_options 函数中会打印 uboot 的版本信息等,具体的函数实现只能后后面需要的时候自行了解了。

  3. relocate_code

    relocate_code 函数在文件 arch/arm/lib/relocate.S 中,主要作用是用于代码拷贝。

  4. relocate_vectors

    relocate_vectors 函数在文件 arch/arm/lib/relocate.S 中,主要作用是用于重定位向量表。

  5. c_runtime_cpu_setup

    c_runtime_cpu_setup 函数在文件 arch/arm/cpu/armv7/start.S 中

  6. board_init_r

    board_init_r 函数在文件 common/board_r.c 中,主要作用是完成 board_init_f 没有初始化的外设,以及一些后续工作。也会执行 init_sequence_r 表中的函数,在函数最后会调用 run_main_loop 函数。

  7. run_main_loop

    函数 run_main_loop 也在文件 common/board_r.c 中,此函数主要是在死循环中调用 main_loop() 函数

四、uboot 命令执行

  1. main_loop()

    main_loop 函数在文件 common/main.c 中,在函数中主要执行 autoboot_command 和 cli_loop 函数。

  2. autoboot_command

    autoboot_command 函数在 common/autoboot.c 中,其中会通过 Abortboot 函数判断在控制台打印的倒计时结束之前是否有按键按下,如果存在按键按下时,会执行 run_command_list 函数进入 uboot 系统。反之会返回到 main_loop 函数中执行 cli_loop 函数

    注意:run_command_list 函数也在 cli.c 文件中,只是流程图不好直观的表示出来。

  3. cli_loop

    cli_loop 在文件 common/cli.c 中,主要作用是执行相应的命令操作,在 cli_simple_loop 函数存在一个死循环,用于接收控制台的命,并处理相应的命令工作。

  4. cli_simple_run_command

    cli_simple_run_command 函数在 common/cli_simple.c 文件中,主要作用是执行相应的命令操作,从图中可以看出,不论是正常启动 linux 或 进入uboot系统,最终都会执行此函数,在函数中会调用 find_cmd 查找命令,调用 cmd_call 执行命令操作。

  5. find_cmd

    find_cmd 函数在 common/command.c 文件中,主要作用是在映射表中查找相应的命令是否存在,命令通过宏 U_BOOT_CMD 进行定义的。

  6. find_call

    find_call 函数在 common/command.c 文件中,主要作用是调用 find_cmd 中查找到的 do_xxx 函数,最终执行相应的命令操作。

  7. do_xxx

    do_xxx 函数在 cmd 目录下,作用就是命令操作的实现函数,比如启动函数 bootz 或 bootm ,所以从图中可知,不论是正常启动 linux 还是在 uboot 中通过命令启动 linux 原理都是一样的,最终也是执行 bootz 或 bootm 命令。

五、bootm 启动 Linux 内核



注意:这里我就没有画对应的流程图了,因为在正点原子的教材中有相应的流程图,所以我这里就直接引用了。关于启动linux 的流程我也没有仔细分析,只是大体看了一下,此笔记的主要原因是我好奇 uboot 都做了些什么,学习驱动开发是否有必要去学习 uboot 中的驱动开发。

通过对 uboot 流程的启动分析,发现 uboot 中的驱动主要根据自己在启动阶段的去求是实现驱动即可,因为在启动 linux 的时候,会在对外设驱动进行实现,达到同一管理,并且在 linux 启动后 uboot 就没有作用了,想在再次进入uboot,执行重新启动。

  1. bootm

    bootm 命令的执行函数为 do_bootm,在文件 cmd/bootm.c 中,do_bootm 最后调用的就是函数 do_bootm_states

  2. do_bootm_states

    do_bootm_states 函数定义在文件 common/bootm.c 中,函数会根据不同的 BOOT 状态执行不同的代码段。

  3. bootm_start

    bootm_start 函数在 common/bootm.c 文件中,作用是清空 images 结构体,获取 uboot 的环境变量 verify 的值

  4. bootm_find_os

    bootm_find_os 函数,函数在 common/bootm.c 文件中,在函数中会调用 boot_get_kernel,

    boot_get_kernel 会根据 bootm 传过来的参数去获取 uImage(镜像)的存储地址,如果 bootm 没有参数就使用全局变量 load_addr,最后会调用 image_get_kernel 函数进行 kernel 格式校验。

  5. bootm_find_other

    bootm_find_other 函数common/bootm.c 文件中,主要作用是获取 ramdisk 或者设备树信息。

  6. bootm_disable_interrupts

    bootm_disable_interrupts 的作用是函数禁用中断。

  7. do_bootm_linux

    do_bootm_linux 函数在 arch/arm/lib/bootm.c 文件中,次函数就是最终启动 Linux 内核的函数。

到此 uboot 的启动流程也算完成,有什么不对的地方望大佬指出,我会积极学习。

参考链接

u-boot (3) —— spl:https://blog.csdn.net/zhoutaopower/article/details/123133291

UBOOT 启动流程的更多相关文章

  1. 嵌入式Linux驱动学习之路(五)u-boot启动流程分析

    这里说的u-boot启动流程,值得是从上电开机执行u-boot,到u-boot,到u-boot加载操作系统的过程.这一过程可以分为两个过程,各个阶段的功能如下. 第一阶段的功能: 硬件设备初始化. 加 ...

  2. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  3. 1.移植uboot-分析uboot启动流程(详解)

    本节总结: uboot启动流程如下: 1)设置CPU为管理模式 2)关看门狗 3)关中断 4)设置时钟频率   (FCLK:HCLK:PCLK=1:2:4,FCLK=120Mhz) 5)关mmu,初始 ...

  4. 海思uboot启动流程详细分析(三)【转】

    1. 前言 书接上文(u-boot启动流程分析(二)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_init_r所代表的. ...

  5. RK3288 uboot启动流程

    VS-RK3288嵌入式板卡 U-boot 启动流程小结 bl    board_init_f -> crt0.S    initcall_run_list(init_sequence_f) - ...

  6. u-boot移植随笔(7):u-boot启动流程简图【转】

    转自:http://www.latelee.org/porting-uboot/u-boot-porting-bootstrap.html u-boot移植随笔:u-boot启动流程简图 画上面这张图 ...

  7. am335x uboot启动流程分析

    基本指令含义 .globl _start .globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号 b,bl b是不带返回的跳转  bl带返回的跳 ...

  8. imx6 uboot启动流程分析

    参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...

  9. Uboot启动流程分析(三)

    1.前言 在前面的文章Uboot启动流程分析(二)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12002764.html 已经对_main函数的整个大体调用流程 ...

  10. Uboot启动流程分析(二)

    1.前言 在前面的文章Uboot启动流程分析(一)中,链接如下: https://www.cnblogs.com/Cqlismy/p/12000889.html 已经简单地分析了low_level_i ...

随机推荐

  1. CentOS 7.7系统安装Redis 6.0.3

    前提操作 避免出现如下的错误 yum -y install gcc tcl yum -y install centos-release-scl yum -y install devtoolset-9- ...

  2. 16. 综合使用tail、forward、copy和stdout

    通过一个例子进行阶段总结. 本示例使用到如下插件:in_tail, out_copy, out_stdout, out_forward, in_forward. 本示例包含两个节点: node_for ...

  3. CentOS 7.9 安装 MySQL 5.7.35

    CentOS 7.9 安装 MySQL 5.7.35 1 下载地址:https://downloads.mysql.com/archives/community/ 2 mysql5.7.35 安装包上 ...

  4. this硬绑定

    一.this显示绑定 this显示绑定,顾名思义,它有别于this的隐式绑定,而隐式绑定必须要求一个对象内部包含一个指向某个函数的属性(或者某个对象或者上下文包含一个函数调用位置),并通过这个属性间接 ...

  5. 【JavaScript排序】 sort()方法(解决null、undefined、0之间的排序(混乱)问题)

    JavaScript排序 - sort()方法 --解决null.undefined.0之间的排序(混乱)问题 一.普通的数组排序 ​ JavaScript中用方法sort()为数组排序.sort() ...

  6. 【强烈推荐】用glob库的一行命令显著加速批量读取处理数据

    在我们气象领域,对数据进行批处理随处可见,尤其是在处理模式数据的时候.为了能让这个过程加速,很多大佬们提出了不同的方法,比如使用numba库进行计算.使用dask库进行并行等等,都是非常好的加速手段. ...

  7. Java中的名称命名规范

    包名:多单词组成时所有字母都小写:xxxyyyzzz 类名.接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz 变量名.方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首 ...

  8. JSP Webshell免杀设计

    JSP Webshell免杀设计 @author:drag0nf1y 介绍 什么是Webshell? 被服务端解析执行的php.jsp文件 什么是RCE? remote command execute ...

  9. ajax-Xhr

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Python学习之实例2

    一.根据输入的各科成绩统计学生成绩是否达标 1 (背景:输入学生数量,以及各个学生语文.数学.英语.历史四科的成绩,如果总成绩小于 240,则成绩不达标,否则成绩合格) 2 3 #coding=utf ...