第三章 MenuOS的构造
构造一个简单地Linux内核
第一步、构建Linux系统MenuOS
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
注:qemu仿真kernel;bzImage是vnLinux经过gzip压缩后的文件,是压缩的内核映像;initrd是内存根文件系统;rootfs是编译好的文件系统。
运行结果如图:
第二步、跟踪调试Linux内核的启动过程(使用gdb跟踪)
-
输入如下命令将内核启动:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
注:
- -s:在1234端口上创建了一个gdb-server,可用于之后设置断点跟踪内核;
- -S:使CPU初始化之前冻结起来。
启动效果如下图:
-
启动gdb输入如下指令加载内核,建立连接
file linux-3.18.6/vmlinux //在gdb界面中target remote之前加载符号表 target remote:1234 //用1234这个端口进行连接
-
gdb中输入如下指令在start_kernel处设置断点
break start_kernel //可在target remote之前,也可在之后
效果如图:
查看strat_kernel代码:
分析: strat_kernel是一切的起点,用于完成硬件系统的初始化工作,为C代码的运行设置环境。
其中,比较重要的init_task是手工创建的PCB,是进程描述符,0号进程,即最终的idle进程。
-
gdb中输入如下指令在rest_init()处设置断点
break rest_init
查看rest_init()代码:
分析: 通过rest_init()新建kernel_init和kthreadd内核线程
注:
- init_task(0号进程)是唯一没有通过fork方式产生的进程;
- 所有的内核线程都是直接或间接地一kthreadd为父进程。
-
总结进程创建过程
- init_task()(PID为0)通过调用cpu_idle()转为idle进程,运行在内核空间;
- init_task()创建的kernel_init()(1号内核线程)通过调用do_execve可转为init用 户态1号进程,这是内核启动的第一个用户态进程;
- init_task()创建的kthreadd()(2号内核线程)始终运行在内核,负责所有内核线程的调度和管理。
整个过程如图所示: