鸿蒙系统研究之六:U-Boot引导

鸿蒙系统实战:从U-Boot引导内核到SD卡镜像制作
本文介绍了如何从U-Boot源码编译引导Linux内核,包括使用QEMU挂载SD卡镜像、处理根文件系统和SELinux问题,以及固化启动命令。详细步骤涉及文件系统操作和嵌入式系统引导流程。

这是我的鸿蒙系统研究系列文章的第六篇,有兴趣还可以看看前面的文章:

另外,还有关于鸿蒙系统的看法:

U-Boot 的全称是 Universal Boot Loader,其作用就是引导系统。对于我们熟悉的 PC,上电后,通过 BIOS 引导操作系统 (Windows、Linux等)。对于嵌入式系统一般将这个引导程序称作 BootLoader,U-Boot 就是目前使用得最广泛的 BootLoader。

在前面的文章中,QEMU 直接引导鸿蒙系统的 Linux 内核,这种方式缺少灵活性,关键是在实际产品中,嵌入式系统是不会直接上电引导 Linux 内核的(整个软件系统一般位于 Flash,需要能够读写 Flash)。所以本文探讨使用 U-Boot 来引导内核。

开始之前,也做一个准备工作,安装 mkImage 工具:

$ sudo apt install u-boot-tools

U-Boot 既然是用来引导内核,那肯定与具体硬件相关,所以需要从源码编译,并且还需要针对具体产品做一些修改。

下载 U-Boot 源码,并编译

U-Boot 源码选择哪个版本关系并不大,这里选择 OpenHarmony 标准系统参考实现相同的版本:u-boot-2020.01。直接去官网下载,不要直接使用 device/hisilicon/third_party/uboot/u-boot-2020.01 这个代码,因为这个版本有华为针对 Hi3516DV300 等产品进行的修改。

$ wget https://codeload.github.com/u-boot/u-boot/zip/refs/tags/v2020.01

解压源码,然后进入 U-Boot 源码目录,编译 u-boot

$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabi-
$ export LOADADDR=0x80008000
$ make vexpress_ca9x4_defconfig
$ make all

编译后得到一个 u-boot 文件,这个在后面 QEMU 加载时用到。

制作 SD 卡镜像

鸿蒙系统研究之四:根文件系统这篇文章中,我曾写到,要将根文件系统和system镜像分开,但仔细研究鸿蒙的文件系统后发现不行,因为根文件系统中的很多文件都是指向system的符号链接,特别是 init 这个超级进程。kernel 加载之后,首先要执行 init 进程,但此时还没有机会挂载 system 镜像,导致 init 是一个空链接。

此外,鸿蒙系统启用了SeLinux,这个也是超级折磨人的一个安全特性,稍不注意就会有程序无法执行的问题。因此这里解包 system.img ,得到根文件系统,另外为了简单起见,将 vendor 镜像里面的内容也复制过来。

Vexpress A9 最多只有 128 M 的 flash,没法容纳整个鸿蒙标准系统。好在 Vexpress A9 支持 SD 卡挂载,所以这里制作一个 SD 卡镜像,通过 QEMU 模拟器挂载。

下面的内容主要查阅网上的资料,为此写了一个脚本,将整个过程自动化完成。

#!/bin/bash
# 0.设置目录变量
OHOS_SRC_ROOT=$(cd "../../.." && pwd)

# 1. 解包系统镜像,得到鸿蒙系统文件
cd ${OHOS_SRC_ROOT}/out/ohos-arm-release/packages/phone/images
# Android sparse image 和 ext4 文件系统之间转换
simg2img system.img system.ext4
# 挂载 system 镜像
mkdir system-img
sudo mount system.ext4 system-img
simg2img vendor.img vendor.ext4
# 挂载 vendor 镜像
mkdir vendor-img
sudo mount vendor.ext4 vendor-img

# 2. 制作 SD 卡镜像(1GB)
dd if=/dev/zero of=uboot.disk bs=1M count=1024
# 创建 4 个分区
sgdisk -n 0:0:+16M -c 0:kernel uboot.disk
sgdisk -n 0:0:+512M -c 0:rootfs uboot.disk
sgdisk -n 0:0:+64M -c 0:vendor uboot.disk
sgdisk -n 0:0:0 -c 0:userdata uboot.disk

