• linux内核启动过程分析


            分为第一阶段汇编和第二阶段。

    内核启动第一阶段

            先总结出第一阶段主要任务

    • 确保处于SVC模式,且关闭所有中断
    • get processor id/procinfo
    • 创建页表项
    • 使能MMU
    • 跳转start_kernel,开启第二阶段

    内核链接脚本

    arch/arm/kernel/vmlinux.lds

    如下,可以看出内核入口在ENTRY(stext),stext在汇编中head.S中实现

    1. OUTPUT_ARCH(arm)
    2. ENTRY(stext)
    3. jiffies = jiffies_64;
    4. SECTIONS
    5. {
    6. /*
    7. * XXX: The linker does not define how output sections are
    8. * assigned to input sections when there are multiple statements
    9. * matching the same input section name. There is no documented
    10. * order of matching.
    11. *
    12. * unwind exit sections must be discarded before the rest of the
    13. * unwind sections get included.
    14. */
    15. /DISCARD/ : {
    16. *(.ARM.exidx.exit.text)
    17. *(.ARM.extab.exit.text)
    18. *(.exitcall.exit)
    19. *(.discard)
    20. *(.discard.*)
    21. }
    22. . = 0x80000000 + 0x00008000;
    23. .head.text : {
    24. _text = .;
    25. *(.head.text)
    26. }
    27. .text : { /* Real text segment */
    28. _stext = .; /* Text and read-only data */
    29. . = ALIGN(8); __idmap_text_start = .; *(.idmap.text) __idmap_text_end = .; . = ALIGN((1 << 12)); __hyp_idmap_text_start = .; *(.hyp.idmap. text) __hyp_idmap_text_end = .;
    30. __exception_text_start = .;
    31. *(.exception.text)
    32. __exception_text_end = .;
    33. . = ALIGN(8); *(.text.hot) *(.text .text.fixup) *(.ref.text) *(.text.unlikely)
    34. . = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .;
    35. . = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .;

    head.S入口stext

            注释看出,启动内核要求:MMU关闭、DCACHE关闭,ICACHE无所谓,然后传入r0的参数为0,r1是机器ID,r2是tag或者设备树地址指针。02-uboot启动内核前到底做了哪些必要工作_【星星之火】的博客-CSDN博客,在这边文章已经说明了这点,就是Bootloader调用 kernel_entry(0, machid, r2) 传入r0 r1 r2进入到此处。

    1. 59 /*
    2. 60 * Kernel startup entry point.
    3. 61 * ---------------------------
    4. 62 *
    5. 63 * This is normally called from the decompressor code. The requirements
    6. 64 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
    7. 65 * r1 = machine nr, r2 = atags or dtb pointer.
    8. 66 *
    9. 67 * This code is mostly position independent, so if you link the kernel at
    10. 68 * 0xc0008000, you call this at __pa(0xc0008000).
    11. 69 *
    12. 70 * See linux/arch/arm/tools/mach-types for the complete list of machine
    13. 71 * numbers for r1.
    14. 72 *
    15. 73 * We're trying to keep crap to a minimum; DO NOT add any machine specific
    16. 74 * crap here - that's what the boot loader (or in extreme, well justified
    17. 75 * circumstances, zImage) is for.
    18. 76 */
    19. 77 .arm
    20. 78
    21. 79 __HEAD
    22. 80 ENTRY(stext)
    23. 81 ARM_BE8(setend be ) @ ensure we are in BE8 mode
    24. 82
    25. 83 THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
    26. 84 THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
    27. 85 THUMB( .thumb ) @ switch to Thumb now.
    28. 86 THUMB(1: )
    29. 87
    30. 88 #ifdef CONFIG_ARM_VIRT_EXT
    31. 89 bl __hyp_stub_install
    32. 90 #endif
    33. 91 @ ensure svc mode and all interrupts masked
    34. 92 safe_svcmode_maskall r9
    35. 93
    36. 94 mrc p15, 0, r9, c0, c0 @ get processor id
    37. 95 bl __lookup_processor_type @ r5=procinfo r9=cpuid
    38. 96 movs r10, r5 @ invalid processor (r5=0)?
    39. 97 THUMB( it eq ) @ force fixup-able long branch encoding
    40. 98 beq __error_p @ yes, error 'p'

    SVC模式与禁止中断-safe_svcmode_maskall

    1. arch/arm/include/asm/assembler.h
    2. 320 #if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
    3. 321 mrs \reg , cpsr
    4. 322 eor \reg, \reg, #HYP_MODE
    5. 323 tst \reg, #MODE_MASK
    6. 324 bic \reg , \reg , #MODE_MASK
    7. 325 orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
    8. 326 THUMB( orr \reg , \reg , #PSR_T_BIT )
    9. 327 bne 1f
    10. 328 orr \reg, \reg, #PSR_A_BIT
    11. 329 adr lr, BSYM(2f)
    12. 330 msr spsr_cxsf, \reg
    13. 331 __MSR_ELR_HYP(14)
    14. 332 __ERET
    15. 333 1: msr cpsr_c, \reg
    16. 334 2:
    17. 335 #else

    arm的7种模式

    • 用户模式 USR
    • 系统模式 SYS(特权模式)
    • 管理模式 SVC (特权模式 异常模式)

            操作系统保护模式

    • 快中断 FIQ (特权模式 异常模式)
    • 中断模式 IRQ (特权模式 异常模式)
    • 中止模式 ATB (特权模式 异常模式)
    • 未定义模式 UND (特权模式 异常模式)

    模式设置

            参考ARM® Architecture Reference Manual ARMv7-A and ARMv7-R edition

            设置CPSR的低5位。 

     关闭中断

            系统进行初始化过程中,资源未准备好,产生中断将出现不可预计的错误。关闭中断方法同上寄存器中。

    获取CPU信息

    获取cpu id

            从协处理器p15中的c0寄存器中获取CPU ID

    mrc p15, 0, r9, c0, c0

    获取procinfo信息

            通过如下结构体存储,里面包含了MMU启动信息,所有在早起就需要获取到。在内核文件的“.init.proc.info”段中存放,根据CPU ID查找procinfo信息。

    1. 20 /*
    2. 21 * Note! struct processor is always defined if we're
    3. 22 * using MULTI_CPU, otherwise this entry is unused,
    4. 23 * but still exists.
    5. 24 *
    6. 25 * NOTE! The following structure is defined by assembly
    7. 26 * language, NOT C code. For more information, check:
    8. 27 * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S
    9. 28 */
    10. 29 struct proc_info_list {
    11. 30 unsigned int cpu_val;
    12. 31 unsigned int cpu_mask;
    13. 32 unsigned long __cpu_mm_mmu_flags; /* used by head.S */
    14. 33 unsigned long __cpu_io_mmu_flags; /* used by head.S */
    15. 34 unsigned long __cpu_flush; /* used by head.S */
    16. 35 const char *arch_name;
    17. 36 const char *elf_name;
    18. 37 unsigned int elf_hwcap;
    19. 38 const char *cpu_name;
    20. 39 struct processor *proc;
    21. 40 struct cpu_tlb_fns *tlb;
    22. 41 struct cpu_user_fns *user;
    23. 42 struct cpu_cache_fns *cache;
    24. 43 };

    检查设备树

            __vet_atags中,检查设备树头部4字节是否是magic(d00dfeed)。

    1. 118 * r1 = machine no, r2 = atags or dtb,
    2. 119 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
    3. 120 */
    4. 121 bl __vet_atags
    5. 122 #ifdef CONFIG_SMP_ON_UP
    6. 123 bl __fixup_smp
    7. 124 #endif
    8. 125 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
    9. 126 bl __fixup_pv_table
    10. 127 #endif
    11. 128 bl __create_page_tables

    创建临时页表

            内核启动后,要尽快开启MMU,开启MMU之前需要有页表。因此准备好页表环境是开启MMU的前提。由__create_page_tables 来创建。

    1. 108 #ifndef CONFIG_XIP_KERNEL ~
    2. 109 adr r3, 2f ~
    3. 110 ldmia r3, {r4, r8} ~
    4. 111 sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET) ~
    5. 112 add r8, r8, r4 @ PHYS_OFFSET ~
    6. 113 #else ~
    7. 114 ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case ~
    8. 115 #endif ~
    9. 116 ~
    10. 117 /* ~
    11. 118 * r1 = machine no, r2 = atags or dtb, ~
    12. 119 * r8 = phys_offset, r9 = cpuid, r10 = procinfo ~
    13. 120 */ ~
    14. 121 bl __vet_atags ~
    15. 122 #ifdef CONFIG_SMP_ON_UP ~
    16. 123 bl __fixup_smp ~
    17. 124 #endif ~
    18. 125 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT ~
    19. 126 bl __fixup_pv_table ~
    20. 127 #endif ~
    21. 128 bl __create_page_tables

    MMU功能

            通过页表完成虚拟地址到物理地址的映射。页表基地址存储在cp15的c2寄存器中。

    段映射

            将4G空间分成4096个1M的段空间。虚拟地址的高12bit是段基址,在页表基地址的基础上得出虚拟地址段页表的位置,在加上虚拟地址的低20bit得出物理地址(MMU硬件自动完成地址转换)。

    映射内容

    • 恒等映射

            开启MMU之前 和开启MMU瞬间,物理地址到虚拟地址的pc指针改变的时候,需要是的虚拟地址和物理地址一致。

    • 内核映射
    • dtb映射

    代码解析

    • 页表物理地址给r4
    • 将页表的16k空间清0
    • __turn_mmu_on函数进行恒等映射,确保开启前后地址一致,该函数的物理地址和虚拟地址一致
    • 内核映射页表
    • 设备树映射页表
    1. 152 /*
    2. 153 * Setup the initial page tables. We only setup the barest
    3. 154 * amount which are required to get the kernel running, which
    4. 155 * generally means mapping in the kernel code.
    5. 156 *
    6. 157 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
    7. 158 *
    8. 159 * Returns:
    9. 160 * r0, r3, r5-r7 corrupted
    10. 161 * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
    11. 162 */
    12. 163 __create_page_tables:
    13. 164 pgtbl r4, r8 @ page table address 1.页表物理地址给r4
    14. 165
    15. 166 /*
    16. 167 * Clear the swapper page table 2.清空页表空间
    17. 168 */
    18. 169 mov r0, r4
    19. 170 mov r3, #0
    20. 171 add r6, r0, #PG_DIR_SIZE
    21. 172 1: str r3, [r0], #4
    22. 173 str r3, [r0], #4
    23. 174 str r3, [r0], #4
    24. 175 str r3, [r0], #4
    25. 176 teq r0, r6
    26. 177 bne 1b
    27. 178
    28. 179 #ifdef CONFIG_ARM_LPAE
    29. 180 /*
    30. 181 * Build the PGD table (first level) to point to the PMD table. A PGD
    31. 182 * entry is 64-bit wide.
    32. 183 */
    33. 184 mov r0, r4
    34. 185 add r3, r4, #0x1000 @ first PMD table address
    35. 186 orr r3, r3, #3 @ PGD block type
    36. 187 mov r6, #4 @ PTRS_PER_PGD
    37. 188 mov r7, #1 << (55 - 32) @ L_PGD_SWAPPER
    38. 189 1:
    39. 190 #ifdef CONFIG_CPU_ENDIAN_BE8
    40. 191 str r7, [r0], #4 @ set top PGD entry bits
    41. 192 str r3, [r0], #4 @ set bottom PGD entry bits
    42. 193 #else
    43. 194 str r3, [r0], #4 @ set bottom PGD entry bits
    44. 195 str r7, [r0], #4 @ set top PGD entry bits
    45. 196 #endif
    46. 197 add r3, r3, #0x1000 @ next PMD table
    47. 198 subs r6, r6, #1
    48. 199 bne 1b
    49. 200
    50. 201 add r4, r4, #0x1000 @ point to the PMD tables
    51. 202 #ifdef CONFIG_CPU_ENDIAN_BE8
    52. 203 add r4, r4, #4 @ we only write the bottom word
    53. 204 #endif
    54. 205 #endif
    55. 206
    56. 207 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags //将proc中mmuflag信息存到r10
    57. 208
    58. 209 /* 3.创建__turn_mmu_on的恒等映射,衔接mmu开启动作
    59. 210 * Create identity mapping to cater for __enable_mmu.
    60. 211 * This identity mapping will be removed by paging_init().
    61. 212 */
    62. 213 adr r0, __turn_mmu_on_loc
    63. 214 ldmia r0, {r3, r5, r6}
    64. 215 sub r0, r0, r3 @ virt->phys offset
    65. 216 add r5, r5, r0 @ phys __turn_mmu_on
    66. 217 add r6, r6, r0 @ phys __turn_mmu_on_end
    67. 218 mov r5, r5, lsr #SECTION_SHIFT
    68. 219 mov r6, r6, lsr #SECTION_SHIFT
    69. 220
    70. 221 1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base
    71. 222 str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping
    72. 223 cmp r5, r6
    73. 224 addlo r5, r5, #1 @ next section
    74. 225 blo 1b
    75. 226
    76. 227 /* 4.内核映射
    77. 228 * Map our RAM from the start to the end of the kernel .bss section.
    78. 229 */
    79. 230 add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER)
    80. 231 ldr r6, =(_end - 1)
    81. 232 orr r3, r8, r7
    82. 233 add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
    83. 234 1: str r3, [r0], #1 << PMD_ORDER
    84. 235 add r3, r3, #1 << SECTION_SHIFT
    85. 236 cmp r0, r6
    86. 237 bls 1b
    87. 238
    88. 239 #ifdef CONFIG_XIP_KERNEL
    89. 242 */
    90. 246 orr r3, r7, r3, lsl #SECTION_SHIFT
    91. 247 add r0, r4, #(XIP_START & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)
    92. 248 str r3, [r0, #((XIP_START & 0x00f00000) >> SECTION_SHIFT) << PMD_ORDER]!
    93. 252 1: cmp r0, r6
    94. 253 add r3, r3, #1 << SECTION_SHIFT
    95. 251 add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
    96. 252 1: cmp r0, r6
    97. 253 add r3, r3, #1 << SECTION_SHIFT
    98. 254 strls r3, [r0], #1 << PMD_ORDER
    99. 255 bls 1b
    100. 256 #endif
    101. 257
    102. 258 /* 5.dtb映射页表
    103. 259 * Then map boot params address in r2 if specified.
    104. 260 * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
    105. 261 */
    106. 262 mov r0, r2, lsr #SECTION_SHIFT
    107. 263 movs r0, r0, lsl #SECTION_SHIFT
    108. 264 subne r3, r0, r8
    109. 265 addne r3, r3, #PAGE_OFFSET
    110. 266 addne r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
    111. 267 orrne r6, r7, r0
    112. 268 strne r6, [r3], #1 << PMD_ORDER
    113. 269 addne r6, r6, #1 << SECTION_SHIFT
    114. 270 strne r6, [r3]

    开启MMU

            通过下面几个函数调用,开启MMU,也就是操作cp15协处理器,最终通过设置协处理器的c1的bit0为1开启MMU。之后跳转到__mmap_switched,准备开启第二阶段。

    1. 130 /*
    2. 131 * The following calls CPU specific code in a position independent
    3. 132 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
    4. 133 * xxx_proc_info structure selected by __lookup_processor_type
    5. 134 * above. On return, the CPU will be ready for the MMU to be
    6. 135 * turned on, and r0 will hold the CPU control register value.
    7. 136 */
    8. 137 ldr r13, =__mmap_switched @ address to jump to after
    9. 138 @ mmu has been enabled
    10. 139 adr lr, BSYM(1f) @ return (PIC) address
    11. 140 mov r8, r4 @ set TTBR1 to swapper_pg_dir
    12. 141 ldr r12, [r10, #PROCINFO_INITFUNC]
    13. 142 add r12, r12, r10
    14. 143 ret r12
    15. 144 1: b __enable_mmu

    1. 428 __enable_mmu:
    2. 429 #if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
    3. 430 orr r0, r0, #CR_A
    4. 431 #else
    5. 432 bic r0, r0, #CR_A
    6. 433 #endif
    7. 434 #ifdef CONFIG_CPU_DCACHE_DISABLE
    8. 435 bic r0, r0, #CR_C
    9. 436 #endif
    10. 437 #ifdef CONFIG_CPU_BPREDICT_DISABLE
    11. 438 bic r0, r0, #CR_Z
    12. 439 #endif
    13. 440 #ifdef CONFIG_CPU_ICACHE_DISABLE
    14. 441 bic r0, r0, #CR_I
    15. 442 #endif
    16. 443 #ifndef CONFIG_ARM_LPAE
    17. 444 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
    18. 445 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
    19. 446 domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
    20. 447 domain_val(DOMAIN_IO, DOMAIN_CLIENT))
    21. 448 mcr p15, 0, r5, c3, c0, 0 @ load domain access register
    22. 449 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
    23. 450 #endif
    24. 451 b __turn_mmu_on
    25. 452 ENDPROC(__enable_mmu)

    1. 454 /*
    2. 455 * Enable the MMU. This completely changes the structure of the visible
    3. 456 * memory space. You will not be able to trace execution through this.
    4. 457 * If you have an enquiry about this, *please* check the linux-arm-kernel
    5. 458 * mailing list archives BEFORE sending another post to the list.
    6. 459 *
    7. 460 * r0 = cp#15 control register
    8. 461 * r1 = machine ID
    9. 462 * r2 = atags or dtb pointer
    10. 463 * r9 = processor ID
    11. 464 * r13 = *virtual* address to jump to upon completion
    12. 465 *
    13. 466 * other registers depend on the function called upon completion
    14. 467 */
    15. 468 .align 5
    16. 469 .pushsection .idmap.text, "ax"
    17. 470 ENTRY(__turn_mmu_on)
    18. 471 mov r0, r0
    19. 472 instr_sync
    20. 473 mcr p15, 0, r0, c1, c0, 0 @ write control reg
    21. 474 mrc p15, 0, r3, c0, c0, 0 @ read id reg
    22. 475 instr_sync
    23. 476 mov r3, r3
    24. 477 mov r3, r13
    25. 478 ret r3
    26. 479 __turn_mmu_on_end:
    27. 480 ENDPROC(__turn_mmu_on)
    28. 481 .popsection

    跳转start_kernel前__mmap_switched

            映射好__turn_mmu_on、内核、设备树后,开启MMU,一切开始运行在虚拟地址中,MMU开始工作。之后可以进入到C函数进行常规初始化。head.S调用__mmap_switched,完成C环境初始化后,跳转start_kernel。

    1. 71 /*
    2. 72 * The following fragment of code is executed with the MMU on in MMU mode,
    3. 73 * and uses absolute addresses; this is not position independent.
    4. 74 *
    5. 75 * r0 = cp#15 control register
    6. 76 * r1 = machine ID
    7. 77 * r2 = atags/dtb pointer
    8. 78 * r9 = processor ID
    9. 79 */
    10. 80 __INIT
    11. 81 __mmap_switched:
    12. 82 adr r3, __mmap_switched_data
    13. 83
    14. 84 ldmia r3!, {r4, r5, r6, r7}
    15. 85 cmp r4, r5 @ Copy data segment if needed
    16. 86 1: cmpne r5, r6
    17. 87 ldrne fp, [r4], #4
    18. 88 strne fp, [r5], #4
    19. 89 bne 1b
    20. 90
    21. 91 mov fp, #0 @ Clear BSS (and zero fp)
    22. 92 1: cmp r6, r7
    23. 93 strcc fp, [r6],#4
    24. 94 bcc 1b
    25. 95
    26. 96 ARM( ldmia r3, {r4, r5, r6, r7, sp})
    27. 97 THUMB( ldmia r3, {r4, r5, r6, r7} )
    28. 98 THUMB( ldr sp, [r3, #16] )
    29. 99 str r9, [r4] @ Save processor ID
    30. 100 str r1, [r5] @ Save machine type
    31. 101 str r2, [r6] @ Save atags pointer
    32. 102 cmp r7, #0
    33. 103 strne r0, [r7] @ Save control register values
    34. 104 b start_kernel
    35. 105 ENDPROC(__mmap_switched)

    内核启动第二阶段

            一大顿初始化,想必都很关键。

    1. asmlinkage __visible void __init start_kernel(void)
    2. {
    3. char *command_line;
    4. char *after_dashes;
    5. /*
    6. * Need to run as early as possible, to initialize the
    7. * lockdep hash:
    8. */
    9. lockdep_init();
    10. set_task_stack_end_magic(&init_task);
    11. smp_setup_processor_id();
    12. debug_objects_early_init();
    13. /*
    14. * Set up the the initial canary ASAP:
    15. */
    16. boot_init_stack_canary();
    17. cgroup_init_early();
    18. local_irq_disable();
    19. early_boot_irqs_disabled = true;
    20. /*
    21. * Interrupts are still disabled. Do necessary setups, then
    22. * enable them
    23. */
    24. boot_cpu_init();
    25. page_address_init();
    26. pr_notice("%s", linux_banner);
    27. setup_arch(&command_line);
    28. mm_init_cpumask(&init_mm);
    29. setup_command_line(command_line);
    30. setup_nr_cpu_ids();
    31. setup_per_cpu_areas();
    32. smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
    33. build_all_zonelists(NULL, NULL);
    34. page_alloc_init();
    35. pr_notice("Kernel command line: %s\n", boot_command_line);
    36. parse_early_param();
    37. after_dashes = parse_args("Booting kernel",
    38. static_command_line, __start___param,
    39. __stop___param - __start___param,
    40. -1, -1, &unknown_bootoption);
    41. if (!IS_ERR_OR_NULL(after_dashes))
    42. parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
    43. set_init_arg);
    44. jump_label_init();
    45. /*
    46. * These use large bootmem allocations and must precede
    47. * kmem_cache_init()
    48. */
    49. setup_log_buf(0);
    50. pidhash_init();
    51. vfs_caches_init_early();
    52. sort_main_extable();
    53. trap_init();
    54. mm_init();
    55. /*
    56. * Set up the scheduler prior starting any interrupts (such as the
    57. * timer interrupt). Full topology setup happens at smp_init()
    58. * time - but meanwhile we still have a functioning scheduler.
    59. */
    60. sched_init();
    61. /*
    62. * Disable preemption - early bootup scheduling is extremely
    63. * fragile until we cpu_idle() for the first time.
    64. */
    65. preempt_disable();
    66. if (WARN(!irqs_disabled(),
    67. "Interrupts were enabled *very* early, fixing it\n"))
    68. local_irq_disable();
    69. idr_init_cache();
    70. rcu_init();
    71. /* trace_printk() and trace points may be used after this */
    72. trace_init();
    73. context_tracking_init();
    74. radix_tree_init();
    75. /* init some links before init_ISA_irqs() */
    76. early_irq_init();
    77. init_IRQ();
    78. tick_init();
    79. rcu_init_nohz();
    80. init_timers();
    81. hrtimers_init();
    82. softirq_init();
    83. timekeeping_init();
    84. time_init();
    85. sched_clock_postinit();
    86. perf_event_init();
    87. profile_init();
    88. call_function_init();
    89. WARN(!irqs_disabled(), "Interrupts were enabled early\n");
    90. early_boot_irqs_disabled = false;
    91. local_irq_enable();
    92. kmem_cache_init_late();
    93. /*
    94. * HACK ALERT! This is early. We're enabling the console before
    95. * we've done PCI setups etc, and console_init() must be aware of
    96. * this. But we do want output early, in case something goes wrong.
    97. */
    98. console_init();
    99. if (panic_later)
    100. panic("Too many boot %s vars at `%s'", panic_later,
    101. panic_param);
    102. lockdep_info();
    103. /*
    104. * Need to run this when irqs are enabled, because it wants
    105. * to self-test [hard/soft]-irqs on/off lock inversion bugs
    106. * too:
    107. */
    108. locking_selftest();
    109. #ifdef CONFIG_BLK_DEV_INITRD
    110. if (initrd_start && !initrd_below_start_ok &&
    111. page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
    112. pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
    113. page_to_pfn(virt_to_page((void *)initrd_start)),
    114. min_low_pfn);
    115. initrd_start = 0;
    116. }
    117. #endif
    118. page_ext_init();
    119. debug_objects_mem_init();
    120. kmemleak_init();
    121. setup_per_cpu_pageset();
    122. numa_policy_init();
    123. if (late_time_init)
    124. late_time_init();
    125. sched_clock_init();
    126. calibrate_delay();
    127. pidmap_init();
    128. anon_vma_init();
    129. acpi_early_init();
    130. thread_info_cache_init();
    131. cred_init();
    132. fork_init();
    133. proc_caches_init();
    134. buffer_init();
    135. key_init();
    136. security_init();
    137. dbg_late_init();
    138. vfs_caches_init(totalram_pages);
    139. signals_init();
    140. /* rootfs populating might need page-writeback */
    141. page_writeback_init();
    142. proc_root_init();
    143. nsfs_init();
    144. cpuset_init();
    145. cgroup_init();
    146. taskstats_init_early();
    147. delayacct_init();
    148. check_bugs();
    149. acpi_subsystem_init();
    150. sfi_init_late();
    151. if (efi_enabled(EFI_RUNTIME_SERVICES)) {
    152. efi_late_init();
    153. efi_free_boot_services();
    154. }
    155. ftrace_init();
    156. /* Do the rest non-__init'ed, we're now alive */
    157. rest_init();
    158. }

    lockdep_init

            初始化全局锁链表

    set_task_stack_end_magic

            在init_task栈底存入魔数0x57AC6E9D,用于栈溢出检测。

    smp_setup_processor_id

            多核检测,暂时不管,单核使用

    debug_objects_early_init

            初始化obj_hash、obj_static_pool全局变量

    boot_init_stack_canary

    cgroup_init_early

            control group早起初始化

    local_irq_disable、early_boot_irqs_disabled

            关闭中断

    boot_cpu_init

            获取cpuid,激活CPU

    page_address_init

            初始化高端内存,arm没有使用

    setup_arch(&command_line)

            处理器变量设置、获取设备树中bootargs,cmdline等初始化相关的参数、初始化init进程的内存描述符init_mm

    mm_init_cpumask

            mm_init里面的初始化cpu mask

    setup_command_line

            保存cmdline

    setup_per_cpu_areas

            为系统cpu变量申请per_cpu

    smp_prepare_boot_cpu

            设置引导CPU

    build_all_zonelists

            内存管理,node,zone

    page_alloc_init

            内存页初始化

    parse_early_param

            解析内核参数

    setup_log_buf

    pidhash_init

    vfs_caches_init_early

    sort_main_extable

    trap_init

    mm_init

    sched_init

            进程调度器初始化

    preempt_disable

            禁止抢占

    idr_init_cache

    rcu_init

    trace_init

    context_tracking_init

    radix_tree_init

    early_irq_init

    init_IRQ

    tick_init

    rcu_init_nohz

    init_timers

    hrtimers_init

    softirq_init

    timekeeping_init

    time_init

    sched_clock_postinit

    perf_event_init

    profile_init

    call_function_init

    early_boot_irqs_disabled

    local_irq_enable

    kmem_cache_init_late

    console_init

    lockdep_info

    locking_selftest

    page_ext_init

    debug_objects_mem_init

    kmemleak_init

    setup_per_cpu_pageset

    numa_policy_init

    sched_clock_init

    calibrate_delay

    pidmap_init

    anon_vma_init

    acpi_early_init

    thread_info_cache_init

    cred_init

    fork_init

    proc_caches_init

    buffer_init

    key_init

    security_init

    dbg_late_init

    vfs_caches_init

    signals_init

    page_writeback_init

    proc_root_init

    nsfs_init

    cpuset_init

    cgroup_init

    taskstats_init_early

    delayacct_init

    check_bugs

    acpi_subsystem_init

    sfi_init_late

    efi_enabled

    ftrace_init

    rest_init

  • 相关阅读:
    编辑器报警处理
    Vue知识点---Vuex、路由
    基于Flask_admin库,编写个人工作平台详述。
    JavaScript倒计时
    算法学习 | 回溯算法之深度优先搜索常见题型练习
    k8s Pod简介与探针实现零宕机发布
    用户画像系列——Lookalike在营销圈选扩量中的应用
    树结构工具-TreeUtil使用
    【jenkins】pipeline控制多job顺序执行,进行定时持续集成
    【SSM框架】Mybatis详解07(源码自取)之动态代理的实现
  • 原文地址:https://blog.csdn.net/fengyuwuzu0519/article/details/126380403