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, \tmp 247 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