作者:昱辰190974945122 | 来源:互联网 | 2023-10-10 16:48
本文目标是构建随处可用的内核开发环境,用于Linux内核调度器的研究。开发环境的开发套件由docker,ubuntu14.04,qemu,vim,zsh等构成。按照该开发环境的套件
本文目标是构建随处可用的内核开发环境,用于Linux内核调度器的研究。开发环境的开发套件由docker,ubuntu14.04,qemu,vim,zsh等构成。
按照该开发环境的套件要求,将在docker中构建ubuntu14.04系统,并构建内核编译和源码查看环境。主要步骤如下:
- 基于Docker安装Ubuntu-14.04
- 登录Docker中的Ubuntu-14.04
- 在ubuntu中安装qemu,vim,zsh
- 下载Linux内核源码,并编译
- 创建磁盘,启动编译后的内核
1. 基于Docker安装Ubuntu-14.04。指令如下所示:
axel -n 10 https://download.openvz.org/template/precreated/ubuntu-14.04-x86_64.tar.gz
cat ubuntu-14.04-x86_64.tar.gz | docker import - ubuntu:14.04
docker images
2. 登录Docker中的ubuntu-14.04
docker run -p 301:22 -d --name test ubuntu /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
ssh [email protected] -p 301
3. 在ubuntu中安装qemu,vim,zsh
sudo apt-get install qemu vim zsh axel wget curl
4. 下载Linux内核源码,并编译
axel -n 10 https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.18.tar.gz
tar -zxfv linux-4.18.tar.gz
cd linux-4.18
关于Linux内核编译,可以参考博客。具体过程如下:
make help # 查看make参数
make x86_64_defconfig
结果发现,缺乏编译器,此外,在编译过程中,还发现缺乏依赖库。因此,一次安装如下依赖库
sudo apt-get install bison flex qemu bc build-essential gcc g++ libelf-dev libssl-dev
make x86_64_defconfig
make bzImage # 编译内核
make modules # 编译模块
编译完成之后,将生成内核压缩文件arch/x86/boot/bzImage
5. 创建磁盘,启动编译后的内核
起初,打算直接在docker中用qemu启动bzImage,然而,出现了图形化界面使用错误的情况。
root# qemu-system-x86_64 -m 512M -smp 4 -kernel ./bzImage
Could not initialize SDL(No available video device) - exiting
鉴于这样的情况,有两种方案:
(1)在qemu启动时使用-curses参数,可直接启动(亲测有效)
(2)将容器中编译好的压缩内核bzImage复制(docker cp)到本地host系统中,基于qemu启动。
基于第二种方案构建的开发环境,缺少了docker一贯的隔离性,即要求host系统中安装qemu环境,且主机系统和虚拟机系统的内容来回传递。因此,直接使用第一种方案,但是需要另外连接的终端终止当前qemu程序才能重新回到容器的shell中。
在启动编译后的压缩内核时,出现无法找到文件系统的错误:
为此,需要创建磁盘镜像,制作根文件系统,且准备init程序才能启动编译后的内核。
但是在创建磁盘并挂在的过程中,出现无法找到loop设备的错误。
qemu-img create -f raw disk.raw 512M
mkfs -t ext4 ./disk.raw # 若没有mkfs.ext4,则安装e2fsprogs套件,sudo apt-get install e2fsprogs
sudo mount -o loop ./disk.raw ./img
mount: Could not find any loop device. Maybe this kernel does not know
about the loop device? (If so, recompile or `modprobe loop'.)
最快捷方便的解决方案就是在docker run时,加入特权:
docker run --privileged=true ...
目前,可以挂在文件系统,但是缺乏启动程序init,因此基于busybox构建启动程序。但是在编译过程中,出现缺少curses.h头文件的情况,这是因为缺少套件ncurses devel。
make defconfig
make menuconfig
In file included from scripts/kconfig/lxdialog/checklist.c:24:0:
scripts/kconfig/lxdialog/dialog.h:31:20: fatal error: curses.h: No such file or directory
#include CURSES_LOC
^
compilation terminated.
make[2]: *** [scripts/kconfig/lxdialog/checklist.o] Error 1
make[1]: *** [menuconfig] Error 2
make: *** [menuconfig] Error 2
sudo apt-get install libncurses5-dev # 缺少ncurses devel套件
然后,再次编译时,将busybox编译为静态的二进制文件。然后make编译,并安装到挂在的img目录中。
Busybox Settings --->
--- Build Options
[*] Build BusyBox as a static binary (no shared libs)
# make
# make CONFIG_PREFIX= install
# ls #可以看到包含了更多目录
此外,还需要创建额外的文件,包括rcS,inittab,proc,sys,dev等,具体可以参考博客。
以下是直接可用的脚本,需要修改相应的路径。
#!/bin/sh
# note: Linux kernel and busybox are in the same directory
path_to_Linux_kernel=linux-4.18
path_to_busybox=busybox-1.30.0
path_to_root=`pwd`
cd $path_to_Linux_kernel
#make clean
#make distclean
#make x86_64_defconfig
#make bzImage
#make modules
# obtain the bzImage
cp arch/x86/boot/bzImage $path_to_root
# create disk by type ext4
cd $path_to_root
if [ -d img ]; then
umount img
rm -rf img
fi
if [ -e disk.raw ]; then
rm disk.raw
fi
qemu-img create -f raw disk.raw 512M
mkfs -t ext4 disk.raw
mkdir img
sudo mount -o loop disk.raw img # note that, docker run --privileged=true
# install modules and init program
cd $path_to_Linux_kernel
sudo make modules_install INSTALL_MOD_PATH=../img
cd $path_to_root/$path_to_busybox
if [ -e busybox ]; then
make CONFIG_PREFIX=../img install
else
echo "Busybox is not built yet. Please build the busybox first!"
exit 2
fi
# update the init program
cd $path_to_root/img
mkdir -p etc/init.d
mkdir proc
mkdir sys
mkdir dev
touch etc/init.d/rcS
echo "#/bin/sh" > etc/init.d/rcS
echo "mount -t proc proc /proc" >> etc/init.d/rcS
echo "mount -t sysfs sysfs /sys" >> etc/init.d/rcS
chmod +777 etc/init.d/rcS
# start the bzImage
cd $path_to_root
qemu-system-x86_64 -curses -m 512M -smp 4 -kernel bzImage -drive format=raw,file=disk.raw -append "init=/linuxrc root=/dev/sda"
最后,在docker容器中的ubuntu就可以启动qemu了。
qemu-system-x86_64 -curses -m 512M -smp 2 -kernel bzImage -drive format=raw,file=disk.raw -append "init=/linuxrc root=/dev/sda"
终结
在所有的环境搭建好之后,要保存(commit)当前容器的状态,并推送到远程网络(push),这样就可以在任何一台装有docker的系统中,使用该环境,进行Linux内核开发和学习。
docker commit -m "update with busybox" [:]