bugsplat( 二 )


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
1441: 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.h中的定义如下:
示例代码36.2.1.3 proc_info_list结构体
struct proc_info_list {
unsignedint cpu_val;
unsignedint cpu_mask;
unsignedlong __cpu_mm_mmu_flags; /* used by head.S */
unsignedlong __cpu_io_mmu_flags; /* used by head.S */
unsignedlong __cpu_flush; /* used by head.S */
constchar *arch_name;
constchar *elf_name;
unsignedint elf_hwcap;
constchar *cpu_name;
struct processor *proc;
struct cpu_tlb_fns *tlb;
struct cpu_user_fns *user;
struct cpu_cache_fns *cache;
};
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函数 。
36.2.2 __mmap_switched函数__mmap_switched函数定义在文件
arch/arm/kernel/head-common.S中,函数代码如下:
示例代码36.2.2.1 __mmap_switched函数
81 __mmap_switched:
82 adr r3, __mmap_switched_data
83
84 ldmia r3!,{r4, r5, r6, r7}
85 cmp r4, r5 @ Copy data segment if needed
861: cmpne r5, r6
87 ldrne fp,[r4], #4
88 strne fp,[r5], #4
89 bne 1b
90
91 mov fp, #0 @ Clear BSS (and zero fp)
921: cmp r6, r7
93 strcc fp,[r6],#4
94 bcc 1b
95
96 ARM( ldmia r3,{r4, r5, r6, r7, sp})
97 THUMB( ldmia r3,{r4, r5, r6, r7})
98 THUMB( ldr sp,[r3, #16])
99 str r9,[r4] @ Save processor ID
100 str r1,[r5] @ Save machine type
101 str r2,[r6] @ Save atags pointer
102 cmp r7, #0
103 strne r0,[r7] @ Save control register values
104 b start_kernel
105 ENDPROC(__mmap_switched)
第104行最终调用start_kernel来启动Linux内核,start_kernel函数定义在文件init/main.c中 。
36.2.3 start_kernel函数start_kernel通过调用众多的子函数来完成Linux启动之前的一些初始化工作,由于start_kernel函数里面调用的子函数太多,而这些子函数又很复杂,因此我们简单的来看一下一些重要的子函数 。精简并添加注释后的start_kernel函数内容如下:
示例代码36.2.3.1 start_kernel函数
asmlinkage __visible void __init start_kernel(void)
{
char*command_line;
char*after_dashes;


lockdep_init();/* lockdep是死锁检测模块,此函数会初始化
* 两个hash表 。此函数要求尽可能早的执行!


特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。