I.MX6ULL_Linux_系统篇(17) uboot分析-启动linux
bootz 启动 Linux 内核
images 全局变量
不管是 bootz 还是 bootm 命令,在启动 Linux 内核的时候都会用到一个重要的全局变量:images, images 在文件 cmd/bootm.c 中有如下定义:![]()
images 是 bootm_headers_t 类型的全局变量, bootm_headers_t 是个 boot 头结构体,在文件include/image.h 中的定义如下:


第 335 行的 os 成员变量是 image_info_t 类型的,为系统镜像信息。
第 352~362 行这 11 个宏定义表示 BOOT 的不同阶段。
接下来看一下结构体 image_info_t,也就是系统镜像信息结构体,此结构体在文件include/image.h 中的定义如下:

全局变量 images 会在 bootz 命令的执行中频繁使用到,相当于 Linux 内核启动的“灵魂”。
do_bootz 函数
bootz 命令的执行函数为 do_bootz,在文件 cmd/bootm.c 中有如下定义:
第 629 行,调用 bootz_start 函数, bootz_start 函数执行过程稍后分析。
第 636 行,调用函数 bootm_disable_interrupts 关闭中断。
第 638 行,设置 images.os.os 为 IH_OS_LINUX,也就是设置系统镜像为 Linux,表示我们要启动的是 Linux 系统!后面会用到 images.os.os 来挑选具体的启动函数。
第 639 行,调用函数 do_bootm_states 来执行不同的 BOOT 阶段,这里要执行的 BOOT 阶段有: BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 和BOOTM_STATE_OS_GO。
bootz_start 函数
bootz_srart 函数也定义在文件 cmd/bootm.c 中,函数内容如下:
第 584 行,调用函数 do_bootm_states,执行 BOOTM_STATE_START 阶段。
第 593 行,设置 images 的 ep 成员变量,也就是系统镜像的入口点,使用 bootz 命令启动系统的时候就会设置系统在 DRAM 中的存储位置,这个存储位置就是系统镜像的入口点,因
此 images->ep=0X80800000。
第 598 行,调用 bootz_setup 函数,此函数会判断当前的系统镜像文件是否为 Linux 的镜像文件,并且会打印出镜像相关信息, bootz_setup 函数稍后会讲解。
第 608 行,调用函数 bootm_find_images 查找 ramdisk 和设备树(dtb)文件,但是我们没有用到 ramdisk,因此此函数在这里仅仅用于查找设备树(dtb)文件,此函数稍后也会讲解。
先来看一下 bootz_setup 函数,此函数定义在文件 arch/arm/lib/bootm.c 中,函数内容如下:

第 370 行,宏 LINUX_ARM_ZIMAGE_MAGIC 就是 ARM Linux 系统魔术数。
第 376 行,从传递进来的参数 image(也就是系统镜像首地址)中获取 zimage 头。 zImage 头结构体为 zimage_header。
第 377~380 行,判断 image 是否为 ARM 的 Linux 系统镜像,如果不是的话就直接返回,并且打印出“Bad Linux ARM zImage magic!”。
第 382、 383 行初始化函数 bootz_setup 的参数 start 和 end。
第 385 行,打印启动信息,如果 Linux 系统镜像正常的话就会输出如图所示的信息:![]()
接下来看一下函数 bootm_find_images,此函数定义在文件 common/bootm.c 中,函数内容如下:

第 230~235 行是跟查找 ramdisk,但是我们没有用到 ramdisk,因此这部分代码不用管。
第 237~244 行是查找设备树(dtb)文件,找到以后就将设备树的起始地址和长度分别写到images 的 ft_addr 和 ft_len 成员变量中。我们使用 bootz 启动 Linux 的时候已经指明了设备树在
DRAM 中的存储地址,因此 images.ft_addr=0X83000000,长度根据具体的设备树文件而定,比如我现在使用的设备树文件长度为 0X8C81,因此 images.ft_len=0X8C81。
bootz_start 函数就讲解到这里, bootz_start 主要用于初始化 images 的相关成员变量。
do_bootm_states 函数
do_bootz 最 后 调 用 的 就 是 函 数 do_bootm_states , 而 且 在 bootz_start 中 也 调 用 了do_bootm_states 函数 ,看 来 do_bootm_states 函数 还 是 个 香 饽 饽 。此函 数 定 义 在 文件
common/bootm.c 中,函数代码如下:


