- 論壇徽章:
- 0
|
5. 開啟mmu
開啟mmu是又函數(shù) __enable_mmu 實(shí)現(xiàn)的.
在進(jìn)入 __enable_mmu 的時(shí)候, r0中已經(jīng)存放了控制寄存器c1的一些配置(在上一步中進(jìn)行的設(shè)置), 但是并沒有真正的打開mmu,
在 __enable_mmu 中,我們將打開mmu.
此時(shí),一些特定寄存器的值如下所示:
r0 = c1 parameters (用來配置控制寄存器的參數(shù))
r4 = pgtbl (page table 的物理基地址)
r8 = machine info (struct machine_desc的基地址)
r9 = cpu id (通過cp15協(xié)處理器獲得的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: orr r0, r0, #CR_A
00150: #else
00151: bic r0, r0, #CR_A
00152: #endif
00153: #ifdef CONFIG_CPU_DCACHE_DISABLE
00154: bic r0, r0, #CR_C
00155: #endif
00156: #ifdef CONFIG_CPU_BPREDICT_DISABLE
00157: bic r0, r0, #CR_Z
00158: #endif
00159: #ifdef CONFIG_CPU_ICACHE_DISABLE
00160: bic r0, r0, #CR_I
00161: #endif
00162: mov r5, #(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: mcr p15, 0, r5, c3, c0, 0 @ load domain access register
00167: mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
00168: b __turn_mmu_on
00169:
00170: /*
00171: * Enable the MMU. This completely changes the structure of the visible
00172: * memory space. You will not be able to trace execution through this.
00173: * If you have an enquiry about this, *please* check the linux-arm-kernel
00174: * mailing list archives BEFORE sending another post to the list.
00175: *
00176: * r0 = cp#15 control register
00177: * r13 = *virtual* address to jump to upon completion
00178: *
00179: * other registers depend on the function called upon completion
00180: */
00181: .align 5
00182: .type __turn_mmu_on, %function
00183: __turn_mmu_on:
00184: mov r0, r0
00185: mcr p15, 0, r0, c1, c0, 0 @ write control reg
00186: mrc p15, 0, r3, c0, c0, 0 @ read id reg
00187: mov r3, r3
00188: mov r3, r3
00189: mov pc, r13
第146, 147行: 函數(shù)聲明
第148 - 161行: 根據(jù)相應(yīng)的配置,設(shè)置r0中的相應(yīng)的Bit. (r0 將用來配置控制寄存器c1)
第162 - 165行: 設(shè)置 domain 參數(shù)r5.(r5 將用來配置domain)
第166行: 配置 domain (詳細(xì)信息清參考arm相關(guān)手冊)
第167行: 配置頁表在存儲器中的位置(set ttb).這里頁表的基地址是r4, 通過寫cp15的c2寄存器來設(shè)置頁表基地址.
第168行: 跳轉(zhuǎn)到 __turn_mmu_on. 從名稱我們可以猜到,下面是要真正打開mmu了.
(繼續(xù)向下看,我們會發(fā)現(xiàn),__turn_mmu_on就下當(dāng)前代碼的下方,為什么要跳轉(zhuǎn)一下呢? 這是有原因的. go on)
第169 - 180行: 空行和注釋. 這里的注釋我們可以看到, r0是cp15控制寄存器的內(nèi)容, r13存儲了完成后需要跳轉(zhuǎn)的虛擬地址(因?yàn)橥瓿珊髆mu已經(jīng)打開了,都是虛擬地址了).
第181行: .algin 5 這句是cache line對齊. 我們可以看到下面一行就是 __turn_mmu_on, 之所以
第182 - 183行: __turn_mmu_on 的函數(shù)聲明. 這里我們可以看到, __turn_mmu_on 是緊接著上面第168行的跳轉(zhuǎn)指令的,只是中間在第181行多了一個(gè)cache line對齊.
這么做的原因是: 下面我們要進(jìn)行真正的打開mmu操作了, 我們要把打開mmu的操作放到一個(gè)單獨(dú)的cache line上. 而在之前的"啟動條件"一節(jié)我們說了,I Cache是可以打開也可以關(guān)閉的,這里這么做的原因是要保證在I Cache打開的時(shí)候,打開mmu的操作也能正常執(zhí)行.
第184行: 這是一個(gè)空操作,相當(dāng)于nop. 在arm中,nop操作經(jīng)常用指令 mov rd, rd 來實(shí)現(xiàn).
注意: 為什么這里要有一個(gè)nop,我思考了很長時(shí)間,這里是我的猜測,可能不是正確的:
因?yàn)橹霸O(shè)置了頁表基地址(set ttb),到下一行(185行)打開mmu操作,中間的指令序列是這樣的:
set ttb(第167行)
branch(第168行)
nop(第184行)
enable mmu(第185行)
對于arm的五級流水線: fetch - decode - execute - memory - write
他們執(zhí)行的情況如下圖所示:
pipeline.gif (3.77 KB, 下載次數(shù): 239)
下載附件
2008-07-30 16:34 上傳
這里需要說明的是,branch操作會在3個(gè)cycle中完成,并且會導(dǎo)致重新取指.
從這個(gè)圖我們可以看出來,在enable mmu操作取指的時(shí)候, set ttb操作剛好完成.
第185行: 寫cp15的控制寄存器c1, 這里是打開mmu的操作,同時(shí)會打開cache等(根據(jù)r0相應(yīng)的配置)
第186行: 讀取id寄存器.
第187 - 188行: 兩個(gè)nop.
第189行: 取r13到pc中,我們前面已經(jīng)看到了, r13中存儲的是 __switch_data (在 arch/arm/kernel/head.S 91行),下面會跳到 __switch_data.
第187,188行的兩個(gè)nop是非常重要的,因?yàn)樵?85行打開mmu操作之后,要等到3個(gè)cycle之后才會生效,這和arm的流水線有關(guān)系.
因而,在打開mmu操作之后的加了兩個(gè)nop操作. |
|