linux内核分析实验三,跟踪分析Linux内核的启动过程

前面我们学习一些函数调用堆栈和进程切换的一些知识,现在开始来接触linux的内核代码。

Linux内核代码很庞大,不可能完全吃下它,我们只能选取一些核心的我们关心的来解读。

现在,我们先来看看Linux内核的目录结构,选取比较新的Linux-3.18.6这个版本来看一看。

Linux内核代码目录结构

arch : 针对不同的计算机体系结构

block : 块设备驱动

crypto

documentation : 内核文档

drivers : 设备驱动

fs : 文件系统

include : 头文件

init : 初始化

ipc : 进程间通信

kernel : Linux大多数关键的核心功能都在此目录

lib : 库

mm : 内存管理

net : 网络协议

samples :

scripts: 配置内核的脚本

security :

sound : 音频设备驱动

usr :

virt :

启动内核

使用实验楼环境,内核启动完成后进入menu程序(《软件工程C编码实践篇》的课程项目),支持三个命令help、version和quit。实验截图如下

9Kh0c38pgiNXRApVng7WRdQ4yP7YlnjpkA5hWrVu-wm

gdb跟踪调试

我们主要关心的是start_kernel的启动过程,使用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)

# -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

EZLVBeapTu9VDNZwnJBssqIy7LKkMuIhjDsZ9sJD-wm

分析代码

start_kernel的详细代码,可以看到,里面调用了很多函数,这些都是重量级函数,如

setup_arch(&command_line) ,完成内存映像的初始化;

page_alloc_init(),创建内核页表,映射所有物理内存和io空间;

trap_init(),初始化硬件中断,函数中设置了很多中断门;

sched_init(),任务调度初始化。

还有很多重要初始化工作都在这里进行,就不一一列举了。

我们来看看start_kernel里面最后一个调用的函数rest_init()。

static noinline void __init_refok rest_init(void)

{

int pid;

rcu_scheduler_starting();

/*

* We need to spawn init first so that it obtains pid 1, however

* the init task will end up wanting to create kthreads, which, if

* we schedule it before we create kthreadd, will OOPS.

*/

kernel_thread(kernel_init, NULL, CLONE_FS);

numa_default_policy();

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

rcu_read_lock();

kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);

rcu_read_unlock();

complete(&kthreadd_done);

/*

* The boot idle thread must execute schedule()

* at least once to get things moving:

*/

init_idle_bootup_task(current);

schedule_preempt_disabled();

/* Call into cpu_idle with preempt disabled */

cpu_startup_entry(CPUHP_ONLINE);

}

kernel_thread()创建了一个线程,其参数kernel_init是一个函数,可以看到这个函数末尾的代码

if (!try_to_run_init_process("/sbin/init") ||

!try_to_run_init_process("/etc/init") ||

!try_to_run_init_process("/bin/init") ||

!try_to_run_init_process("/bin/sh"))

return 0;

执行/sbin/init程序。init进程是Linux系统的1号进程,由Linux内核直接启动,是其他用户进程的祖先。

然后新建kthread进程,即2号进程,是内核态进程的祖先。

总结

linux内核很复杂,这里只是分析从start_kernel到init,来理解linux的第一个用户进程的产生过程。然而这只是九牛一毛,还需要做很多很多的工作才能更深入的了解操作系统的内核。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值