一、从__create_page_tables返回后,寄存器如下:
r4= pgtbl (0x30004000)
r8 = machine_info
r9 = cpu_ID
r10 = proc_info (arch/arm/mm/proc-arm920.S中的__arm920_proc_info )
在arch/arm/kernel/head.S中
首先执行L102, pc= r10(__arm920_proc_info)+PROCINFO_INITFUNC(16)= b __arm920_setup
在arm920_setup结束时会调用mov pc, lr, 而此时的lr是L101的__enable_mmu,
L101 __enable_mmu结束时会调用mov pc, r13, 而此时的r13是L99的__switch_data
L99 __switch_data结束时会调用 b start_kernel
二、 arch/arm/mm/proc-arm920.S中 __arm920_setup
函数的作用是关闭I-cache D-cache, 清write_buffer, 清TLB, 获取控制寄存器之后,修改状态
注意: 这个函数只是配置好状态并保存在r0中,真正的状态不是在这个函数中完成的,
arch/arm/mm/proc-macros.S中定义了宏crval
三、 __enable_mmu,打开MMU
程序返回后进入到上一次
在arch/arm/kernel/head.S中
101 adr lr, __enable_mmu
102 add pc, r10, #PROCINFO_INITFUNC
L102行执行完后 mov pc , lr, 而lr中保存的是__enable_mmu,所以下一步进入__enable_mmu中
四、完成数据保存并跳转到start_kernel中
__turn_mmu_on 的最后是: mov pc, r13,
而在arch/arm/head.S中 ldr r13, __switch_data
所以下一步要执行__switch_data
在 arch/arm/kernel/head-common.S中
最终跳到start_kernel中。
附: 调试方法
对于苦B青年来说,其实没啥好说的, 直接打印
比如: arch/arm/head.S中__create_page_tables
想知道L250前后r0, 有没有变化, 加上如下打印(因为是在函数中,所以要保存lr的值)
r4= pgtbl (0x30004000)
r8 = machine_info
r9 = cpu_ID
r10 = proc_info (arch/arm/mm/proc-arm920.S中的__arm920_proc_info )
在arch/arm/kernel/head.S中
- 99 ldr r13, __switch_data @ address to jump to after //L99-L102 每个函数的调用顺序是:
- 100 @ mmu has been enabled // L102的arm920_setup--> L101 __enable_mmu --> L99 switch_data --> b start_kernel
- 101 adr lr, __enable_mmu @ return (PIC) address
- 102 add pc, r10, #PROCINFO_INITFUNC
在arm920_setup结束时会调用mov pc, lr, 而此时的lr是L101的__enable_mmu,
L101 __enable_mmu结束时会调用mov pc, r13, 而此时的r13是L99的__switch_data
L99 __switch_data结束时会调用 b start_kernel
二、 arch/arm/mm/proc-arm920.S中 __arm920_setup
函数的作用是关闭I-cache D-cache, 清write_buffer, 清TLB, 获取控制寄存器之后,修改状态
注意: 这个函数只是配置好状态并保存在r0中,真正的状态不是在这个函数中完成的,
- 385 .type __arm920_setup, #function
- 386 __arm920_setup:
- 387 mov r0, #0
- 388 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 //关闭I-cache D-cache
- 389 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 //清write_buffer
- 390 #ifdef CONFIG_MMU
- 391 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 //清TLB
- 392 #endif
- 393 adr r5, arm920_crval //
- 394 ldmia r5, {r5, r6} //把状态读到寄存器中,r5=clear, r6=mmuset
- 395 mrc p15, 0, r0, c1, c0 @ get control register v4 //获取当前状态
- 396 bic r0, r0, r5 //把状态保存到r0中
- 397 orr r0, r0, r6 //到时候用mcr设置
- 398 mov pc, lr
- 399 .size __arm920_setup, . - __arm920_setup
- 400
- 401 /*
- 402 * R
- 403 * .RVI ZFRS BLDP WCAM
- 404 * ..11 0001 ..11 0101
- 405 *
- 406 */
- 407 .type arm920_crval, #object
- 408 arm920_crval:
- 409 crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
- 410
- 411 __INITDATA
arch/arm/mm/proc-macros.S中定义了宏crval
- 53 .macro crval, clear, mmuset, ucset
- 54 #ifdef CONFIG_MMU
- 55 .word \clear
- 56 .word \mmuset
- 57 #else
- 58 .word \clear
- 59 .word \ucset
- 60 #endif
- 61 .endm
程序返回后进入到上一次
在arch/arm/kernel/head.S中
101 adr lr, __enable_mmu
102 add pc, r10, #PROCINFO_INITFUNC
L102行执行完后 mov pc , lr, 而lr中保存的是__enable_mmu,所以下一步进入__enable_mmu中
- 154 .type __enable_mmu, %function
- 155 __enable_mmu: //L155-L176根据不同的config,修改r0, 的r0是要配置的控制寄存器的内容
- 156 #ifdef CONFIG_ALIGNMENT_TRAP
- 157 orr r0, r0, #CR_A
- 158 #else
- 159 bic r0, r0, #CR_A
- 160 #endif
- 161 #ifdef CONFIG_CPU_DCACHE_DISABLE
- 162 bic r0, r0, #CR_C
- 163 #endif
- 164 #ifdef CONFIG_CPU_BPREDICT_DISABLE
- 165 bic r0, r0, #CR_Z
- 166 #endif
- 167 #ifdef CONFIG_CPU_ICACHE_DISABLE
- 168 bic r0, r0, #CR_I
- 169 #endif
- 170 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
- 171 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
- 172 domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
- 173 domain_val(DOMAIN_IO, DOMAIN_CLIENT))
- 174 mcr p15, 0, r5, c3, c0, 0 @ load domain access register
- 175 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
- 176 b __turn_mmu_on
- ...
- 189 .align 5
190 .type __turn_mmu_on, %functionr10, #PROCINFO_INITFUNC
191 __turn_mmu_on:
192 mov r0, r0
193 mcr p15, 0, r0, c1, c0, 0 @ write control reg //r0是控制寄存器的内容,把r0写到控制寄存器中,使生效
194 mrc p15, 0, r3, c0, c0, 0 @ read id reg
195 mov r3, r3
196 mov r3, r3
197 mov pc, r13
__turn_mmu_on 的最后是: mov pc, r13,
而在arch/arm/head.S中 ldr r13, __switch_data
所以下一步要执行__switch_data
在 arch/arm/kernel/head-common.S中
- 14 #define ATAG_CORE 0x54410001
- 15 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
- 16
- 17 .type __switch_data, %object
- 18 __switch_data:
- 19 .long __mmap_switched
- 20 .long __data_loc @ r4
- 21 .long __data_start @ r5
- 22 .long __bss_start @ r6
- 23 .long _end @ r7
- 24 .long processor_id @ r4
- 25 .long __machine_arch_type @ r5
- 26 .long __atags_pointer @ r6
- 27 .long cr_alignment @ r7
- 28 .long init_thread_union + THREAD_START_SP @ sp
- 29
- 30 /*
31 * The following fragment of code is executed with the MMU on in MMU mode,
32 * and uses absolute addresses; this is not position independent.
33 *
34 * r0 = cp#15 control register
35 * r1 = machine ID
36 * r2 = atags pointer
37 * r9 = processor ID
38 */
39 .type __mmap_switched, %function
40 __mmap_switched:
41 adr r3, __switch_data + 4
42
43 ldmia r3!, {r4, r5, r6, r7}
44 cmp r4, r5 @ Copy data segment if needed
45 1: cmpne r5, r6
46 ldrne fp, [r4], #4
47 strne fp, [r5], #4
48 bne 1b
49
50 mov fp, #0 @ Clear BSS (and zero fp)
51 1: cmp r6, r7
52 strcc fp, [r6],#4
53 bcc 1b
54
55 ldmia r3, {r4, r5, r6, r7, sp}
56 str r9, [r4] @ Save processor ID
57 str r1, [r5] @ Save machine type
58 str r2, [r6] @ Save atags pointer
59 bic r4, r0, #CR_A @ Clear 'A' bit
60 stmia r7, {r0, r4} @ Save control register values
61 b start_kernel
62
附: 调试方法
对于苦B青年来说,其实没啥好说的, 直接打印
- //函数会以16进制形式打印r0中的数值
- __right_p:
- adr r13, spbuf1
- STMIA r13, {R0-R4,R7}
- mov r7, lr
- mov r4, r0
- adr r0, str_p3
- bl printascii
- mov r0 ,r4
- bl printhex8
- adr r0,str_p4
- bl printascii
- mov lr,r7
- ldmia r13,{R0-R4,R7}
- mov pc,lr
- str_p3: .asciz "\nTNND:kernel boot step 0x"
- str_p4: .asciz "\n"
- .align
- ENDPROC(__right_p)
- spbuf1: .space 20
- 248 add r0, r4, #(KERNEL_START & 0xff000000) >> 18
- 249
- 250 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
- 251
- mov r6, lr
- bl __right_p
- mov lr, r6
- 248 add r0, r4, #(KERNEL_START & 0xff000000) >> 18
- 249
- mov r6, lr
- bl __right_p
- mov lr, r6
- 250 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!