Linux内核分析— —构造一个简单的Linux系统MenuOS

    • 实验内容

    • Linux内核的启动过程,从start_kernel到init进程启动

使用实验楼的虚拟机打开shell

cd LinuxKernel/

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

 

内核启动完成后进入menu程序(《软件工程C编码实践篇》的课程项目),支持三个命令help、version和quit,您也可以添加更多的命令,对选修过《软件工程C编码实践篇》的童鞋应该是a piece of cake.

使用gdb跟踪调试内核

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

# 关于-s和-S选项的说明:

-S freeze CPU at startup (use ’c’ to start execution)

-s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

另开一个shell窗口

gdb

(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表

(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行

(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后

(gdb)c # 系统开始启动,启动到start_kernel

(gdb)list # 可以看到start_kernel上下的代码

(gdb)break rest_init

(gdb)c # 当前系统执行到rest_init

    • 分析start_kernel函数的执行过程

trap_init:硬件中断,初始化一些中断向量,系统调用。

set_intr_gate:设置中断门。

set_system_trap_gate:系统陷阱门SYSCALL VECTOR。

mm_init:内存管理模块初始化。

sched_init:进程调度初始化函数,函数内做了很关键的一步初始化——对0号进程,即idle进程进行初始化。

rest_init:其他初始化函数,函数内将创建1号进程,即init进程。

start_kernel函数之前的内容基本都是汇编语言,而从该函数开始内核进入c语言部分,功能则是内核主要功能的初始化。

    • 总结部分

1.内核编译的时候为什么要生成符号表:

所谓内核符号表就是在内核内部函数或变量中可供外部引用的函数和变量的符号表。

在内核符号表中,左边一列是符号地址,右边一列是函数和变量。

(简单来理解,就是需要一个把函数名等外部用的东西和机器指令联系起来,这些关系对应的表格就是符号表)

符号表加载成功之后断点设置成功,可以跟踪分析调试。

2.对“Linux系统启动过程”的理解:

要启动一个内核,挂一个硬盘,然后再运行一个init即1号进程。

而rest init()就是一个0号进程,在start_kernel内核一启动时就一直存在;

然后这个0号进程就创建了1号进程kernel_init,接下来还创建了其他的一些服务类的内核线程如kthreadd。这样整个系统就启动起来了。

    • 注:

      姓名:林涵锦 

       《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000