上一节介绍了如何编译指定平台上的Linux内核,并说明了如何使用QEMU模拟器安装和运行编译后的Linux内核。

在此基础上,我们尝试修改了 linux 内核源码,成功的让 linux 内核在启动时,打印出了我们的名字。

我不明白,上一篇是一个一个字手打出来的原创文章,为何头条给了 0 推荐。感兴趣的朋友手动点我过去看看吧。

还记得上一节遗留的问题吗?虽然 qemu 模拟器成功的运行了 linux 内核,但是内核启动后,因为找不到文件系统,陷入“kernel panic(内核恐慌)”。本节,我们一起来解决这个问题,让 qemu 真正的运行起 linux 系统。

我们计划在一台电脑上模拟运行我们编译的 linux 内核,那文件系统放在哪呢?再新建一个磁盘分区太浪费了吧?好在我们的主机是 linux 系统,可以新建一个文件用于模拟磁盘分区。执行下面这条命令:

dd if=/dev/zero of=di bs=20k count=25600

这条命令的意思是,在当前目录新建一个空文件 di,这个空文件的大小等于 20K x 25600,也即约 524MB。现在 di 文件是个空文件,相当于一块没有格式化的硬盘,所以如果想让它做 linux 的文件系统,首先就要把它格式化为 linux 内核能够识别格式,这里选择 ext2 格式:

mkfs -t ext2 di

格式化可能需要我们输入 y。命令执行完毕,我们就得到了“一块 ext2 格式的硬盘”。我们新建一个目录 rootfs,把它挂在到这个目录上。

mkdir rootfs
sudo mount -o loop di rootfs
ls rootfs

现在 rootfs 里面的内容就是 di 的内容。我们将 linux 内核的一些库安装到这个目录:

cd linux-2.6.26
make modules_install INSTALL_MOD_PATH=../rootfs

执行上面的命令后,发现库已经被安装在我们的“虚拟磁盘”里了。

我们卸载 rootfs,把改动刷新到 di

cd ..
sudo umount rootfs

接下来,为了测试方便,我们先把内核镜像拷贝到当前目录:

cp linux-2.6.26/arch/x86_64/boot/bzImage .

上一节,我们使用 qemu 模拟运行 linux 内核时,内核找不到文件系统陷入恐慌,那我们现在用 di 作为文件系统,看看会怎样:

qemu-system-x86_64
-m 512M
-smp 1
-kernel bzImage
-drive format=raw,file=di # 指定文件作为磁盘
-append "root=/dev/hda" # 内核启动参数,指定根文件系统所在设备
-curses

执行这条命令,发现 linux 内核启动了,但是最后还是陷入“内核恐慌”:

不过这次不是因为找不到文件系统了,而是因为找不到 init 程序,而且也找不到 console。linux 内核在启动差不多完成时,需要一个 init 程序,用于做根目录挂载等一些初始化工作,一些终端信息会通过 console 打印出来。现在 linux 内核找不到 init 程序,完成不了工作,自然“恐慌”的一批。那我们给他指定一个 init 程序,再创建一个 console 就好了嘛。

我们先用 c语言 写一个 init 程序:

#include <;
int main()
{
printf("nhello, i am init program!nn");
return 0;
}

然后编译之:

gcc -static -o init init.c

这样就得到了 init 程序。然后,再把 di 挂载到 rootfs 上,因为我们需要把 init 放进去。放进 init 之后,还要创建 dev 目录,并且在里面创建 console:

sudo mount -o loop di rootfs
cp init rootfs
cd rootfs
mkdir dev
mknod dev/console c 5 1
cd ..
sudo umount rootfs

上面的最后一条命令是卸载 di,目的是把改动刷新到 di 里,好了一切都改动好了,现在再来运行一次试试:

qemu-system-x86_64
-m 512M
-smp 1
-kernel bzImage
-drive format=raw,file=di
-append "init=/init root=/dev/hda"
-curses

发现我们的 init 程序被内核启动了,而且 linux 内核找到 console,并把信息打印出来了,但最后还是报错了。这是肯定的,因为我们指定的 init 程序除了打印信息,什么也没做。真正能把 linux 内核启动起来的 init 程序还是挺复杂的,当然,这些工作有人已经完成了,例如 busybox。限于篇幅,下一节再介绍如何真正的把我们自己编译的linux 内核启动起来。

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

相关推荐