start_kernel()函数分析

asmlinkage void __init start_kernel(void)   
{   
    char * command_line;   
    extern struct kernel_param __start___param[], __stop___param[];   
   
    smp_setup_processor_id();    
    //空函数    
   
    /*  
     * Need to run as early as possible, to initialize the  
     * lockdep hash:  
     */   
   
       
    lockdep_init();/*初始化一些数据*/   
    debug_objects_early_init();   
    cgroup_init_early();   
   
    local_irq_disable(); /*关闭中断*/   
    early_boot_irqs_off();   
    /*    
     * 每一个中断都有一个中断描述符(struct irq_desc)来进行描述,这个函数的    
     * 作用就是设置所有中断描述符的锁    
     */     
    early_init_irq_lock_class();   
   
/*  
 * Interrupts are still disabled. Do necessary setups, then  
 * enable them  
 */   
    lock_kernel(); /*锁上内核,Linux是支持抢占CPU,放弃启动被中断(针对多处理器)*/   
    tick_init(); /*初始化时钟*/   
    boot_cpu_init();/*//这个实际上是在多CPU环境下选择CPU,这里直接CPUID选择的是0号cpu*/   
    page_address_init(); /* 初始化页地址,使用链表将其链接起来 */     
    printk(KERN_NOTICE);   
    printk(linux_banner); /*打印Linux版本*/   
    setup_arch(&command_line); /* 这是一个重量级的函数了,会比较仔细地分析一下,主要完成了4个方面的工作,一个就是取得MACHINE和PROCESSOR的信息然或将他们赋值给kernel相应的全局变量,然后呢是对boot_command_line和tags接行解析,再然后呢就是memory、cach的初始化,最后是为kernel的后续运行请求资源。 */   
    /*初始化内存*/   
    mm_init_owner(&init_mm, &init_task);   
    setup_command_line(command_line); /*保存命令行参数*/   
    setup_per_cpu_areas();/* 为每个cpu申请内存空间 */   
    setup_nr_cpu_ids();   
    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks//设置启动的CPU为在线状态.在多CPU架构下 */   
   
    /*  
     * Set up the scheduler prior starting any interrupts (such as the  
     * timer interrupt). Full topology setup happens at smp_init()  
     * time - but meanwhile we still have a functioning scheduler.  
     */   
    sched_init();/*初始化进程调度器*/   
    /*  
     * Disable preemption - early bootup scheduling is extremely  
     * fragile until we cpu_idle() for the first time.  
     */   
    preempt_disable(); /*禁止系统调用,即禁止抢占*/   
    build_all_zonelists(); /*建立内存区域链表*/   
    page_alloc_init();/*内存页初始化*/   
    printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);/*打印Linux命令行启动参数*/   
    parse_early_param();/*解析参数*/   
    parse_args("Booting kernel", static_command_line, __start___param,   
           __stop___param - __start___param,   
           &unknown_bootoption); //执行命令行解析,若参数不存在,则调用unknown_bootoption    
    if (!irqs_disabled()) {   
        printk(KERN_WARNING "start_kernel(): bug: interrupts were "   
                "enabled *very* early, fixing it\n");   
        local_irq_disable();   
    }/*判断中断是否关闭,若打开则关闭中断*/   
    sort_main_extable(); /*对异常处理函数排序*/   
    trap_init();/*空函数*/   
    rcu_init();/*初始化互斥机制*/   
    /* init some links before init_ISA_irqs() */   
    early_irq_init();/*中断向量的初始化*/   
    init_IRQ();/*完成其余中断向量的初始化*/   
    pidhash_init();/*进程Hash table的初始化*/   
    init_timers();/*初始化定时器*/   
    hrtimers_init();/*高精度时钟初始化*/   
    softirq_init();/*软中断初始化*/   
    timekeeping_init();/*共用时钟的初始化*/   
    time_init();/*初始化系统时钟*/   
    sched_clock_init();/*进程调度时钟初始化*/   
    profile_init(); /* 对内核的profile(一个内核性能调式工具)功能进行初始化 */     
    if (!irqs_disabled())   
        printk(KERN_CRIT "start_kernel(): bug: interrupts were "   
                 "enabled early\n");   
    early_boot_irqs_on(); /*打开IRQ中断*/   
    local_irq_enable();   
   
    /*  
     * HACK ALERT! This is early. We're enabling the console before  
     * we've done PCI setups etc, and console_init() must be aware of  
     * this. But we do want output early, in case something goes wrong.  
     */   
    console_init();/*打印中断的初始化*/   
    if (panic_later)   
        panic(panic_later, panic_param);   
   
    lockdep_info();   
   
    /*  
     * Need to run this when irqs are enabled, because it wants  
     * to self-test [hard/soft]-irqs on/off lock inversion bugs  
     * too:  
     */   
    locking_selftest();   
   