第 604、 605 行,处理 BOOTM_STATE_START 阶段, bootz_start 会执行这一段代码,这里调用函数 bootm_start,此函数定义在文件 common/bootm.c 中,函数内容如下:

接着回到do_bootm_states函数中,继续分析函数 do_bootm_states。第 658 行非常重要!通过函数 bootm_os_get_boot_func 来查找系统启动函数,参数 images->os.os 就是系统类型,根据这
个系统类型来选择对应的启动函数,在 do_bootz 中设置 images.os.os= IH_OS_LINUX。函数返回值就是找到的系统启动函数,这里找到的 Linux 系统启动函数为 do_bootm_linux,关于此函
数查找系统启动函数的过程稍后分析。因此 boot_fn=do_bootm_linux,后面执行 boot_fn函数的地方实际上是执行的 do_bootm_linux 函数。
第 676 行,处理 BOOTM_STATE_OS_PREP 状态,调用函数 do_bootm_linux, do_bootm_linux也是调用 boot_prep_linux 来完成具体的处理过程。 boot_prep_linux 主要用于处理环境变量
bootargs, bootargs 保存着传递给 Linux kernel 的参数。
第 679~689 行是处理 BOOTM_STATE_OS_FAKE_GO 状态的,但是要我们没用使能 TRACE功能,因此宏 CONFIG_TRACE 也就没有定义,所以这段程序不会编译。
第 699 行,调用函数 boot_selected_os 启动 Linux 内核,此函数第 4 个参数为 Linux 系统镜像头,第 5 个参数就是 Linux 系统启动函数 do_bootm_linux。 boot_selected_os 函数定义在文件
common/bootm_os.c 中,函数内容如下:

第 480 行调用 boot_fn 函数,也就是 do_bootm_linux 函数来启动 Linux 内核。
bootm_os_get_boot_func 函数
do_bootm_states 会调用 bootm_os_get_boot_func 来查找对应系统的启动函数,此函数定义在文件 common/bootm_os.c 中,函数内容如下:
第 495~508 行是条件编译,在本 uboot 中没有用到,因此这段代码无效,只有 509 行有效。
在 509 行中 boot_os 是个数组,这个数组里面存放着不同的系统对应的启动函数。 boot_os 也定义在文件 common/bootm_os.c 中,如下所示:

第 438 行就是 Linux 系统对应的启动函数: do_bootm_linux。
do_bootm_linux 函数
经过前面的分析,我们知道了 do_bootm_linux 就是最终启动 Linux 内核的函数,此函数定义在文件 arch/arm/lib/bootm.c,函数内容如下:
第351行,如果参数flag等于BOOTM_STATE_OS_GO或者BOOTM_STATE_OS_FAKE_GO的话就执行 boot_jump_linux 函数。 boot_selected_os 函数在调用 do_bootm_linux 的时候会将 flag
设置为 BOOTM_STATE_OS_GO。
第 352 行,执行函数 boot_jump_linux,此函数定义在文件 arch/arm/lib/bootm.c 中,函数内容如下:

第 274~292 行是 64 位 ARM 芯片对应的代码, Cortex-A7 是 32 位芯片,因此用不到。
第 293 行,变量 machid 保存机器 ID,如果不使用设备树的话这个机器 ID 会被传递给 Linux内核, Linux 内核会在自己的机器 ID 列表里面查找是否存在与 uboot 传递进来的 machid 匹配的
项目,如果存在就说明 Linux 内核支持这个机器,那么 Linux 就会启动!如果使用设备树的话这个 machid 就无效了,设备树存有一个“兼容性”这个属性, Linux 内核会比较“兼容性”属
性的值(字符串)来查看是否支持这个机器。
第 295 行,函数 kernel_entry,看名字“内核_进入”,说明此函数是进入 Linux 内核的,也就是最终的大 boos!!此函数有三个参数: zero, arch, params,第一个参数 zero 同样为 0;第
二个参数为机器 ID; 第三个参数 ATAGS 或者设备树(DTB)首地址, ATAGS 是传统的方法,用于传递一些命令行信息啥的,如果使用设备树的话就要传递设备树(DTB)。
第 299 行,获取 kernel_entry 函数,函数 kernel_entry 并不是 uboot 定义的,而是 Linux 内核定义的, Linux 内核镜像文件的第一行代码就是函数 kernel_entry,而 images->ep 保存着 Linux
内核镜像的起始地址,起始地址保存的正是 Linux 内核第一行代码!
第 313 行,调用函数 announce_and_cleanup 来打印一些信息并做一些清理工作,此函数定义在文件 arch/arm/lib/bootm.c 中,函数内容如下:

