自然flw

linux内核学习之三 跟踪分析内核的启动过程

一   前期准备工作

      1 搭建环境

        1.1下载内核源代码并编译内核

             创建目录,并进入该目录:

               

             下载源码:              

             

             解压缩,并进入该目录:xz -d linux-3.18.6.tar.xz

                                            tar -xvf linux-3.18.6 

                                            cd  linux-3.18.6

            选定x86架构的相关文件编译:

            

           编译:

            

        1.2 制作根文件系统

           在工作目录下新建一个文件夹:

               mkdir rootfs

           下载老师提供的资料:git clone https://github.com/mengning/menu.git

            

            cd menu

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

            cd ../rootfs

            cp ../menu/init ./

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

            返回工作目录,即可启动Menuos

             cd ..

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

            

           运行效果:

            

 

    2   调试工具gdb 简介

       gdb 调试器是一款GNU开发组织并发布的UNIX/linux 下的程序调试工具。虽然没有图形化的界面,但是它的强大调试功能足以和windows 下专业工具如Visual studio 媲美,甚至更简洁。(注意:gdb进行调试的是可执行文件,而不是如“**.c”的源代码 。)

              使用的命令             命令介绍

                gdb                   //   进入需要调试的文件所在目录,进入gdb调试环境

                l                        //查看文件(所有载入的文件)

                b                       //设置断点,如b 6 ,表示在第6行设置断点                     

                info   b               //查看断点信息

                r                        // 运行代码

                p    “变量名 ”          //查看变量的值,如 :p   n ,查看变量n的值

                n                         //单步运行

                s                         //单步运行,与上面的区别是,当发生函数调用时,“s”会进入该函数,但是“n”不会进入该函数

二 调试跟踪

               为了直观显示在调试过程中的内核动态,使用qemu模拟器,初始时使为停止态:

               

               -S 表示冻结在开始状态

               -s   为gdb 调试工具设定端口1234,也可用其他

                

               再打开一个gdb调试窗口,加载符号表,建立连接,设定断点

                

               其中第一个断点在start_kernel 处,第二个断点在rest_init处,继续执行,停在第一个断点处:

                

                输入“c”,继续执行,停在第二个断点处:

               

               接着执行:

               

三  个人对linux启动过程的理解

       start_kernel()函数的作用是完成linux内核的初始化,几乎所有模块都是由这个函数初始化的,通过阅读代码和使用gdb 工具,完成了下列动作:

       调用sched_init()函数来初始化调度程序;调用page_alloc_init()初始化伙伴系统分配程序;调用trap_init()和init_IRQ()完成异常和中断初始化;调用softirq_init()函数初始化软中断;调用time_init()函数初始化系统和时间;等等。。。

      启动过程分析:计算机上电后,加载BIOS的硬件信息与进行自我测试,读取并执行第一个启动设备内主引导记录内的Bootloader,依据bootloader的设置加载Kernel ,Kernel会开始检测硬件与加载驱动程序。这其中的每一部分都需要大篇的文字描述,这里只是重点从进程角度来了解一下:init_task进程(0号进程)是静态创造的,是内核开发人员创造的,而不是其他进程通过do_fork形成的。它从start_kernel()初始化直到start_kernel()中最后一个函数rest_init(),从rest_init开始,Linux开始产生进程,在rest_init函数中,内核将通过kernel_thread()产生第一个真正的进程(pid=1),而此时init_task的任务基本上已经完全结束了,它将沦落为一个idle 进程,事实上在更早前的sched_init()函数中,通过init_idle(current, smp_processor_id())函数的调用就已经把init_task初始化成了一个idle 进程。

        

     

by:方龙伟

原创作品 转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

posted on 2016-03-12 19:53  自然flw  阅读(632)  评论(0编辑  收藏  举报

导航