start_kernel函数

4.2 内核初始化

如图4.6所示,内核的初始化过程由start_kernel函数开始,至第一个用户进程init结束,调用了一系列的初始化函数对所有的内核组件进行初始化。其中,start_kernel、rest_init、kernel_init、init_post等4个函数构成了整个初始化过程的主线。

 
(点击查看大图)图4.6  内核初始化

本节接下来的内容会结合内核代码,对内核初始化过程主线上的几个函数进行分析,使读者对该过程有个整体上的认识,以此为基础,读者可以根据自己的兴趣或需要,选择与某些组件相关的初始化函数,进行更进一步的研究分析。

4.2.1  start_kernel函数

从start_kernel函数开始,内核即进入了C语言部分,它完成了内核的大部分初始化工作。实际上,可以将start_kernel函数看做内核的main函数。

代码清单4.1  start_kernel函数

  
  
  
  
  1. 513 asmlinkage void __init start_kernel(void)  
  2. 514 {  
  3. 515     char * command_line;  
  4. 516     extern struct kernel_param __start___param[], __stop___param[];  
  5. 517  
  6.         /*  
  7.          * 当只有一个CPU的时候这个函数就什么都不做,
    但是如果有多个CPU的时候那么它就  
  8.          * 返回在启动的时候的那个CPU的号  
  9.          */  
  10. 518     smp_setup_processor_id();  
  11. 519  
  12. 520     /*  
  13. 521      * Need to run as early as possible, to initialize the  
  14. 522      * lockdep hash:  
  15. 523      */  
  16. 524     unwind_init();  
  17. 525     lockdep_init();  
  18. 526  
  19.         /* 关闭当前CPU的中断 */  
  20. 527     local_irq_disable();  
  21. 528     early_boot_irqs_off();  
  22.         /*  
  23.          * 每一个中断都有一个中断描述符(struct irq_desc)
    来进行描述,这个函数的  
  24.          * 作用就是设置所有中断描述符的锁  
  25.          */  
  26. 529     early_init_irq_lock_class();  
  27. 530  
  28. 531 /*  
  29. 532  * Interrupts are still disabled. Do necessary setups, then  
  30. 533  * enable them  
  31. 534  */  
  32.         /* 获取大内核锁,锁定整个内核。 */  
  33. 535     lock_kernel();  
  34.         /* 如果定义了CONFIG_GENERIC_CLOCKEVENTS,则注册clockevents框架 */  
  35. 536     tick_init();  
  36. 537     boot_cpu_init();  
  37.         /* 初始化页地址,使用链表将其链接起来 */  
  38. 538     page_address_init();  
  39. 539     printk(KERN_NOTICE);  
  40.         /* 显示内核的版本信息 */  
  41. 540     printk(linux_banner);  
  42.         /*  
  43.          * 每种体系结构都有自己的setup_arch()函数,是
    体系结构相关的,具体编译哪个  
  44.          * 体系结构的setup_arch()函数,由源码树顶层目录
    下的Makefile中的ARCH变量  
  45.          * 决定  
  46.          */  
  47. 541     setup_arch(&command_line);  
  48. 542     setup_command_line(command_line);  
  49. 543     unwind_setup();  
  50.         /* 每个CPU分配pre-cpu结构内存, 并复制.data.percpu段的数据 */  
  51. 544     setup_per_cpu_areas();  
  52. 545     smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */  
  53. 546  
  54. 547     /*  
  55. 548      * Set up the scheduler prior starting any 
    interrupts (such as the  
  56. 549      * timer interrupt). Full topology setup 
    happens at smp_init()  
  57. 550      * time - but meanwhile we still have a 
    functioning scheduler.  
  58. 551      */  
  59.         /* 进程调度器初始化 */  
  60. 552     sched_init();  
  61. 553     /*  
  62. 554      * Disable preemption - early bootup scheduling is extremely  
  63. 555      * fragile until we cpu_idle() for the first time.  
  64. 556      */  
  65.         /* 禁止内核抢占 */  
  66. 557     preempt_disable();  
  67. 558     build_all_zonelists();  
  68. 559     page_alloc_init();  
  69.         /* 打印Linux启动命令行参数 */  
  70. 560     printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);  
  71.         /* 对内核选项的两次解析 */  
  72. 561     parse_early_param();  
  73. 562     parse_args("Booting kernel", static_command_line, __start___param,  
  74. 563            __stop___param - __start___param,  
  75. 564            &unknown_bootoption);  
  76.         /* 检查中断是否已经打开,如果已经打开,则关闭中断 */  
  77. 565     if (!irqs_disabled()) {  
  78. 566         printk(KERN_WARNING "start_kernel(): bug: interrupts were "  
  79. 567                 "enabled *very* early, fixing it\n");  
  80. 568         local_irq_disable();  
  81. 569     }  
  82. 570     sort_main_extable();  
  83.         /*  
  84.          * trap_init函数完成对系统保留中断向量(异常、
    非屏蔽中断以及系统调用)                * 的初始化,init_IRQ函
    数则完成其余中断向量的初始化  
  85.          */  
  86. 571     trap_init();  
  87.         /* 初始化RCU(Read-Copy Update)机制 */  
  88. 572     rcu_init();  
  89. 573     init_IRQ();  
  90.         /* 初始化hash表,便于从进程的PID获得对应的进程描述符指针 */  
  91. 574     pidhash_init();  
  92.         /* 初始化定时器相关的数据结构 */  
  93. 575     init_timers();  
  94.         /* 对高精度时钟进行初始化 */  
  95. 576     hrtimers_init();  
  96.         /* 初始化tasklet_softirq和hi_softirq */  
  97. 577     softirq_init();  
  98. 578     timekeeping_init();  
  99.         /* 初始化系统时钟源 */  
  100. 579     time_init();  
  101.         /* 对内核的profile(一个内核性能调式工具)功能进行初始化 */  
  102. 580     profile_init();  
  103. 581     if (!irqs_disabled())  
  104. 582         printk("start_kernel(): bug: interrupts
    were enabled early\n");  
  105. 583     early_boot_irqs_on();  
  106. 584     local_irq_enable();  
  107. 585  
  108. 586     /*  
  109. 587      * HACK ALERT! This is early. We're enabling 
    the console before  
  110. 588      * we've done PCI setups etc, and console_init()
    must be aware of  
  111. 589      * this. But we do want output early, in
    case something goes wrong.  
  112. 590      */  
  113.         /*  
  114.          * 初始化控制台以显示printk的内容,在此之前调用的printk  
  115.          * 只是把数据存到缓冲区里  
  116.          */  
  117. 591     console_init();  
  118. 592     if (panic_later)  
  119. 593         panic(panic_later, panic_param);  
  120. 594  
  121.         /* 如果定义了CONFIG_LOCKDEP宏,则打印锁依赖信息,否则什么也不做 */  
  122. 595     lockdep_info();  
  123. 596  
  124. 597     /*  
  125. 598      * Need to run this when irqs are enabled, because it wants  
  126. 599      * to self-test [hard/soft]-irqs on/off lock inversion bugs  
  127. 600      * too:  
  128. 601      */  
  129. 602     locking_selftest();  
  130. 603  
  131. 604 #ifdef CONFIG_BLK_DEV_INITRD  
  132. 605     if (initrd_start && !initrd_below_start_ok &&  
  133. 606             initrd_start < min_low_pfn << PAGE_SHIFT) {  
  134. 607         printk(KERN_CRIT "initrd overwritten 
    (0x%08lx 
    < 0x%08lx) - "  
  135. 608             "disabling it.\n",initrd_start,
    min_low_pfn 
    << PAGE_SHIFT);  
  136. 609         initrd_start = 0;  
  137. 610     }  
  138. 611 #endif  
  139.         /* 虚拟文件系统的初始化 */  
  140. 612     vfs_caches_init_early();  
  141. 613     cpuset_init_early();  
  142. 614     mem_init();  
  143.         /* slab初始化 */  
  144. 615     kmem_cache_init();  
  145. 616     setup_per_cpu_pageset();  
  146. 617     numa_policy_init();  
  147. 618     if (late_time_init)  
  148. 619         late_time_init();  
  149.         /*  
  150.          * 一个非常有趣的CPU性能测试函数,可以计
    算出CPU在1s内执行了多少次一个  
  151.          * 极短的循环,计算出来的值经过处理后得
    到BogoMIPS值(Bogo是Bogus的意思),  
  152.          */  
  153. 620     calibrate_delay();  
  154. 621     pidmap_init();  
  155.         /* 接下来的函数中,大多数都是为有关的管理机制建立专用的slab缓存 */  
  156. 622     pgtable_cache_init();  
  157.         /* 初始化优先级树index_bits_to_maxindex数组 */  
  158. 623     prio_tree_init();  
  159. 624     anon_vma_init();  
  160. 625 #ifdef CONFIG_X86  
  161. 626     if (efi_enabled)  
  162. 627         efi_enter_virtual_mode();  
  163. 628 #endif  
  164.         /* 根据物理内存大小计算允许创建进程的数量 */  
  165. 629     fork_init(num_physpages);  
  166.         /*  
  167.          * proc_caches_init(),buffer_init(),
    unnamed_dev_init(), key_init()  
  168.          *  
  169.          */  
  170. 630     proc_caches_init();  
  171. 631     buffer_init();  
  172. 632     unnamed_dev_init();  
  173. 633     key_init();  
  174. 634     security_init();  
  175. 635     vfs_caches_init(num_physpages);  
  176. 636     radix_tree_init();  
  177. 637     signals_init();  
  178. 638     /* rootfs populating might need page-writeback */  
  179. 639     page_writeback_init();  
  180. 640 #ifdef CONFIG_PROC_FS  
  181. 641     proc_root_init();  
  182. 642 #endif  
  183. 643     cpuset_init();  
  184. 644     taskstats_init_early();  
  185. 645     delayacct_init();  
  186. 646  
  187.         /*  
  188.          * 测试该CPU的各种缺陷,记录检测到的缺陷,以
    便于内核的其他部分以后可以  
  189.          * 使用它们的工作。  
  190.          */  
  191. 647     check_bugs();  
  192. 648  
  193. 649     acpi_early_init(); /* before LAPIC and SMP init */  
  194. 650  
  195. 651     /* Do the rest non-__init'ed, we're now alive */  
  196.         /* 创建init进程 */  
  197. 652     rest_init();  

你可能感兴趣的:(linux,职场,休闲,内核启动)