ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
原來R2中存儲的是虛拟位址值(如0x80000000),通過上面的代碼,将R2中資料的[29-21]位置為1,前面已經說過将空間劃分成了多個1MB的段,那麼就必須以1MB對齊,而且WinCE最多隻能支援512MB的實體記憶體,是以虛拟位址的合法區間是0x80000000~0x9FFFFFFF,正好是512MB的大小(這段是帶緩沖的虛拟位址,相應的不帶緩沖的虛拟位址是0xA0000000~0xBFFFFFFF)。R2中的資料正是虛拟位址對應的頁表相對于頁表首位址的偏移位址,也就是R2用來計算該虛拟位址對應的頁表的存儲位址,從下面的代碼會看出這點。
ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
原來R3中存儲的是實體位址的位址值,頁表項的内容由兩部分組成:實體位址的高12位(高12位)+緩沖讀寫屬性(低12位),這裡的代碼正是保留了實體位址的高12位,清空低20位,正是為了形成頁表項内容進行準備。
add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page
這兩條代碼正是在前面計算得基礎上,用R2中虛拟位址的高14位的偏移量+R10中存儲的頁表的基位址,進而将該虛拟位址對應的頁表要存儲的位址計算出來,并指派給R2。而R0存儲的資料是關于頁表對應的虛拟頁的緩沖讀寫屬性,再加上R3中存儲的實體位址的高12位,進而形成了相應頁表項的内容,并指派給R0。
35
str r0, [r2], #4
add r0, r0, #0x00100000 ; (r0) = PTE for next physical page
sub r4, r4, #1 ; Decrement number of MB left
cmp r4, #0
bne %B35 ; Map next MB
上面的第一條代碼,通過str指令将R0中存儲的頁表項内容,寫入R2指向的位址中,同時R2指向下一個位址。接下來将頁表項的内容增加1MB的大小,從oemaddrtab_cfg.inc的映射表可以看出,最後一個參數表示的配置設定存儲空間的大小,是以MB為機關,是以R0指向的是下一個實體位址頁(機關1M)的頁表項的内容。之後将R4中空間大小的值減1,表示剩餘要構造的頁表數目,如果不為0,則跳轉到标号35處,繼續構造頁表,知道這一個頁表條目完成為止(或者說這一段存儲空間全部映射完成為止)。
bic r0, r0, #0xF0000000 ; Clear Section Base Address Field
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B30 ; Get next element
這部分代碼簡單的說就是清空R0中的高12位,即清空上一個實體位址的高12位,因為要用來存儲下一個實體位址的高12位,同時保留低20位中的緩沖讀寫屬性,完成後跳轉到标号30處,繼續讀取全局記憶體映射表的内容,構造位址映射的頁表。其中%B30表示向前尋找标号為30的位址(B=Before)。
40
tst r0, #8
bic r0, r0, #0x0C ; clear cachable & bufferable bits in PTE
add r10, r10, #0x0800 ; (r10) = ptr to 1st PTE for "unmapped uncached space"
bne %B25 ; go setup PTEs for uncached space
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
一般WinCE會根據全局記憶體映射表進行兩份虛實映射,一份帶緩沖的虛拟位址和不帶緩沖的虛拟位址。到這裡的時候,說明0x80000000~0x9FFFFFFF這段512M的虛拟位址的頁表已經構造完成了,這段位址是帶緩沖的,下面需要對不帶緩沖的虛拟位址構造頁表。
第一條tst語句表示判斷R0的位[7]的值是否為1,進而影響bne跳轉語句的結果。R0的第7位在頁表項内容中表示的是緩沖的屬性,如果為1,表明還沒有開始構造不帶緩沖的虛拟位址對應的頁表,如果不為0,說明不帶緩沖的虛拟位址對應的頁表也已經構造完成了(是不是有點暈啊,呵呵,因為當第二次循環運作這條語句的時候,已經就完成了不帶緩沖的頁表的構造,不行你自己走一遍代碼就知道了)。第二條bic的語句很簡單,就是為了将高速緩沖和寫緩沖的屬性值去掉。第三條語句有點意思,其實就是為了将R10指向存儲不帶緩沖的虛拟位址對應的頁表的存儲位址(0xA0000000),但是采用的方法是計算偏移量,目前R10中存儲的是帶緩沖的虛拟位址對應的頁表的存儲位址(0x80000000),而0xA0000000于0x8000000相差0x20000000,那麼把0x20000000>>18得到的結果就是0x0800,是以在R10的基礎加上0x0800就是頁表應該存儲的位址(其實就是依據虛拟位址高14位代表的是相對于頁表首位址的偏移量,是以也可以直接用0xA0000000>>18位來計算頁表的存儲位址,不信你試試,結果是一樣的)。第四條語句就簡單了,向前跳轉到标号25處,像緩沖虛拟位址的頁表構造的方法對不帶緩沖虛拟位址的頁表進行構造。第五條語句為下面的代碼做準備,将R10指向的位址重新指向頁表基位址,即PT_1ST_BASE,網上有人說這句有問題,其實沒有問題,不過這一句确實沒什麼用處,因為下面對R10進行了重新指派,即将PT_1ST_BASE重新賦給了R10。不過為了了解明白,本人還是解釋一下這句是怎麼計算出來的?首先在最開始R10增加了0x2000,上這裡有兩次增加了0x0800(為什麼是兩次呢?好好看代碼,上面的第三條語句會被執行兩次),加起來正好是0x3000,是以減去這個值得到的正是頁表的基位址。
;----------------------------------------------
; Setup mmu to map (VA == 0) to (PA == 0x30000000).
; cached area
ldr r0, =PT_1ST_BASE ; PTE entry for VA = 0
ldr r1, =PT_1ST_ENTRY_CNB ; Cache/Unbuffer/RW
str r1, [r0]
上面是将0x0的帶緩沖的虛拟位址映射到0x30000000的實體位址處, 0x0的虛拟位址對應的頁表的存儲位址就在PT_1ST_BASE處(0x0>>18得到的是偏移量,說明就在頁表基位址處)。第二條語句是設定頁表項的内容:實體位址的高12位+緩沖讀寫屬性。第三條語句str将頁表項的内容寫入到對應的頁表存儲位址處。
; uncached area.
add r0, r0, #0x0800 ; PTE entry for VA = 0x02000000
ldr r1, =PT_1ST_ENTRY_NCNB ; Uncache/Unbuffer/RW
這部分用來映射不帶緩沖的虛拟位址0x20000000(後面的注釋不對)到實體位址0x30000000,上之前分析的一樣,采用計算偏移量的方法,第二條和第三條語句和上一部分的一樣,這裡不再贅述。
本文轉自jazka 51CTO部落格,原文連結:http://blog.51cto.com/jazka/572626,如需轉載請自行聯系原作者