文章目录

  • 一、U-Boot
    • 1.1 如何下载
  • 二、u-boot是如何引导内核的
    • 2.1 u-boot连接脚本
      • 2.1.1 扫盲
    • 2.2 u-boot.lds

一、U-Boot

对于嵌入式玩家来说,uboot是再熟悉不过的了,它属于BootLoader的一种,而BootLoader是在操作系统内核运行之前运行,也就是引导硬件从上电到操作系统的过程,BootLoader就是这么一段小程序(当然在这之前还有一段存在于硬盘MBR中的启动代码,这就不描述了)。
宏观的看,BootLoader主要的工作就是初始化硬件设备、建立内存空间的映射表,最终创建一个适当的系统软硬件环境。
微观的看BootLoader程序会先初始化 DDR 等外设,然后将 Linux 内核从 flash(NAND、NOR FLASH、SD、MMC 等)拷贝到DDR 中,最后启动 Linux 内核。当然了,BootLoader的实际工作要复杂的多,但是它最主要的工作就是启动 Linux 内核。
BootLoader有很多,本篇主要讲用得最广泛的u-boot。

1.1 如何下载

正常来说,学习u-boot去了了解工作原理或者是用于移植适配工作,对于移植一般而言,芯片厂商都会提供支持自家芯片的uboot版本,因为是芯片厂商自己维护的,而且是经过定制的,所以支持会很全,用户可以很方便的到芯片产商的官网下载,比如TI、Xilinx等。
如果是纯粹想阅读源码,那么可以到uboot 官网去下载,如图所示:



这里提供的方法有几种,你可以通过git直接从denx下载,也可以通过https或ftp的方式下载;

git方式

u-boot ftp服务器

本篇以u-boot2018.01开始;

二、u-boot是如何引导内核的

2.1 u-boot连接脚本

很多朋友刚开始接触uboot可能会一头雾水,要怎么开始入手进行分析,干啃整套uboot源码明显是不现实的,要分析uboot的启动流程,需要先弄清楚uboot的作用,像前面所述,uboot初始化硬件,引导内核,那么怎么开始初始化呢?第一行程序在哪里呢?从哪里开始入手去分析?
其实有办法,那就是uboot的链接脚本,我们可以从u-boot.lds入手分析。

2.1.1 扫盲

网上有很多关于u-boot.lds的解析的文章,但是都没有说得清楚根源,这里简单得总结一下,大伙应该都知道编译分为四个步骤:

1. 预处理
2. 编译
3. 汇编
4. 链接

预处理阶段:像很多程序中都有包含头文件、有宏定义、有很多注释代码等等,在预处理过程中会把所有包含的头文件的内容插入到该程序的文本中,把所有的宏定义直接展开,同时删除注释代码,添加行号和文件表示等

可以通过以下指令得到预处理后的文件

# gcc -E xxx.c -o xxx.i

编译阶段:在该阶段中编译器开始检查代码的规范性即语法分析、语义分析等,也是将高级语言转化成汇编语言的过程

可以通过以下指令得到编译后的文件

# gcc -S xxx.i -o xxx.s

汇编阶段:该阶段很多人搞混,以为汇编阶段就是把高级语言转成汇编代码,其实在上一步已经完成了,该阶段只要是将前面编译阶段生成.s文件转成二进制也就是计算机可以读懂的机器语言的过程

可以通过以下指令得到汇编后的文件

# gcc -c xxx.s -o xxx.o

链接阶段:指前面生成的二进制文件,该二进制文件还不可以直接执行,因为很多程序都使用到了比如标准库啊、链接了别的源代码啊等等,这个时候所有生成的.o文件都是离散的,需要一个规则将所有的库按部就班的绑在一起,这个过程就叫链接过程

可以通过一下指令的到链接后的文件

# gcc xxx.o -o xxx

2.2 u-boot.lds

