说明

本文主要创建一个完整的系统,它包括前面介绍的BIOS,以及这里会介绍的GRUB、内核和文件系统等内容。

内核下载和编译

由于使用的坏境是Ubuntu18.04,所以内核的下载和编译是比较简单的事情。首先是下载内核,需要使用如下的命令:

sudo apt install linux-source

下载过程如下:

下载到的代码可以在/usr/src这个目录找到:

我们将它下载并放到指定的目录:

tar -xjvf linux-source-4.15.0.tar.bz2 -C /home/jw/code/

其中的-C是用来指定解压缩的目标文件夹的,这样就可以在指定的目录找到linux源代码并使用了。之后进入到/home/jw/code/linux-source-4.15.0目录,开始编译。在编译之前需要先创建.config文件,为了方便起见这里直接使用默认的配置(后续可以根据实际情况修改):

make defconfig

之后就可以通过make进行编译,不过编译过程中可能会报错,原因是某些依赖的库不存在,安装即可,这里需要安装(不同Ubuntu版本需要安装的库可能不同,请按实际情况安装):

sudo apt install libelf-dev
sudo apt install libssl-dev

编译成功之后可以在~/code/linux-source-4.15.0/arch/x86/boot下面找到我们需要的内核文件:

到这里编译结束,注意不要使用make install安装内核,因为我们不是要在编译机上安装这个内核,而是需要使用虚拟机(QEMU)来运行内核,即bzImage将被用于QEMU启动系统。

GRUB

可以通过git下载GRUB,这里使用GRUB 2.02版本,命令如下:

git clone https://gitee.com/jiangwei0512/grub-2.02

下载完成之后进入目录,首先运行./configure:

./configure --target=x86_64 --with-platform=efi

这里使用了几个参数,其中--target参数用来指定对应的平台,这里指定了x86的64位平台,而另一个参数--with-platform用来指定用于UEFI。但是configure时会出现报错的情况,原因是有一些库还需要安装:

sudo apt install flex bison

之后configure运行成功,可以执行make命令。编译时如果出现没有alcocal-1.15的错误,可以安装automake并运行autoreconf -i -f来解决,不过有更简单的方法就是touch一下所有的文件即可。make成功之后通过如下的命令来生成GRUB二进制:

./grub-mkimage -p . -d ./grub-core/ -O x86_64-efi -o bootx64.efi XXX

简单说明下参数:-p指定了grub.cfg,独立模块等文件所在的目录;-d指定了我们刚才编译出来的image和module的位置,因为它们才是我们需要的,而不是系统中已经存在的;-O指定了二进制的格式,我们需要x86平台下UEFI的格式;-o用来指定输出的文件名;最后的XXX是GRUB模块,就是grub-core目录下的*.module文件:

这里使用的模块指定如下:

./grub-mkimage -p . -d ./grub-core/ -O x86_64-efi -o bootx64.efi boot linux part_msdos part_gpt fat normal serial efi_gop minicmd

最终编译出来的二进制是bootx64.efi(之所以要使用这个名字,是因为它是UEFI里面通用的OS加载器名称),后面会使用到这个文件。除此之外,GRUB还有一个对应的配置文件称为grub.cfg,后面会介绍它的具体内容。GRUB及其配置文件将被用于QEMU启动系统。

busybox

可以在Index of /downloads下载到busybox的源码,这里下载的是1.29.1版本,解压到指定的目录:

tar -xjvf busybox-1.29.2.tar.bz2 -C /home/jw/code

然后进入该目录进行配置(在源代码目录下执行make menuconfig):

我们之类需要配置的是选择静态编译,位置在Settings项下。需要注意为了使用menuconfig,可能需要安装额外的库(libncurses5-dev)。配置之后就可以使用make进行编译。编译完成之后通过make install命令进行安装:

make install

执行上述命令之后,会在当前目录生成一个新的目录称为_install,我们需要这些文件生成initramfs,供内核使用,对应的文件如下:

创建initramfs的方法,这里使用最简单的,对应的命令如下:

mkdir initramfs
cd initramfs
mkdir dev proc sys
cp ../_install/* ./ -ra
sudo cp -a /dev/{null,console,tty1,tty2,tty3,tty4} dev/
touch init
chmod a+x init

其中init的内容如下:

mount -t proc none /proc
mount -t sysfs none /sys
mdev -s
exec /sbin/init

最后再通过如下的命令打包:

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

initramfs.cpio.gz就是我们最终得到的文件,它将被用于QEMU启动系统。

QEMU启动系统

首先是创建一个QEMU使用的硬盘(其实就是个文件而已),并格式化成FAT格式(因为UEFI默认只识别这种类型):

dd if=/dev/zero of=disk.img bs=1M count=32
mkfs.fat disk.img

这里创建的disk.img大小是32M,这个不是硬性规定,只要大于内核、initramfs、GRUB等大小的总和即可。之后的操作就是挂载disk.img,并将上述提到的文件放到disk.img中:

sudo mount disk.img tmp
sudo mkdir tmp/EFI tmp/EFI/BOOT
sudo cp bootx64.efi grub.cfg tmp/EFI/BOOT
sudo cp bzImage initramfs.cpio.gz tmp

我们首先需要讲disk.img挂载到一个目录下(这里就是tmp),然后再往里面放文件,需要特别注意的是GRUB及其配置文件,需要放到/EFI/BOOT目录下,最终的文件如下:

到这里我们就已经将需要的文件放到了disk.img中,可以把它当做QEMU的硬盘来使用,对应的指令如下:

qemu-system-x86_64 -bios OVMF.fd -hda disk.img -m 512M

这里的QEMU参数如下:-bios指定BIOS名,这里就是OVMF.fd;-hda指定硬盘,这里就是disk.img;-m指定虚拟机使用的内存大小。启动之后的最终状态如下:

到这里一个基本的内核就已经启动起来,后面我们可以依赖该系统进行调试。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