为什么QEMU在填写PML4的上半部分时返回错误的地址? [英] Why does QEMU return the wrong addresses when filling the higher half of the PML4?

查看:0
本文介绍了为什么QEMU在填写PML4的上半部分时返回错误的地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个使用UEFI引导的小型x86-64操作系统。我试图通过将内核的可执行文件移到0x800000000000来使内核成为更高的半内核。此地址应该在PML4的中间。基本上,我应该填写PML4的第256项来处理这较高的一半。我试图这样做,但我的代码出现了三重错误。由于我在QEMU上测试内核并使用gdb进行调试,因此我在gdb中使用monitor info mem来查看虚拟地址到物理地址的映射。它返回以下内容:

(gdb) monitor info mem
0000000000000000-0000000000400000 0000000000400000 -rw
ffff800000000000-ffff800000c00000 0000000000c00000 -rw

它映射的不是0x800000000000,而是ffff800000000000。这可能就是当我跳到较高的一半时代码出现三重故障的原因。以下是我的代码的一个小示例:

typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
typedef unsigned long UINT64;

struct GDT{
    UINT64 nullDescriptor;
    
    UINT16 codeLimit;
    UINT16 codeBaseLow;
    UINT8 codeBaseMid;
    UINT8 codeFlags;
    UINT8 codeLimitMid;
    UINT8 codeBaseHigh;
    
    UINT16 dataLimit;
    UINT16 dataBaseLow;
    UINT8 dataBaseMid;
    UINT8 dataFlags;
    UINT8 dataLimitMid;
    UINT8 dataBaseHigh;
}__attribute__((packed));

struct GDTR{
    UINT16 size;
    GDT* address;
}__attribute__((packed));

void main(){
    //Identity mapping for the first 4MB
    UINT64* pml4Ptr = (UINT64*)0x200000;
    *pml4Ptr = 0x20101b;
    
    UINT64* pdpPtr = (UINT64*)0x201000;
    *pdpPtr = 0x20201b;
    
    UINT64* pdPtr = (UINT64*)0x202000;
    *pdPtr = 0x20301b;
    *(pdPtr + 1) = 0x20401b;
    
    UINT64* ptPtr = (UINT64*)0x203000;
    UINT64 physAddr = 0x1b;
    for (UINT32 i = 0; i < 2 * 512; i++){
        *(ptPtr + i) = physAddr;
        physAddr += 0x1000;
    }
    
    //Kernel mapping for the higher half
    *(pml4Ptr + 256) = 0x20601b; //When this is less then 256 I get the right addresses
    
    pdpPtr = (UINT64*)0x206000;
    *pdpPtr = 0x20701b;
    
    pdPtr = (UINT64*)0x207000;
    *pdPtr = 0x20801b;
    *(pdPtr + 1) = 0x20901b;
    *(pdPtr + 2) = 0x20a01b;
    *(pdPtr + 3) = 0x20b01b;
    *(pdPtr + 4) = 0x20c01b;
    *(pdPtr + 5) = 0x20d01b;
    
    ptPtr = (UINT64*)0x208000;
    physAddr = 0x1b;
    for (UINT32 i = 0; i < 6 * 512; i++){
        *(ptPtr + i) = physAddr;
        physAddr += 0x1000;
    }

    asm volatile(
    "movq $0x200018, %rax
	"
    "mov %rax, %cr3
	"
    "movq $0x375000, %rsp
	"
    );
        
    GDT gdt = {
        .nullDescriptor = 0,
        
        .codeLimit = 0x0000,
        .codeBaseLow = 0,
        .codeBaseMid = 0,
        .codeFlags = 0x9a,
        .codeLimitMid = 0xaf,
        .codeBaseHigh = 0,
        
        .dataLimit = 0x0000,
        .dataBaseLow = 0,
        .dataBaseMid = 0,
        .dataFlags = 0x92,
        .dataLimitMid = 0x00,
        .dataBaseHigh = 0
    };
    
    GDT* gdtAddr = &gdt;
    GDTR gdtr = { 23, gdtAddr };
    GDTR* gdtrAddr = &gdtr;
    
    asm volatile("lgdt (%0)" : : "r"(gdtrAddr));
    
    asm volatile(
    "sub $16, %rsp
	"
    "movq $8, 8(%rsp)
	"
    "movabsq $fun, %rax
	"
    "mov %rax, (%rsp)
	"
    "lretq
	"
    "fun:
	"
    "movq $0x10, %rax
	"
    "mov %ax, %ss
	"
    "mov %ax, %es
	"
    "mov %ax, %ds
	"
    "mov %ax, %gs
	"
    "mov %ax, %fs
	"
    "hlt"
    );
}

我有指向PML4地址的指针,然后我就有了。这应该在不缓存的情况下将PML4的条目256映射到0x206000。内核映射部分下的其余小代码片段应该映射从物理地址0开始的虚拟地址的上半部分中的12MB数据。相反,我得到了上面的地址,这似乎很奇怪。

如果我用相同的代码(*(pml4Ptr + 255) = 0x20601b;)设置PML4的条目255,结果如下:

(gdb) monitor info mem
0000000000000000-0000000000400000 0000000000400000 -rw
00007f8000000000-00007f8000c00000 0000000000c00000 -rw

我实际上得到了正确的地址!?是否存在已知的错误,即QEMU在填写上半部分时无法正确处理PML4,或者我的代码中有什么疏忽?

我还直接查看了页表(因为它们被放置在RAM中的静态位置)。我得到以下结果:

user@user-System-Product-Name:~$ hexdump -C result.bin
00000000  3b 10 20 00 00 00 00 00  00 00 00 00 00 00 00 00  |;. .............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000800  1b 60 20 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  3b 20 20 00 00 00 00 00  00 00 00 00 00 00 00 00  |;  .............|
00001010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00002000  1b 30 20 00 00 00 00 00  3b 40 20 00 00 00 00 00  |.0 .....;@ .....|
00002010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00003000  1b 00 00 00 00 00 00 00  1b 10 00 00 00 00 00 00  |................|
00003010  1b 20 00 00 00 00 00 00  1b 30 00 00 00 00 00 00  |. .......0......|
00003020  1b 40 00 00 00 00 00 00  1b 50 00 00 00 00 00 00  |.@.......P......|
00003030  1b 60 00 00 00 00 00 00  1b 70 00 00 00 00 00 00  |.`.......p......|
00003040  1b 80 00 00 00 00 00 00  1b 90 00 00 00 00 00 00  |................|
00003050  1b a0 00 00 00 00 00 00  1b b0 00 00 00 00 00 00  |................|
00003060  1b c0 00 00 00 00 00 00  1b d0 00 00 00 00 00 00  |................|
00003070  1b e0 00 00 00 00 00 00  1b f0 00 00 00 00 00 00  |................|
00003080  1b 00 01 00 00 00 00 00  1b 10 01 00 00 00 00 00  |................|
00003090  1b 20 01 00 00 00 00 00  1b 30 01 00 00 00 00 00  |. .......0......|
000030a0  1b 40 01 00 00 00 00 00  1b 50 01 00 00 00 00 00  |.@.......P......|
000030b0  1b 60 01 00 00 00 00 00  1b 70 01 00 00 00 00 00  |.`.......p......|
000030c0  1b 80 01 00 00 00 00 00  1b 90 01 00 00 00 00 00  |................|
000030d0  1b a0 01 00 00 00 00 00  1b b0 01 00 00 00 00 00  |................|
000030e0  1b c0 01 00 00 00 00 00  1b d0 01 00 00 00 00 00  |................|
000030f0  1b e0 01 00 00 00 00 00  1b f0 01 00 00 00 00 00  |................|
00003100  1b 00 02 00 00 00 00 00  1b 10 02 00 00 00 00 00  |................|
00003110  1b 20 02 00 00 00 00 00  1b 30 02 00 00 00 00 00  |. .......0......|
00003120  1b 40 02 00 00 00 00 00  1b 50 02 00 00 00 00 00  |.@.......P......|
00003130  1b 60 02 00 00 00 00 00  1b 70 02 00 00 00 00 00  |.`.......p......|
00003140  1b 80 02 00 00 00 00 00  1b 90 02 00 00 00 00 00  |................|
00003150  1b a0 02 00 00 00 00 00  1b b0 02 00 00 00 00 00  |................|
00003160  1b c0 02 00 00 00 00 00  1b d0 02 00 00 00 00 00  |................|
00003170  1b e0 02 00 00 00 00 00  1b f0 02 00 00 00 00 00  |................|
00003180  1b 00 03 00 00 00 00 00  1b 10 03 00 00 00 00 00  |................|
00003190  1b 20 03 00 00 00 00 00  1b 30 03 00 00 00 00 00  |. .......0......|
000031a0  1b 40 03 00 00 00 00 00  1b 50 03 00 00 00 00 00  |.@.......P......|
000031b0  1b 60 03 00 00 00 00 00  1b 70 03 00 00 00 00 00  |.`.......p......|
000031c0  1b 80 03 00 00 00 00 00  1b 90 03 00 00 00 00 00  |................|
000031d0  1b a0 03 00 00 00 00 00  1b b0 03 00 00 00 00 00  |................|
000031e0  1b c0 03 00 00 00 00 00  1b d0 03 00 00 00 00 00  |................|
000031f0  1b e0 03 00 00 00 00 00  1b f0 03 00 00 00 00 00  |................|
00003200  1b 00 04 00 00 00 00 00  1b 10 04 00 00 00 00 00  |................|
00003210  1b 20 04 00 00 00 00 00  1b 30 04 00 00 00 00 00  |. .......0......|
00003220  1b 40 04 00 00 00 00 00  1b 50 04 00 00 00 00 00  |.@.......P......|
00003230  1b 60 04 00 00 00 00 00  1b 70 04 00 00 00 00 00  |.`.......p......|
00003240  1b 80 04 00 00 00 00 00  1b 90 04 00 00 00 00 00  |................|
00003250  1b a0 04 00 00 00 00 00  1b b0 04 00 00 00 00 00  |................|
00003260  1b c0 04 00 00 00 00 00  1b d0 04 00 00 00 00 00  |................|
00003270  1b e0 04 00 00 00 00 00  1b f0 04 00 00 00 00 00  |................|
00003280  1b 00 05 00 00 00 00 00  1b 10 05 00 00 00 00 00  |................|
...
...
00004fa0  1b 40 3f 00 00 00 00 00  1b 50 3f 00 00 00 00 00  |.@?......P?.....|
00004fb0  1b 60 3f 00 00 00 00 00  1b 70 3f 00 00 00 00 00  |.`?......p?.....|
00004fc0  1b 80 3f 00 00 00 00 00  1b 90 3f 00 00 00 00 00  |..?.......?.....|
00004fd0  1b a0 3f 00 00 00 00 00  1b b0 3f 00 00 00 00 00  |..?.......?.....|
00004fe0  1b c0 3f 00 00 00 00 00  1b d0 3f 00 00 00 00 00  |..?.......?.....|
00004ff0  1b e0 3f 00 00 00 00 00  1b f0 3f 00 00 00 00 00  |..?.......?.....|
00005000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00006000  1b 70 20 00 00 00 00 00  00 00 00 00 00 00 00 00  |.p .............|
00006010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00007000  1b 80 20 00 00 00 00 00  1b 90 20 00 00 00 00 00  |.. ....... .....|
00007010  1b a0 20 00 00 00 00 00  1b b0 20 00 00 00 00 00  |.. ....... .....|
00007020  1b c0 20 00 00 00 00 00  1b d0 20 00 00 00 00 00  |.. ....... .....|
00007030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00008000  1b 00 00 00 00 00 00 00  1b 10 00 00 00 00 00 00  |................|
00008010  1b 20 00 00 00 00 00 00  1b 30 00 00 00 00 00 00  |. .......0......|
00008020  1b 40 00 00 00 00 00 00  1b 50 00 00 00 00 00 00  |.@.......P......|
00008030  1b 60 00 00 00 00 00 00  1b 70 00 00 00 00 00 00  |.`.......p......|
00008040  1b 80 00 00 00 00 00 00  1b 90 00 00 00 00 00 00  |................|
00008050  1b a0 00 00 00 00 00 00  1b b0 00 00 00 00 00 00  |................|
00008060  1b c0 00 00 00 00 00 00  1b d0 00 00 00 00 00 00  |................|
00008070  1b e0 00 00 00 00 00 00  1b f0 00 00 00 00 00 00  |................|
00008080  1b 00 01 00 00 00 00 00  1b 10 01 00 00 00 00 00  |................|
00008090  1b 20 01 00 00 00 00 00  1b 30 01 00 00 00 00 00  |. .......0......|
000080a0  1b 40 01 00 00 00 00 00  1b 50 01 00 00 00 00 00  |.@.......P......|
000080b0  1b 60 01 00 00 00 00 00  1b 70 01 00 00 00 00 00  |.`.......p......|
000080c0  1b 80 01 00 00 00 00 00  1b 90 01 00 00 00 00 00  |................|
000080d0  1b a0 01 00 00 00 00 00  1b b0 01 00 00 00 00 00  |................|
000080e0  1b c0 01 00 00 00 00 00  1b d0 01 00 00 00 00 00  |................|
000080f0  1b e0 01 00 00 00 00 00  1b f0 01 00 00 00 00 00  |................|
00008100  1b 00 02 00 00 00 00 00  1b 10 02 00 00 00 00 00  |................|
00008110  1b 20 02 00 00 00 00 00  1b 30 02 00 00 00 00 00  |. .......0......|
00008120  1b 40 02 00 00 00 00 00  1b 50 02 00 00 00 00 00  |.@.......P......|
00008130  1b 60 02 00 00 00 00 00  1b 70 02 00 00 00 00 00  |.`.......p......|
00008140  1b 80 02 00 00 00 00 00  1b 90 02 00 00 00 00 00  |................|
00008150  1b a0 02 00 00 00 00 00  1b b0 02 00 00 00 00 00  |................|
00008160  1b c0 02 00 00 00 00 00  1b d0 02 00 00 00 00 00  |................|
00008170  1b e0 02 00 00 00 00 00  1b f0 02 00 00 00 00 00  |................|
00008180  1b 00 03 00 00 00 00 00  1b 10 03 00 00 00 00 00  |................|
00008190  1b 20 03 00 00 00 00 00  1b 30 03 00 00 00 00 00  |. .......0......|
000081a0  1b 40 03 00 00 00 00 00  1b 50 03 00 00 00 00 00  |.@.......P......|
000081b0  1b 60 03 00 00 00 00 00  1b 70 03 00 00 00 00 00  |.`.......p......|
000081c0  1b 80 03 00 00 00 00 00  1b 90 03 00 00 00 00 00  |................|
000081d0  1b a0 03 00 00 00 00 00  1b b0 03 00 00 00 00 00  |................|
000081e0  1b c0 03 00 00 00 00 00  1b d0 03 00 00 00 00 00  |................|
000081f0  1b e0 03 00 00 00 00 00  1b f0 03 00 00 00 00 00  |................|
00008200  1b 00 04 00 00 00 00 00  1b 10 04 00 00 00 00 00  |................|
00008210  1b 20 04 00 00 00 00 00  1b 30 04 00 00 00 00 00  |. .......0......|
00008220  1b 40 04 00 00 00 00 00  1b 50 04 00 00 00 00 00  |.@.......P......|
00008230  1b 60 04 00 00 00 00 00  1b 70 04 00 00 00 00 00  |.`.......p......|
00008240  1b 80 04 00 00 00 00 00  1b 90 04 00 00 00 00 00  |................|
00008250  1b a0 04 00 00 00 00 00  1b b0 04 00 00 00 00 00  |................|
00008260  1b c0 04 00 00 00 00 00  1b d0 04 00 00 00 00 00  |................|
00008270  1b e0 04 00 00 00 00 00  1b f0 04 00 00 00 00 00  |................|
00008280  1b 00 05 00 00 00 00 00  1b 10 05 00 00 00 00 00  |................|
00008290  1b 20 05 00 00 00 00 00  1b 30 05 00 00 00 00 00  |. .......0......|
000082a0  1b 40 05 00 00 00 00 00  1b 50 05 00 00 00 00 00  |.@.......P......|
000082b0  1b 60 05 00 00 00 00 00  1b 70 05 00 00 00 00 00  |.`.......p......|
000082c0  1b 80 05 00 00 00 00 00  1b 90 05 00 00 00 00 00  |................|
000082d0  1b a0 05 00 00 00 00 00  1b b0 05 00 00 00 00 00  |................|
000082e0  1b c0 05 00 00 00 00 00  1b d0 05 00 00 00 00 00  |................|
000082f0  1b e0 05 00 00 00 00 00  1b f0 05 00 00 00 00 00  |................|
00008300  1b 00 06 00 00 00 00 00  1b 10 06 00 00 00 00 00  |................|
00008310  1b 20 06 00 00 00 00 00  1b 30 06 00 00 00 00 00  |. .......0......|
00008320  1b 40 06 00 00 00 00 00  1b 50 06 00 00 00 00 00  |.@.......P......|
00008330  1b 60 06 00 00 00 00 00  1b 70 06 00 00 00 00 00  |.`.......p......|
00008340  1b 80 06 00 00 00 00 00  1b 90 06 00 00 00 00 00  |................|
00008350  1b a0 06 00 00 00 00 00  1b b0 06 00 00 00 00 00  |................|
00008360  1b c0 06 00 00 00 00 00  1b d0 06 00 00 00 00 00  |................|
00008370  1b e0 06 00 00 00 00 00  1b f0 06 00 00 00 00 00  |................|
00008380  1b 00 07 00 00 00 00 00  1b 10 07 00 00 00 00 00  |................|
00008390  1b 20 07 00 00 00 00 00  1b 30 07 00 00 00 00 00  |. .......0......|
000083a0  1b 40 07 00 00 00 00 00  1b 50 07 00 00 00 00 00  |.@.......P......|
000083b0  1b 60 07 00 00 00 00 00  1b 70 07 00 00 00 00 00  |.`.......p......|
000083c0  1b 80 07 00 00 00 00 00  1b 90 07 00 00 00 00 00  |................|
000083d0  1b a0 07 00 00 00 00 00  1b b0 07 00 00 00 00 00  |................|
000083e0  1b c0 07 00 00 00 00 00  1b d0 07 00 00 00 00 00  |................|

