linux内核启动跟踪,Linux内核分析------跟踪分析Linux内核的启动过程

1、基础知识

(1)Linux内核中经常使用的目录

1.arch/:与体系结构相关的代码,(内容庞大,支持不一样cpu的源代码)。

2.Documentation/:文档文件

3.fs/:file system 文件系统

4.drivers/:与驱动相关的代码

5.lib/:连接库文件

6.ipc/:与进程间通讯相关的文件

7.mm/:memory managment 内存管理

8.kernel/:Linux内核的核心代码

9.init/:与内核启动相关的代码,其中有main.c,main.c中的start_kernel()函数是初始化Linux的起点

(2)使用gdb调试工具的基本指令

1.gdb 可执行文件名:进入gdb调试

2.(gdb)l:至关于list,从第一行开始列出源码

3.(gdb)回车:重复上一次指令

4.(gdb)break 函数名/行数:在某一行或者某个函数处设置断点

5.(gdb)info break:查看断点信息

6.在断点内能够使用:r(run运行),n(next单句执行),c(contiune继续执行)

7.(gdb)bt:查看函数堆栈

8.(gdb)finis:退出函数

9.(gdb)q:退出gdb

(3)Linux内核启动过程

Linux系统的启动分为4个部分:引导加载程序(bootloader),Linux内核,文件系统,应用程序,其中,在Linux内核启动时咱们完成了系统的重要初始化,并建立了init进程。

内核启动主要能够分为两个阶段:第一阶段主要是与硬件相关的初始化工做,此次咱们讨论的主要是第二部分。

在内核源码的init/main.c中,定义了内核启动的入口函数start_kernel(),在start _kernel()中调用相关处理程序函数,

建立了0号进程(set _task _stack _end _magic(&init _task)),

设置体系结构的相关环境(setup _arch),

初始化内存结构(bootmem _init),

开启mmu,

创建页表(paging _init),

初始化串口(console _init),

0号进程是全部进程的父进程,0号进程建立了1号进程init,又建立了其余服务例程。

2、实验执行——经过gdb调试,分析Linux的内核启动过程

(1)实验步骤:

使用实验楼已配置好的环境,web

cd LinuxKernel/

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

8f47a11169672e7157cedb0bcb60d0cd.png

进入了菜单内核:

能够执行help、version和quit命令

e9b4a813e91130f440f26cd3e862b027.png

进入gdb调试:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

其中:

-S 是指在初始化cpu以前将cpu冻结

-s 是指在-gdb tcp ::1234,建立一个gdb server

54e0cc836c8f321cc30707303eee185d.png

已将cpu冻结

另开一个shell窗口:

(gdb)file linux-3.18.6/vmlinux

eb65461bec238c8a2f188ee73f521f8b.png

(gdb)target remote:1234

(gdb)break start_kernel

(gdb)c

cf492213c432f9f69d8a1b2d74059d0d.png

在start_kernel处设置断点,执行c调试,冻结的系统开始启动,断点执行到start _kernel

若设置断点在rest_init,

85fade8599e675699c58a85a70314297.png

利用list命令查看,发现rest_ init在start _kernel的尾部,几乎全部重要的内核模块初始化都在start _kernel完成,这是内核启动的关键。

(2)实验分析

进入并分析start_kernel:

1.init_task全局变量:即手工建立的PCB,0号进程即最终的idle进程.

在start_ kernel()中set _ task_ stack_ end_ magic (&init_task)中进行设置和初始化。0号进程是全部进程的父进程

2.trap_init():初始化中断向量

在trap_ init()中set_ intr_ gate(…)设置了不少中断门,执行不一样的硬件中断。set _ system _ trap _ gate(SYSCALL_ VECTOR,&system_call),设置系统陷阱门,就是系统调用!

3.mm_init()内存管理的初始化,sched _ init()调度模块的初始化

4.在start_ kernel的最后执行rest_init():

在rest_ init()中调用了kernel_thread(kernel _init,NULL,CLONE _FS),在kernel _init中,调用了run _init _process (),默认的init是根目录下的init,若是在根目录下没有,则找/sbin/init,/etc/init,/bin/init,/bin/sh做为1号进程,则kernel _init建立了一个1号进程,

执行kernel _ thread(kernel _ threaddd,NULL,CLONE _ FS|CLONE _ FILES),建立内核线程管理系统的运行资源,在rest init()尾部,进入了cpu startup _ entry(…),进入cpu _ idle,执行cpu _ idle _ loop(),在cpu idle loop()进行while(1)的循环处理,这就是0号进程。当系统没有进程须要执行时就调度到idle进程

start_kernel()启动时rest _init就一直存在,也就是0号进程,0号进程建立了1号进程,还建立了其余的服务线程,这样内核就启动起来了。

3、实验总结

本次实验主要分析了在内核启动过程当中的第一个函数:start_kernel的执行。

start_kernel()是init/main.c第一个启动的函数,主要完成了不少重要的与硬件平台相关和内核相关的初始化,并建立了init进程。

在init的start_ kernel()中调用了setup_ arch()进行与体系结构相关的第一个初始化,

经过bottom_init()函数根据系统定义的meminfo结构进行内存初始化,

最后paging_init()开启mmu,建立内核页表,映射全部的物理内存和I/O空间,

完成了建立异常向量表和初始化中断处理函数,初始化系统核心进程调度器和时钟中断处理机制,初始化串口控制台(serial_console)等等,

当全部的相关操做结束后,start_ kernel()会调用rest_ init()进行最后初始化,包括建立系统的第一个进程——init进程,init进程首先进行一系列的硬件初始化,而后经过命令行传递过来的参数挂在根文件系统,init进程会执行用户传递过来的参数执行用户指定的命令或者执行/sbin/init,/etc/init,/bin/init,/bin/sh 之一完成初始化工做,cpu_idle会被调用使系统处于闲置状态并等待用户输入。

到此,Linux内核启动完毕。

注意:

(1)内核启动过程包括start_kernel以前和以后,以前所有是作初始化的汇编指令,以后开始C代码的操做系统初始化,最后执行第一个用户态进程init

(2)从rest_ init开始,Linux开始产生进程,由于init_ task是静态制造出来的,pid=0,它试图将从最先的汇编代码一直到start_ kernel的执行都归入到init_ task进程上下文中。在rest _init函数中,内核将经过下面的代码产生第一个真正的进程(pid=1):

道生一(start_ kernel….cpu_ idle),一辈子二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是全部用户态进程的祖先,2号进程是全部内核线程的祖先)

经过此次实验,要重点理解内核启动时各个函数的功能以及调用顺序等,Linux启动过程很复杂,有不少硬件软件等初始化,应好好理解!shell

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值