《Linux操作系统分析》之跟踪分析Linux内核的启动过程 Bertha 。 2022-08-21 02:18 155阅读 0赞 本篇文章分析的是一个经过精简后的Linux系统MENUOS,通过对idle进程、1号进程的分析。来说明系统中进程的启动过程。 **相关知识** 首先关于这篇文章会介绍一些用到的知识。 一、什么是中断的上下文和进程的上下文。在这里大家很容易混淆这两个概念。先看下面这句话。 处理器总处于以下状态中的一种: 1、内核态,运行于进程上下文,内核代表进程运行于内核空间; 2、内核态,运行于中断上下文,内核代表硬件运行于内核空间; 3、用户态,运行于用户空间。 对于上面的话,我觉得可以理解为程序本身在执行的时候由于内陷指令、读数据或者其他的原因,导致进入到内核态,那么这时候保存的就是进程上下文。如果在内核态下由于硬件等的原因,导致的中断,保存的就是中断上下文,其中包含硬件的信息等。 这是另一个解释:陷入(或异常)到内核时,此时内核代表某个进程运行,一般要访问进程的数据结构,此时的上下文称进程上下文。中断时,内核不代表任何进程运行,一般不访问当前进程的数据结构,此时的上下文称中断上下文。 这里有兴趣的同学可以参考[什么是进程上下文,什么是中断上下文][Link 1]。 而这两者的差别是进程上下文可以睡眠,阻塞,但是中断上下文不行。(请参考[再思linux内核在中断路径内不能睡眠/调度的原因(2010)][linux_2010]和[关于中断上下文为什么不能睡眠?][Link 2]) 二、idle进程的相关知识简单的说idle是一个进程,其pid号为 0。其前身是系统创建的第一个进程,也是唯一一个没有通过fork()产生的进程。 这里用到的代码可以在一下地址知道:Latest Stable Kernel:[linux-3.18.6][] 首先使用自己的Linux系统环境搭建MenuOS的过程: # 下载内核源代码编译内核 cd ~/LinuxKernel/ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz xz -d linux-3.18.6.tar.xz tar -xvf linux-3.18.6.tar cd linux-3.18.6 make i386_defconfig make # 一般要编译很长时间,少则20分钟多则数小时 # 制作根文件系统 cd ~/LinuxKernel/ mkdir rootfs git clone https://github.com/mengning/menu.git # 如果被墙,可以使用附件menu.zip cd menu gcc -o init linktable.c menu.c test.c -m32 -static –lpthread cd ../rootfs cp ../menu/init ./ find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img # 启动MenuOS系统 cd ~/LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 重新配置编译Linux使之携带调试信息 在原来配置的基础上,make menuconfig选中如下选项重新配置Linux,使之携带调试信息 kernel hacking—> [*] compile the kernel with debug info 然后就可以进行下一步: 打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img ![20160310230349028][] 使用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选项 ![20160310230403745][] 另开一个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之前,也可以在之后 ![20160310230413043][] 通过设置断点来观察启动的过程。设置断点后输入c点enter,程序继续执行,到断点时停止。这时候可以输入list指令显示断点前后的代码。 ![20160310230436168][] 然后继续执行,menuOS加载完成,系统现在提供有三个指令help、version、quit。 ![20160310230442637][] 现在我们就可以用gdb的调试断点来帮助我们跟踪和调试系统了。 我们可以简单的来看一下: 在main.c中首先将各种变量进行初始化,这些变量一般是宏静态定义。 然后执行[asmlinkage][] [ \_\_visible][_visible] **void** [ \_\_init][_init] [start\_kernel][start_kernel](**void**)这个函数,在其中的有一个[set\_task\_stack\_end\_magic][set_task_stack_end_magic](&[init\_task][init_task]);函数,这个函数中该结构体(init\_task)在linux启动时被设置为current\_task。(此时idle进程已经启动) 在 /[linux-3.18.6][]/[arch][]/[x86][]/[kernel][]/[cpu][]/[common.c][]中: DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned = &init_task; 然后对其他的信息也进行初始化。接着进行到了[rest\_init][rest_init]();这个地方。 static noinline void __init_refok rest_init(void) 394{ 395 int pid; 396 397 rcu_scheduler_starting(); 398 /* 399 * We need to spawn init first so that it obtains pid 1, however 400 * the init task will end up wanting to create kthreads, which, if 401 * we schedule it before we create kthreadd, will OOPS. 402 */ 403 kernel_thread(kernel_init, NULL, CLONE_FS); 404 numa_default_policy(); 405 pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); 406 rcu_read_lock(); 407 kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); 408 rcu_read_unlock(); 409 complete(&kthreadd_done); 410 411 /* 412 * The boot idle thread must execute schedule() 413 * at least once to get things moving: 414 */ 415 init_idle_bootup_task(current); 416 schedule_preempt_disabled(); 417 /* Call into cpu_idle with preempt disabled */ 418 cpu_startup_entry(CPUHP_ONLINE); 419} 当初始化到rest\_init函数中时调用[kernel\_thread][kernel_thread]([kernel\_init][kernel_init], [ NULL][NULL], [ CLONE\_FS][CLONE_FS]);函数启动第一个内核线程kernel\_init。由kernel\_init再通过do\_execve启动/sbin/init。这就是我们看到的init进程,进程号为1。初始化完成后linux调用scheule整个系统就运行起来了。 **结论:** idle是一个进程,其pid为0。是Linux引导中创建的第一个进程,完成加载系统后,演变为进程调度、交换及存储管理进程。主处理器上的idle由原始进程(pid=0)演变而来。从处理器上的idle由init进程fork得到,但是它们的pid都为0。Idle进程为最低优先级,且不参与调度,只是在运行队列为空的时候才被调度。Idle循环等待need\_resched置位。1号进程是init 进程,由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程 **备注:** 杨峻鹏 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 [Link 1]: http://blog.csdn.net/gangyanliang/article/details/6887128 [linux_2010]: http://blog.csdn.net/maray/article/details/5770889 [Link 2]: http://blog.csdn.net/dandelionj/article/details/9402609 [linux-3.18.6]: http://codelab.shiyanlou.com/xref/linux-3.18.6/ [20160310230349028]: /images/20220731/02d68375b5b745a9bb5f69c9d0338460.png [20160310230403745]: /images/20220731/9213a06951e24b519eda4822e49ea577.png [20160310230413043]: /images/20220731/b6d59c0407594e3a9e1cc46cffd911b0.png [20160310230436168]: /images/20220731/ea4d33c7d2494ebd8345a3022cc6705e.png [20160310230442637]: /images/20220731/0f933e405e4b41e993cd0486f15e890e.png [asmlinkage]: http://codelab.shiyanlou.com/s?defs=asmlinkage&project=linux-3.18.6 [_visible]: http://codelab.shiyanlou.com/s?defs=__visible&project=linux-3.18.6 [_init]: http://codelab.shiyanlou.com/s?defs=__init&project=linux-3.18.6 [start_kernel]: http://codelab.shiyanlou.com/s?refs=start_kernel&project=linux-3.18.6 [set_task_stack_end_magic]: http://codelab.shiyanlou.com/s?defs=set_task_stack_end_magic&project=linux-3.18.6 [init_task]: http://codelab.shiyanlou.com/s?defs=init_task&project=linux-3.18.6 [arch]: http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/ [x86]: http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/ [kernel]: http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/kernel/ [cpu]: http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/kernel/cpu/ [common.c]: http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/kernel/cpu/common.c [rest_init]: http://codelab.shiyanlou.com/xref/linux-3.18.6/init/main.c#rest_init [kernel_thread]: http://codelab.shiyanlou.com/s?defs=kernel_thread&project=linux-3.18.6 [kernel_init]: http://codelab.shiyanlou.com/xref/linux-3.18.6/init/main.c#kernel_init [NULL]: http://codelab.shiyanlou.com/s?defs=NULL&project=linux-3.18.6 [CLONE_FS]: http://codelab.shiyanlou.com/s?defs=CLONE_FS&project=linux-3.18.6
还没有评论,来说两句吧...