第 74 行,在启动 Linux 之前输出“Starting kernel ...”信息,如图所示:

第 87 行调用 cleanup_before_linux 函数做一些清理工作。
继续回到函数 boot_jump_linux,第 315~318 行是设置寄存器 r2 的值?为什么要设置 r2 的值呢? Linux 内核一开始是汇编代码,因此函数 kernel_entry 就是个汇编函
数。向汇编函数传递参数要使用 r0、 r1 和 r2(参数数量不超过 3 个的时候),所以 r2 寄存器就是函数 kernel_entry 的第三个参数。
第 316 行,如果使用设备树的话, r2 应该是设备树的起始地址,而设备树地址保存在 images的 ftd_addr 成员变量中。
第 317 行,如果不使用设备树的话, r2 应该是 uboot 传递给 Linux 的参数起始地址,也就是环境变量 bootargs 的值。
第 328 行,调用 kernel_entry 函数进入 Linux 内核,此行将一去不复返, uboot 的使命也就完成了!
总结一下 bootz 命令的执行过程,如图所示:

相关文章:
I.MX6ULL_Linux_系统篇(17) uboot分析-启动linux
bootz 启动 Linux 内核 images 全局变量 不管是 bootz 还是 bootm 命令,在启动 Linux 内核的时候都会用到一个重要的全局变量:images, images 在文件 cmd/bootm.c 中有如下定义: images 是 bootm_headers_t 类型的全局变量&…...
C/C++每日一练(20230221)
目录 1. 格雷编码 2. 矩阵问题 3. 搜索旋转排序数组 II 1. 格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。即使有多个不同答案&#…...
用Python采集热门城市景点数据并简单制作数据可视化图
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 模块使用: 爬虫部分: requests parsel csv 数据分析部分: pandas pyecharts 如何安装模块: win R 输入 cmd 输入安装命令: pip install 模块名 回车 pycharm里面安装 terminal 输入安装命令…...
论文阅读:pixelNeRF: Neural Radiance Fields from One or Few Images
中文标题:从一或少量图像中构建神经辐射场 提出问题 NeRF效果虽然惊艳,但是其需要大量环绕图像以及长时间的训练。 创新点 与原始的NeRF网络不使用任何图像特征不同,pixelNeRF将与每个像素对齐的空间图像特征作为输入。也可以集合更多输入…...
C++项目——高并发内存池(1)--介绍及定长内存池
1.什么是内存池 1.1 池化技术 将程序中需要经常使用的核心资源先申请出来,放在一个池内,由程序自己管理,这样可以提高资源的使用效率,也可以保证本程序占有的资源数量。 比如之前博文实现的线程池,就是预先的申请出…...
网络有线无线配置
一、需求 在无线接入区内,当Lsw1的上联口出现故障时,需要通过AP1-LSw1-LSw2-LSw3的路径访问公网server3。这是因为AP1通过无线网连接到LSw1,而LSw1与LSw3之间的链路出现故障,无法直接访问公网server3。因此,流量需要通…...
阅读笔记——Feature-Point Matching for Aerial and Ground Images方法
阅读笔记——Feature-Point Matching for Aerial and Ground Images 1.应用背景 在三维重建应用中,常用的是航空影像,但在城市环境中,面对大量的高层建筑物,航空影像往往不能很好的重建出完整的三维模型。因为航空影像视角约束以…...
前端工程师面试题10条必会笔试题
布局 左边20% 中间自适应 右边200px 不能用定位答案:圣杯布局/双飞翼布局或者flex什么叫优雅降级和渐进增强?渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进…...
【技术分享】Web自动化之Selenium安装
Web 应用程序的验收测试常常涉及一些手工任务,例如打开一个浏览器,并执行一个测试用例中所描述的操作。但是手工执行的任务容易出现人为的错误,也比较费时间。因此,将这些任务自动化,就可以消除人为因素。Selenium 可以…...
【Linux】进程状态的理解
✍作者:阿润菜菜 📖专栏:Liunx系统编程 本文目录概述两个先行概念我们为啥创建进程Linux下的进程状态1. R 运行状态2.S 休眠状态 --- 可中断休眠状态3. D 磁盘休眠状态 ---不可中断休眠4.T 暂停状态 (t 追踪暂停状态)5…...
打游戏哪种蓝牙耳机比较好?适合玩游戏的无线蓝牙耳机
2023年耳机市场一如既往地卷,不只是卷音质,还在外观和功能上做了许多的改进,以至于现在哪怕不懂耳机的人从各电商平台都能闭眼入一个款平价品牌耳机且极少会踩雷,玩游戏是当前年轻人的娱乐方式,下面整理了几款适合玩游…...
Fortinet推出新一代自研安全芯片,跨所有网络边缘加速网络与安全融合
专注网络与安全融合的全球网络安全领导者 Fortinet(NASDAQ:FTNT),近日宣布推出新一代自研安全芯片 FortiSP5,作为 Fortinet ASIC 技术的最新突破,有力推动了分布式网络边缘安全的重大飞跃。FortiSP5 源自 F…...
ChatGPT爆火背后的真相:学编程已经成为必选项
这一阵最热门的话题,莫过于人工智能新选手——ChatGPT,在推出后只用了两个月就积累了1亿用户!它的出现在科技圈掀起了一阵“惊涛骇浪”,有人称ChatGPT的意义,堪比当年蒸汽机的出现,它足以爆发新一轮的“工业…...
Unity UI框架
一、简介 最近在各大网站看了一下 Unity3d 的 UI 框架,各种 UI 框架已经有很多的版本了,各有千秋,有的功能虽然写的完善,但用起来太复杂,有的框架功能不完善,搞个课程就上架了,还有什么 MVC 框…...
vue2提取vue-router的title单独存放,使用i18n实现
成品效果 首先引入i18n(vue-i18n官网文档) 依赖包 npm install vue-i18n8然后单独在src目录下新建一个文件夹lang,存放相对应的变量名称,我这里只做显示中文所以其他引入我都注释了,具体目录如下: src\lang/zh.js部分代码 export…...
【Linux操作系统】【综合实验三 用户帐号、文件系统与系统安全管理】
文章目录一、实验目的二、实验要求三、实验内容四、实验报告要求一、实验目的 要求掌握Linux系统用户的创建、删除与管理操作;熟悉Linux文件系统的管理模式,学会创建用户文件系统并装载和卸载文件系统;掌握超级用户的管理方式与权限…...
sqlite3数据库-sqlite语句1(五)
DML(Data Manipulation Language,数据操作语言) SELECT:查询表中的数据;SELECT语句中使用WHERE子句SELECT <列名>,... FROM <表名> WHERE <条件表达式>;SELECT id,name,purchase_price FROM Product; /*使用逗号分隔查询多列,顺序同子句顺序*/ SELECT * FROM…...
【图像分类】卷积神经网络之LeNet5网络模型实现MNIST手写数字识别
写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 在上一篇博文中我们对LeNet5网络模型的结构进行了剖析,本篇博文,我们将使用PyTorch搭建LeNet5实现MNIST手写数字…...
前端开发环境搭建
文章目录Node.js是什么安装查看版本入门示例NPM使用 npm 命令安装模块常见命令使用淘宝 NPM 镜像TypeScript安装入门示例从github拉取构建项目如何从零创建一个TypeScript项目规划目录结构新建项目Web App运行服务添加依赖打包使用browserify打包使用webpack打包推荐流程目录配…...
学习Flask之四、网页表单
第二章介绍的request对象,使用了客户端请求的所有信息。特别地,request.form提供了对POST请求提交的表单数据的访问。尽管Flask请求对象的支持足于处理网页单,但是还有很多作务很繁锁和重复。两个很好的例子是产生HTML表单代码和验证表单数据…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
