如何通过uboot加载硬盘

不需要你自己从头编写 U-Boot 代码。U-Boot 是一个开源的引导加载程序,官方已经提供了针对 QEMU 虚拟机(包括 ARM64 的 virt 机器)的默认配置。你只需要下载源码、进行配置和编译即可。

要将你之前的"直接内核启动"改造为"U-Boot 引导启动",你可以按照以下步骤操作:

1. 编译 U-Boot

首先,你需要获取 U-Boot 的源码并编译出适用于 QEMU ARM64 的固件(u-boot.bin)。

bash 复制代码
# 克隆 U-Boot 源码(这里以 v2022.04 版本为例)
git clone https://gitee.com/mirrors/u-boot.git -b v2022.04 u-boot-2022.04
cd u-boot-2022.04

# 设置交叉编译工具链前缀(根据你的环境调整)
export CROSS_COMPILE=aarch64-linux-gnu-

# 使用 QEMU ARM64 的默认配置
make qemu_arm64_defconfig

# 编译
make -j$(nproc)

编译完成后,当前目录下会生成 u-boot.bin 文件。

2. 修改 QEMU 启动命令

你需要将编译好的 u-boot.bin 通过 -bios 参数传给 QEMU,同时挂载包含内核和根文件系统的磁盘镜像。假设你的根文件系统镜像为 rootfs.img(里面已经包含了内核 boot/Image),启动脚本可以这样写:

bash 复制代码
#!/bin/bash
qemu-system-aarch64 \
  -M virt \
  -cpu cortex-a72 \
  -m 512M \
  -nographic \
  -bios u-boot-2022.04/u-boot.bin \
  -drive file=rootfs.img,format=raw,id=hd0,if=none \
  -device virtio-blk-device,drive=hd0

3. 在 U-Boot 中手动引导内核

运行上述脚本后,QEMU 会加载 U-Boot 并停留在 U-Boot 的命令行界面。此时,你需要手动输入命令让 U-Boot 去读取磁盘并启动内核:

text 复制代码
# 1. 从 virtio 磁盘的 /boot 目录加载内核到内存地址 0x40200000
U-Boot# load virtio 0 0x40200000 boot/Image

# 2. 设置传递给 Linux 内核的启动参数(如根文件系统位置和控制台)
U-Boot# setenv bootargs "root=/dev/vda rw console=ttyAMA0"

# 3. 从指定内存地址启动 ARM64 内核
U-Boot# booti 0x40200000 - 0x40000000

总结

通过这种方式,启动流程变为了:QEMU 加载 U-Boot -> U-Boot 读取磁盘加载内核 -> 内核启动。虽然步骤变多了,但这能让你更深入地理解真实嵌入式设备中系统启动的每一个环节。

rootfs.img怎么制作, 为什么有 driver 和 device两个参数

针对你提出的两个问题,以下是详细的解答:

一、 rootfs.img 是如何制作的?

制作根文件系统镜像(rootfs.img)通常分为"准备文件系统内容"和"打包为镜像文件"两个阶段。以下是使用 Linux 原生工具链的标准制作流程:

1. 准备根文件系统目录

首先,你需要在宿主机上准备一个包含完整目录结构(如 /bin, /sbin, /etc, /lib 等)的文件夹(例如命名为 rootfs_staging)。你可以通过交叉编译 BusyBox 或使用 Buildroot/Yocto 等自动化构建工具来生成这些基础文件。

注意:必须确保目录内文件的拥有者和权限正确(通常需要使用 fakerootsudo 环境),否则系统启动后会因为权限问题无法正常运行。

2. 制作镜像文件(dd + mkfs.ext4 组合)

使用 dd 命令创建一个指定大小的空文件,然后使用 mkfs.ext4 将其格式化为 Ext4 文件系统,接着挂载并将准备好的文件拷贝进去。具体命令示例如下:

bash 复制代码
# 1. 创建一个 512MB 的全零空文件
dd if=/dev/zero of=rootfs.img bs=1M count=512 status=progress

# 2. 在该文件上创建 Ext4 文件系统
sudo mkfs.ext4 -F rootfs.img

# 3. 创建临时挂载点并挂载
mkdir -p mnt_point
sudo mount -o loop rootfs.img mnt_point

