news 2026/6/18 16:54:23

Qemu模拟arm64启动Uboot + Linux

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qemu模拟arm64启动Uboot + Linux

目的:

由 U-Boot 引导 Linux 是一套非常经典的“全栈”仿真玩法,虽然Qemu可以跳过U-Boot直接启动Linux,但是要还原真实硬件的启动流程,U-Boot是绕不开要调试和学习的,以此简单记录下。使用Qemu可以用于早期的方案验证,提前排除风险。无实物,纯模拟,不用担心硬件bug,省去了很多调试力气。

一、uboot

1.1 安装依赖库

编译uboot时,需要编译主机工具,而编译工具,又依赖于一些常用的开发库。

sudo apt install -y uuid-dev libssl-dev libgnutls28-dev libncurses-dev swig python3-dev u-boot-tools mtd-utils pkg-config cpio

1.2 编译uboot

下载,编译,启动,不再赘述。ubifs依赖于ubi,ubi依赖于mtd,mtd可以是nor,spi,nand。

#下载 wget https://ftp.denx.de/pub/u-boot/u-boot-2026.01.tar.bz2 tar -jxvf u-boot-2026.01.tar.bz2 cd u-boot-2026.01 #配置,已开启ubi配置 make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- qemu_arm64_defconfig make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- menuconfig (或以下方法) cat << EOF >> .config CONFIG_CMD_MTD=y CONFIG_MTD=y CONFIG_FLASH_CFI_DRIVER=y CONFIG_SYS_FLASH_CFI=y CONFIG_MTD_NOR_FLASH=y CONFIG_MTD_DEVICE=y CONFIG_CMD_UBI=y CONFIG_CMD_UBIFS=y EOF make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- olddefconfig #编译 make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- -j4 cp u-boot.bin ../ 启动 qemu-system-aarch64 -machine virt -cpu cortex-a53 -smp 2 -m 512 -kernel u-boot -nographic

1.3 启动uboot

启动uboot,可以识别两个mtd设备,以及操作ubi卷。镜像文件可以裸放到支持norflash上,ubi卷上,或者ubifs文件系统中。需要uboot支持读接口获取镜像文件并启动,因为重心不在此,就不继续考究了。

Bloblist at 0 not found (err=-2) alloc space exhausted ptr 400 limit 0 Bloblist at 0 not found (err=-2) U-Boot 2026.01 (Jun 11 2026 - 11:35:10 +0800) DRAM: 512 MiB using memory 0x5e637000-0x5f677000 for malloc() Core: 51 devices, 14 uclasses, devicetree: board Flash: 64 MiB Loading Environment from Flash... *** Warning - bad CRC, using default environment In: serial,usbkbd Out: serial,vidconsole Err: serial,vidconsole No USB controllers found Net: eth0: virtio-net#32 Hit any key to stop autoboot: 0 => => mtd list List of MTD devices: * nor0 - device: flash@0 - parent: root_driver - driver: cfi_flash - path: /flash@0 - type: NOR flash - block size: 0x20000 bytes - min I/O: 0x1 bytes - 0x000000000000-0x000002000000 : "nor0" * nor1 - device: flash@0 - parent: root_driver - driver: cfi_flash - path: /flash@0 - type: NOR flash - block size: 0x20000 bytes - min I/O: 0x1 bytes - 0x000000000000-0x000002000000 : "nor1"

1.4 初探UBI

擦除nor,attach mtd设备,创建ubi卷。uboot下似乎只支持读,没有支持ubifs格式化、写入的操作,因此无法挂载ubifs文件系统。我想这是安全的行为,如果在uboot下创建文件系统,要做好和kernel的版本同步。这个很麻烦,也很容易把不一致性传递给kernel,导致长期使用后ubifs的累加错误。

=> protect off all Un-Protect Flash Bank # 1 Un-Protect Flash Bank # 2 => erase all Erase Flash Bank # 1 ................................................................................................................................................................................................................................................................ done Erase Flash Bank # 2 ................................................................................................................................................................................................................................................................ done => ubi part nor0 0 force ubi0: attaching mtd0 ubi0: scanning is finished ubi0: empty MTD device detected ubi0: attached mtd0 (name "nor0", size 32 MiB) ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 130944 bytes ubi0: min./max. I/O unit sizes: 1/1, sub-page size 1 ubi0: VID header offset: 64 (aligned 64), data offset: 128 ubi0: good PEBs: 256, bad PEBs: 0, corrupted PEBs: 0 ubi0: user volume: 0, internal volumes: 1, max. volumes count: 128 ubi0: max/mean erase counter: 0/0, WL threshold: 4096, image sequence number: 0 ubi0: available PEBs: 252, total reserved PEBs: 4, PEBs reserved for bad PEB handling: 0 => ubi create system 0xa00000 dynamic Creating dynamic volume system of size 10485760 => ubi info layout Volume information dump: vol_id 0 reserved_pebs 81 alignment 1 data_pad 0 vol_type 3 name_len 6 usable_leb_size 130944 used_ebs 81 used_bytes 10606464 last_eb_bytes 130944 corrupted 0 upd_marker 0 skip_check 0 name system Volume information dump: vol_id 2147479551 reserved_pebs 2 alignment 1 data_pad 0 vol_type 3 name_len 13 usable_leb_size 130944 used_ebs 2 used_bytes 261888 last_eb_bytes 2 corrupted 0 upd_marker 0 skip_check 0 name layout volume => ubi ubi ubifsload ubifsls ubifsmount ubifsumount => ubifsmount system UBIFS error (pid: 1): cannot open "system", error -22 Error reading superblock on volume 'system' errno=-22!

