1.问题描述
在前面的文章中,已经接触过一些Linux内核的知识,本文将进一步从Linux内核源代码的目录结构入手,在Oracle VM VirtualBox的Linux环境中构造一个简单的操作系统MenuOS,内核代码版本为3.18.6,解决了不同于实验楼出现的问题,同时通过gdb跟踪启动操作系统的过程。
2.解决过程
2.1 Linux内核源码目录
arch:用于存放CPU体系结构的相关代码。
block:存放Linux存储体系中关于块设备管理的代码。
crypto:存放常见的加密算法的C语言代码。
Documentation:存放一些文档。
drivers:驱动目录,分类别存放了Linux内核支持的所有硬件设备的驱动源代码。
firmware:固件。
fs:文件系统,存放了Linux支持的各文件系统的实现。
include:头文件目录,存放公共的头文件。
init:存放Linux内核启动时的初始化代码。
lib:存放Linux的共用库文件。
mm:存放内存管理。
net:存放Linux网络的相关代码。
README:内核文件解读文档。
2.2 构造MenuOS系统
2.2.1 源码下载
cd 20199310 #进入20199310目录
mkdir LinuxKernel #创建LinuxKernel目录
cd LinuxKernel #进入Linux目录
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz #在官网下载内核源码,版本未3.18.6
xz -d linux-3.18.6.tar.xz #解压压缩包得到linux-3.18.6.tar
tar -xvf linux-3.18.6.tar #解压压缩包得到linux-3.18.6
cd linux-3.18.6 #进入linux-3.18.6目录
make i386_defconfig #开始编译源码
make
编译过程中可能会出现如下错误:
fatal error: linux/compiler-gcc6.h:没有那个文件或目录
原因是本系统gcc编译器版本过高,与内核源码不兼容,需要从网上下载compiler-gcc6.h放入include/linux目录下,由于compiler-gcc6.h与compiler-gcc5.h大体相似,所以也可以复制compiler-gcc5.h重命名为compiler-gcc6.h,后续编译过程中可能还会遇到类似错误提示,可以用同样方法解决。
修改内容如下图:
2.2.2 根文件系统制作
返回LinuxKernel目录,然后输入如下指令:
mkdir rootfs #创建rootfs目录
git clone https://github.com/mengning/menu.git #从GitHub上克隆menu
cd menu #进入menu目录
gcc -pthread -o init linktable.c menu.c test.c -m32 -static #编译
cd ../rootfs #进入rootfs目录
cp ../menu/init ./ #把init复制到rootfs下
find . | cpio -o -Hnewc |grip -9 > ../rootfs.img #把当前rootfs下的所用文件打包成一个镜像文件
在执行到gcc命令时,出现如下错误:
上网查询后,才知道gcc安装环境没有安装完善,尝试sudo apt-get install gcc-multilib完善gcc安装环境
镜像文件打包成功:
2.2.3 对内核进行跟踪调试
重新配置编译Linux内核,使之携带调试信息,代码如下:
sudo apt-get install libncurses5-dev #安装libncurses5-dev
make menuconfig #配置Linux内核,依次选择kernel hacking -> Conpile-time checks and compiler options -> [*]compile the kernel with debug info
make #开始编译
执行完第一步后会出现如下错误
原因是在没有全屏的状态下执行 make menuconfig,表示终端的窗口太小,需要放大窗口或者全屏操作。
通过查询,了解到虚拟机可以通过安装增强功能,自动调整页面分辨率,同时还具有以下6个功能:
(1)实现宿主机与虚拟机间的鼠标平滑移动
(2)实现宿主机与虚拟机间的文件共享
(3)支持无缝模式
(4)宿主机与虚拟机交换数据、监控客户机,也可以启动客户机中的程序
(5)与主机实现时间同步
(6)虚拟机与宿主机共享剪贴板的内容,也就是说直接可以在主机、客户机之间复制、粘贴
在虚拟机运行窗口栏点击设备 -> 安装增强功能,重启以后即可通过缩放窗口改变自动适应分辨率。
在调整完窗口大小后进入Kernel Configuration,根据步骤操作如下:
最后make指令进行编译,时间较长,编译完成以后就可以跟踪调试Linux内核的启动过程了。
2.3 跟踪调试Linux内核的启动过程
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s #开启内核
此时突然出现qemu命令无法找到的错误提示,使用sudo apt-get install qemu安装更新后发现问题依然没有解决,通过查询资料发现,qemu命令集安装指令为sudo apt-get install qemu-system,其相关命令还包括qemu-system-arm 启动仿真arm芯片,qemu-system-arm -M 察看支持arm平台有哪些(开发板),qemu-system-arm -cpu 察看支持arm哪些cpu,qemu-img 格式化虚拟客户端映像、附加存储设备以及网络存储等等,qemu只是其中的一个。
进入内核程序,由于使用参数-S使其被冻结,显示如下:
另一个参数-s表示在端口上创建一个gdb-server。
用ctrl+shift+t打开另一个终端窗口,在LinuxKernel下进入gdb,输入如下代码:
gdb #进入gdb
file linux-3.18.6/vmlinux #选择调试文件
target remote:1234 #用1234这个端口进行链接
break start_kernel #在start_kernel()设置断点
c #运行至第一个断点
break rest_init #在rest_init ()设置断点
c #运行至第二个断点
c #运行剩余启动代码
运行结果如下:
内核运行的主要代码为arch/main.c,其中start_init()相当于一般main.c的main函数,是内核运行的开始,用于完成硬件系统的初始化,0号进程init_task为task_struct类型,是进程描述符,rest_init()用于新建kernel_init和kthreadd内核线程。
3.总结
本文主要学习了Linux内核源代码的目录结构,并且在Oracle VM VirtualBox的Linux环境中构造一个简单的操作系统MenuOS,在这过程中解决了不少问题。在配置和编译Linux内核的时,由于实验环境不同经常缺少一些文件或者没有安装好命令;在make menuconfig中遇到的问题查找了很久,一开始用快捷键切换全屏模式、无缝模式和比例模式,发现实际分辨率没有变化,然后又通过命令的方式修改配置文件,重启后也没有成功,最后还发现安装增强功能这么一个强大的功能找到了修改分辨率的方法。总之,本次实验还是让我收获很多。