Mapping full kernel causes garbage page mappings
Posted: Wed Nov 12, 2025 3:35 pm
Hi all! I have been porting a 32-bit legacy BIOS kernel to 64-bit UEFI since Sunday. The past few weeks I've gotten most stuff working, for example the GDT, and interrupts. The next thing on the list to port to 64-bit was paging. I pretty much understand the concept, and what I need to do for this port is quite simple, just
SetCR3 just sets CR3 to whatever is in RDI (which is PML4).
With the for loop condition being i < pg_size-1, I get the expected result:
However, if I set it to i < pg_size, I get a LOT of garbage mappings (over 10000!!!!!).
Why is this happening? If needed, I can provide more code.
Thanks in advance!!!!!!
- Identity map kernel space and framebuffer
- Setup recursive paging.
Code: Select all
#define MEM_PML4_INDEX(x) ((x >> (MEM_PAGE_SHIFT + 27)) & 0x1FF)
#define MEM_PDPT_INDEX(x) ((x >> (MEM_PAGE_SHIFT + 18)) & 0x1FF)
#define MEM_PAGEDIR_INDEX(x) ((x >> (MEM_PAGE_SHIFT + 9)) & 0x1FF)
#define MEM_PAGETBL_INDEX(x) ((x >> MEM_PAGE_SHIFT) & 0x1FF)
typedef union {
/* Intel SDM page 3206, Table 5-19
* (We only care about 4kb page) */
struct {
uint8_t present : 1; // Must be set if the page actually exists
uint8_t readwrite : 1; // Readonly if not set.
uint8_t user_super : 1; // Set if accessible through user mode
uint8_t pwt : 1;
uint8_t pcd : 1;
uint8_t accessed : 1; // CPU sets whenever the page table entry is accessed.
uint8_t ignored0 : 1;
uint8_t page_size : 1; // Not set if referring to a 4KB page, otherwise 2MB page.
uint8_t ignored1 : 3;
uint8_t hlat_rest : 1; // Ignored, unless HLAT paging.
uint64_t address : 28; // Physical address
uint64_t ignored2 : 23; // Thank you intel, very cool!
uint8_t exec_dis : 1;
} bits;
uint64_t data;
} page_entry;
[...]
void setup_paging(){
uint64_t kernel_start = (uint64_t)&__kernel_start;
uint64_t kernel_end = (uint64_t)&__kernel_end;
uint8_t pg_size = (kernel_end - kernel_start) / PAGE_SIZE;
printf("Mapping %08x -> %08x (kernel space), %d pages\n", kernel_start, kernel_end, pg_size);
for(uint8_t i = 0; i < pg_size; i++){
uint64_t phys = kernel_start + (i*PAGE_SIZE);
page_table[MEM_PAGETBL_INDEX(phys)].data = phys | 0b11;
}
page_directory[MEM_PAGEDIR_INDEX(kernel_start)].data = (uint64_t)&page_table | 0b11;
pdpt[MEM_PDPT_INDEX(kernel_start)].data = (uint64_t)&page_directory | 0b11;
pml4[MEM_PML4_INDEX(kernel_start)].data = (uint64_t)&pdpt | 0b11;
SetCR3(pml4);
}
With the for loop condition being i < pg_size-1, I get the expected result:
Code: Select all
(qemu) info mem
0000000000200000-0000000000212000 0000000000012000 -rw
(qemu) gva2gpa 0x200000
gpa: 0x200000
Why is this happening? If needed, I can provide more code.
Thanks in advance!!!!!!