Linux系统启动分析-从start_kernel到init进程的启动
来源:互联网 发布:win10激活 知乎 编辑:程序博客网 时间:2024/06/06 03:08
#####################################
作者:张卓
原创作品转载请注明出处:《Linux操作系统分析》MOOC课程 http://www.xuetangx.com/courses/course-v1:ustcX+USTC001+_/about
#####################################
一 Linux源代码目录介绍
现在,我们研究Linux内核,在x86平台上,重点需要我们关注的是下面的三个目录:
1. arch/x86
与x86系统架构相关代码,是我们研究的重点
2. init
init目录下存放内核启动相关的代码
main.c中的start_kernel函数相当于普通的C程序的main函数
3. kernel
Linux内核核心代码都在kernel目录下
1. qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
2. # -S freeze CPU at startup (use ’c’ to start execution)
3. # -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
另开一个shell窗口
1. gdb
2. (gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
3. (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
4. (gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
Note:设置断点是时候,即可以指定函数名,也可以指定行号。
start_kernel()函数相当于C语言中的mian函数,程序总是从main函数开始执行,
设置一个断点在系统设置PCB的时候,break 510
smp_task_stack_end_magic(&init_task)
init_task是一个全局变量,即手工创建的PCB,0号进程即最终的idle进程。
接下来执行一些列的初始化,在这里我们需要关注一下下面的几个初始化,在后面我们会继续分析他们。
trap_init()
与中断向量相关的初始化
mm_init()
与存储管理相关的初始化
接下来有一个特别重要的初始化,我们下一个断点看一下:break 569
sched_init()与进程调度相关的初始化
再接下来,还是一些列的初始化,我们直接跳到start_kernel函数的最后,下一个断点在680行:break 680
start_kernel函数调用rest_init,于是进入rest_init函数执行:
为了更直观看到进入rest_init()函数中执行,我们在403行下一个断点:break 403
kernel_thread(kernel_init,NULL,CLOSE_FS)
在此处创建一个进程去执行kernel_init,然后在文件系统中寻找并执行init程序,这个就是系统的1号进程。
接下来执行:
pid = kernel_thread(kthreadd,NULL,CLONE_FS| CLONE_FILES)
这个函数是创建一个内核线程去管理系统资源,也是就系统的2号进程。
在rest_init函数的末尾下一个断点:break 418
cpu_startup_entry(CPUHP_ONLINE)执行这个函数后系统启动完毕, 进入cpu_idle_loop()(函数位于linux-3.18.6/kernel/sched/idle.c)当系统没有进程需要执行时就调度到idle进程, 这个就是0号进程。
1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先。
三 总结
Linux系统启动,从start_kernel开始执行,中间执行一系列的初始化动作,为后面系统启动开始运行作准备。start_kernel函数的最后会调用rest_init, 然后在rest_init里创建一个进程去寻找文件系统中init程序并执行,这个就是系统的1号进程。1,2号进程后,系统会进入cpu_idle_loop()死循环,这个就是原始的启动进程,也就是0号进程;当系统没有进程需要执行的时候,就会调用这个idle进程。
总之,Linux系统启动过程,可以想象成一个超大型程序的执行过程,按顺序执行所有的初始化;当完成所有的工作时,程序不能退出,而要进人一个死循环。
关于更详细的内核启动函数的分析,可以参考一下的链接
http://blog.csdn.net/xichangbao/article/details/52938240
Linux内核启动之后,文件系统启动过程,可以参考下面的链接
http://blog.csdn.net/cl11010/article/details/24484979
作者:张卓
原创作品转载请注明出处:《Linux操作系统分析》MOOC课程 http://www.xuetangx.com/courses/course-v1:ustcX+USTC001+_/about
#####################################
一 Linux源代码目录介绍
现在,我们研究Linux内核,在x86平台上,重点需要我们关注的是下面的三个目录:
1. arch/x86
与x86系统架构相关代码,是我们研究的重点
2. init
init目录下存放内核启动相关的代码
main.c中的start_kernel函数相当于普通的C程序的main函数
3. kernel
Linux内核核心代码都在kernel目录下
二 使用gdb跟踪调试内核从start_kernel到init进程启动过程
1 使用gdb跟踪调试内核
进入实验楼环境,执行下面的命令即可开始跟踪查看Linux启动过程:1. qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
2. # -S freeze CPU at startup (use ’c’ to start execution)
3. # -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
另开一个shell窗口
1. gdb
2. (gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
3. (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
4. (gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后
Note:设置断点是时候,即可以指定函数名,也可以指定行号。
2. 内核启动分析
内核启动从init/main.c开始执行代码,于是可以设置断点:break start_kernelstart_kernel()函数相当于C语言中的mian函数,程序总是从main函数开始执行,
设置一个断点在系统设置PCB的时候,break 510
smp_task_stack_end_magic(&init_task)
init_task是一个全局变量,即手工创建的PCB,0号进程即最终的idle进程。
接下来执行一些列的初始化,在这里我们需要关注一下下面的几个初始化,在后面我们会继续分析他们。
trap_init()
与中断向量相关的初始化
mm_init()
与存储管理相关的初始化
接下来有一个特别重要的初始化,我们下一个断点看一下:break 569
sched_init()与进程调度相关的初始化
再接下来,还是一些列的初始化,我们直接跳到start_kernel函数的最后,下一个断点在680行:break 680
start_kernel函数调用rest_init,于是进入rest_init函数执行:
为了更直观看到进入rest_init()函数中执行,我们在403行下一个断点:break 403
kernel_thread(kernel_init,NULL,CLOSE_FS)
在此处创建一个进程去执行kernel_init,然后在文件系统中寻找并执行init程序,这个就是系统的1号进程。
接下来执行:
pid = kernel_thread(kthreadd,NULL,CLONE_FS| CLONE_FILES)
这个函数是创建一个内核线程去管理系统资源,也是就系统的2号进程。
在rest_init函数的末尾下一个断点:break 418
cpu_startup_entry(CPUHP_ONLINE)执行这个函数后系统启动完毕, 进入cpu_idle_loop()(函数位于linux-3.18.6/kernel/sched/idle.c)当系统没有进程需要执行时就调度到idle进程, 这个就是0号进程。
1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先。
三 总结
Linux系统启动,从start_kernel开始执行,中间执行一系列的初始化动作,为后面系统启动开始运行作准备。start_kernel函数的最后会调用rest_init, 然后在rest_init里创建一个进程去寻找文件系统中init程序并执行,这个就是系统的1号进程。1,2号进程后,系统会进入cpu_idle_loop()死循环,这个就是原始的启动进程,也就是0号进程;当系统没有进程需要执行的时候,就会调用这个idle进程。
总之,Linux系统启动过程,可以想象成一个超大型程序的执行过程,按顺序执行所有的初始化;当完成所有的工作时,程序不能退出,而要进人一个死循环。
关于更详细的内核启动函数的分析,可以参考一下的链接
http://blog.csdn.net/xichangbao/article/details/52938240
Linux内核启动之后,文件系统启动过程,可以参考下面的链接
http://blog.csdn.net/cl11010/article/details/24484979
0 0
- Linux系统启动分析-从start_kernel到init进程的启动
- 从start_kernel到init进程启动 《Linux内核分析》笔记
- 跟踪分析Linux内核的启动过程(从start_kernel到init进程)
- 分析Linux内核启动过程:从start_kernel到init
- 分析Linux内核启动过程:从start_kernel到init
- 跟踪分析Linux内核的启动过程(start_kernel到init进程启动)
- 利用gdb分析从start_kernel到init启动的过程
- start_kernel到init进程启动的过程
- start_kernel到init进程启动的过程
- Linux内核分析之三——使用gdb跟踪调试内核从start_kernel到init进程启动
- gdb跟踪调试内核从start_kernel到init进程启动
- 跟踪内核从start_kernel到init进程启动
- linux启动流程(从start_kernel中的rest_init函数到init进程(1))
- MOOC-Linux内核lab3 调试内核从start_kernel到init进程启动
- 学习Linux内核启动过程:从start_kernel到init
- Linux内核分析(三)从start_kernel到init
- linux内核从start_kernel到init
- 从start_kernel到init
- java设计模式--代理模式(结构型)
- 微信支付 java 服务端demo (v3版本app支付 springMVC框架中)
- 第三周:[LeetCode]102. Binary Tree Level Order Traversal
- 长波通信、中波通信、短波通信、超短波通信与微波通信介绍
- mysql 存储过程 函数 使用
- Linux系统启动分析-从start_kernel到init进程的启动
- android中的动画之布局动画
- Hadoop集群安装配置手册
- 阿帕奇文档
- openwrt配置文件选项 /etc/config/wireless
- Spring单例与线程安全小结(通俗易懂)
- 使用数组作为参数传递
- python 继承中的self和__init__
- AIDL的使用