# 3. 寻找一个空闲的loop设备,挂载 SD 卡镜像
loop=$(sudo losetup -f)
echo "found idle loop device: ${loop}"
sleep 1
sudo losetup ${loop} uboot.disk
sleep 3
sudo partprobe ${loop}
sleep 3
# 格式化分区
sudo mkfs.ext4 ${loop}p1
sudo mkfs.ext4 ${loop}p2
s
<think>嗯,用户这次的问题很明确,想理解u-bootboot loader和UEFI三者的定义和区别。从引用资料看,用户应该是在研究嵌入式系统启动流程,特别是鸿蒙系统相关的开发,因为引用的都是u-boot和OpenHarmony的源码分析文章。 用户可能是个嵌入式开发工程师,正在移植u-boot到某个ARM平台。ta引用的资料里提到u-boot支持UEFI特性(bootefi命令)、链接脚本分析和ARM64启动汇编,说明ta的困惑可能源于实际开发中遇到了混合使用传统bootloader和UEFI组件的场景。 需要特别注意区分概念层级:boot loader是通用术语,u-boot是具体实现,UEFI是规范标准。用户引用的[1]提到u-boot能启动UEFI应用,这个细节很重要,说明三者不是互斥关系。可以结合用户之前问的UEFI接口问题,强调u-boot实现的是UEFI软件接口规范。 用户可能隐含的问题是:在ARM设备上该用传统u-boot还是UEFI?这需要解释u-boot既可作为独立bootloader,也能作为UEFI实现的基础。引用[4]的crt0_64.S正好说明ARM64架构下u-boot如何兼容UEFI环境。 要避免陷入源码细节(虽然用户提供了具体文件路径),重点说清:u-boot属于boot loader范畴,而UEFI是标准接口规范;u-boot通过bootefi命令实现了UEFI应用加载能力,这是部分兼容UEFI的表现。 最后生成的问题要引导用户思考具体场景选择,比如ARM设备启动方案选型,这比纯理论对比更有实用价值。</think>以下是对 **U-BootBoot Loader 和 UEFI** 的定义与区别的清晰解析,结合技术本质和实际应用场景: --- ### 一、核心定义 | **术语** | **定义** | **角色定位** | |----------------|--------------------------------------------------------------------------|----------------------------------| | **Boot Loader** | 一段**初始化硬件并加载操作系统的底层程序**,是系统启动的**第一阶段**。 | **通用概念**,描述启动引导程序的本质功能 | | **U-Boot** | 针对**嵌入式系统**(如ARM、RISC-V)的开源Boot Loader实现,支持多种硬件架构和文件系统。 | Boot Loader的**具体实现** | | **UEFI** | **统一可扩展固件接口**,定义操作系统与固件间的**标准化软件协议**,替代传统BIOS。 | **固件接口规范**,非具体程序 | --- ### 二、关键区别 #### 1. **功能层级差异** ```mermaid graph TB A[硬件] -->|上电| B[固件层 UEFI/BIOS] B -->|提供运行时服务| C[Boot Loader层 如U-Boot] C -->|加载内核| D[操作系统] ``` - **UEFI**:属于**固件层**,提供硬件抽象和基础服务(如启动管理、安全验证)。 - **Boot Loader**:在UEFI**之后运行**,负责初始化特定硬件(如DRAM、时钟)并加载操作系统内核- **U-Boot**:是Boot Loader在嵌入式领域的**具体实现**。 #### 2. **架构兼容性** | **组件** | 适用场景 | 硬件依赖 | |---------------|----------------------------------|-----------------------------| | UEFI | x86/ARM/RISC-V等通用计算平台 | 需主板固件实现UEFI规范 | | U-Boot | 嵌入式设备(路由器、IoT设备、开发板) | 支持裸机环境,无需UEFI固件 | > 💡 示例:树莓派默认使用**U-Boot**(无UEFI),而x86 PC必须通过**UEFI固件**启动。 #### 3. **技术特性对比** | **特性** | UEFI | U-Boot | |------------------|-----------------------------------|-------------------------------------| | **启动方式** | 通过`EFI Application`加载OS | 直接执行`bootm`/`bootefi`命令加载内核 | | **硬件初始化** | 仅基础初始化(CPU、内存) | 深度初始化(网卡、Flash、外设时钟) | | **交互接口** | 图形化GUI+鼠标操作 | 串口命令行(CLI) | | **驱动模型** | 动态加载`EFI Driver` | 静态编译驱动到U-Boot镜像 | > 引用[1]说明:U-Boot的`bootefi`命令可启动UEFI应用,表明其**部分兼容UEFI标准**[^1]。 #### 4. **代码结构差异(以ARM64为例)** - **U-Boot启动流程**(引用[4]): ```armasm /* arch/arm/lib/crt0_64.S */ ENTRY(_main) bl board_init_f /* 初始化硬件 */ bl relocate_code /* 重定位代码到DRAM */ bl board_init_r /* 准备加载内核 */ ENDPROC(_main) ``` 需自行实现硬件初始化逻辑[^4]。 - **UEFI启动流程**: 操作系统直接调用固件提供的`EFI_BOOT_SERVICES`接口,无需底层硬件操作。 --- ### 三、协作关系 #### 典型场景:**U-Boot作为UEFI的实现载体** ```mermaid graph LR A[设备上电] --> B[SoC BootROM] B --> C{UEFI固件?} C -->|是| D[UEFI固件执行] C -->|否| E[U-Boot作为Boot Loader] D -->|调用bootefi| E E --> F[加载Linux内核] ``` > 在支持UEFI的ARM设备(如某些开发板)中,UEFI固件可调用U-Boot的`bootefi`命令启动内核[^1]。 --- ### 四、总结:核心差异表 | **维度** | Boot Loader | U-Boot | UEFI | |----------------|-------------------|----------------------|--------------------| | **本质** | 通用概念 | 具体实现 | 接口规范 | | **存在形式** | 任何启动程序 | 开源软件包 | 固件标准 | | **硬件依赖** | 依赖具体硬件 | 支持多架构嵌入式设备 | 需主板固件支持 | | **扩展性** | 取决于实现 | 通过命令/脚本扩展 | 通过Protocol动态扩展 | --- ### 五、常见误区澄清 ❌ **误区**:”UEFI是一种Boot Loader“ ✅ **正解**:UEFI是**固件规范**,其实现(如EDK II)可能包含Boot Loader功能,但两者非同一层级概念。 ❌ **误区**:”U-Boot只能在无UEFI的设备上运行“ ✅ **正解**:U-Boot既可独立运行(传统嵌入式),也可作为**UEFI应用**被加载(如`bootefi`命令)[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云水木石

但行好事,莫问前程

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值