用gdb来检验Linux内核的启动流程

        程  序 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

        Linux系统作为世界主流操作系统之一,一直是各位Linux爱好者研究操作系统的一个优秀的样本,从Linux系统中

我们能看到操作系统运行的整个流程。当然,在分析完Linux系统后,我们也能自己搭建自己的简易版的Linux系统。

       首先,我们来看看Linux系统的构成:

      大体上来说,我们一般认为Linux系统有4个部分,分别是内核、shell、文件系统和应用程序。其中人们关心最多

的是Linux内核和文件系统,Linux内核有一个专门的维护团队,可以负责更新系统版本,而全世界的人们都可以提交

自己对于Linux系统的更新。本次,我也只关注内核和文件系统,我首先来说一下Linux内核的构成。

Linux内核包含很多文件夹,比较重要的有以下文件夹:

       arch:这个文件是有关CPU架构的文件,比较常见的有arm、x86、MIPS等,本次我们以x86为例,不同的架构

有些指令是不一样的。

      drivers:驱动目录,里面放了很多Linux支持的硬件设备的驱动代码

      fs:文件系统,里面放的为文件系统的实现

      include:里面放置各种头文件目录

      icp:放的是进程间通信的文件

      kernel:就是Linux内核,放置内核本身需要的一些代码文件

      lib:里面放置一些公用的有用的库函数

      mm:内存管理的代码放置处

      init:Linux内核启动时初始化内核的代码

      Makefile:系统中有很多Makefile,整个内核工程用整个Makefile来管理的

 

      下面我们来说一下怎么构建自己的Linux操作系统,由于我们在一个真机上面进行测试不是很方便,此处我们引入  一个qemu软件,可以模拟相应的硬件,然后就可以在上面搭建Linux系统了。在qemu上面搭建这个的Linux系统的步骤如下:

(以下操作代码来自孟宁老师)

1.  # 下载内核源代码编译内核

2.  cd ~/LinuxKernel/

3.  wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz

4.  xz -d linux-3.18.6.tar.xz

5.  tar -xvf linux-3.18.6.tar

6.  cd linux-3.18.6

7.  make i386_defconfig

8.  make # 一般要编译很长时间,少则20分钟多则数小时

9.   

10. # 制作根文件系统

11. cd ~/LinuxKernel/

12. mkdir rootfs

13. git clone https://github.com/mengning/menu.git  # 如果被墙,可以使用附件menu.zip 

14. cd menu

15. gcc -o init linktable.c menu.c test.c -m32 -static –lpthread

16. cd ../rootfs

17. cp ../menu/init ./

18. find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

19.  

20. # 启动MenuOS系统

21. cd ~/LinuxKernel/

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

 

    通过上述的代码,我们就可以在Linux系统上面建立一个简易的MenuOS系统。下面我们来看看这个系统的文件系统

是怎么一个布局,文件系统中总共有如下的指令。


  /bin 二进制可执行命令

  /dev 设备特殊文件

  /etc 系统管理和配置文件

  /etc/rc.d 启动的配置文件和脚本

  /home 用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示

  /lib 标准程序设计库,又叫动态链接共享库,作用类似windows里的.dll文件

  /sbin 系统管理命令,这里存放的是系统管理员使用的管理程序

  /tmp 公用的临时文件存储点

  /root 系统管理员的主目录

  /mnt 系统提供这个目录是让用户临时挂载其他的文件系统。

  /usr 最庞大的目录,要用到的应用程序和文件几乎都在这个目录。

  /usr/bin 众多的应用程序

  /usr/sbin 超级用户的一些管理程序

 

       文件系统指文件存在的物理空间,Linux系统中每个分区都是一个文件系统,都有自己的目录层次结构。而且文件系统是Linux系统的一个重要的组成部分。本次主要是利用gdb来跟踪相关start_kernel代码,然后分析系统的启动流程,下面我们来看看系统的启动的流程,这里先来简单介绍一下gdb这个工具。

       GDB是一个强大的命令行调试工具,大家可能比较害怕命令行,感觉要记住好多东西,但是在Linux环境下,有很多时候是可以提示的,所以并不用担心,而且我们只需要记住常见的一些命令行就好了,以你为命令行可以形成一串指令的集合,所以可以做成脚本。

GDB主要有4项功能:

       1.     动态改变程序执行环境

       2.     动态检查程序断点处发生的事情

       3.     可以让程序在断点处暂停运行

       4.     启动你的程序,可以随意设置断点

       GDB主要的指令有以下这些东西,这里不是很全,需要全部指令的朋友可以自己去查看相应的文件,下面这些指令在一般的调试过程中已经够用了。

         gdb tst ===》启动GDB

         (gdb) l ===》l命令相当于list,此功能是列出源码

         (gdb) break 10 ===>设置断点,在源程序10行处

         (gdb) break start_kernel ===》设置断点,在源程序start_kernel处

         (gdb) break info break ===》查看断点信息。

         (gdb) r ===》 运行程序

         (gdb) n  ===》 单条语句执行

         (gdb) c ===》 继续运行程序

         (gdb) p a ===》 打印变量a

 

     在系统的启动过程中,我们常见的一个函数就是start_kernel,下面我们就来看看start_kernel函数是怎么执行的。

     在Linux启动进程中,从start_kernel开始进行c语言执行,它完成了内核的大部分初始化工作。从start_kernel开始,就进行一系列的初始化活动,包括关闭当前CPU的中断(local_irq_disable()),初始化页地址(tick_init()),使用链表将页链接起来(boot_cpu_init()),还有打印内核版本信息(printk(KERN_NOTICE))、进程调度初始化(sched_init())、完成对系统保留中断向量(trap_init函数)。这里面有一系列初始化活动,一直执行到init_post函数,这个时候第一个用户空间进程init将开始运行了,其中启动init进程的语句。

        run_init_process(“/sbin/init”);run_init_process(“etc/init”);run_init_process(“/bin/init”);run_init_process(“/bin/sh”),到这里,整个start_kernel就要执行完了,也完成整个系统的初始化,以及第一个进程init已经启动起来了。

       说了这么多,下面我们来看看效果怎么样吧,直接看图!

                                              图1.直接启动qemu,开启第二个命令行控制台


                                      图2.调用GDB进行调试


                                图3.图上表示gdb已经就绪


                                图4.图上表示通过端口1234,和qemu上Linux联系起来

                                图5.表示在start_kernel处打上断点


                           图6.然后输入c表示继续运行,此处qemu上系统运行停止在start_kernel处


                                             图7.图上显示的start_kernel处的代码,list命令的效果


                                            图8.在sched_init处打上第二个断点


                                          图9.调用list命令提供sched_init()处代码详情

       总结:Linux启动还是比较复杂的,主要是其中的初始化过程要清楚,里面初始化的中断屏蔽,以及硬件的初始化,第一个进程的启动,以及服务的开启等都是十分复杂的。其中idle是0号进程,注处理器上的idle由原始进程演变而来,从处理器上的idle由init进程fork得到,但是它们的pid都是0,且idle进程为最低优先级,且不参与调度,只是在运行队列为空的时候才被调度。而1号进程则由idle进程fork()而来,是系统中其他所有进程的祖先。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值