#ifdef CONFIG_BLK_DEV_INITRD    
    if (initrd_start && !initrd_below_start_ok &&   
        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {   
        printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "   
            "disabling it.\n",   
            page_to_pfn(virt_to_page((void *)initrd_start)),   
            min_low_pfn);   
        initrd_start = 0;   
    }   
#endif    
    vmalloc_init(); /*内存池的初始化*/   
    vfs_caches_init_early();/*虚拟文件系统的初始化*/   
    cpuset_init_early();/*空函数*/   
    page_cgroup_init();/**/   
    mem_init();/*对全局的物理页变量初始化,对没有分配的页面初始化*/   
    enable_debug_pagealloc();   
    cpu_hotplug_init();/*空函数*/   
    kmem_cache_init();/*内核内存缓冲池的初始化*/   
    debug_objects_mem_init();   
    idr_init_cache();/*idr初始化缓冲*/   
    setup_per_cpu_pageset();/*空函数*/   
    numa_policy_init();/*空函数*/   
    if (late_time_init)   
        late_time_init();   
    calibrate_delay(); /*校验延时函数的精确度*/   
    pidmap_init();/*进程号位图初始化,一般用一个page来只是所有的进程PID占用情况*/   
    pgtable_cache_init();/*空函数*/   
    prio_tree_init();/*初始化优先级数组*/   
    anon_vma_init();/*空函数*/   
#ifdef CONFIG_X86    
    if (efi_enabled)   
        efi_enter_virtual_mode();   
#endif    
    thread_info_cache_init();/*空函数*/   
    cred_init();   
    fork_init(num_physpages);/*初始化fork()环境*/   
    proc_caches_init();/*为proc文件系统创建高速缓存*/   
    buffer_init();/*空函数*/   
    key_init();/*没有键盘为空,有键盘初始化一个高速缓存*/   
    security_init();/*空函数*/   
    vfs_caches_init(num_physpages); /*虚拟文件系统挂载*/   
    radix_tree_init();/*radix树的初始化,供页面查找*/   
    signals_init();/*初始化信号量*/   
    /* rootfs populating might need page-writeback */   
    page_writeback_init();/*CPU在内存中开辟高速缓存,CPU直接访问高速缓存提以高速度。当cpu更新了高速缓存的数据后,需要定期将高速缓存的数据写回到存储介质中,比如磁盘和flash等。这个函数初始化写回的周期*/   
#ifdef CONFIG_PROC_FS    
    proc_root_init();/*如果配置了proc文件系统,则需初始化并加载proc文件系统。在根目录的proc文件夹就是proc文件系统,这个文件系统是ram类型的,记录系统的临时数据,系统关机后不会写回到flash中*/   
#endif    
    cgroup_init();/*空函数*/   
    cpuset_init();/*空函数*/   
    taskstats_init_early();/*进程状态初始化,实际上就是分配了一个存储线程状态的高速缓存*/   
    delayacct_init();/*空函数*/   
   
    check_bugs();/*测试CPU的缺陷,记录检测的缺陷,便于内核其他部分工作的需要*/   
   
    acpi_early_init(); /* before LAPIC and SMP init */   
   
    ftrace_init();   
   
    /* Do the rest non-__init'ed, we're now alive */   
    rest_init(); /* 创建init进程 */     
}  


下面是国嵌培训

asmlinkage void __init start_kernel(void)

{

       char * command_line;

       extern struct kernel_param __start___param[], __stop___param[];

 

       smp_setup_processor_id();

 

       /*

        * Need to run as early as possible, to initialize the

        * lockdep hash:

        */

       lockdep_init();

       debug_objects_early_init();

       cgroup_init_early();

 

       local_irq_disable();

       early_boot_irqs_off();

       early_init_irq_lock_class();

 

/*

 * Interrupts are still disabled. Do necessary setups, then

 * enable them

 */

       lock_kernel();

       tick_init();

       boot_cpu_init();

       page_address_init();

       printk(KERN_NOTICE);

       printk(linux_banner);

       setup_arch(&command_line);

       mm_init_owner(&init_mm, &init_task);

       setup_command_line(command_line);

       setup_per_cpu_areas();

       setup_nr_cpu_ids();

       smp_prepare_boot_cpu();     /* arch-specific boot-cpu hooks */

 

       /*

        * Set up the scheduler prior starting any interrupts (such as the

        * timer interrupt). Full topology setup happens at smp_init()

        * time - but meanwhile we still have a functioning scheduler.

        */

       sched_init();

       /*

        * Disable preemption - early bootup scheduling is extremely

        * fragile until we cpu_idle() for the first time.

        */

       preempt_disable();

       build_all_zonelists();

       page_alloc_init();

       printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);

       parse_early_param();

       parse_args("Booting kernel", static_command_line, __start___param,

                 __stop___param - __start___param,

                 &unknown_bootoption);

       if (!irqs_disabled()) {

              printk(KERN_WARNING "start_kernel(): bug: interrupts were "

                            "enabled *very* early, fixing it\n");

              local_irq_disable();

       }

       sort_main_extable();

       trap_init();

       rcu_init();

       /* init some links before init_ISA_irqs() */

       early_irq_init();

       init_IRQ();

       pidhash_init();

       init_timers();

       hrtimers_init();

       softirq_init();

       timekeeping_init();

       time_init();

       sched_clock_init();

       profile_init();

       if (!irqs_disabled())

              printk(KERN_CRIT "start_kernel(): bug: interrupts were "

                             "enabled early\n");

       early_boot_irqs_on();

       local_irq_enable();

 

       /*

        * HACK ALERT! This is early. We're enabling the console before

        * we've done PCI setups etc, and console_init() must be aware of

        * this. But we do want output early, in case something goes wrong.

        */

       console_init();

       if (panic_later)

              panic(panic_later, panic_param);

 

       lockdep_info();

 

       /*

        * Need to run this when irqs are enabled, because it wants

        * to self-test [hard/soft]-irqs on/off lock inversion bugs

        * too:

        */

       locking_selftest();

 

