zoukankan      html  css  js  c++  java
  • Linux内核分析——跟踪分析Linux内核的启动过程

    万子惠 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程

    实验部分

    menu程序:

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

    其中:

    1.qemu 是一个快速的动态译指的虚拟机

    2.-kernel bzImage: 内核镜像

    3.-initrd file使用file作为初始的ram磁盘。

    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之前,也可以在之后
    

    第一个断点(start_kernel):很多重要的模块都在这里初始化

    list查看上下文

    第二个断点(rest_init):

    list查看上下文:

    mm_init(有两处)

    kernel_thread

    run_init_process

    总结部分:

    Part1知识点总结

    Linux-3.18.6/:(笔记只放一些比较重要的目录)

    arch/ 占有量相当大,有支持不同cpu的源代码 (x86重要)
    Documentation/ 文档
    fs/ 文件系统(file system)
    init/ 内核启动相关代码大部分都在此处 (其中的main.c 整个内核启动起点)
    ipc/ 进程之间通信
    kernel/ 内核核心代码	(进程调度)
    mm/ memory management
    

    //一号进程部分(run_init_process:第一个用户态进程)

    if (ramdisk_execute_command) {
    ret = run_init_process(ramdisk_execute_command);
    if (!ret)
    	return 0;
    	pr_err("Failed to execute %s (error %d)
    ",
    	       ramdisk_execute_command, ret);
    }
    

    //kernel_init,kthreadd

    kernel_thread(kernel_init, NULL, CLONE_FS);
    numa_default_policy();
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);//创建内核线程管理资源
    

    //0号进程 内核一启动就会一直存在。

    static noinline void __init_refok rest_init(void)
    {
    int pid;
    
    rcu_scheduler_starting();
    /*
     * We need to spawn init first so that it obtains pid 1, however
     * the init task will end up wanting to create kthreads, which, if
     * we schedule it before we create kthreadd, will OOPS.
     */
    kernel_thread(kernel_init, NULL, CLONE_FS);
    numa_default_policy();
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    rcu_read_lock();
    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    rcu_read_unlock();
    complete(&kthreadd_done);
    
    /*
     * The boot idle thread must execute schedule()
     * at least once to get things moving:
     */
    init_idle_bootup_task(current);
    schedule_preempt_disabled();
    /* Call into cpu_idle with preempt disabled */
    cpu_startup_entry(CPUHP_ONLINE);
    }
    

    内核启动参考资料:

    • x86 CPU启动的第一个动作CS:EIP=FFFF:0000H(换算为物理地址为000FFFF0H,因为16位CPU有20根地址线),即BIOS程序的位置

    • 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程序进而将开机过程持续下去

    Part2 start_kernel

    /init/main.c中 很多重要的模块都在这里进行初始化

    lockdep_init 初始化hash表,只调用一次

    init_task:手工创建的PCB,0号进程即最终的idle进程

    trap_init():这里初始化很多中断向量

    mm_init():内存管理模块

    sched_init 进程调度初始化

    关于Linux的启动

    0号进程即最终的idle进程,当系统没有进程需要执行时就调度到idle进程(一直循环啊循环)

    道生一(start_kernel....cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先)

  • 相关阅读:
    【题解】LOJ #6488 数表【FWT】
    【题解】[Comet OJ Contest #11 F] arewell【子集卷积】
    【CF757F】 Team Rocket Rises Again 【支配树】
    支配树学习笔记
    JS模拟实现题目(new debounce throwee 等)
    React生命周期
    js转义符
    CSS3中的transform转换属性
    animation动画
    flex
  • 原文地址:https://www.cnblogs.com/midori/p/5271582.html
Copyright © 2011-2022 走看看