环境
Qemu 4.1
vexpress-ca9
参考
Using the initial RAM disk (initrd)
pivot_root - change the root filesystem
概述
为了减小linux内核的大小,可以把一些外设驱动编译成内核模块,但是在启动ubuntu的时候,需要加载存放在ubuntu文件系统中的flash驱动,而ubuntu文件系统本身也存放在flash中。为了解决这样的问题,可以使用ramdisk内存文件系统,将必备的驱动模块,比如这里的flash驱动模块放到ramdisk中,当uboot引导linux时,可以将ramdisk和内核镜像先加载到内存,启动内核时,会将ramdisk在内存中的内存地址传给内核。
当内核启动后,会先将ramdisk作为根文件系统,然后使用insmod加载存放在ramdisk文件系统中的flash驱动,就可以访问存放有ubuntu文件系统的块设备节点,最后再通过命令将根文件系统切换为ubuntu文件系统。
正文
这里为了简单起见,没有把存储器驱动编译成内核模块,只是演示一下从ramdisk切到ubuntu的过程。
原先直接启动ubuntu使用的命令是:
kernel_dir=./linux-4.14.13 kernel_image=${kernel_dir}/arch/arm/boot/zImage dtb_image=${kernel_dir}/arch/arm/boot/dts/vexpress-v2p-ca9.dtb sudo qemu-system-arm \ -M vexpress-a9 \ -m 1024M \ -smp 4 \ -kernel ${kernel_image} \ -append "noinitrd root=/dev/vda1 rw rootfstype=ext4 console=ttyAMA0,115200" \ -dtb ${dtb_image} \ -drive if=none,file=./ubuntu_rootfs/ubuntu.fulldisk,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -nic tap \ -serial stdio
其中vda是一个虚拟磁盘,它的第一个分区中存放的是ubuntu根文件系统。
现在,如果使用ramdisk启动ubuntu的话,修改启动命令:
kernel_dir=./linux-4.14.13 kernel_image=${kernel_dir}/arch/arm/boot/zImage dtb_image=${kernel_dir}/arch/arm/boot/dts/vexpress-v2p-ca9.dtb sudo qemu-system-arm \ -M vexpress-a9 \ -m 1024M \ -smp 4 \ -kernel ${kernel_image} \ -dtb ${dtb_image} \ -drive if=none,file=./ubuntu_rootfs/ubuntu.fulldisk,id=hd0 \ -device virtio-blk-device,drive=hd0 \ -append "root=/dev/ram0 rw rootfstype=ext4 console=ttyAMA0 init=/linuxrc ignore_loglevel" \ -initrd ./rootfs/ramdisk.img \ -nic tap \ -serial stdio
为此,需要修改ramdisk的内容,原先我用的ramdisk中的根文件系统是用busybox编译生成的,/linuxrc是指向/bin/busybox的软连接。需要对此进行修改,修改后的ramdisk内容如下(为了简单明了,我仅保留必备的一些命令):
. ├── bin │ ├── busybox │ ├── cd -> busybox │ ├── chroot -> busybox │ ├── echo -> busybox │ ├── exec -> busybox │ ├── mdev -> busybox │ ├── mkdir -> busybox │ ├── mount -> busybox │ ├── pivot_root -> busybox │ ├── sh -> busybox │ └── umount -> busybox ├── dev ├── linuxrc └── sys
其中linuxrc是一个shell脚本,内容如下:
#!/bin/sh echo "hello world" echo "mount -t sysfs sysfs /sys" mount -t sysfs sysfs /sys echo "mdev -s" mdev -s echo "mkdir /newroot" mkdir /newroot echo "mount -t ext4 /dev/vda1 /newroot" mount -t ext4 /dev/vda1 /newroot echo "sys" umount /sys echo "cd /newroot" cd /newroot echo "mkdir -p oldroot" mkdir -p oldroot echo "pivot_root . oldroot" pivot_root . oldroot echo "exec chroot . /sbin/init <dev/console >dev/console 2>&1" exec chroot . /sbin/init <dev/console >dev/console 2>&1
如果ramdisk里有需要加载的flash驱动,需要先insmod,然后才能看到/dev/vda1。
ubuntu文件系统中/sbin/init是一个软连接,实际指向的是/lib/systemd/systemd。
制作ramdisk镜像的命令:
#!/bin/bash sudo dd if=/dev/zero of=ramdisk bs=1M count=32 sudo mkfs.ext4 -F ramdisk sudo mkdir -p tmpfs sudo mount -t ext4 ramdisk ./tmpfs/ -o loop sudo cp -raf rootfs/* tmpfs/ sudo umount tmpfs sudo gzip --best -c ramdisk > ramdisk.gz sudo mkimage -n "ramdisk" -A arm -O linux -T ramdisk -C gzip -d ramdisk.gz ramdisk.img
下面是启动log:
完。