2020-2021-1 20209316《Linux内核原理与分析》第四周作业

《Linux内核原理与分析》第四周作业

一、实验:跟踪分析Linux内核的启动过程

1、在终端输入以下命令

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

可得

2、用gdb跟踪调试内核
输入以下命令
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

  • -s参数:freeze CPU at startup (use ’c’ to start execution)
    即启动后冻结CPU
  • -S参数:shorthand for -gdb tcp::1234
    即选择端口1234启动
    另开终端窗口,进入Linuxkernel目录下输入gdb,在gdb下设置断点

进行以下调试

file linux-3.18.6/vmlinux  //加载符号表
target remote:1234  //建立gdb和gdbserver之间的连接
break start_kernel  //设置断点
c   //让qemu上的linux继续运行
break rest_init //设置另一个断点
c  //继续执行

可得

二、分析实验与学习知识

1、分析start_kernel函数的执行过程
在终端输入
cd LinuxKernel/linux-3.18.6/init

找到main.c#500
start_kernel代码如下图

各个函数作用:

sched_init():初始化调度模块
build_all_zonelists():初始化内存管理
page_alloc_init():初始化伙伴系统分配程序
trap_init()、init_IRQ():初始化中断向量
mm_init():初始化内存管理模块
softing_init():软中断,初始化TASKLET_SOFTIRQ和HI_SOFTIRQ
time_init():初始化系统日期时间
kmem_cache_init():普通和高速缓存,初始化slab分配器
calibrate_delay():延迟函数,用于确定CPU时钟
kernel_thread():为进程1创建内核线程,这个内核线程又会创建其他的内核线程并执行/sbin/init程序。所有内核线程都是直接或间接地以kthreadd为父进程的
kthreadd():管理和调度其他内核线程kernel_thread

所以经过分析,知道其执行过程

调用sched_init()函数初始化调度程序
调用build_all_zonelists()函数初始化内存管理
调用page_alloc_init()函数初始化伙伴系统分配程序
调用trap_init()、init_IRQ()函数初始化IDT
调用softing_init()函数初始化TASKLET_SOFTIRQ和HI_SOFTIRQ(软中断)
调用time_init()初始化系统日期时间
调用kmem_cache_init()函数初始化slab分配器(普通和高速缓存)
调用calibrate_delay()函数用于确定CPU时钟
调用kernel_thread()函数为进程1创建内个线程,这个内核线程又会创建其他的内核线程并执行/sbin/init程序
在start_kernel()开始执行之后会显示linux版本,在init程序和内核线程执行的最后阶段还会显示很多其他信息。最后,就会在控制台上出现熟悉的登陆提示,通知用户Linux内核已经启动正在运行。

2、分析Linux 内核启动过程

最初执行的进程即是0号进程init_task,它是在系统初始化阶段由start_kernel()函数从无到有手工创建的一个内核线程,进程0在创建1号内核线程kernel_init后,调用cpu_idle()成为idle进程,而idle进程就是当系统没有进程需要执行的时候来调度用的。1号内核进程负责执行内核的部分初始化工作及进行系统配置,然后使用kernel_thread(kernel_init, NULL, CLONE_FS)函数(也就是fork方式)建立了pid=1的1号进程,也是init进程(用户态1号进程),成为系统中的其他所有进程的祖先进程,当调度程序选择到init进程时,init进程继续完成剩下的初始化工作。然后调用kernel_thread执行kthreadd,创建PID为2的内核线程,这一进程始终运行在内核空间,负责所有内核线程的调度和管理。

3、Linux内核源码目录结构

  • arch:用于存放CPU体系结构的相关代码。
  • block:存放Linux存储体系中关于块设备管理的代码。
  • crypto:存放常见的加密算法的C语言代码。
  • Documentation:存放一些文档。
  • drivers:驱动目录,分类别存放了Linux内核支持的所有硬件设备的驱动源代码。
  • firmware:固件。
  • fs:文件系统,存放了Linux支持的各文件系统的实现。
  • include:头文件目录,存放公共的头文件。
  • init:存放Linux内核启动时的初始化代码。
  • lib:存放Linux的共用库文件。
  • mm:存放内存管理。
  • net:存放Linux网络的相关代码。

三、总结

本周学习了怎么构造一个简单的Linux内核,并通过gdb跟踪调试内核启动。通过阅读内核源码,学习了内核启动需要调用的函数的过程及步骤,受益匪浅。

原文地址:https://www.cnblogs.com/camusxd/p/13894499.html