为什么物理地址对齐 4KiB 时,虚拟地址却不是 4KiB 对齐?

为什么物理地址对齐 4KiB 时,虚拟地址却不是 4KiB 对齐?

简而言之,我有一个实际地址内核内部(9,932,111,872 或0x250000000),这显然是对齐到 4KiB(页面大小)。当我使用核__va()函数来获取内核虚拟地址,我得到类似的东西0xf570660f(每次启动时都不同),即未与 4KiB 对齐

我使用的是 64 位系统,因此没有 HIGHMEM,并且我认为由于线性内存模型,4KiB 对齐的物理地址的虚拟地址也应该是 4KiB 对齐的。我错过了什么?虚拟地址不应该是吗phys_addr + PAGE_OFFSET?或者是sparsemem的影响?但也许它也应该是 4KiB 对齐的?

以下是更多详细信息:

我的工作环境是在 x86 64 位 QEMU VM 上。我正在尝试在模式下使用 PMEMDEV-DAX作为普通内存。我可以得到它的物理起始地址(0x250000000),已经确认是正确的。然后我需要将它转移到内核空间中的虚拟地址,以便我可以根据需要使用它。这是一些代码:

static long nvpc_map_whole_dev(struct dax_device *dax_dev, void **kaddr, pfn_t *pfn)
{
    // get the device
    struct dev_dax_nvpc *dax_nvpc = (struct dev_dax_nvpc *)dax_get_private(dax_dev);
    
    // get the virtual address and the pfn_t
    *kaddr = __va(dax_nvpc->phys_start);
    *pfn = phys_to_pfn_t(dax_nvpc->phys_start, PFN_MAP);
    
    pr_info("[NVPC DEBUG]: paddr %#llx kaddr %p pfn %lu\n", dax_nvpc->phys_start, *kaddr, pfn_t_to_pfn(*pfn));
    pr_info("[NVPC DEBUG]: kaddr-paddr %#llx\n", __pa(*kaddr));
    return PHYS_PFN(dax_nvpc->size);
}

这是我得到的结果:

在此输入图像描述

如图所示, 、paddr dax_nvpc->phys_startpfn、 都是正确的。但kaddr(虚拟地址)让我感到困惑。然后,当我将其传输kaddr回物理地址(下一个输出行)时,结果是正确的。

更重要的是,我可以对内存从kaddr到进行任何操作kaddr + dax_nvpc->size,没有页面错误。

谁能告诉我为什么虚拟地址不是 4KiB 对齐的?我在某个地方是不是傻瓜?此外,我可以做些什么来确保虚拟地址也与页面对齐吗?

答案1

原因%p在于printk.当我更改%p%#llx进行快速检查时,内核地址的输出按预期变为 4KB 对齐。

原因可以在这里找到:内核文档:printk 格式指针类型%pprintk 内部将打印散列指针地址以防止泄漏内核信息。这就是为什么指针看起来很奇怪。如果你想检查真实的虚拟地址,只需使用%px, 或添加no_hash_pointers到启动参数中。更多使用方法请参考链接。

相关内容