从eMMC中加载镜像并启动是我们常见开发板的启动方式,通过Qemu模拟eMMC设备,这样我们可以在Qemu上直接验证我们很多相关的逻辑功能,比如eMMC的启动、文件系统的mount、文件读写等。
Qemu: v7.2.0
U-Boot: v2022.04
Linux Kernel: linux-6.1.12
U-Boot eMMC架构
eMMC镜像制作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 dd if =/dev/zero of=emmc.img bs=1M count=2048sudo parted emmc.img mktable gpt sudo parted emmc.img mkpart misc 2048KiB 2559KiB sudo parted -s -a none emmc.img mkpart ubootenv 2560KiB 3071KiB sudo parted -s -a none emmc.img mkpart vbmeta_a 3072KiB 3583KiB sudo parted -s -a none emmc.img mkpart vbmeta_b 3584KiB 4095KiB sudo parted -s -a none emmc.img mkpart boot_a 4MiB 154MiB sudo parted -s -a none emmc.img mkpart boot_b 154MiB 304MiB sudo parted emmc.img set 5 boot on sudo parted emmc.img set 6 boot on sudo parted -s -a none emmc.img mkpart buildroot 304MiB 816MiB sudo parted -s -a none emmc.img mkpart buildroot 816MiB 2046MiB sync sudo kpartx -av emmc.img sudo mkfs.vfat /dev/mapper/loopXp5 sudo mkfs.vfat /dev/mapper/loopXp6 sudo mkfs.ext4 /dev/mapper/loopXp7 sudo mkfs.ext4 /dev/mapper/loopXp8 sudo tune2fs -f -O ^metadata_csum /dev/mapper/loopXp7 sudo tune2fs -f -O ^metadata_csum /dev/mapper/loopXp8 sync sudo kpartx -dv emmc.img
注意:loopX是kpartx自动生成的,X根据实际情况替换成数字
eMMC验证 U-Boot配置选项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 CONFIG_MMC=y CONFIG_MMC_WRITE=y CONFIG_DM_MMC=y CONFIG_MMC_SDHCI_ADMA_HELPERS=y CONFIG_MMC_HW_PARTITIONING=y CONFIG_SUPPORT_EMMC_RPMB=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_CMD_MMC=y CONFIG_MMC_VERBOSE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_SDMA=y CONFIG_MMC_SDHCI_ADMA=y # CONFIG_SPL_MMC_SDHCI_ADMA is not set # CONFIG_MMC_SDHCI_BCMSTB is not set CONFIG_MMC_SDHCI_CADENCE=y
运行验证 1 qemu-system-aarch64 -M hobot-sigi-virt,emmc=on,virt=on -m 4G -display none -device loader,addr=0x3000200000,file=/path/to/u-boot/u-boot-dtb.bin,cpu-num=0 -drive file=/path/to/emmc.img,format=raw,if =emmc -serial stdio
U-Boot distro配置 将U-Boot distro
运行需要的文件复制到emmc.img
的分区part 5
或者part 6
,这样U-Boot后面将自动地从eMMC媒介中加载内核等镜像,完成启动引导。
extlinux.cfg配置文件的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ## /boot/extlinux/extlinux.conf ## menu title U-Boot menu prompt 0 timeout 50 label sigi-kernel-buildroot kernel /Image fdt /hobot-sigi-virt.dtb append earlycon=uart8250,mmio32,0x39050000,115200n8 console=ttyS0,115200n8 loglevel=10 root=/dev/mmcblk0p7 rootwait init=/init rw label sigi-kernel-ubuntu kernel /Image fdt /hobot-sigi-virt.dtb append earlycon=uart8250,mmio32,0x39050000,115200n8 console=ttyS0,115200n8 loglevel=10 root=/dev/mmcblk0p8 rootwait init=/init rw label sigi-kernel-nvme kernel /Image fdt /hobot-sigi-virt.dtb append earlycon=uart8250,mmio32,0x39050000,115200n8 console=ttyS0,115200n8 loglevel=10 root=/dev/nvme0n1p7 rootwait init=/init rw
下面脚本将Image、initramfs、dtb等文件复制到emmc.img的boot_a分区:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #!/usr/bin/bash mkdir -p rootfsset -xpart_map=$(sudo kpartx -av emmc.img) sudo mount /dev/mapper/$(echo "$part_map " | sed -n '5p' | awk '{print $3}' ) rootfs/ sudo mkdir -p rootfs/extlinux/ sudo cp extlinux.conf rootfs/extlinux/ sudo cp linux/arch/arm64/boot/Image rootfs/ sudo cp linux/arch/arm64/boot/Image.gz rootfs/ sudo cp linux/arch/arm64/boot/dts/hobot/hobot-sigi-virt.dtb rootfs/ sudo cp buildroot/output/images/rootfs.cpio.lz4 rootfs/ sudo umount rootfs sudo kpartx -dv emmc.img sync
Ubuntu启动 Ubuntu镜像制作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 wget http://cdimage.ubuntu.com/ubuntu-base/releases/20.04.4/release/ubuntu-base-20.04.4-base-arm64.tar.gz dd if =/dev/zero of=ubuntu.img bs=1M count=1024 oflag=directmkfs.ext4 ubuntu.img mkdir -p rootfssudo mount -t ext4 ubuntu.img rootfs/ sudo tar -xzf ubuntu-base-20.04.4-base-arm64.tar.gz -C rootfs/ sudo cp /usr/bin/qemu-aarch64-static rootfs/usr/bin/ sudo cp /etc/resolv.conf rootfs/etc/resolv.conf sudo mount -t proc /proc rootfs/proc sudo mount -t sysfs /sys rootfs/sys sudo mount -o bind /dev rootfs/dev sudo mount -o bind /dev/pts rootfs/dev/pts sudo chroot rootfs/ apt-get update apt-get install sudo vim-tiny -y apt-get install net-tools iputils-ping -y apt-get install network-manager netplan.io systemd -y apt-get install kmod net-tools ifupdown -y useradd -m -d /home/charley -s /bin/bash -p ubuntu "charley" usermod -a -G sudo charley /bin/bash -c "echo \"virt\" >/etc/hostname" /bin/bash -c "echo \"127.0.0.1 localhost\" >/etc/hosts" /bin/bash -c "echo \"127.0.0.1 virt\" >>/etc/hosts" exit sudo umount rootfs/proc sudo umount rootfs/sys sudo umount rootfs/dev/pts sudo umount rootfs/dev sudo umount rootfs/
将生成的ubuntu.img
里面的内容都复制到emmc.img
的分区part 8
里面,这样U-Boot启动时才能挂载Ubuntu文件系统。
运行验证 1 qemu-system-aarch64 -M hobot-sigi-virt,emmc=on,virt=on -m 4G -display none -device loader,addr=0x3000200000,file=/path/to/u-boot/u-boot-dtb.bin,cpu-num=0 -drive file=/path/to/emmc.img,format=raw,if =emmc -serial stdio
启动日志附件:U-Boot -> Kernel -> Ubuntu Booting
基于Buildroot文件系统启动 将buildroot生成的rootfs.cpio.lz4里面的内容展开到emmc.img
的分区part 7
里面,这样U-Boot启动时才能挂载buildroot根文件系统。
1 qemu-system-aarch64 -M hobot-sigi-virt,emmc=on,virt=on -m 4G -display none -device loader,addr=0x3000200000,file=/path/to/u-boot/u-boot-dtb.bin,cpu-num=0 -drive file=/path/to/emmc.img,format=raw,if =emmc -serial stdio
启动日志附件:U-Boot -> Kernel -> Buildroot Booting
eMMC RPMB访问 RPMB介绍 RPMB(Replay Protected Memory Block) Partition是eMMC中的一个具有安全特性的分区。 eMMC在写入数据到RPMB时,会校验数据的合法性,只有指定的Host才能够写入,同时在读数据时,也提供了签名机制,保证Host读取到的数据是RPMB内部数据,而不是攻击者伪造的数据。
RPMB在实际应用中,通常用于存储一些有防止非法篡改需求的数据,例如手机上指纹支付相关的公钥、序列号等。RPMB可以对写入操作进行鉴权,但是读取并不需要鉴权,任何人都可以进行读取的操作,因此存储到RPMB的数据通常会进行加密后再存储。
运行验证 上面我们制作的emmc.img镜像里面都没有包含rpmb.img镜像,因此我们要制作一个rpmb.img的空间,和emmc.img拼在一起,这样U-Boot才能够访问RPMB的空间。
1 2 3 4 5 dd if =/dev/zero of=rpmb.img bs=1M count=2dd if =/dev/zero of=emmc.img bs=1M count=2046cat rpmb.img emmc.img >emmc-with-rpmb.img
emmc.img大小必须是1G、2G、4G等(要满足2的N次方形式) 否者,就会报如下的错误信息:
1 qemu-system-aarch64 -M hobot-sigi-virt,emmc=on,part-config=0x20,virt=on -m 4G -display none -device loader,addr=0x3000200000,file=/path/to/u-boot/u-boot-dtb.bin,cpu-num=0 -drive file=/path/to/emmc-with-rpmb.img,format=raw,if =emmc -serial stdio
1 2 3 4 5 6 7 8 9 10 11 12 load mmc 0:5 0x3090000000 /rpmb-key.txt;mmc rpmb key 0x3090000000 fatload mmc 0:5 0x3091000000 Image;mmc rpmb write 0x3091000000 0x0 0x10 0x3090000000 md 0x3092000000 0x10 mmc rpmb read 0x3092000000 0x0 0x10 md 0x3092000000 0x10