LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS
黄韧(原创作品转载请注明出处)
《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
", 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
"))
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
");
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.
",
625 page_to_pfn(virt_to_page((void *