MenuOs的构造
1.跟踪调试Linux内核的启动过程
2.从start_kernel到init进程启动的过程分析
3.总结
1.跟踪调试Linux内核的启动过程
- 启动MenuOS
输入命令:
$ cd LinuxKernel/
$ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
- 跟踪调试Linux内核的启动过程
$ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
- 再打开一个窗口,水平分割,启动gdb,把内核加载进来,建立连接。
打开gdb调试器
$ gdb
在gdb中输入以下命令:
在gdb界面中targe remote之前加载符号表:
(gdb)file linux-3.18.6/vmlinux
建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行:
(gdb)target remote:1234
断点的设置可以在target remote之前,也可以在之后:
(gdb)break start_kernel
在start_kernel处设置断点,刚才是stop状态,如果按c继续执行,那么系统开始启动执行,启动到start_kernel函数的位置停在断点处
再设置一个断点rest_init,继续执行,停在断点处。
2.从start_kernel到init进程启动的过程分析
init目录中的main.c源文件是整个Linux内核启动的起点,但它的起点不是main函数,而是start_kernel函数,start_kernel函数是初始化Linux内核启动的起点,start_kernel函数几乎涉及了内核的所有主要模块,如中断向量的初始化,内存管理的初始化,调度模块的初始化等。start_kernel前的代码使用汇编语言来进行硬件的初始化,为C代码的运行设置环境。Linux在无进程概念的情况下将一直从初始化部分的代码执行到start_kernel,然后再到其最后一个函数调用rest_init。从rest_init开始,Linux开始产生进程,init_task是0号进程,但它不是系统通过kernel_thread的方式创建的,init_task创建了1号内核进程kernel_init后,调用cpu_idle()演变成了idle进程,执行一次调度后,init内核进程运行,1号内核进程负责执行内核的部分初始化工作及进行系统配置,最后调用do_execve加载init程序,演变成init进程(用户态1号进程),init进程是内核启动的第一个用户态进程,是其它用户进程的祖先进程。init_task调用kernel_thread创建2号内核线程,2号内核线程始终运行在内核空间,是所有内核态其它守护线程的父线程。
3.总结
计算机3大法宝:存储程序计算机,函数调用堆栈,中断。
操作系统2把宝剑:中断上下文的切换(保存现场和中断现场),进程上下文的切换。
内核源代码根目录下的几个关键目录:
- block:存放linux存储体系中关于块设备管理的代码
- crypto:存放常见的加密算法的C语言代码
- Documentation: 存放一些文档
- drivers:驱动目录,里面分门别类的存放了linux内核支持的所有硬件设备的驱动源代码
- firmware:固件
- fs:文件系统,里面列出了linux支持的各种文件系统的实现
- include:头文件目录,存放公共的头文件
- init:存放linux内核启动时的初始化代码
- kernel:存放内核本身需要的一些核心代码文件
- lib:公用的库文件,里面是一些公用的库函数
- mm:存放linux的内存管理代码
- net:存放与网络相关的代码,例如TCP/IP协议栈等