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
 

 

posted @ 2022-03-20 17:40  张志伟122  阅读(284)  评论(0编辑  收藏  举报