这个转储似乎是正确的。从0x200000开始。表示转储中的地址0为0x200000,地址0x1000为0x201000,依此类推。

我用以下脚本编译代码:

g++ -fomit-frame-pointer --static -ffreestanding -nostdlib -mgeneral-regs-only -mno-red-zone -c -m64 Startup/Source/Main.cpp -oStartup/Object/Main.o
ld -entry main --oformat elf64-x86-64 --no-dynamic-linker -static -nostdlib -Ttext-segment=300000 Startup/Object/Main.o -ostartup.elf

有人能指出代码或我忽略的任何问题吗?

推荐答案

0x800000000000不是规范地址,因此在页面目录布局中没有它的位置。(并尝试取消引用它将#GP错误,而不是触发TLB未命中=&>页面遍历。)

您有PML4,因此前16个虚拟地址位必须是第#47位的副本。即指针必须可表示为48位值符号-扩展到64位。
((int64_t)addr << 16) >> 16 == addr必须为真。
(使用sar算术右移进行右移)。
(x86-64 canonical address?)。

可用(规范)范围的上半部分实际上从ffff800000000000开始,其PML4E紧跟在下半部分上半部分的PML4E之后,00007f8000000000

Address canonical form and pointer arithmetic包括虚拟地址空间中漏洞的ASCII图。

关于下半部分的顶部在哪里,您是正确的,但是您忘记了将0x800000000000符号扩展到64位以达到上半部分的底部。指针名义上仍然是64位的,而不仅仅是被截断为48位。这就是为什么像ffff800000000000这样的地址可以存在。


如果您启用了PML5(例如,Ice Lake硬件或该功能的软件模拟),则额外的页目录级别将为您提供高达57位的虚拟地址空间,从而可以寻址0x800000000000

另见x86-64: canonical addresses and actual available range

这篇关于为什么QEMU在填写PML4的上半部分时返回错误的地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