init:
当PC启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处的代码.这就是对内核初始化过程的一个最简单的描述。
最初,Linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余部分装入到0x10000。
当系统装入时,会显示Loading...信息。装入完成后,控制转向另一个实模式下的汇编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。
接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄存器和调用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c, Boot/unzip.c 和Boot/misc.c组成。解压缩后的数据被装入到了0x100000处,这也是Linux不能在内存小于2M的环境下运行的主要原因。
解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成: IDT、GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。这大概是整个内核中最为复杂的部分。
以上一段引自http://www.joyfire.net/jln/kernel/1.html
初始化顺序:
416 asmlinkage void __init start_kernel(void)
417 {
418 char * command_line;
419 extern struct kernel_param __start___param[], __stop___param[];
420 /*
421 * Interrupts are still disabled. Do necessary setups, then
422 * enable them
423 */
424 lock_kernel();
425 page_address_init();
426 printk(linux_banner);
427 setup_arch(&command_line);
428 setup_per_cpu_areas();
429
430 /*
431 * Mark the boot cpu "online" so that it can call console drivers in
432 * printk() and can access its per-cpu storage.
433 */
434 smp_prepare_boot_cpu();
435
436 /*
437 * Set up the scheduler prior starting any interrupts (such as the
438 * timer interrupt). Full topology setup happens at smp_init()
439 * time - but meanwhile we still have a functioning scheduler.
440 */
441 sched_init();
442 /*
443 * Disable preemption - early bootup scheduling is extremely
444 * fragile until we cpu_idle() for the first time.
445 */
446 preempt_disable();
447 build_all_zonelists();
448 page_alloc_init();
449 printk("Kernel command line: %s/n", saved_command_line);
450 parse_early_param();
451 parse_args("Booting kernel", command_line, __start___param,
452 __stop___param - __start___param,
453 &unknown_bootoption);
454 sort_main_extable();
455 trap_init();
456 rcu_init();
457 init_IRQ();
458 pidhash_init();
459 init_timers();
460 softirq_init();
461 time_init();
462
463 /*
464 * HACK ALERT! This is early. We're enabling the console before
465 * we've done PCI setups etc, and console_init() must be aware of
466 * this. But we do want output early, in case something goes wrong.
467 */
468 console_init();
469 if (panic_later)
470 panic(panic_later, panic_param);
471 profile_init();
472 local_irq_enable();
473 #ifdef CONFIG_BLK_DEV_INITRD
474 if (initrd_start && !initrd_below_start_ok &&
475 initrd_start < min_low_pfn << PAGE_SHIFT) {
476 printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
477 "disabling it./n",initrd_start,min_low_pfn << PAGE_SHIFT);
478 initrd_start = 0;
479 }
480 #endif
481 vfs_caches_init_early();
482 mem_init();
483 kmem_cache_init();
484 numa_policy_init();
485 if (late_time_init)
486 late_time_init();
487 calibrate_delay();
488 pidmap_init();
489 pgtable_cache_init();
490 prio_tree_init();
491 anon_vma_init();
492 #ifdef CONFIG_X86
493 if (efi_enabled)
494 efi_enter_virtual_mode();
495 #endif
496 fork_init(num_physpages);
497 proc_caches_init();
498 buffer_init();
499 unnamed_dev_init();
500 security_init();
501 vfs_caches_init(num_physpages);
502 radix_tree_init();
503 signals_init();
504 /* rootfs populating might need page-writeback */
505 page_writeback_init();
506 #ifdef CONFIG_PROC_FS
507 proc_root_init();
508 #endif
509 check_bugs();
510
511 acpi_early_init(); /* before LAPIC and SMP init */
512
513 /* Do the rest non-__init'ed, we're now alive */
514 rest_init();
515 }
产生init进程:
371 static void noinline rest_init(void)
372 __releases(kernel_lock)
373 {
374 kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
375 numa_default_policy();
376 unlock_kernel();
377 preempt_enable_no_resched();
378 cpu_idle();
379 }
init进程函数:
625 static int init(void * unused)
626 {
627 lock_kernel();
628 /*
629 * Tell the world that we're going to be the grim
630 * reaper of innocent orphaned children.
631 *
632 * We don't want people to have to make incorrect
633 * assumptions about where in the task array this
634 * can be found.
635 */
636 child_reaper = current;
637
638 /* Sets up cpus_possible() */
639 smp_prepare_cpus(max_cpus);
640
641 do_pre_smp_initcalls();
642
643 fixup_cpu_present_map();
644 smp_init();
645 sched_init_smp();
646
647 /*
648 * Do this before initcalls, because some drivers want to access
649 * firmware files.
650 */
651 populate_rootfs();
652
653 do_basic_setup();
654
655 /*
656 * check if there is an early userspace init. If yes, let it do all
657 * the work
658 */
659 if (sys_access((const char __user *) "/init", 0) == 0)
660 execute_command = "/init";
661 else
662 prepare_namespace();
663
664 /*
665 * Ok, we have completed the initial bootup, and
666 * we're essentially up and running. Get rid of the
667 * initmem segments and start the user-mode stuff..
668 */
669 free_initmem();
670 unlock_kernel();
671 system_state = SYSTEM_RUNNING;
672 numa_default_policy();
673
674 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
675 printk("Warning: unable to open an initial console./n");
676
677 (void) sys_dup(0);
678 (void) sys_dup(0);
679
680 /*
681 * We try each of these until one succeeds.
682 *
683 * The Bourne shell can be used instead of init if we are
684 * trying to recover a really broken machine.
685 */
686
687 if (execute_command)
688 run_init_process(execute_command);
689
690 run_init_process("/sbin/init");
691 run_init_process("/etc/init");
692 run_init_process("/bin/init");
693 run_init_process("/bin/sh");
694
695 panic("No init found. Try passing init= option to kernel.");
696 }