为什么我的页表没有映射正确的物理地址?

Why are my page tables not mapping the right physical addresses?

我正在编写一个使用 UEFI 启动的小型 x86-64 内核。我认为我在代码中忽略了一些东西,我无法弄清楚它是什么。我正在尝试在我的高半内核中分页 xHCI BAR。我有这个小代码片段应该可以做到这一点:

__attribute__((aligned (4096))) UINT64 Paging::xhciPageDir;
__attribute__((packed)) __attribute__((aligned (4096))) UINT64 Paging::xhciPageTable[512];

void Paging::PageXHCIConfigSpace(UINT64 baseAddrRegSpace, UINT64 barAreaSize){
    /*
    Divide the BAR address by 1GB (0x40000000) to determine the position in the PDP
    */
    UINT64 pdpEntryNum = baseAddrRegSpace / 0x40000000;
    
    UINT64* pdpPtr = (UINT64*)0xffff800000601000; //Pointer to the PDP
    /*
    Make the PDP entry point to the page directory for the xHCI ored with 0x1b to mark
    the page as present and uncached minus 0xffff800000000000 because the PDP contains physical
    addresses.
    */
    *(pdpPtr + pdpEntryNum) = (((UINT64)&xhciPageDir) | 0x1b) - 0xffff800000000000;
    
    //Make the first entry of the PD of the xHCI point to the page table.
    xhciPageDir = (((UINT64)&xhciPageTable) | 0x1b) - 0xffff800000000000;
    
    /*
    Make the page table 4th entry map to the BAR address
    */
    UINT64 ptEntry = baseAddrRegSpace | 0x1b;
    for (UINT32 i = 4; i < 4 + (barAreaSize / 4096); i++){
        xhciPageTable[i] = ptEntry;
        ptEntry += 0x1000;
    }
}

此代码片段被另一个代码片段调用:

    /*Bar0 and Bar1 combining*/
    UINT32* pciPtr = (UINT32*)configSpacePhysAddr;
    UINT32 register4 = *(pciPtr + 4);
    UINT32 register5 = *(pciPtr + 5);
    UINT64 bar0 = (UINT64)register4;
    UINT64 bar1 = (UINT64)register5;
    baseAddrRegSpace = (bar1 << 32) + (bar0 & 0xfffffff0);
    
    *(pciPtr + 4) = 0xffffffff;
    UINT32 barAreaSize = *(pciPtr + 4);
    barAreaSize &= 0xfffffff0;
    barAreaSize = ~barAreaSize;
    barAreaSize += 1;
    Paging::PageXHCIConfigSpace(baseAddrRegSpace, barAreaSize);

此代码片段的第一部分通过组合 BAR1BAR0 来获取 BAR 地址。 BAR 指向的地址是 0x800004000。它是第 32 GB 之后的 4 页。然后我使用此代码片段的第二部分来计算 BAR 指向的 BAR 区域的大小。结果是 4 页或 16384 字节大小。

因此,在第一个代码片段中,我做了一些假设,我需要填写页面的第 4 个条目 table 以将 0xffff800800004000 映射到 0xffff800800008000。然后我用 0x800004000、0x800005000、0x800006000 和 0x800007000 填充这 4 页 table 条目。这似乎工作正常,但是当我在 GDB 中使用 monitor info mem 时,它 returns 以下内容:

(gdb) monitor info mem
ffff800000000000-ffff800100000000 0000000100000000 -rw
ffff800800004000-ffff800800008000 0000000000004000 -rw

我有正确的虚拟地址,但它们从 0x0000 映射到 0x4000,这不是正确的物理地址。因此,我在记忆中寻找罪魁祸首。这是显示所有页面 tables:

的几个内存转储
(gdb) dump memory result.bin 0xffff800000601000 0xffff800000602000
(gdb) dump memory result.bin 0xffff800000511000 0xffff800000512000
(gdb) dump memory result.bin 0xffff800000512000 0xffff800000513000