二、kernel

2.1 编译kernel

编译,启动,不再赘述。

#配置,去掉nor,后续模拟nand make ARCH=arm64 defconfig ./scripts/config --enable DEBUG_INFO \ --enable DEBUG_KERNEL \ --enable GDB_SCRIPTS \ --enable KALLSYMS_ALL \ --enable FRAME_POINTER ./scripts/config --disable MTD_CFI \ --disable MTD_GENPROBE \ --disable MTD_CFI_AMDSTD \ --disable MTD_CFI_UTIL \ --disable MTD_PHYSMAP \ --disable MTD_PHYSMAP_OF cat << EOF >> .config # MTD 核心与分区支持 CONFIG_MTD=y CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y # 核心 1:启用 block2mtd 驱动 CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK2MTD=y # 核心 2:启用 nandsim 驱动及其依赖的 NAND 框架 CONFIG_MTD_RAW_NAND=y CONFIG_MTD_NAND_NANDSIM=m # UBI 与 UBIFS 配置 CONFIG_MTD_UBI=y CONFIG_MTD_UBI_WL_THRESHOLD=4096 CONFIG_MTD_UBI_BEB_LIMIT=20 CONFIG_UBIFS_FS=y CONFIG_UBIFS_FS_ADVANCED_COMPR=y CONFIG_UBIFS_FS_LZO=y CONFIG_UBIFS_FS_ZLIB=y EOF make ARCH=arm64 olddefconfig #编译 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 cp arch/arm64/boot/Image ../ #启动 qemu-system-aarch64 \ -machine virt,virtualization=on \ -cpu cortex-a53 \ -kernel arch/arm64/boot/Image \ -append "console=ttyAMA0 nokaslr" \ -nographic

2.2 制作rootfs

解决Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)问题,需要busybox做个rootfs。

#下载 wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 tar -jxvf busybox-1.36.1.tar.bz2 cd busybox-1.36.1/ #配置,启用静态链接 ,配置为静态编译。简单,无需拷贝动态链接库 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig sed -i 's/^# CONFIG_STATIC.*/CONFIG_STATIC=y/' .config #关闭tc,解决编译问题 sed -i 's/CONFIG_TC=y/CONFIG_TC=n/' .config #编译 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j4 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install #打包rootfs mkdir -p rootfs cp -av busybox-1.36.1/_install/* rootfs/ cd rootfs mkdir -p {dev,etc,lib,proc,sys,mnt,root,etc/init.d,tmp} #创建基础设备节点 sudo mknod -m 666 dev/tty1 c 4 1 sudo mknod -m 666 dev/tty2 c 4 2 sudo mknod -m 666 dev/tty3 c 4 3 sudo mknod -m 666 dev/tty4 c 4 4 sudo mknod -m 666 dev/console c 5 1 sudo mknod -m 666 dev/null c 1 3 #创建初始启动脚本 cat > etc/init.d/rcS << EOF #!/bin/sh mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev mount -t tmpfs tmpfs /tmp EOF chmod +x etc/init.d/rcS #制作initramfs镜像 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initrd.img cd .. #容量信息 @@@:~/linux$ ls -alh ./ -rw-r--r-- 1 l16952 l16952 33M Jun 16 10:24 Image -rw-r--r-- 1 l16952 l16952 1.2M Jun 16 10:45 initrd.img -rw-r--r-- 1 l16952 l16952 1.6M Jun 16 09:37 u-boot.bin

三、uboot启动kernel

3.1 制作镜像

创建虚拟磁盘,存放Image,initrd.img。让uboot通过virtio读取并加载启动

#创建128MB的空磁盘文件 dd if=/dev/zero of=disk.img bs=1M count=128 #烧录内核 Image 到磁盘的 0 偏移处 dd if=Image of=disk.img bs=1M conv=notrunc #烧录根文件系统 initrd.img 到磁盘偏移 50MB 处 dd if=initrd.img of=disk.img bs=1M seek=50 conv=notrunc

3.2 启动镜像