# 4. 将准备好的根文件系统拷贝进去(-a 参数保留权限和时间戳)
sudo cp -a rootfs_staging/* mnt_point/

# 5. 卸载镜像(这一步会强制写入所有缓存,至关重要)
sudo umount mnt_point

# 6. 检查文件系统并调整大小为实际内容的最小值(节省空间)
sudo e2fsck -p -f rootfs.img
sudo resize2fs -M rootfs.img

通过上述步骤,你就得到了一个可以直接挂载给 QEMU 使用的 rootfs.img 文件。


二、 为什么 QEMU 启动时有 -drive-device 两个参数?

在 QEMU 的架构设计中,存储设备的定义被拆分成了后端(Backend)前端(Frontend),这两个参数正是分别对应这两部分:

1. -drive 参数:定义存储后端(Backend)

-drive 负责定义实际的存储介质(即"厨师"的角色),它关注的是数据如何被存储和读取。

  • 它指定了磁盘镜像文件的路径(file=)、镜像格式(format=raw/qcow2)以及缓存模式(cache=)等。
  • 当使用 -drive if=none 时,表示只定义后端存储,不直接连接到前端设备,必须配合 -device 使用。

2. -device 参数:定义存储前端(Frontend)

-device 负责定义虚拟机内部看到的虚拟硬件设备(即"服务员"的角色),它关注的是 Guest 操作系统如何与硬件交互。

  • 它指定了虚拟硬件的类型(如 virtio-blk-device 表示高性能 VirtIO 磁盘,ide-hd 表示传统 IDE 硬盘)。
  • 通过 drive=hd0 参数,前端设备会与 -drive 定义的后端存储进行绑定。

3. 为什么要分离前后端?

这种前后端分离的设计带来了极大的灵活性。一个后端可以被多个前端复用,同时你可以自由组合硬件和存储。例如,你可以用 -drive 定义一个 qcow2 格式的镜像文件,然后用 -device 将其挂载为高性能的 VirtIO 磁盘,或者挂载为传统的 SCSI 硬盘,从而实现对虚拟硬件的细粒度控制。


-drive if=none --这里如果不是none呢,应该怎么写

如果在 -drive 参数中不使用 if=none,你可以直接指定 QEMU 支持的其他虚拟硬件接口类型。常见的选项包括 virtioidescsi 等。

当你直接指定了这些接口类型时,QEMU 会自动将后端存储(-drive)与对应的前端虚拟硬件(-device)绑定在一起,因此你不再需要 单独编写 -device 参数。

以下是几种常见的替代写法:

1. 使用 virtio 接口(推荐,性能较高)

bash 复制代码
-drive file=rootfs.img,format=raw,id=hd0,if=virtio

说明:这种写法等同于你之前使用的 -drive if=none ... -device virtio-blk-device,drive=hd0 的组合。

2. 使用 ide 接口(模拟传统 IDE 硬盘)

bash 复制代码
-drive file=rootfs.img,format=raw,id=hd0,if=ide

3. 使用 scsi 接口(模拟 SCSI 硬盘)

bash 复制代码
-drive file=rootfs.img,format=raw,id=hd0,if=scsi

总结对比:

  • 分离写法(if=none + -device:前后端解耦,配置更灵活,适合需要精细控制硬件拓扑的场景。
  • 合并写法(直接指定 if=virtio/ide/scsi:配置更简洁,QEMU 自动完成前后端绑定,适合快速启动和常规测试。
相关推荐
尔染君子1 小时前
嵌入式Linux驱动开发(按键驱动)
linux·驱动开发
kebidaixu1 小时前
BCU 平台 Modbus 主机功能开发:液冷机组 & 消防传感器
linux
vsropy1 小时前
安装虚拟机VMware
linux·windows
Jason_chen2 小时前
Linux 3.0 串口机制深度解析:传统8250驱动与基础RS-232/485支持
linux·前端
Jason_chen2 小时前
Linux 5.10 串口机制深度解析:serial_core重构与RS-485自动方向控制革命
linux
无敌的牛2 小时前
自省。。。。
linux
lqjun08272 小时前
Linux 下 Hermes Agent 代理配置不生效问题的解决
linux·服务器
Gary Studio2 小时前
复杂 SoC(RK3568)PCB 布局的五步
android·linux·硬件
一拳一个娘娘腔2 小时前
CVE-2026-43284 — Dirty Frag 深度拆解:当零拷贝遇上原地解密,页缓存成了攻击者的画板
linux·缓存