user@user-System-Product-Name:~$ hexdump -C result.bin
00000000  3b 20 60 00 00 00 00 00  1b 30 60 00 00 00 00 00  |; `......0`.....|
00000010  1b 40 60 00 00 00 00 00  3b 50 60 00 00 00 00 00  |.@`.....;P`.....|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000100  1b 10 51 00 00 00 00 00  00 00 00 00 00 00 00 00  |..Q.............|
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000
user@user-System-Product-Name:~$ hexdump -C result.bin
00000000  1b 20 51 00 00 00 00 00  00 00 00 00 00 00 00 00  |. Q.............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000
user@user-System-Product-Name:~$ hexdump -C result.bin
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000020  1b 40 00 00 08 00 00 00  1b 50 00 00 08 00 00 00  |.@.......P......|
00000030  1b 60 00 00 08 00 00 00  1b 70 00 00 08 00 00 00  |.`.......p......|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000

在页面 tables 中(在最后一个转储中)它显示了正确的物理地址。它们不会反映在 GDB 的 monitor info mem 命令中。看了半天还是不明白为什么。

有人知道哪里出了问题吗?

编辑

这是 PML4 输出:

(gdb) dump memory result.bin 0xffff800000600000 0xffff800000601000

user@user-System-Product-Name:~$ hexdump -C result.bin
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000800  3b 10 60 00 00 00 00 00  00 00 00 00 00 00 00 00  |;.`.............|
00000810  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000

编辑 2

最后我用monitor info tlb来了解更多细节。之前没用过,因为第一个4GB的mapping会导致很多输出。输出的结尾如下所示:

ffff8000ffff9000: 00000000ffff9000 -----CT-W
ffff8000ffffa000: 00000000ffffa000 -----CT-W
ffff8000ffffb000: 00000000ffffb000 -----CT-W
ffff8000ffffc000: 00000000ffffc000 -----CT-W
ffff8000ffffd000: 00000000ffffd000 -----CT-W
ffff8000ffffe000: 00000000ffffe000 -----CT-W
ffff8000fffff000: 00000000fffff000 -----CT-W
ffff800800004000: 0000000800004000 -----CT-W
ffff800800005000: 0000000800005000 -----CT-W
ffff800800006000: 0000000800006000 -----CT-W
ffff800800007000: 0000000800007000 -----CT-W

根据monitor info tlb,我的映射是正确的。这可能与缓存相关吗?这很奇怪,因为我认为错误的映射应该在 monitor info mem 中而不是在 tlb 中。如果正确的映射在 TLB 中,那么它应该可以正常工作。 monitor info mem 中是否存在某种错误?

编辑 3

我仍在努力,我从 monitor xp/fmt 命令获得了物理内存映射。开始了:

