《庖丁解牛Linux内核分析》第三章
Linux内核源代码简介
使用cat /proc/version或uname -a命令,可以查看当前系统的Linux内核版本。
Linux内核源码目录结构
arch目录:与CPU体系结构相关的子目录列表
block目录:存放Linux存储体系中关于块设备管理的代码
crypto目录:存放常见的加密算法的C语言代码
drivers目录:驱动目录,里面分门别类地存放了Linux内核支持的所有硬件设备的驱动源代码
firmware目录:固件
fs目录:文件系统
include目录:存放公共的头文件
init:存放Linux内核启动时的初始化代码(lnit目录中的main.c源文件是整个Linux内核启动的起点,但它的起点不是main函数,是start_kernel函数。start_kernel函数是初始化Linux内核启动的起点。)
ipc目录:IPC是进程间通信,ipc目录里面是Linux支持的IPC的代码实现
kernel目录:kernel意思是内核,这个文件夹存放内核本身需要的一些核心代码文件,包括进程号pid等
lib目录:公用的库文件
mm目录:内存管理
构造一个简单的Linux内核
在“实验楼”虚拟机中,通过两个简单的命令就可以把Linux系统和一个简单的文件系统运行起来:
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
使用自己的Linux系统环境搭建MenuOS的过程
实验楼实验三
跟踪分析Linux内核的启动过程
使用实验楼的虚拟机打开shell
$ cd ~/LinuxKernel/
$ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
内核启动完成后进入 menu程序,支持三个命令 help、version 和 quit。
使用gdb跟踪调试内核
$ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
/* 关于-s和-S选项的说明:
1. -S
-S freeze CPU at startup (use ’c’ to start execution)
2. -s
-s shorthand for -gdb tcp::1234
若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项 */
用上述命令启动内核,发现被冻结了。
再打开一个shell窗口,用Ctrl+Shift+O水平分割,启动gdb把内核加载进来,建立连接。
/* 打开 GDB 调试器 */
$ gdb
在 GDB 中输入以下命令:
/* 在gdb界面中targe remote之前加载符号表 */
(gdb)file linux-3.18.6/vmlinux
/* 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行 */
(gdb)target remote:1234
/* 断点的设置可以在target remote之前,也可以在之后 */
(gdb)break start_kernel
在start_kernel处设置断点,刚才是stop状态,如果按“c”继续执行,那么系统开始启动执行,启动到start_kernel函数的位置停在断点处,就可以看到start_kernel上下的代码。
再设置一个断点rest_init,继续执行,停在断点处,可以看到rest_init是在start_kernel的尾部进行调用的。
/* 在rest_init设置断点 */
(gdb)break rest_init
/* 继续执行 */
(gdb)c
start_kernel()与init_task()/reat_init()中部分函数的分析
start_kernel():相当于C语言中的main函数,是一切的起点。完成了Linux内核的初始化工作。每个内核部件都是用这个函数进行初始化的。在start_kernel()开始执行之后会显示linux版本,除此之外,在init程序和内核线程执行的最后阶段还会显示很多其他信息。最后,就会在控制台上出现熟悉的登陆提示,通知用户Linux内核已经启动正在运行。
init_task():几乎涵盖了内核的所有主要模块,是唯一没有通过fork方式产生的进程,使用宏进行初始化。
rest_init():通过rest_init()新建kernel_init和kthreadd内核线程。
其中各函数功能如下:
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
本周遇到的挫折
虽然之前说安了虚拟机,其实这个假期才开始配置。然而,在任何一个教程中都会一笔带过的VMware下载环节,我遭遇了很多挫折!!!看过了一个帖子总结的可能遇到的所有报错!!!其中,安装VM需要的vmnetbridge.dll在哪这个问题问了我无数遍。
后来我新的一轮下载中,给我们的VMware小朋友新建了个文件夹,不知为什么就好了。虽然这问题很傻没什么意义,但鉴于我终于按好了很开心,所以来这叨叨两句~
此为本人Linux学习第四周的内容,如有不足,还请批评指正,不胜感激。
以上