Linux系统移植篇(七)Linux 内核kernel 启动流程

链接脚本 vmlinux.lds

要分析 Linux 启动流程,同样需要先编译一下 Linux 源码,因为有很多文件是需要编译才
会生成的。首先分析 Linux 内核的连接脚本文件 arch/arm/kernel/vmlinux.lds ,通过链接脚本可以
找到 Linux 内核的第一行程序是从哪里执行的。
(跟Uboot启动流程的ids一样)
492 OUTPUT_ARCH(arm)
493 ENTRY(stext)
494 jiffies = jiffies_64;
495 SECTIONS
496 {
497 /*
498 * XXX: The linker does not define how output sections are
499 * assigned to input sections when there are multiple statements
500 * matching the same input section name. There is no documented
501 * order of matching.
502 *
503 * unwind exit sections must be discarded before the rest of the
504 * unwind sections get included.
505 */
506 /DISCARD/ : {
507 *(.ARM.exidx.exit.text)
508 *(.ARM.extab.exit.text)
509 
......
645 }
ENTRY 指明了了 Linux 内核入口,入口为 stext stext 定义在文件
arch/arm/kernel/head.S 中 , 因 此 要 分 析 Linux 内 核 的 启 动 流 程 , 就 得 先 从 文 件
arch/arm/kernel/head.S stext 处开始分析。
Linux 内核启动流程分析
Linux 内核入口 stext
stext Linux 内核的入口地址,在文件 arch/arm/kernel/head.S 中有如下所示提示内容:
/*
* Kernel startup entry point.
* ---------------------------
*
* This is normally called from the decompressor code. The requirements
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
* r1 = machine nr, r2 = atags or dtb pointer.
*/
①、关闭 MMU
②、关闭 D-cache
③、 I-Cache 无所谓。
④、 r0=0
⑤、 r1=machine nr( 也就是机器 ID)
⑥、 r2=atags 或者设备树 (dtb) 首地址。
Linux 内核的入口点 stext 其实相当于内核的入口函数, stext 函数内容如下:
80 ENTRY(stext)
......
91 @ ensure svc mode and all interrupts masked
92 safe_svcmode_maskall r9
93 
94 mrc p15, 0, r9, c0, c0 @ get processor id
95 bl __lookup_processor_type @ r5=procinfo r9=cpuid
96 movs r10, r5 @ invalid processor (r5=0)?
97 THUMB( it eq ) @ force fixup-able long branch encoding
98 beq __error_p @ yes, error 'p'
99 
......
107
108 #ifndef CONFIG_XIP_KERNEL
......
113 #else
114 ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case
115 #endif
116
117 /*
118 * r1 = machine no, r2 = atags or dtb,
119 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
120 */
121 bl __vet_atags
......
128 bl __create_page_tables
129
130 /*
131 * The following calls CPU specific code in a position independent
132 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
133 * xxx_proc_info structure selected by __lookup_processor_type
134 * above. On return, the CPU will be ready for the MMU to be
135 * turned on, and r0 will hold the CPU control register value.
136 */
137 ldr r13, =__mmap_switched @ address to jump to after
138 @ mmu has been enabled
139 adr lr, BSYM(1f) @ return (PIC) address
140 mov r8, r4 @ set TTBR1 to swapper_pg_dir
141 ldr r12, [r10, #PROCINFO_INITFUNC]
142 add r12, r12, r10
143 ret r12
144 1: b __enable_mmu
145 ENDPROC(stext)
92 行,调用函数 safe_svcmode_maskall 确保 CPU 处于 SVC 模式,并且关闭了所有的中
断。 safe_svcmode_maskall 定义在文件 arch/arm/include/asm/assembler.h 中。
94 行,读处理器 ID ID 值保存在 r9 寄存器中。
95 行,调用函数 __lookup_processor_type 检查当前系统是否支持此 CPU ,如果支持就获
procinfo 信 息 。 procinfo proc_info_list 类 型 的 结 构 体 , proc_info_list 在 文 件
arch/arm/include/asm/procinfo. 中。
Linux 内核将每种处理器都抽象为一个 proc_info_list 结构体,每种处理器都对应一个
procinfo 。因此可以通过处理器 ID 来找到对应的 procinfo 结构, __lookup_processor_type 函数找
到对应处理器的 procinfo 以后会将其保存到 r5 寄存器中。
继续回到示例代码 36.2.1.2 中,第 121 行,调用函数 __vet_atags 验证 atags 或设备树 (dtb)
合法性。函数 __vet_atags 定义在文件 arch/arm/kernel/head-common.S 中。
128 行,调用函数 __create_page_tables 创建页表。
137 行,将函数 __mmap_switched 的地址保存到 r13 寄存器中。 __mmap_switched 定义在
文件 arch/arm/kernel/head-common.S __mmap_switched 最终会调用 start_kernel 函数。
144 行 , 调 用 __enable_mmu 函 数 使 能 MMU __enable_mmu 定 义 在 文 件
arch/arm/kernel/head.S 中。 __enable_mmu 最终会通过调用 __turn_mmu_on 来打开 MMU
__turn_mmu_on 最后会执行 r13 里面保存的 __mmap_switched 函数。

你可能感兴趣的:(【Linux,系统移植】,linux,运维,服务器,驱动开发)