分析代码
/*
* Compute indices of table entries from virtual address range. If multiple entries
* were needed in the previous page table level then the next page table level is assumed
* to be composed of multiple pages. (This effectively scales the end index).
*
* vstart: virtual address of start of range
* vend: virtual address of end of range - we map [vstart, vend]
* shift: shift used to transform virtual address into index
* ptrs: number of entries in page table
* istart: index in table corresponding to vstart
* iend: index in table corresponding to vend
* count: On entry: how many extra entries were required in previous level, scales
* our end index.
* On exit: returns how many extra entries required for next page table level
*
* Preserves: vstart, vend, shift, ptrs
* Returns: istart, iend, count
*/
.macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count
lsr \iend, \vend, \shift
mov \istart, \ptrs
sub \istart, \istart, #1
and \iend, \iend, \istart // iend = (vend >> shift) & (ptrs - 1)
mov \istart, \ptrs
mul \istart, \istart, \count
add \iend, \iend, \istart // iend += (count - 1) * ptrs
// our entries span multiple tables
lsr \istart, \vstart, \shift
mov \count, \ptrs
sub \count, \count, #1
and \istart, \istart, \count
sub \count, \iend, \istart
.endm
注释
第1行到14行是注释,大概意思就是计算虚拟地址的有效索引。
需要注意的一点是,如果上一级页表需要很多有效条目,则下一级页表可能由多页组成。这句话什么意思呢,我们接着分析各个参数的含义。
第一个参数 vstart 入参,虚拟地址的起始地址
第二个参数 vend 入参,虚拟地址的结束地址,在上一章节中我们是将 vend 自减1的,恰好符合注释描述的区间概念,否则就多分配了一个页表项
第三个参数 shift 入参, 将虚拟地址转换为索引需要偏移的位数,调用者传过来的参数是 PGDIR_SHIFT,该参数我们在以前的章节中分析过,为39
第四个参数 ptrs 入参,表示该页表最多支持的索引数目,该参数我们在以前的章节中分析过,页全局目录最大支持 512
第五个参数 istart 出参,有效虚拟起始地址的的索引项
第六个参数 iend 出参,有效结束虚拟地址的索引项
第七个参数 count 即是入参,又是出参。
第一次调用的时候,入参传递0,
根据注释,出参统计有效页表项的数目,包括了跨多个页表的场景。
对于全局页表来说,最多就一个页,不会超过512,但是后面级别的页表就不好说了,只要全局页表的有效索引超过1,下一级的页表肯定是跨多个页表。
正式分析
下面我们正式分析这个宏
第20行 计算 将虚拟地址 vend 右移 shift 位,并存放在 iend 里面,处理掉 vend 的右半部分(对于 iend 来说);
第21行 第22行 将 ptrs 减1存放在 istart 里面,该数前面为多个bit0,后面全为bit1;
第23行 将 iend 与 istart 进行按位与的运算,计算出结果并存放在 iend 里面,这样处理掉了 vend 左半部分的无用位(对于 iend 来说);
对于 iend 来说,就剩下跨页的情况没有被处理了。不过不要着急,下面马上安排:)
第24行 再将 ptrs 存放在 istart 里面
第25行 将 count 与 ptrs 相乘,计算跨页的情况,跨页意味这增加 count 个页表项以及下一级 count 个页表
当计算 页全局目录时,如果该入参为0,可以认为全局目录的上一级页表为0;
当计算其余的目录时,如果该入参为2,表示需要增加2个页表项
第26行 表示补充了跨页的场景,iend 盖棺定论
第29行到第32行计算 istart,过程比 iend 简单,少了跨页的计算,别的都差不多
第34行 计算需要填充的索引数目,将结果赋值到 count;如果 iend 和 istart 相减为0, 表示这两个索引在一个页面,不存在跨页情况;
如果两着相减不为0,则表示两个索引不在一个页面,存在跨页情况