平台 and conf class res ldm 正文 enc page
彭东林
pengdonglin137@163.com
TQ2440
Qemu+vexpress-ca9
Linux-4.10.17
继续分析head.S:
- ldr r13,
- =__mmap_switched@address to jump to after@mmu has been enabled badr lr,
- 1f@
- return (PIC) address mov r8,
- r4@set TTBR1 to swapper_pg_dir ldr r12,
- [r10, #PROCINFO_INITFUNC] add r12,
- r12,
- r10 ret r12 1 : b __enable_mmu
第1行将__mmp_switched标号的虚拟地址赋给r13,后面从__turn_mmu_on返回时会用到
第3行将1f标号的物理地址赋给lr,后面从__arm920_setup返回时会用到
第4行将段式页表的物理起始地址赋给r8,对于TQ2440来说,是0x3000_4000,对于vexpress是0x6000_4000
第5行,因为r10指向匹配到的proc_info_list结构体的首地址,对于TQ2440来说,偏移#PROCINFO_INITFUNC得到的是__arm920_setup 与__arm920_proc_info的差值,存放到r12中,此时r10存放的就是__arm920_proc_info物理地址
第6行,r10加r12就得到了__arm920_setup的物理地址,对于vexpress来说是__v7_ca9mp_setup
第7行,开始执行__arm920_setup,定义在arch/arm/mm/proc-arm920.S中
- .type __arm920_setup, #function
- __arm920_setup:
- mov r0, #0
- mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
- mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
- mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
- adr r5, arm920_crval
- ldmia r5, {r5, r6}
- mrc p15, 0, r0, c1, c0 @ get control register v4
- bic r0, r0, r5
- orr r0, r0, r6
- ret lr
- .size __arm920_setup, . - __arm920_setup
- /*
- * R
- * .RVI ZFRS BLDP WCAM
- * ..11 0001 ..11 0101
- *
- */
- .type arm920_crval, #object
- arm920_crval:
- crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
这个函数执行一些开启MMU之前的准备工作。上面对cache、tlb的操作可以参考手册 ARM920T Technical Reference Manual 的2.3.11 Register 7, cache operations register和2.3.12 Register 8, TLB operations register
第14行执行完毕后,会跳转到前面所说的head.S中的1f标号处,也就是 b __enable_mmu
关于MMU的操作,可以参考手册 ARM920T Technical Reference Manual 的2.3.5 Register 1, control register
回到head.S继续分析。
- __enable_mmu:
- #if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
- orr r0, r0, #CR_A
- #else
- bic r0, r0, #CR_A
- #endif
- mov r5, #DACR_INIT
- mcr p15, 0, r5, c3, c0, 0 @ load domain access register
- mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
- b __turn_mmu_on
第10行将段表的物理起始地址设置到CP15的C2寄存器中,即0x30004000或者0x60004000,可以参考ARM920T Technical Reference Manual 的2.3.6 Register 2, translation table base (TTB) register
第12行准备打开MMU
下面开始打开MMU:
- .align 5.pushsection.idmap.text,
- "ax"ENTRY(__turn_mmu_on) mov r0,
- r0 instr_sync mcr p15,
- 0,
- r0,
- c1,
- c0,
- 0@write control reg mrc p15,
- 0,
- r3,
- c0,
- c0,
- 0@read id reg instr_sync mov r3,
- r3 mov r3,
- r13 ret r3 __turn_mmu_on_end: ENDPROC(__turn_mmu_on).popsection
第6行开启MMU, 由于之前已经建立了映射这部分的段表,所以程序可以继续执行,不会出错
第10行,r13中存放的是__mmap_switched的虚拟地址
第11行,开始跳到__mmap_switched处执行,自此以后的虚拟地址就跟链接地址相同了
__mmap_switched定义在arch/arm/kernel/head-common.S中:
- __mmap_switched:
- adr r3, __mmap_switched_data
- ldmia r3!, {r4, r5, r6, r7}
- cmp r4, r5 @ Copy data segment if needed
- 1: cmpne r5, r6
- ldrne fp, [r4], #4
- strne fp, [r5], #4
- bne 1b
- mov fp, #0 @ Clear BSS (and zero fp)
- 1: cmp r6, r7
- strcc fp, [r6],#4
- bcc 1b
- ARM( ldmia r3, {r4, r5, r6, r7, sp})
- str r9, [r4] @ Save processor ID
- str r1, [r5] @ Save machine type
- str r2, [r6] @ Save atags pointer
- cmp r7, #0
- strne r0, [r7] @ Save control register values
- b start_kernel
- ENDPROC(__mmap_switched)
- .align 2
- .type __mmap_switched_data, %object
- __mmap_switched_data:
- .long __data_loc @ r4
- .long _sdata @ r5
- .long __bss_start @ r6
- .long _end @ r7
- .long processor_id @ r4
- .long __machine_arch_type @ r5
- .long __atags_pointer @ r6
- .long cr_alignment @ r7
- .long init_thread_union + THREAD_START_SP @ sp
- .size __mmap_switched_data, . - __mmap_switched_data
这里主要关注一下第16到第23行,这里将r9中存放的CPU ID赋给processor_id, 将dtb所在的物理地址赋给__atags_pointer,将sp设置为init_thread_union + THREAD_START_SP, 这里init_thread_union定义在init/init_task.c中,THREAD_START_SP的值是(8KB-8),也就是sp指向init进程的内核栈。然后第23行跳转到init/main.c中的start_kernel。
完。
Linux内存管理学习3 —— head.S中的段页表的建立
来源: http://www.bubuko.com/infodetail-2391389.html