标签:
黄韧(原创作品转载请注明出处)
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
1)存储程序计算机
2)函数调用堆栈
3)中断
1)中断上下文的切换:保存现场和恢复现场
2)进程上下文的切换
一、使用gdb跟踪调试内核从start_kernel到init进程启动
使用实验楼的虚拟机打开shell
cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
内核启动完成后进入menu程序,支持三个命令help、version和quit。
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) -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项
现在系统是stop的状态,如下图:
按c后系统开始运行,启动到start_cernel的位置,如下:


list之后看到执行的位置

再设一个断点,系统执行到rest_init的位置,如下:

二、详细分析从start_kernel到init进程启动的过程
start_kernel函数的执行过程
代码在init目录下的main.c
500asmlinkage __visible void __init start_kernel(void)
501{
502    char *command_line;
503    char *after_dashes;
504
505    /*
506     * Need to run as early as possible, to initialize the
507     * lockdep hash:
508     */
509    lockdep_init();
510    set_task_stack_end_magic(&init_task);     init_task即手工创建的PCB,0号进程即最终的idle进程。
511    smp_setup_processor_id();
512    debug_objects_early_init();
513
514    /*
515     * Set up the the initial canary ASAP:
516     */
517    boot_init_stack_canary();
518
519    cgroup_init_early();
520
521    local_irq_disable();
522    early_boot_irqs_disabled = true;
523
524/*
525 * Interrupts are still disabled. Do necessary setups, then
526 * enable them
527 */
528    boot_cpu_init();
529    page_address_init();
530    pr_notice("%s", linux_banner);
531    setup_arch(&command_line);
532    mm_init_cpumask(&init_mm);
533    setup_command_line(command_line);
534    setup_nr_cpu_ids();
535    setup_per_cpu_areas();
536    smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */
537
538    build_all_zonelists(NULL, NULL);
539    page_alloc_init();
540
541    pr_notice("Kernel command line: %s\n", boot_command_line);
542    parse_early_param();
543    after_dashes = parse_args("Booting kernel",
544                  static_command_line, __start___param,
545                  __stop___param - __start___param,
546                  -1, -1, &unknown_bootoption);
547    if (!IS_ERR_OR_NULL(after_dashes))
548        parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
549               set_init_arg);
550
551    jump_label_init();
552
553    /*
554     * These use large bootmem allocations and must precede
555     * kmem_cache_init()
556     */
557    setup_log_buf(0);
558    pidhash_init();
559    vfs_caches_init_early();
560    sort_main_extable();
561    trap_init();   涉及到中断的初始化
562    mm_init();
563
564    /*
565     * Set up the scheduler prior starting any interrupts (such as the
566     * timer interrupt). Full topology setup happens at smp_init()
567     * time - but meanwhile we still have a functioning scheduler.
568     */
569    sched_init();
570    /*
571     * Disable preemption - early bootup scheduling is extremely
572     * fragile until we cpu_idle() for the first time.
573     */
574    preempt_disable();
575    if (WARN(!irqs_disabled(),
576         "Interrupts were enabled *very* early, fixing it\n"))
577        local_irq_disable();
578    idr_init_cache();
579    rcu_init();
580    context_tracking_init();
581    radix_tree_init();
582    /* init some links before init_ISA_irqs() */
583    early_irq_init();
584    init_IRQ();
585    tick_init();
586    rcu_init_nohz();
587    init_timers();
588    hrtimers_init();
589    softirq_init();
590    timekeeping_init();
591    time_init();
592    sched_clock_postinit();
593    perf_event_init();
594    profile_init();
595    call_function_init();
596    WARN(!irqs_disabled(), "Interrupts were enabled early\n");
597    early_boot_irqs_disabled = false;
598    local_irq_enable();
599
600    kmem_cache_init_late();
601
602    /*
603     * HACK ALERT! This is early. We‘re enabling the console before
604     * we‘ve done PCI setups etc, and console_init() must be aware of
605     * this. But we do want output early, in case something goes wrong.
606     */
607    console_init();
608    if (panic_later)
609        panic("Too many boot %s vars at `%s‘", panic_later,
610              panic_param);
611
612    lockdep_info();
613
614    /*
615     * Need to run this when irqs are enabled, because it wants
616     * to self-test [hard/soft]-irqs on/off lock inversion bugs
617     * too:
618     */
619    locking_selftest();
620
621#ifdef CONFIG_BLK_DEV_INITRD
622    if (initrd_start && !initrd_below_start_ok &&
623        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
624        pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
625            page_to_pfn(virt_to_page((void *)initrd_start)),
626