(gdb) monitor xp/260xg 0x600000
0000000000600000: 0x0000000000000000 0x0000000000000000
0000000000600010: 0x0000000000000000 0x0000000000000000
0000000000600020: 0x0000000000000000 0x0000000000000000
0000000000600030: 0x0000000000000000 0x0000000000000000
0000000000600040: 0x0000000000000000 0x0000000000000000
0000000000600050: 0x0000000000000000 0x0000000000000000
0000000000600060: 0x0000000000000000 0x0000000000000000
0000000000600070: 0x0000000000000000 0x0000000000000000
0000000000600080: 0x0000000000000000 0x0000000000000000
0000000000600090: 0x0000000000000000 0x0000000000000000
00000000006000a0: 0x0000000000000000 0x0000000000000000
00000000006000b0: 0x0000000000000000 0x0000000000000000
00000000006000c0: 0x0000000000000000 0x0000000000000000
00000000006000d0: 0x0000000000000000 0x0000000000000000
00000000006000e0: 0x0000000000000000 0x0000000000000000
00000000006000f0: 0x0000000000000000 0x0000000000000000
0000000000600100: 0x0000000000000000 0x0000000000000000
0000000000600110: 0x0000000000000000 0x0000000000000000
0000000000600120: 0x0000000000000000 0x0000000000000000
0000000000600130: 0x0000000000000000 0x0000000000000000
0000000000600140: 0x0000000000000000 0x0000000000000000
0000000000600150: 0x0000000000000000 0x0000000000000000
0000000000600160: 0x0000000000000000 0x0000000000000000
0000000000600170: 0x0000000000000000 0x0000000000000000
0000000000600180: 0x0000000000000000 0x0000000000000000
0000000000600190: 0x0000000000000000 0x0000000000000000
00000000006001a0: 0x0000000000000000 0x0000000000000000
00000000006001b0: 0x0000000000000000 0x0000000000000000
00000000006001c0: 0x0000000000000000 0x0000000000000000
00000000006001d0: 0x0000000000000000 0x0000000000000000
00000000006001e0: 0x0000000000000000 0x0000000000000000
00000000006001f0: 0x0000000000000000 0x0000000000000000
0000000000600200: 0x0000000000000000 0x0000000000000000
0000000000600210: 0x0000000000000000 0x0000000000000000
0000000000600220: 0x0000000000000000 0x0000000000000000
0000000000600230: 0x0000000000000000 0x0000000000000000
0000000000600240: 0x0000000000000000 0x0000000000000000
0000000000600250: 0x0000000000000000 0x0000000000000000
0000000000600260: 0x0000000000000000 0x0000000000000000
0000000000600270: 0x0000000000000000 0x0000000000000000
0000000000600280: 0x0000000000000000 0x0000000000000000
0000000000600290: 0x0000000000000000 0x0000000000000000
00000000006002a0: 0x0000000000000000 0x0000000000000000
00000000006002b0: 0x0000000000000000 0x0000000000000000
00000000006002c0: 0x0000000000000000 0x0000000000000000
00000000006002d0: 0x0000000000000000 0x0000000000000000
00000000006002e0: 0x0000000000000000 0x0000000000000000
00000000006002f0: 0x0000000000000000 0x0000000000000000
0000000000600300: 0x0000000000000000 0x0000000000000000
0000000000600310: 0x0000000000000000 0x0000000000000000
0000000000600320: 0x0000000000000000 0x0000000000000000
0000000000600330: 0x0000000000000000 0x0000000000000000
0000000000600340: 0x0000000000000000 0x0000000000000000
0000000000600350: 0x0000000000000000 0x0000000000000000
0000000000600360: 0x0000000000000000 0x0000000000000000
0000000000600370: 0x0000000000000000 0x0000000000000000
0000000000600380: 0x0000000000000000 0x0000000000000000
0000000000600390: 0x0000000000000000 0x0000000000000000
00000000006003a0: 0x0000000000000000 0x0000000000000000
00000000006003b0: 0x0000000000000000 0x0000000000000000
00000000006003c0: 0x0000000000000000 0x0000000000000000
00000000006003d0: 0x0000000000000000 0x0000000000000000
00000000006003e0: 0x0000000000000000 0x0000000000000000
00000000006003f0: 0x0000000000000000 0x0000000000000000
0000000000600400: 0x0000000000000000 0x0000000000000000
0000000000600410: 0x0000000000000000 0x0000000000000000
0000000000600420: 0x0000000000000000 0x0000000000000000
0000000000600430: 0x0000000000000000 0x0000000000000000
0000000000600440: 0x0000000000000000 0x0000000000000000
0000000000600450: 0x0000000000000000 0x0000000000000000
0000000000600460: 0x0000000000000000 0x0000000000000000
0000000000600470: 0x0000000000000000 0x0000000000000000
0000000000600480: 0x0000000000000000 0x0000000000000000
0000000000600490: 0x0000000000000000 0x0000000000000000
00000000006004a0: 0x0000000000000000 0x0000000000000000
00000000006004b0: 0x0000000000000000 0x0000000000000000
00000000006004c0: 0x0000000000000000 0x0000000000000000
00000000006004d0: 0x0000000000000000 0x0000000000000000
00000000006004e0: 0x0000000000000000 0x0000000000000000
00000000006004f0: 0x0000000000000000 0x0000000000000000
0000000000600500: 0x0000000000000000 0x0000000000000000
0000000000600510: 0x0000000000000000 0x0000000000000000
0000000000600520: 0x0000000000000000 0x0000000000000000
0000000000600530: 0x0000000000000000 0x0000000000000000
0000000000600540: 0x0000000000000000 0x0000000000000000
0000000000600550: 0x0000000000000000 0x0000000000000000
0000000000600560: 0x0000000000000000 0x0000000000000000
0000000000600570: 0x0000000000000000 0x0000000000000000
0000000000600580: 0x0000000000000000 0x0000000000000000
0000000000600590: 0x0000000000000000 0x0000000000000000
00000000006005a0: 0x0000000000000000 0x0000000000000000
00000000006005b0: 0x0000000000000000 0x0000000000000000
00000000006005c0: 0x0000000000000000 0x0000000000000000
00000000006005d0: 0x0000000000000000 0x0000000000000000
00000000006005e0: 0x0000000000000000 0x0000000000000000
00000000006005f0: 0x0000000000000000 0x0000000000000000
0000000000600600: 0x0000000000000000 0x0000000000000000
0000000000600610: 0x0000000000000000 0x0000000000000000
0000000000600620: 0x0000000000000000 0x0000000000000000
0000000000600630: 0x0000000000000000 0x0000000000000000
0000000000600640: 0x0000000000000000 0x0000000000000000
0000000000600650: 0x0000000000000000 0x0000000000000000
0000000000600660: 0x0000000000000000 0x0000000000000000
0000000000600670: 0x0000000000000000 0x0000000000000000
0000000000600680: 0x0000000000000000 0x0000000000000000
0000000000600690: 0x0000000000000000 0x0000000000000000
00000000006006a0: 0x0000000000000000 0x0000000000000000
00000000006006b0: 0x0000000000000000 0x0000000000000000
00000000006006c0: 0x0000000000000000 0x0000000000000000
00000000006006d0: 0x0000000000000000 0x0000000000000000
00000000006006e0: 0x0000000000000000 0x0000000000000000
00000000006006f0: 0x0000000000000000 0x0000000000000000
0000000000600700: 0x0000000000000000 0x0000000000000000
0000000000600710: 0x0000000000000000 0x0000000000000000
0000000000600720: 0x0000000000000000 0x0000000000000000
0000000000600730: 0x0000000000000000 0x0000000000000000
0000000000600740: 0x0000000000000000 0x0000000000000000
0000000000600750: 0x0000000000000000 0x0000000000000000
0000000000600760: 0x0000000000000000 0x0000000000000000
0000000000600770: 0x0000000000000000 0x0000000000000000
0000000000600780: 0x0000000000000000 0x0000000000000000
0000000000600790: 0x0000000000000000 0x0000000000000000
00000000006007a0: 0x0000000000000000 0x0000000000000000
00000000006007b0: 0x0000000000000000 0x0000000000000000
00000000006007c0: 0x0000000000000000 0x0000000000000000
00000000006007d0: 0x0000000000000000 0x0000000000000000
00000000006007e0: 0x0000000000000000 0x0000000000000000
00000000006007f0: 0x0000000000000000 0x0000000000000000
0000000000600800: 0x000000000060103b 0x0000000000000000
0000000000600810: 0x0000000000000000 0x0000000000000000
(gdb) monitor xp/64xg 0x601000
0000000000601000: 0x000000000060203b 0x000000000060301b
0000000000601010: 0x000000000060401b 0x000000000060503b
0000000000601020: 0x0000000000000000 0x0000000000000000
0000000000601030: 0x0000000000000000 0x0000000000000000
0000000000601040: 0x0000000000000000 0x0000000000000000
0000000000601050: 0x0000000000000000 0x0000000000000000
0000000000601060: 0x0000000000000000 0x0000000000000000
0000000000601070: 0x0000000000000000 0x0000000000000000
0000000000601080: 0x0000000000000000 0x0000000000000000
0000000000601090: 0x0000000000000000 0x0000000000000000
00000000006010a0: 0x0000000000000000 0x0000000000000000
00000000006010b0: 0x0000000000000000 0x0000000000000000
00000000006010c0: 0x0000000000000000 0x0000000000000000
00000000006010d0: 0x0000000000000000 0x0000000000000000
00000000006010e0: 0x0000000000000000 0x0000000000000000
00000000006010f0: 0x0000000000000000 0x0000000000000000
0000000000601100: 0x000000000051101b 0x0000000000000000
0000000000601110: 0x0000000000000000 0x0000000000000000
0000000000601120: 0x0000000000000000 0x0000000000000000
0000000000601130: 0x0000000000000000 0x0000000000000000
0000000000601140: 0x0000000000000000 0x0000000000000000
0000000000601150: 0x0000000000000000 0x0000000000000000
0000000000601160: 0x0000000000000000 0x0000000000000000
0000000000601170: 0x0000000000000000 0x0000000000000000
0000000000601180: 0x0000000000000000 0x0000000000000000
0000000000601190: 0x0000000000000000 0x0000000000000000
00000000006011a0: 0x0000000000000000 0x0000000000000000
00000000006011b0: 0x0000000000000000 0x0000000000000000
00000000006011c0: 0x0000000000000000 0x0000000000000000
00000000006011d0: 0x0000000000000000 0x0000000000000000
00000000006011e0: 0x0000000000000000 0x0000000000000000
00000000006011f0: 0x0000000000000000 0x0000000000000000
(gdb) monitor xp/16xg 0x511000
0000000000511000: 0x000000000051201b 0x0000000000000000
0000000000511010: 0x0000000000000000 0x0000000000000000
0000000000511020: 0x0000000000000000 0x0000000000000000
0000000000511030: 0x0000000000000000 0x0000000000000000
0000000000511040: 0x0000000000000000 0x0000000000000000
0000000000511050: 0x0000000000000000 0x0000000000000000
0000000000511060: 0x0000000000000000 0x0000000000000000
0000000000511070: 0x0000000000000000 0x0000000000000000
(gdb) monitor xp/16xg 0x512000
0000000000512000: 0x0000000000000000 0x0000000000000000
0000000000512010: 0x0000000000000000 0x0000000000000000
0000000000512020: 0x000000080000401b 0x000000080000501b
0000000000512030: 0x000000080000601b 0x000000080000701b
0000000000512040: 0x0000000000000000 0x0000000000000000
0000000000512050: 0x0000000000000000 0x0000000000000000
0000000000512060: 0x0000000000000000 0x0000000000000000
0000000000512070: 0x0000000000000000 0x0000000000000000

映射似乎是正确的。我认为问题是缓存,但 CR3 寄存器是 0x600018(缓存禁用位设置)。基本上应该禁用缓存。

基本上,我使用这个 link 来找出 BAR 指向的配置 space 的大小:How is a PCI / PCIe BAR size determined?.

这是一种误导,因为它也没有说明,当您执行此操作时,BAR 会改变位置并破坏我的代码。

monitor info mem命令return地址错误是正常的,因为BAR指向的内存(32GB以上)不存在。因此,该命令返回到 0x4000 而不是 returning 正确的地址。与此同时,monitor info tlb return 是正确的地址。这可能只是软件行为。我发现 link 指出 info tlb 名称具有误导性,因为它实际上并不 return TLB 条目。它只是读取页表并return找到它的内容。

到头来,一切都是固定的。我只需要用它的最后一个值重写 xHCI BAR 就可以使代码工作。即使这样,monitor info mem 命令也不会 return 正确的地址,但实际使用的映射会映射到正确的地址。我的困惑来自这样一个事实,即读取 xHC 的寄存器总是 returned 0。当我使用 info mem 时,它 returned 错误的地址所以我认为这是罪魁祸首,而真正的罪魁祸首是检查 BAR 指向的配置 space 大小的代码。