/*
* Setup common bits before finally enabling the MMU. Essentially
* this is just loading the page table pointer and domain access
* registers.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*/
__enable_mmu:
#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
orrr0, r0, #CR_A #r0为什么不先清0?
#else
bicr0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
bicr0, r0, #CR_C
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
bicr0, r0, #CR_Z
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
bicr0, r0, #CR_I
#endif
#ifndef CONFIG_ARM_LPAE
movr5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
domain_val(DOMAIN_IO, DOMAIN_CLIENT))
/*
结合数据手册,此段是将D0、D1两个域,D1对应于USER域,D0对应于KERNEL和TABLE域,配置为管理模式,
对这两个域的访问和执行不受TLB中相应标志位影响,
D2域,对应于IO域,配置为客户模式,对此域的访问受TLB中相应标志位的检查;
*/
mcrp15, 0, r5, c3, c0, 0@ load domain access register
mcrp15, 0, r4, c2, c0, 0@ load page table pointer
#endif
b__turn_mmu_on
ENDPROC(__enable_mmu)
/*
* Enable the MMU. This completely changes the structure of the visible
* memory space. You will not be able to trace execution through this.
* If you have an enquiry about this, *please* check the linux-arm-kernel
* mailing list archives BEFORE sending another post to the list.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*
* other registers depend on the function called upon completion
*/
.align5
.pushsection.idmap.text, "ax"
ENTRY(__turn_mmu_on)
movr0, r0
instr_sync
mcrp15, 0, r0, c1, c0, 0@ write control reg
mrcp15, 0, r3, c0, c0, 0@ read id reg
instr_sync
movr3, r3
movr3, r13
movpc, r3
__turn_mmu_on_end:
ENDPROC(__turn_mmu_on)
.popsection
/*
* The following fragment of code is executed with the MMU on in MMU mode,
* and uses absolute addresses; this is not position independent.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
*/
__INIT
__mmap_switched:
adrr3, __mmap_switched_data
ldmiar3!, {r4, r5, r6, r7}
cmpr4, r5@ Copy data segment if needed,from[r4]__data_loc to [r5]_sdata
@ __data_loc是数据段在内核代码映像中的存储位置
@ _sdata是数据段的链接位置(在内存中的位置)
@ 如果是XIP技术的内核,这两个数据肯定不同
1:cmpner5, r6
ldrnefp, [r4], #4 @ fp(frame pointer) == r11
strnefp, [r5], #4
bne1b
movfp, #0@ Clear BSS (and zero fp)
1:cmpr6, r7
strccfp, [r6],#4
bcc1b
@ 这里将需要的数据从寄存器中转移到全局变量中,因为最后会跳入C代码,寄存器会被使用
ARM(ldmiar3, {r4, r5, r6, r7, sp})
THUMB(ldmiar3, {r4, r5, r6, r7})
THUMB(ldrsp, [r3, #16])
strr9, [r4]@ Save processor ID
strr1, [r5]@ Save machine type
strr2, [r6]@ Save atags pointer
cmpr7, #0
bicner4, r0, #CR_A@ Clear 'A' bit @ 禁用对齐错误检查
stmneiar7, {r0, r4}@ Save control register values
@ 保存控制寄存器值到全局变量cr_alignment(在arch/arm/kernel/entry-armv.S)
/*
.globl cr_alignment @ [r0]
.globl cr_not_alignment @ [r4]
cr_alignment:
.space 4
cr_not_alignment
.space 4
*/
bstart_kernel
ENDPROC(__mmap_switched)