Linux系统启动过程的部分理解

 

作者:xujianguo

 原创作品转载请注明出处,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

——————————————————————————————————————————————————————-————

实验目的:

       通过gdb调试来加强理解Linux系统启动过程。

实验环境:

  

        实验楼:www.shiyanlou.com

实验步骤:

1.预配置:

  • make menuconfig  
  • kernel hacking—>  
  • compile-time checks and compile options  
  • [*] compile the kernel with debug info

2.打开实验楼虚拟机,运行3.18.6系统进行初步调试。

3.启动过程预配置:

  1. qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
  2. # -S freeze CPU at startup (use ’c’ to start execution)
  3. # -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

 4.另外开启一个终端,进入gdb调试器。

5.调试启动过程:

  • (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之前,也可以在之后

 6.设置相关断点,利用编译命令c和显示命令list来获取启动详情。

 start_kernel:

 cpu_start_entry:

 run_init_process:

 7.启动完成。

实验分析:

  参考源码:

http://codelab.shiyanlou.com/xref/linux-3.18.6/init/main.c

   

      系统启动进程是从start_kernel函数中开始执行的,详细代码如下:

 

       从上面的代码可以看出,start_kernel函数开始就完成一部分初始化操作(如中断,trap_init,内存管理mm_init等),配置init_task进程的结构的详细信息;随后进行调度的初始化(sched_init)、时钟设置(time_init)、控制台的初始化启动(console_init())、proc_root_init的运行;然后进行bug检测等辅助环节,最后调用rest_init函数。rest_init函数在启动完init进程后并没有退出,而是继续往下执行道了cpu_startup_entry函数。执行流生成init进程,作为idle进程继续运行下去。

           idle进程:Linux引导中创建的第一个进程(只在内核中存在),完成加载系统后,演变为进程调度、交换及存储管理进程,又称0号进程。

           init 进程:由idle进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程。

总结:

    通过本次实验,对linux内核启动过程有了些详细了解。pid号为0的原始进程设置了执行环境,然后原是进程开始执行start_kernel()完成Linux内核的初始化工作。包括初始化页表,初始化中断向量表,初始化系统时间等。继而调用 fork(),创建第一个用户进程:kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);idle 进程优先级为MAX_PRIO,即最低优先级。早先版本中,idle是参与调度的,所以将其优先级设为最低,当没有其他进程可以运行时,才会调度执行 idle。而目前的版本中idle并不在运行队列中参与调度,而是在运行队列结构中含idle指针,指向idle进程,在调度器发现运行队列为空的时候运行,调入运行。主处理器上的idle由原始进程(pid=0)演变而来。从处理器上的idle由init进程fork得到,但是它们的pid都为0。init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。所以,init始终是第一个进程(其进程编号始终为1)。

    谢谢前辈的努力和奉献:)

  



参考资料:

http://www.douban.com/note/56531301/

http://blog.chinaunix.net/uid-23769728-id-3127671.html
  

原文地址:https://www.cnblogs.com/emochuanshuo/p/4354444.html