前面针对编译过程进行了简略的介绍,在链接阶段的介绍中提到一个链接规则,这里的**.lds**文件就是一个链接脚本,链接脚本的主要作用相信看了前面的解释应该都清楚,主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局 ,博客园中有一篇详细的解读,大伙有兴趣的话可以自行去研究,这里主要讲解uboot就不过于发散了。
怎么入口看uboot源码呢,首先可以通过u-boot.lds看起,这里有必要说明的是u-boot.lds有两个,一个在arch/arm/cpu/u-boot.lds,一个是根目录下的u-boot.lds,前者不是最终使用的链接脚本,后者才是以前者为基础生成的一套完整的链接脚本,需要先编译uboot后才生成得链接文件,这里有必要区分一下,根目录下的链接脚本如下:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{. = 0x00000000;. = ALIGN(4);.text :{*(.__image_copy_start)*(.vectors)arch/arm/cpu/armv7/start.o (.text*)*(.text*)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : {*(.data*)}. = ALIGN(4);. = .;. = ALIGN(4);.u_boot_list : {KEEP(*(SORT(.u_boot_list*)));}. = ALIGN(4);.__efi_runtime_start : {*(.__efi_runtime_start)}.efi_runtime : {*(efi_runtime_text)*(efi_runtime_data)}.__efi_runtime_stop : {*(.__efi_runtime_stop)}.efi_runtime_rel_start :{*(.__efi_runtime_rel_start)}.efi_runtime_rel : {*(.relefi_runtime_text)*(.relefi_runtime_data)}.efi_runtime_rel_stop :{*(.__efi_runtime_rel_stop)}. = ALIGN(4);.image_copy_end :{*(.__image_copy_end)}.rel_dyn_start :{*(.__rel_dyn_start)}.rel.dyn : {*(.rel*)}.rel_dyn_end :{*(.__rel_dyn_end)}.end :{*(.__end)}_image_binary_end = .;.bss_start __rel_dyn_start (OVERLAY) : {KEEP(*(.__bss_start));__bss_base = .;}.bss __bss_base (OVERLAY) : {*(.bss*). = ALIGN(4);__bss_limit = .;}.bss_end __bss_limit (OVERLAY) : {KEEP(*(.__bss_end));}/DISCARD/ : { *(.dynsym) }/DISCARD/ : { *(.dynbss*) }/DISCARD/ : { *(.dynstr*) }/DISCARD/ : { *(.dynamic*) }/DISCARD/ : { *(.plt*) }/DISCARD/ : { *(.interp*) }/DISCARD/ : { *(.gnu*) }/DISCARD/ : { *(.ARM.exidx*) }/DISCARD/ : { *(.gnu.linkonce.armexidx.*) }
}

链接脚本可以决定生成的uboot镜像中所有的.o文件和.a文件的链接地址。

  • 前两行指的是指定输出格式、小端模式的ELF模式和输出架构,如本篇中平台为ARM,不做解析;
  • 第3行, ENTRY(_start) :将符号_start的值设置成入口地址,_start 在文件 arch/arm/lib/vectors.S 中有定义;
  • 从第4行开始进入正文,第6-7行将定位器符号设置为0x00000000,"."代表当前位置,并且按4字节对齐;
  • 第10行,使用grep -nr "__image_copy_start"在uboot根目录下检索,可以看到如下:
  • uboot.map是uboot的映射文件,可以通过该文件看到某个文件或者函数被链接到什么地址,打开uboot.map文件后如下:
  • u-boot.map这个文件很长,我们可以通过检索想要找的函数链接位置,比如检索__image_copy_start,从1256行和1258行可以看出,.text和__image_copy_start的起始地址都为0x400000;
  • 回到u-boot.lds源码部分,第11行是vectors 段, vectors 段保存中断向量表。从上图第1262行可以看出, vectors段的起始地址也是0x400000,说明整个uboot 的起始地址就是0x400000;
  • 第12行,arch/arm/cpu/armv7/start.oarch/arm/cpu/armv7/start.s编译出来的代码放到了中断向量表后面;
  • 第13行为大家耳熟能详的text段,即其他代码段;像后续还有第16行的只读代码段、第18行的数据段等等,这些位置都是由该连接脚本决定的;
  • 第71~82行,.bss_start标号指向bss段的开始位置以及结束的位置,bss段值用于存放程序中未初始化的全局变量的内存区域,一般该段中的变量会由系统初始化为0;
  • 这里面标定的一些变量在后续分析还会继续出现,比如前面提到的__image_copy_start,该变量地址从0x400000开始,标志uboot拷贝的首地址;__image_copy_end顾名思义就是uboot拷贝的结束地址,后面做了一个表格以供参考:
变量 描述
__image_copy_start uboot拷贝的首地址
__image_copy_end uboot拷贝的结束地址
_image_binary_end 二进制镜像结束地址
__bss_start bss 段开始地址
__bss_end bss 段结束地

以上的变量可以通过上述的方法到u-boot.map文件中进行检索,除了__image_copy_start地址不变,其余的地址会根据uboot的修改,导致地址变化是很正常的,这与编译出来的文件大小、多少有关,与uboot配置以及编译器优化等级都有关联,非必要情况下不要过于纠结这个数值的大小。

以上简述了uboot的作用以及如何入手去开展uboot的学习,后面将进行细致的分析。

以上是个人工作学习的回顾总结,有帮助的可以点个赞!

u-boot移植篇——了解u-boot相关推荐

  1. Spring Boot第二篇:Spring Boot配置文件详解

    springboot采纳了建立生产就绪Spring应用程序的观点. Spring Boot优先于配置的惯例,旨在让您尽快启动和运行.在一般情况下,我们不需要做太多的配置就能够让spring boot正 ...

  2. springboot导包显示不存在_基础篇:Spring Boot入门体验(图文教程)

    优质文章,及时送达 什么是 Spring Boot? Spring Boot 是由 Pivotal 团队提供的全新框架.Spring Boot 是所有基于 Spring Framework 5.0 开 ...

  3. 【树莓派不吃灰】命令篇⑥ 了解树莓派Boot分区,学习Linux启动流程

    目录 1. Linux启动过程 1.1 内核引导 1.2 运行init初始化进程 -- 初始化系统环境 1.3 运行级别 -- runlevel 1.4 系统初始化 -- 加载开机启动程序 1.5 用 ...

  4. 玩转 Spring Boot 应用篇(搭建菜菜的店铺)

    0.  0.0. 历史文章整理 玩转 Spring Boot 入门篇 玩转 Spring Boot 集成篇(MySQL.Druid.HikariCP) 玩转 Spring Boot 集成篇(MyBat ...

  5. 【任务篇】Spring Boot 整合 XXL-JOB 实现定时任务

    写在最前 之前介绍过[任务篇]Spring Boot 内置定时任务 Spring Task 实现定时任务,这次介绍 XXL-JOB 实现定时任务. XXL-JOB XXL-JOB 是一个分布式任务调度 ...

  6. .net core 应用程序“default web site”中的服务器错误_Net程序员讲JAVA系列——Spring Boot“科普篇”...

    通过Spring Boot,可以轻松地创建独立的,基于生产级别的基于Spring的应用程序,您可以"运行"它们. 我们对Spring平台和第三方库持固执己见的观点,因此您可以以最小 ...

  7. 史上最全,Spring Boot入门篇总结,收藏起来慢慢看

    Spring Boot是Spring家族下的一个全新开发框架,其设计目的主要是用来简化Spring应用的创建及开发过程,它提供了自动配置,starter依赖等特性,从而使开发人员从大量的XML配置中解 ...

  8. linux系统移植篇(二)—— Uboot使用介绍

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

  9. T2080 U-BOOT与OS内核移植 u-boot移植篇(一)——创建新目标板的u-boot工程

    T2080 U-BOOT与OS内核移植 u-boot移植篇(一)--创建新目标板的u-boot工程 一.创建新目标板文件夹并修改相应文件 1.创建新目标板文件夹 2.修改t2080tpm文件夹中的相应 ...

  10. STM32MP157系列教程连载-Linux系统移植篇4:STM32MP1微处理器之Bootloader移植

    STM32MP157系列教程连载-Linux系统移植篇4:STM32MP1微处理器之Bootloader移植 第 1 章 BootLoader(Uboot)移植 1.1 实验原理 1.1.1 概念 简 ...

最新文章

  1. DocumentManager 在标签位置显示气泡框 z
  2. 访问Access数据库需要注意的问题
  3. php表单 提交数据,PHP表单提交数据
  4. Python库:wordcloud库介绍、政府工作报告词云、自定义背景词云
  5. 3h精通OpenCV(一)- 读取图像视频与网络摄像头
  6. AvalonDock
  7. 一些有意思的js代码
  8. RabbitMQ登录时guest用户提示User can only log in via localhost
  9. killer queen ctf
  10. 微信企业邮箱添加至Windows邮箱客户端
  11. 华为27asph是什么型号_华为官宣新增P40 Pro+等27款机型支持换原装电池,有你的手机吗?...
  12. 2020年前端安全综述-填坑记
  13. tikz包 安装_TeX系列: tikz pgf 宏包安装步骤
  14. ISO13335标准简介
  15. Android之仿win8的Metro界面
  16. 试一试你就知道:做到自控和自律也不是那么难!!
  17. RPC 和 Web Service 有什么区别?
  18. 你还不懂线程池的设计及原理吗?掰开揉碎了教你设计线程池
  19. top20万_Q3全球超休闲游戏下载、收入TOP20:猎豹移动砖块消消消内购收入高达4390万...
  20. 视频教程-微信小程序系统教程python版[3/3阶段]_微信小程序支付-手游开发

热门文章

  1. 简单理解云桌面的模板,桌面池和虚拟机的概念
  2. 一、MacBook Pro 使用eGPU-WTG篇,mac告别虚拟机
  3. 导出Fbx和obj的工具
  4. C++模板与泛型编程:模板特例化
  5. 为什么VR依然没有出现烧钱向的3A级游戏?
  6. 如何区分“衬线体字”和“无衬线体字”?Linux Mint中如何安装字体?
  7. 怎样将excel表格导入天正_怎样把excel表格转换成cad读取
  8. 最全面的shiro知识点学习
  9. 给人脸戴上口罩,Python实战项目来了
  10. 笨方法学python3怎么样_笨办法学Python3