一、概述

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. FastDFS与nginx配置使用的配置信息

    # 获取图片 location /group[1-9]/M0[0-9] { root /home/vdc1/fastdfs_storage/data; ngx_fastdfs_module; } # ...

  2. 关于Azure-AzCopy在Linux环境下的安装

    关于Azure云中有一个AzCopy工具,它 是一个命令行实用工具,支持各种操作系统 AzCopy可以用于向存储帐户复制上传文件,也可以从存储账号下载文件到本地 这里笔者主要记录一下在Linux-x8 ...

  3. BUUCTF-PWN-第一页writep(32题)

    温故而知新,可以为师矣.所以花了几天时间重新做了下 buuctf 的 pwn 题,先发下第一页共 32 题的题解.还有如果题解都很详细那么本文就太长了,写起来也浪费时间,所以比较简单的题就直接丢 ex ...

  4. 如何编写 Pipeline 脚本

    前言 Pipeline 编写较为麻烦,为此,DataKit 中内置了简单的调试工具,用以辅助大家来编写 Pipeline 脚本. 调试 grok 和 pipeline 指定 pipeline 脚本名称 ...

  5. 在js中正则表达式验证小时分钟,将输入的字符串转换为对应的小时和分钟

    文章目录 1.预备知识 2.在js中的代码片段 3.测试结果 1.预备知识 splict()方法 Date()的相关方法 setHours()的用法 2.在js中的代码片段 //验证小时和分钟 var ...

  6. 齐博x1内容页中下一页上一页的标签

    在模板中分别插入如下代码即可 前一页 {:fun('content@prev',$info,20)} 后一页 {:fun('content@next',$info,20)} 复制 其中20代表取标题多 ...

  7. Codeforces1695 D1.+D2 Tree Queries

    题意 给一个n个点的无向图,其中有一个隐藏点X,可以进行一组询问S来确定S是n个节点中的哪个点.S包括k个询问节点.询问返回的值也为k个值,每个值为X点到每个询问节点的最短路距离,求k最小为多少. 提 ...

  8. golang中的选项模式

    索引 https://waterflow.link/articles/1663835071801 当我在使用go-zero时,我看到了好多像下面这样的代码: ... type ( // RunOpti ...

  9. k8s集群正常kubectl用不了

    今天有个客户反馈k8s集群服务正常,业务也正常.kubectl get no敲入这个命令就有夯住了 仔细去检查配置发现少了一个config 最后在master-2上的config文件cp拷一份过来问题 ...

  10. 解决oracle18c没有hr用户

    1.查找系统变量ORACLE_HOME的值 2.按照路径寻找sql文件 ORACLE_HOME变量值+demo\schema\human_resources 3.把hr_main.sql脚本文件放在此 ...