本文共 4575 字,大约阅读时间需要 15 分钟。
参考陈香兰老师Linux源码分析的课件,编译完linux源码之后,准备制作一个文件系统。
本文介绍了两种文件系统的生成方式,包括:
1. 自己制作init和/dev/ram和/dev/console(遇到了文件系统的错误,花了很长时间才解决) 2. 利用busybox生成文件系统。0x01首先创建一个应用程序
这个程序作为init程序,是linux启动后准备执行的程序。
#include#include void main(){ while(1){ printf("Hello!\n"); sleep(1); }}
静态编译:gcc test.c --static -o init (没有lib,必须静态编译)
0x02 建立文件系统 镜像
dd if=/dev/zero of=myinitrd4M.img bs=4096 count=1024mke2fs myinitrd4M.imgmkdir rootfssudo mount -o loop myinitrd4M.img rootfs
将init拷贝到目标根目录下(linux启动后期会在根目录中寻找一个应用程序来运行,在根目录下提供init是一种可选方案)
sudo cp init rootfs/
准备dev目录
sudo mkdir rootfs/dev#linux启动过程中会启用console设备sudo mknod rootfs/dev/console c 5 1#另外需要提供一个linux根设备,我们使用ramsudo mknod rootfs/dev/ram b 1 0sudo umount rootfs
至此,一个包含简单应用程序的根目录映像myinitrd4M.img就准备好了。
0x03 qemu启动
qemu-system-x86_64 -kernel ./linux-2.6.32.1/arch/x86/boot/bzImage -initrd ./testimg/myinitrd4M.img -append "root=/dev/ram init=/init"
报错:
No filesystem could mount root, tried: ext3 vfat msdos iso9660
kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0 )
搜索了很久很久之后,终于意识到这个问题本质是,qemu启动镜像的时候尝试了ext3 vfat msdos iso9660这些文件格式,却没有尝试ext2。查看一下我们之前创建的镜像文件格式:
解决办法一:在rootfs中使用cpio生成新的镜像文件
find . | cpio -o --format=newc > ../initrd.img# 重新运行qemu-system-x86_64 -kernel ./linux-2.6.32.1/arch/x86/boot/bzImage -initrd testimg/initrd.img -append "root=/dev/ram init=/init"
退出qemu : ctrl+a x
解决办法二(推荐):既然qemu使用了ext3,那么创建img时创建ext3不就可以了吗。
# 重新生成ext3格式的img文件,确保这时rootfs已经unmount了dd if=/dev/zero of=myinitrd4M.img bs=4096 count=1024mkfs.ext3 myinitrd4M.img
mkdir rootfssudo mount -o loop myinitrd4M.img rootfssudo cp init rootfs/sudo mkdir rootfs/devsudo mknod rootfs/dev/console c 5 1sudo mknod rootfs/dev/ram b 1 0sudo umount rootfs
启动qemu:
qemu-system-x86_64 -kernel ./linux-2.6.32.1/arch/x86/boot/bzImage -initrd testimg/myinitrd4M.img -append "root=/dev/ram init=/init"
0x04 利用busybox生成文件系统
上面是在文件系统中放入了init文件个/dev 设备文件,如果需要用busybox创建文件系统,下面从busybox中创建文件系统的方法,第一种最简洁但是换了内核之后会遇到一些问题,第二种比较稳定。
方法一:
参考下面简陋的bash脚本。把busybox中默认install生成的文件安装到rootfs,并创建/dev/console和/dev/ram即可。
条件:运行目录下有编译好的linux-2.6.32.1/arch/x86/boot/bzImage和busybox-1.28.4/_install,如果没有需要从源码重新编译。参考
#!/bin/bash# 1 create myinitrd40M.imgmkdir testimgcd testimgdd if=/dev/zero of=myinitrd40M.img bs=40960 count=1024mkfs.ext3 myinitrd40M.img # 文件格式按需修改# 2 mount myinitrd40M.img to rootfs foldermkdir rootfssudo mount -o loop myinitrd40M.img rootfs# 3 install busybox to rootfscd ../busybox-1.28.4sudo make CONFIG_PREFIX=../testimg/rootfs install# 4 rootfs mknod and create initrd.imgcd ../testimg/rootfssudo rm -rf lost+foundsudo mkdir devsudo mknod dev/console c 5 1sudo mknod dev/ram b 1 0 # find . | cpio -o --format=newc > ../myinitrd40M.img #已经是ext3文件格式,不需要再生成了sleep 1# 5 umount cd ../sudo umount rootfscd ../# 6 start qemuqemu-system-x86_64 -kernel ./linux-2.6.32.1/arch/x86/boot/bzImage -initrd testimg/myinitrd40M.img -append "console=ttyS0 ramdisk_size=409600 root=/dev/ram init=/bin/sh rw" -nographic
方法二:(推荐用这个)
利用busybox创建文件系统参考 https://www.anquanke.com/post/id/85837 里面介的两种方式来创建,测试可以成功。
方案一:
$ cd _install$ mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}$ cat init#!/bin/shecho "INIT SCRIPT"mount -t proc none /procmount -t sysfs none /sysmount -t debugfs none /sys/kernel/debugmkdir /tmpmount -t tmpfs none /tmpmdev -s # We need this to find /dev/sda laterecho -e "nBoot took $(cut -d' ' -f1 /proc/uptime) secondsn"exec /bin/sh$ chmod +x init$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > /tmp/initramfs-busybox-x86.cpio.gz
方案二:
#在install目录中添加inittab文件:$ cat etc/inittab ::sysinit:/etc/init.d/rcS::askfirst:/bin/ash::ctrlaltdel:/sbin/reboot::shutdown:/sbin/swapoff -a::shutdown:/bin/umount -a -r::restart:/sbin/init添加rcS文件$ cat etc/init.d/rcS #!/bin/sh#!/bin/shmount -t proc none /procmount -t sys none /sys/bin/mount -n -t sysfs none /sys/bin/mount -t ramfs none /dev/sbin/mdev -$ chmod +x ./etc/init.d/rcS配置下dev目录mkdir devsudo mknod dev/ttyAMA0 c 204 64sudo mknod dev/null c 1 3sudo mknod dev/console c 5 1$ find . | cpio -o --format=newc > ../rootfs.img
每次修改了busybox下的文件后,执行find . | cpio -o --format=newc > ../rootfs.img重新创建img即可。
PS: 遇到一个小问题,暂时没解决,记录一下。编译linux源码的时候,用的是make defconfig,看了.config配置是x64位的。可是镜像确是在x86目录下创建的,file看了一下是x86镜像,可是qemu起的时候却说需要用64位来启动,很奇怪。希望路过的同学指教....
0x05 参考
[1] find . | cpio -o --format=newc > ../initrd.img
https://balau82.wordpress.com/2010/03/22/compiling-linux-kernel-for-qemu-arm-emulator/ [2] 陈香兰老师ppt http://staff.ustc.edu.cn/~xlanchen/ULK2011Spring/slides/2_2build+run+gdb%20linux-2.6.26.pdf