跟踪分析Linux内核的启动过程
使用 gdb 跟踪调试内核
使用 qemu
qemu -kernel linux-3.18.6 /arch/x86/boot/bzImage -initrd rootfs.img -s -S
- 1
参数:
- -s:在初始化时冻结 CPU
- -S: 为 gdb 分配1234端口
gdb 调试
另开 shell
gdb (gdb) file linux-3.18.6/vmlinux #在 gdb 界面中 target remote之前加载符号表 (gdb) target remote :1234 #建立连接 (gdb) break start_kernel #设置断点
- 1
- 2
- 3
- 4
从 start_kernel 开始到 init 进程启动
set_task_stack_end_magic()
为了检测栈溢出
smp_setup_processor_id()
设置对称多处理器
cgroup_init_early ()
初始化 Control Groups
*Control Groups provide a mechanism for aggregating/partitioning sets of
tasks, and all their future children, into hierarchical groups with
specialized behaviour.*page_address_init()
页地址初始化(属于内存管理部分)
setup_arch()
setup_arch - architecture-specific boot-time initializations
build_all_zonelists()
Called with zonelists_mutex held always unless system_state == SYSTEM_BOOTING.
page_alloc_init ()
setup_log_buf ()
初始化log 缓冲区(kernel/printk/printk.c)
pidhash_init ()
初始化 pid 哈希表
The pid hash table is scaled according to the amount of memory in the machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or more.
vfs_caches_init_early ()
sort_main_extable ()
Sort the kernel’s built-in exception table
trap_init ()
初始化中断向量
mm_init ()
内存管理初始化
sched_init ()
调度服务初始化
……
rest_init()
剩余初始化
- kernel_init:init进程
- kthreadd:内核线程
- cpu_idle进程:代码中一直循环,如果系统中没有可执行的进程时,执行 idle 进程
总结
- 在 start_kernel执行到最后部分时,在 rest_init 中 新建了kernel_init 进程,
kernel_thread(kernel_init, NULL, CLONE_FS);
,init 进程是系统中的1号进程,是以后所有用户态进程的祖先,然后新建kthreadd进程,pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
,kthreadd 作为2号进程,是所有内核线程的祖先,在cpu_startup_entry(CPUHP_ONLINE)
中,是一个while(1)
循环,始终有一个 idle 进程在执行,如果系统还总没有任何可以执行的进程时,idle 进程会执行。
最后引用孟宁老师的一段话:
道生一:(start_kernel)
一生二:(kernel_init 和 kthreadd)
二生三:(即0,1,2号进程)
三生万物:(1号进程是所有用户态进程祖先,2号进程是所有内核线程祖先)
文章来源: blog.csdn.net,作者:冰水比水冰,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/luoyhang003/article/details/46832177