SA16225055 冯金明
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
实验内容
1、内核启动并进入menu
输入命令为:
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
2、GDB调试查看kernel启动流程
使用GDB跟踪调试内核:
先关闭原先的窗口,输入以下的命令:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
打开另一个shell窗口,用于GDB调试:
输入以下命令:
gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)break start_kernel
可以按着这个步骤一步一步调试查看整个kernel启动的过程。
start_kernel到init进程启动过程详解
查看Linux内核源码,在/init/main.c中可以查看start_kernel()函数的相关内容,可以看到其中有一系列的init函数,可以看出start_kernel是一些模块的初始化,比如init_IRQ()函数为中断向量初始化;
tick_init()为时钟初始化等等。
初始化完成后,则会调用rest_init(),此函数创建了1号进程(第一个用户态的进程)和2号进程(内核态的祖先),其中包括了pid1的kernel_init以及kthreadd。同时,此函数在执行的后期还将自己变为idle进程,此进程为一个while(1)的loop。
kernel_init调用run_init_process,至此启动文件根目录的/init程序,pid1的init就开始执行了。
借用一张分析得很到位的进程图:
idle进程、1号进程
rest_init()函数可以算是在运行最后的初始化工作,其中就包括创建1号进程以及第一个内核进程等操作。创建完成后,则使用do_fork()来创建新的进程。pid是会进行一个累加的。内核线程调用cpu_startup_entry,再调用其中的cpu_idel_loop函数进入循环,此即为0号进程。
从rest_init开始,Linux开始产生进程,在rest_init中,通过init_task产生pid=0的进程,即0号进程(idle进程),它是内核状态下的进程;在rest_init函数中,内核通过kernel_init创建1号进程,它是第一个用户态进程。关于init_task(也就是idle),当运行队列中没有别的就绪进程时,init_task(也就是idle)将会被调用,它的核心是一个while(1)循环,在循环中它将会调用schedule函数以便在运行队列中有新进程加入时切换到该新进程上。