美文网首页
3跟踪分析Linux内核的启动过程

3跟踪分析Linux内核的启动过程

作者: 夏天的篮球 | 来源:发表于2017-03-10 09:17 被阅读0次

    安大大 + 原创作品转载请注明出处 + 《Linux操作系统分析》MOOC课程


    实验

    • 使用自己的Linux系统环境搭建MenuOS的过程
    # 下载内核源代码编译内核
    cd ~/LinuxKernel/
    wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz
    xz -d linux-3.18.6.tar.xz
    tar -xvf linux-3.18.6.tar
    cd linux-3.18.6
    make i386_defconfig
    make # 一般要编译很长时间,少则20分钟多则数小时
     
    # 制作根文件系统
    cd ~/LinuxKernel/
    mkdir rootfs
    git clone https://github.com/mengning/menu.git  # 如果被墙,可以使用附件menu.zip 
    cd menu
    gcc -o init linktable.c menu.c test.c -m32 -static –lpthread #init是系统启动后默认启动1号进程,init是第一个用户态进程,第一个用户态进程是1号进程
    cd ../rootfs
    cp ../menu/init ./ #把init拷贝到rootfs目录下边
    find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img #使用cpio方式把当前rootfs目录下所有的文件打包成rootfs.img一个镜像文件
    #至此一个最简单的根文件系统镜像制作完毕
     
    # 启动MenuOS系统
    cd ~/LinuxKernel/
    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
    
    • 重新配置编译Linux使之携带调试信息
    1.在原来配置的基础上,make menuconfig选中如下选项重新配置Linux,使之携带调试信息
    2.1 kernel hacking—>
    2.2 [*] compile the kernel with debug info #把debug信息打开
              #使得跟踪调试时可以边跟踪边看跟踪到某一点的某一行代码时上下那一段的源代码
    3.make重新编译(时间较长)
    
    • 内核启动完成后进入menu程序:
    menu编译好的init文件放在rootfs里

    把menu编译好的init文件放在rootfs里,然后把rootfs做成rootfs.img。根文件系统是rootfs.img,内核启动完后加载根文件系统,根文件系统里的init可执行文件就被执行起来了

    使用gdb跟踪调试内核:

    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:
     -S freeze CPU at startup (use ’c’ to start execution)  CPU初始化之前冻结起来
     -s shorthand for -gdb tcp::1234 在这个端口上创建了一个gdb server,若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
    

    另开一个shell窗口:

    gdb
    (gdb)file linux-3.18.6/vmlinux # 把一个带有符号表的内核镜像加载进来,在gdb界面中targe remote之前加载符号表
    (gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
    (gdb)break start_kernel # 设置断点,跟踪内核,断点的设置可以在target remote之前,也可以在之后
    
    被冻结的linux系统 把带有debug信息(符号表)的内核加载进来 建立gdb和gdbserver之间的连接 设置start_kernel断点 按c回车,系统开始执行,启动到start_kernel的位置 使用list命令就能查看到start_kernel上下的这段代码 设置rest_init断点 查看rest_init处的代码,它是在start_kernel函数的尾部调用的

    全局变量init_task即手工创建的PCB在这里初始化,0号进程即最终的idle进程。
    不管分析内核的哪一部分都会涉及到start_kernel,因为要通过start_kernel进行初始化。

    trap_init();初始化一些中断向量
    mm_init();内存管理模块初始化
    sched_init();调度模块初始化
    等等
    start_kernel的最后一句rest_init();

    当系统没有进程需要执行时就调度到idle进程

    Linux内核启动过程相关的参考资料
    计算机的启动过程概述

    x86 CPU启动的第一个动作CS:EIP=FFFF:0000H(换算为物理地址为000FFFF0H,因为16位CPU有20根地址线),即BIOS程序的位置。http://wenku.baidu.com/view/4e5c49eb172ded630b1cb699.html

    BIOS例行程序检测完硬件并完成相应的初始化之后就会寻找可引导介质,找到后把引导程序加载到指定内存区域后,就把控制权交给了引导程序。这里一般是把硬盘的第一个扇区MBR和活动分区的引导程序加载到内存(即加载BootLoader),加载完整后把控制权交给BootLoader。

    引导程序BootLoader开始负责操作系统初始化,然后起动操作系统。启动操作系统时一般会指定kernel、initrd和root所在的分区和目录,比如root (hd0,0),kernel (hd0,0)/bzImage root=/dev/ram init=/bin/ash,initrd (hd0,0)/myinitrd4M.img

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

    一般分两阶段启动,先是利用initrd的内存文件系统,然后切换到硬盘文件系统继续启动。initrd文件的功能主要有两个:1、提供开机必需的但kernel文件(即vmlinuz)没有提供的驱动模块(modules) 2、负责加载硬盘上的根文件系统并执行其中的/sbin/init程序进而将开机过程持续下去

    init进程详解

    Linux内核中的init_task进程和idle进程

    道生一(start_kernel....cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先),新内核的核心代码已经优化的相当干净,都符合中国传统文化精神了。

    相关文章

      网友评论

          本文标题:3跟踪分析Linux内核的启动过程

          本文链接:https://www.haomeiwen.com/subject/edlngttx.html