start_kernel -> setup_arch -> early_fixmap_init -> pgd_offset_k
pgd_t *pgd;
unsigned long addr = FIXADDR_START; // 0xffff7ffffabfe000
pr_err("Test pgd_index(addr) is 0x%llx \n",pgd_index(addr)); // 0xff
pr_err("sdssglTest swapper_pg_dir is %llx.\n",swapper_pg_dir); // 0xffff800000eec000
pr_err("sdssglTest init_mm->pgd is %llx, pgd is %llx\n",(&init_mm)->pgd,pgd); // 0xffff800000eec000,0xffff800000eec7f8
pr_err("sdssglTest pgd_index(addr) + (&init_mm)->pgd is 0x%llx \n",PGDIR_SHIFT,pgd_index(addr)+(&init_mm)->pgd); // 0xffff800000eec7f8
pr_err("sdssglTest 0xffff800000eec000 + 0xff is 0x%llx.\n",(u64)(0xffff800000eec000) + 0xff); // 0xffff800000eec0ff
pgd = pgd_offset_k(addr); // 0xffff800000eec7f8
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) // 0xffff800000eec000 + 0xff
#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) // addr >> PGDIR_SHIFT = 0xffff7ffffabfe000 >> 39 = 0x1fffeff
// 0x1fffeff & (0x200 -1) = 0x1fffeff & 0x1ff = 0xff
问题描述:
在 early_fixmap_init 函数中,调用 pgd_offset_k 计算 FIXADDR_START 虚拟地址在 pgd 中的虚拟地址,
addr = 0xffff800000eec7f8
由 pgd_offset_k 宏定义可知,需要计算 (mm)->pgd , pgd_index(addr),然后将两者相加
通过打印可知:(mm)->pgd = 0xffff800000eec000
pgd_index(addr) = 0xff
所以 pgd_offset_k(addr) 应该等于 0xffff800000eec0ff ,但是实际上却等于 0xffff800000eec7f8
将两个数,0xffff800000eec000 + 0xff 打印出也是 0xffff800000eec0ff,但是 pgd_index(addr)+(&init_mm)->pgd 这个相加却为 0xffff800000eec7f8
问题解决:
由于arm64,一个pgt页表项占用8个字节,所以0xff个页表项则占用 0xff * 8 = 0x7f8 个字节,再说地址不能f结尾,要对齐,所以为 0xffff800000eec7f8