#ifdef CONFIG_BLK_DEV_INITRD

       if (initrd_start && !initrd_below_start_ok &&

           page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {

              printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "

                  "disabling it.\n",

                  page_to_pfn(virt_to_page((void *)initrd_start)),

                  min_low_pfn);

              initrd_start = 0;

       }

#endif

       vmalloc_init();

       vfs_caches_init_early();

       cpuset_init_early();

       page_cgroup_init();

       mem_init();

       enable_debug_pagealloc();

       cpu_hotplug_init();

       kmem_cache_init();

       debug_objects_mem_init();

       idr_init_cache();

       setup_per_cpu_pageset();

       numa_policy_init();

       if (late_time_init)

              late_time_init();

       calibrate_delay();

       pidmap_init();

       pgtable_cache_init();

       prio_tree_init();

       anon_vma_init();

#ifdef CONFIG_X86

       if (efi_enabled)

              efi_enter_virtual_mode();

#endif

       thread_info_cache_init();

       cred_init();

       fork_init(num_physpages);

       proc_caches_init();

       buffer_init();

       key_init();

       security_init();

       vfs_caches_init(num_physpages);

       radix_tree_init();

       signals_init();

       /* rootfs populating might need page-writeback */

       page_writeback_init();

#ifdef CONFIG_PROC_FS

       proc_root_init();

#endif

       cgroup_init();

       cpuset_init();

       taskstats_init_early();

       delayacct_init();

 

       check_bugs();

 

       acpi_early_init(); /* before LAPIC and SMP init */

 

       ftrace_init();

 

       /* Do the rest non-__init'ed, we're now alive */

       rest_init();

}

 

tatic noinline void __init_refok rest_init(void)

       __releases(kernel_lock)

{

       int pid;

 

       kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

       numa_default_policy();

       pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

       kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);

       unlock_kernel();

 

       /*

        * The boot idle thread must execute schedule()

        * at least once to get things moving:

        */

       init_idle_bootup_task(current);

       rcu_scheduler_starting();

       preempt_enable_no_resched();

       schedule();

       preempt_disable();

 

       /* Call into cpu_idle with preempt disabled */

       cpu_idle();

}

 

static noinline int init_post(void)

{

       /* need to finish all async __init code before freeing the memory */

       async_synchronize_full();

       free_initmem();

       unlock_kernel();

       mark_rodata_ro();

       system_state = SYSTEM_RUNNING;

       numa_default_policy();

 

       if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

              printk(KERN_WARNING "Warning: unable to open an initial console.\n");

 

       (void) sys_dup(0);

       (void) sys_dup(0);

 

       current->signal->flags |= SIGNAL_UNKILLABLE;

 

       if (ramdisk_execute_command) {

              run_init_process(ramdisk_execute_command);

              printk(KERN_WARNING "Failed to execute %s\n",

                            ramdisk_execute_command);

       }

 

       /*

        * We try each of these until one succeeds.

        *

        * The Bourne shell can be used instead of init if we are

        * trying to recover a really broken machine.

        */

       if (execute_command) {

              run_init_process(execute_command);

              printk(KERN_WARNING "Failed to execute %s.  Attempting "

                                   "defaults...\n", execute_command);

       }

       run_init_process("/sbin/init");

       run_init_process("/etc/init");

       run_init_process("/bin/init");

       run_init_process("/bin/sh");

 

       panic("No init found.  Try passing init= option to kernel.");

}

 

你可能感兴趣的:(start_kernel()函数分析)