I'm writing a small x86-64 OS I boot with UEFI. I am trying to make the kernel a higher half kernel by shifting the executable of the kernel to 0x800000000000. This address should be halfway through the PML4. Basically, I should fill entry 256 of the PML4 to address this higher half. I tried to do that but my code was triple faulting. Since I test the kernel on QEMU and debug with GDB I thus used monitor info mem
in GDB to see the virtual to physical address mapping. It returned the following:
(gdb) monitor info mem
0000000000000000-0000000000400000 0000000000400000 -rw
ffff800000000000-ffff800000c00000 0000000000c00000 -rw
Instead of having mapped 0x800000000000 it mapped ffff800000000000. This is probably why the code is triple faulting when I jump to the higher half. Here's a small example of the code I have:
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\n\t"
"mov %rax, %cr3\n\t"
"movq $0x375000, %rsp\n\t"
);
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\n\t"
"movq $8, 8(%rsp)\n\t"
"movabsq $fun, %rax\n\t"
"mov %rax, (%rsp)\n\t"
"lretq\n\t"
"fun:\n\t"
"movq $0x10, %rax\n\t"
"mov %ax, %ss\n\t"
"mov %ax, %es\n\t"
"mov %ax, %ds\n\t"
"mov %ax, %gs\n\t"
"mov %ax, %fs\n\t"
"hlt"
);
}
I have a pointer to the PML4 address then I do *(pml4Ptr + 256) = 0x20601b;
. This should map entry 256 of PML4 to 0x206000 without caching. The rest of the small code snippet under the kernel mapping section should map 12MB of data in the higher half of the virtual address starting from physical address 0. Instead, I get the addresses above which seems weird.
If I set entry 255 of the PML4 with the same code (*(pml4Ptr + 255) = 0x20601b;
), I get the result below:
(gdb) monitor info mem
0000000000000000-0000000000400000 0000000000400000 -rw
00007f8000000000-00007f8000c00000 0000000000c00000 -rw
I actually get the right addresses!? Is there a known bug that QEMU doesn't address the PML4 properly when you fill the higher half or is there something I overlooked in my code?
I also looked at the page tables directly (since they are placed at static positions in RAM). I get the following result:
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |[email protected]......|
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 |................|
This dump seems correct. It starts at 0x200000. It means that address 0 in the dump is 0x200000, address 0x1000 is 0x201000 etc.
I compile the code with this script:
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
Can anyone pinpoint any problem with the code or anything I overlooked?