5. 敞开mmu
敞开mmu是又函数 __enable_mmu 完结的.
在进入 __enable_mmu 的时分, r0中现已存放了操控寄存器c1的一些装备(在上一步中进行的设置), 可是并没有真实的翻开mmu,
在 __enable_mmu 中,咱们将翻开mmu.
此刻,一些特定寄存器的值如下所示:
r0 = c1 parameters (用来装备操控寄存器的参数)
r4 = pgtbl (page table 的物理基地址)
r8 = machine info (struct machine_desc的基地址)
r9 = cpu id (经过cp15协处理器取得的cpu id)
r10 = procinfo (struct proc_info_list的基地址)
在 arch/arm/kernel/head.S 中:
00146: .type__enable_mmu, %function
00147: __enable_mmu:
00148: #ifdef CONFIG_ALIGNMENT_TRAP
00149: orrr0, r0, #CR_A
00150: #else
00151: bicr0, r0, #CR_A
00152: #endif
00153: #ifdef CONFIG_CPU_DCACHE_DISABLE
00154: bicr0, r0, #CR_C
00155: #endif
00156: #ifdef CONFIG_CPU_BPREDICT_DISABLE
00157: bicr0, r0, #CR_Z
00158: #endif
00159: #ifdef CONFIG_CPU_ICACHE_DISABLE
00160: bicr0, r0, #CR_I
00161: #endif
00162: movr5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
00163: domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
00164: domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
00165: domain_val(DOMAIN_IO, DOMAIN_CLIENT))
00166: mcrp15, 0, r5, c3, c0, 0@ load domain access register
00167: mcrp15, 0, r4, c2, c0, 0@ load page table pointer
00168: b__turn_mmu_on
00169:
00170:
00181: .align5
00182: .type__turn_mmu_on, %function
00183: __turn_mmu_on:
00184: movr0, r0
00185: mcrp15, 0, r0, c1, c0, 0@ write control reg
00186: mrcp15, 0, r3, c0, c0, 0@ read id reg
00187: movr3, r3
00188: movr3, r3
00189: movpc, r13
第146, 147行: 函数声明
第148 – 161行: 依据相应的装备,设置r0中的相应的Bit. (r0 将用来装备操控寄存器c1)
第162 – 165行: 设置 domain 参数r5.(r5 将用来装备domain)
第166行: 装备 domain (详细信息清参阅arm相关手册)
第167行: 装备页表在存储器中的方位(set ttb).这儿页表的基地址是r4, 经过写cp15的c2寄存器来设置页表基地址.
第168行: 跳转到 __turn_mmu_on. 从称号咱们能够猜到,下面是要真实翻开mmu了.
(持续向下看,咱们会发现,__turn_mmu_on就下当时代码的下方,为什么要跳转一下呢? 这是有原因的. go on)
第169 – 180行: 空行和注释. 这儿的注释咱们能够看到, r0是cp15操控寄存器的内容, r13存储了完结后需求跳转的虚拟地址(由于完结后mmu现已翻开了,都是虚拟地址了).
第181行: .algin 5 这句是cache line对齐. 咱们能够看到下面一行便是 __turn_mmu_on, 之所以
第182 – 183行: __turn_mmu_on 的函数声明. 这儿咱们能够看到, __turn_mmu_on 是紧接着上面第168行的跳转指令的,仅仅中心在第181行多了一个cache line对齐.
这么做的原因是: 下面咱们要进行真实的翻开mmu操作了, 咱们要把翻开mmu的操作放到一个独自的cache line上. 而在之前的”发动条件”一节咱们说了,I Cache是能够翻开也能够封闭的,这儿这么做的原因是要确保在I Cache翻开的时分,翻开mmu的操作也能正常履行.
第184行: 这是一个空操作,相当于nop. 在arm中,nop操作经常用指令 mov rd, rd 来完结.
留意: 为什么这儿要有一个nop,我考虑了很长时刻,这儿是我的猜想,或许不是正确的:
由于之前设置了页表基地址(set ttb),到下一行(185行)翻开mmu操作,中心的指令序列是这样的:
set ttb(第167行)
branch(第168行)
nop(第184行)
enable mmu(第185行)
关于arm的五级流水线: fetch – decode – execute – memory – write
他们履行的状况如下图所示:
+————+—+—+—+—+—+—+—+—+
| set ttb | F | D | E | M | W | | | |
+————+—+—+—+—+—+—+—+—+
| branch | | F | D | E | | | | |
+————+—+—+—+—+—+—+—+—+
| nop | | | | | F | D | | |
+————+—+—+—+—+—+—+—+—+
| enable mmu | | | | | | F | | |
+————+—+—+—+—+—+—+—+—+
F – fetch
D – Decode
E – Execute
M – Memory
W – Write Register
这儿需求阐明的是,branch操作会在3个cycle中完结,并且会导致从头取指.
从这个图咱们能够看出来,在enable mmu操作取指的时分, set ttb操作刚好完结.
第185行: 写cp15的操控寄存器c1, 这儿是翻开mmu的操作,一起会翻开cache等(依据r0相应的装备)
第186行: 读取id寄存器.
第187 – 188行: 两个nop.
第189行: 取r13到pc中,咱们前面现已看到了, r13中存储的是 __switch_data (在 arch/arm/kernel/head.S 91行),下面会跳到 __switch_data.
第187,188行的两个nop是非常重要的,由于在185行翻开mmu操作之后,要比及3个cycle之后才会收效,这和arm的流水线有联系.
因此,在翻开mmu操作之后的加了两个nop操作.
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/dianlu/275640.html