#定义一块virtio块设备,运行程序访问该设备获取disk.img中的镜像 qemu-system-aarch64 \ -machine virt,virtualization=on \ -cpu cortex-a53 \ -m 1024M \ -bios u-boot.bin \ -drive file=disk.img,format=raw,if=none,id=mydisk \ -device virtio-blk-device,drive=mydisk \ -nographic #进uboot命令行,执行以下操作 #读取内核Image virtio read 0x40080000 0x0 0x11170 #读取initrd.img virtio read 0x44000000 0x19000 0xBB8 #设置启动参数 setenv bootargs "rdinit=/sbin/init console=ttyAMA0 loglevel=8" #指定 initrd 内存段的起始地址和具体十六进制大小 booti 0x40080000 0x44000000:0x125cb4 $fdtcontroladdr

3.3 自动启动

使用环境变量,或者脚本,但是因为没有固化到介质中,所以重启qemu仍会丢失

#设置环境变量 setenv bootcmd 'virtio read 0x40080000 0x0 0x11170; virtio read 0x44000000 0x19000 0xBB8; setenv bootargs "rdinit=/sbin/init console=ttyAMA0 loglevel=8"; booti 0x40080000 0x44000000:0x125cb4 $fdtcontroladdr' #保存环境变量 saveenv #kernel下reboot Please press Enter to activate this console. ~ #reboot umount: devtmpfs busy - remounted read-only umount: can't unmount /: Invalid argument swapoff: can't open '/etc/fstab': No such file or directory The system is going down NOW! Sent SIGTERM to all processes Sent SIGKILL to all processes Requesting system reboot #boot下reset Hit any key to stop autoboot: 0 => reset resetting ...

3.4 固化启动配置

让uboot拥有两块flash,使用文件来模拟,存储boot镜像和环境变量。

#生成第一块 64MB 的 Flash,并把 u-boot.bin 重新烧进去 dd if=/dev/zero of=pflash.img bs=1M count=64 dd if=u-boot.bin of=pflash.img conv=notrunc #生成第二块 64MB 的 Flash,专门给 U-Boot 存环境变量 dd if=/dev/zero of=pflash_env.img bs=1M count=64 #用双flash命令启动QEMU qemu-system-aarch64 \ -machine virt,virtualization=on \ -cpu cortex-a53 \ -m 1024M \ -drive file=pflash.img,format=raw,if=pflash \ -drive file=pflash_env.img,format=raw,if=pflash \ -drive file=disk.img,format=raw,if=none,id=mydisk \ -device virtio-blk-device,drive=mydisk \ -nographic #保存环境变量,这次是真实写入pflash_env.img中 setenv bootcmd 'virtio read 0x40080000 0x0 0x11170; virtio read 0x44000000 0x19000 0xBB8; setenv bootargs "rdinit=/sbin/init console=ttyAMA0 loglevel=8"; booti 0x40080000 0x44000000:0x125cb4 $fdtcontroladdr' saveenv #后续直接用QEMU命令即可启动uboot+kernel qemu-system-aarch64 \ -machine virt,virtualization=on \ -cpu cortex-a53 \ -m 1024M \ -drive file=pflash.img,format=raw,if=pflash \ -drive file=pflash_env.img,format=raw,if=pflash \ -drive file=disk.img,format=raw,if=none,id=mydisk \ -device virtio-blk-device,drive=mydisk \ -nographic
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/18 16:48:56

mysql主从数据同步方案的探讨,解决数据不一致问题

。早期MySQL保证数据一致性的方案&#xff0c;核心是基于二进制日志&#xff08;binlog&#xff09;的主从复制&#xff0c;并围绕它构建了读写分离和双机热备等架构。在保障数据一致性方面存在明显的缺陷&#xff0c;做运维的人都深有体会。这是当时最基础的架构&#xff0c;所…

作者头像 李华
网站建设 2026/6/18 16:48:41

深入解析P4080DS:多核SoC架构、SerDes高速接口与嵌入式系统开发实战

1. 项目概述与核心价值在嵌入式系统和高性能计算领域&#xff0c;我们常常面临一个核心矛盾&#xff1a;如何在一块芯片上同时实现强大的通用计算能力和灵活的高速数据交换能力。十年前&#xff0c;当我第一次接触到飞思卡尔&#xff08;Freescale&#xff0c;现为NXP的一部分&…

作者头像 李华
网站建设 2026/6/18 16:47:18

5090算力卡创建实例问题分析

算力卡租赁出现状态不对的几种情况分析&#xff1a;一&#xff0c;整机绑定调度规则限制 该机型为 4 卡整机机型&#xff0c;平台调度策略默认整机分配&#xff0c;不支持拆分零散空闲卡单独出租。只要 4 张卡里任意 1 张被占用&#xff0c;剩余 3 张空闲卡无法单独创建实例&am…

作者头像 李华
网站建设 2026/6/18 16:45:06

DRF的分页讲解-代码篇 PageNumberPagination类的两种使用方式

本文讲述PageNumberPagination类的两种用法一、全局配置分页前期准备工作&#xff1a;一个配置drf框架的django项目1. 在配置文件中添加下述代码代码解析&#xff1a;指定全局分页器为PageNumberPagination&#xff0c;且每页显示5条数据作用&#xff1a;只要继承了 from rest_…

作者头像 李华