参考陈香兰老师Linux源码分析的课件,编译完linux源码之后,准备制作一个文件系统。
本文介绍了两种文件系统的生成方式,包括:
1. 自己制作init和/dev/ram和/dev/console(遇到了文件系统的错误,花了很长时间才解决)
2. 利用busybox生成文件系统。
0x01首先创建一个应用程序
这个程序作为init程序,是linux启动后准备执行的程序。
#include <stdio.h>
#include <unistd.h>
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=1024
mke2fs myinitrd4M.img
mkdir rootfs
sudo 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根设备,我们使用ram
sudo mknod rootfs/dev/ram b 1 0
sudo 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=1024
mkfs.ext3 myinitrd4M.img
mkdir rootfs
sudo mount -o loop myinitrd4M.img rootfs
sudo cp init rootfs/
sudo mkdir rootfs/dev
sudo mknod rootfs/dev/console c 5 1
sudo mknod rootfs/dev/ram b 1 0
sudo 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.img
mkdir testimg
cd testimg
dd if=/dev/zero of=myinitrd40M.img bs=40960 count=1024
mkfs.ext3 myinitrd40M.img # 文件格式按需修改
# 2 mount myinitrd40M.img to rootfs folder
mkdir rootfs
sudo mount -o loop myinitrd40M.img rootfs
# 3 install busybox to rootfs
cd ../busybox-1.28.4
sudo make CONFIG_PREFIX=../testimg/rootfs install
# 4 rootfs mknod and create initrd.img
cd ../testimg/rootfs
sudo rm -rf lost+found
sudo mkdir dev
sudo mknod dev/console c 5 1
sudo mknod dev/ram b 1 0
# find . | cpio -o --format=newc > ../myinitrd40M.img #已经是ext3文件格式,不需要再生成了
sleep 1
# 5 umount
cd ../
sudo umount rootfs
cd ../
# 6 start qemu
qemu-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/sh
echo "INIT SCRIPT"
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mkdir /tmp
mount -t tmpfs none /tmp
mdev -s # We need this to find /dev/sda later
echo -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/sh
mount -t proc none /proc
mount -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 dev
sudo mknod dev/ttyAMA0 c 204 64
sudo mknod dev/null c 1 3
sudo 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位来启动,很奇怪。希望路过的同学指教....