一. 跟踪Linux内核的启动过程
使用实验楼的虚拟机打开shell
cd ~/LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
使用gdb跟踪调试内核
关于-s和-S选项的说明:
1.-S # -S freeze CPU at startup (use'c' to start execution)
2. -s # -s shorthand for -gdb tcp::1234, 若不想直接使用234端口,则可以使用-gdb tcp:xxxx来取代-s选项
使用qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -inittrd rootfs.img -s -S指令打开内核窗口
打开新的终端通过gdb调试内核
通过gdb指令打开gdb调试器
在gdb中输入以下指令:
file linux-3.18.6/vmlinux #在gdb界面中targe remote之前加载符号表
target remote:1234 #建立gdb和gdbserver之间的连接,连接到内核的1234端口,按c 让qemu上的Linux继续运行
break start_kernel #在start_kernel处设置断点(断点的设置可以在target remote之前,也可以在之后)
按c让程序继续执行后停在断点处。
start_kernel()函数代码如下:
在rest_init处设置断点并查看代码:
二. 分析Linux内核的启动过程
start_kernel()函数在main.c中起着main函数的作用,打开系统以后,首先对硬件系统进行初始化,给C代码的运行配置好环境,start_kernel函数被调用,在start_kernel函数在开始运行后,它会调用各个内核模块的初始化函数,主要包括:trap_init()
中断向量初始化,mm_init()
内存管理初始化,sched_init()
调度模块初始化等,在整个的初始化过程中有一个init_task,它是一个进程描述符,负责内核模块的初始化,也就是0号进程,0号进程会新建kernel_init线程(1号内核线程)和kthreadd线程(2号内核线程),初始化工作完成后,init_task()调用cpu_idle()转化为ideal空进程。