linux aarch64 head.S map_memory
註釋寫的很詳細了。
對映一段 VA 地址。
輸入引數:
tbl table location - 使用呼叫前 設定的值
rtbl - 會覆蓋為 rtbl = tbl + PAGE_SIZE, 所以呼叫前的值不關心。
vstart 虛擬地址的起始值 使用呼叫前 設定的值
vend 虛擬地址的結束值 使用呼叫前 設定的值
flags 最後一層 頁表 block descriptor 裡面 使用 的 flags
phys 實體地址的起始值。
pgds page global dirs 的個數。
=============
呼叫一次 map_memory 後, 傳入的 vstart vend flags 不會被改變; tbl rtbl 會被改變
反覆的呼叫 compute_indices 計算值,然後呼叫 populate_enties 填寫值。
224/* 225 * Map memory for specified virtual address range. Each level of page table needed supports 226 * multiple entries. If a level requires n entries the next page table level is assumed to be 227 * formed from n pages. 228 * 229 * tbl: location of page table 230 * rtbl: address to be used for first level page table entry (typically tbl + PAGE_SIZE) 231 * vstart: start address to map 232 * vend: end address to map - we map [vstart, vend] 233 * flags: flags to use to map last level entries 234 * phys: physical address corresponding to vstart - physical memory is contiguous 235 * pgds: the number of pgd entries 236 * 237 * Temporaries: istart, iend, tmp, count, sv - these need to be different registers 238 * Preserves: vstart, vend, flags 239 * Corrupts: tbl, rtbl, istart, iend, tmp, count, sv 240*/ 241 .macro map_memory, tbl, rtbl, vstart, vend, flags, phys, pgds, istart, iend, tmp, count, sv 242 add \rtbl, \tbl, #PAGE_SIZE 243 mov \sv, \rtbl 244 mov \count, #0 245 compute_indices \vstart, \vend, #PGDIR_SHIFT, \pgds, \istart, \iend, \count 246 populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp247 mov \tbl, \sv 248 mov \sv, \rtbl 249 250#if SWAPPER_PGTABLE_LEVELS > 3 251 compute_indices \vstart, \vend, #PUD_SHIFT, #PTRS_PER_PUD, \istart, \iend, \count 252 populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp 253 mov \tbl, \sv 254 mov \sv, \rtbl 255#endif 256 257#if SWAPPER_PGTABLE_LEVELS > 2 258 compute_indices \vstart, \vend, #SWAPPER_TABLE_SHIFT, #PTRS_PER_PMD, \istart, \iend, \count 259 populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp 260 mov \tbl, \sv 261#endif 262 263 compute_indices \vstart, \vend, #SWAPPER_BLOCK_SHIFT, #PTRS_PER_PTE, \istart, \iend, \count 264 bic \count, \phys, #SWAPPER_BLOCK_SIZE - 1 265 populate_entries \tbl, \count, \istart, \iend, \flags, #SWAPPER_BLOCK_SIZE, \tmp 266 .endm
compute_indices
輸入:
vstart vend 虛擬地址的起始和結尾
shift 虛擬地址中,頁表 index 對應的 bit 位的起始 shift 值。比如 pgd 也表 index 使用 47 ~ 39 bits, 那麼shift 就是 39 。
ptrs 也表中,總的表項的個數,比如 512個。說明這個 頁表 使用的 VA bits 為 9 個 bits.
count 上一級頁表 中,有幾個 頁表 項。
臨時變數: istart iend
輸出
istart vstart 地址在 頁表 中對應的 index
iend vend 地址在 頁表 中 對應 的 index
count count = iend - istart ; 需要的表 項 的個數。
188/* 189 * Compute indices of table entries from virtual address range. If multiple entries 190 * were needed in the previous page table level then the next page table level is assumed 191 * to be composed of multiple pages. (This effectively scales the end index). 192 * 193 * vstart: virtual address of start of range 194 * vend: virtual address of end of range 195 * shift: shift used to transform virtual address into index 196 * ptrs: number of entries in page table 197 * istart: index in table corresponding to vstart 198 * iend: index in table corresponding to vend 199 * count: On entry: how many extra entries were required in previous level, scales 200 * our end index. 201 * On exit: returns how many extra entries required for next page table level 202 * 203 * Preserves: vstart, vend, shift, ptrs 204 * Returns: istart, iend, count 205 */
206 .macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count 207 lsr \iend, \vend, \shift 208 mov \istart, \ptrs 209 sub \istart, \istart, #1 210 and \iend, \iend, \istart // iend = (vend >> shift) & (ptrs - 1) 211 mov \istart, \ptrs 212 mul \istart, \istart, \count 213 add \iend, \iend, \istart // iend += count * ptrs 214 // our entries span multiple tables 215 216 lsr \istart, \vstart, \shift 217 mov \count, \ptrs 218 sub \count, \count, #1 219 and \istart, \istart, \count 220 221 sub \count, \iend, \istart 222 .endm
207 ~ 210 iend = ( vend >> shift ) & ( ptrs - 1)
211 ~ 213 處理 count 對 iend 的影響。 count 表示 上一級頁表 中 表項 的個數。 0 個表示 1 個, 1 表示2個。 註釋有點錯誤,應該是 iend = iend + count * ptrs .
舉例:要對映的 VA start 到 VA end 很大一塊區域,需要兩個 pdg 專案
VA start 0x0000 0000 0000 0000 // bit 39 為 0.
VA end 0x0000 0040 0000 0000 // 8 = 0b1000 ,即 bit 39 為 1
map_memory 中的
244 ~ 245 行。
compute_indices 的輸入: vstart=0x0000 0000 0000 0000 vend=0x0000 0040 0000 0000 shift = #PGDIR_SHIFT (39), ptrs=\pgds (512) 傳入 compute_indices ; count 設定為 0 (因為比 pgd 更高一層的 頁表專案個是就是 0 個)
輸出: istart = 0, iend = 1, count = 1;
246 行, 使用 populate_entries , 在tbl 地址上面建立表,填充了 0 , 1 兩個 表項, 表項裡面填充 指向下一級 頁表 的地址 rtbl
244 mov \count, #0 245 compute_indices \vstart, \vend, #PGDIR_SHIFT, \pgds, \istart, \iend, \count
246 populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
下一級 pud 頁表填充時,即需要考慮 pgd 中 表項的個數了。
251 行 中 count 的值為 1 。 表示 pgd 中填充了 兩個 表項 ,idx 為 0 和 1 的兩項。
vstart=0x0000 0000 0000 0000 vend=0x0000 0040 0000 0000 shift = #PGDIR_SHIFT (30), ptrs=\pgds (512)
249
250#if SWAPPER_PGTABLE_LEVELS > 3
251 compute_indices \vstart, \vend, #PUD_SHIFT, #PTRS_PER_PUD, \istart, \iend, \count 252 populate_entries \tbl, \rtbl, \istart, \iend, #PMD_TYPE_TABLE, #PAGE_SIZE, \tmp
這時的 compute_indecs 中,
iend = ( vend >> 30 ) & ( 512 -1 ) . 注意,這兒只取出了 vend 中的 bit 30 ~ 38 這一段的值,為 0 ( vend 中只有 bit 39 = 1.)
一個 pgd 表項 指向 一張 pud 表,那麼 pgd 有2 個 表項, 就 需要 2 張 pud 表,一張 pud 表中有 ptr 個表項。
所以,我們這兒計算出來的 iend = 0 ,是值 第二張 pud 表中的 index 0 。 所以 ,僅僅通過 207 ~ 218 之間的計算並不完整。需要 211 ~ 213 中的補充
iend = iend + count * ptrs = 0 + 1 * 512 = 512 ;
istart 的計算, istart = vstart >> 30) & 512 = 0 ;
count = 512 - 0 = 512 .
及,需要對映 很大一塊VA ,VA start 0x0000 0000 0000 0000 ~ VA end 0x0000 0040 0000 0000 ,需要 513 個 PUD 表項。
207 lsr \iend, \vend, \shift 208 mov \istart, \ptrs 209 sub \istart, \istart, #1 210 and \iend, \iend, \istart // iend = (vend >> shift) & (ptrs - 1)
211 mov \istart, \ptrs
212 mul \istart, \istart, \count
213 add \iend, \iend, \istart // iend += count * ptrs