System frozen after attempting to modify a page directory entry
Posted: Fri Jul 26, 2024 1:09 am
I'm fairly new to OS development and I've gotten to the point where I'm trying to improve my framebuffer's performance in my UEFI-based OS. I've read that if I want to improve it I should double-buffer my video and set the framebuffer's memory to Write-Combining (WC) using the page attribute table. I was successful in locating the address to the 2 MiB page but when I try to modify it in any way, it causes the entire system to freeze. This only happens on about half of the devices I've tried it on, however. The code can run in QEMU and one of my laptops, but it causes the lockup on VirtualBox and a second laptop. I also know that it is not just the display freaking out since I'm modifying its memory mapping as I tested the code out with the backbuffer as well. (Ignore the messy and horribly unoptimized code)
The link to the entire repository: https://github.com/spatialflunky1/flosp-os
The specific line that causes the lockup (drivers/mem.c):
The code that contains the above line (drivers/mem.c):
The code that calls the above functions (drivers/vga.c):
I recorded a few videos of the system trying to boot. Although after uploading I realized the compression made the quality terrible but you can still somewhat see that the system is or isn't locked up based on how the screen flickers and you can just barely make out the changing address on the topmost line.
----------------------------------------------
Videos of the code working as intended:
https://drive.google.com/file/d/1m8b0AH ... drive_link (Lenovo IdeaPad Z580)
https://drive.google.com/file/d/1aos8Fz ... drive_link (QEMU)
Videos of the system lockup:
https://drive.google.com/file/d/1q1CEm1 ... drive_link (VBox)
https://drive.google.com/file/d/1LJNwr1 ... drive_link (Lenovo Thinkpad P16s)
The link to the entire repository: https://github.com/spatialflunky1/flosp-os
The specific line that causes the lockup (drivers/mem.c):
Code: Select all
(*page) |= flags;
Code: Select all
void set_mem_page_flags(void* addr, ui64_t flags) {
ui64_t* page = (ui64_t*)get_mem_page(addr);
blank_output();
// Address
kprint("\nAddress: ");
kprint_hex((ui64_t)addr, true);
// Page address
kprint("\nPage_Addr: ");
kprint_hex((ui64_t)page, true);
// Page
kprint("\nPage: ");
kprint_hex(*page, true);
// Flags
kprint("\nFlags: ");
kprint_hex(flags, true);
flush_framebuffer();
/*
No Need for the commented out code below as in this current test case the caching type (or memory type at all) does not change
*/
// // Remove previous mapping
// (*page) &= ~0x1;
// // Flush the TLB
// invlpg(addr);
// // Create a new mapping in the page tables
(*page) |= flags;
// (*page) |= 0x1;
// kprint("\nMapping created");
// flush_buffer();
kprint("\nPage(Post): ");
kprint_hex((*page), true);
flush_framebuffer();
blank_output();
flush_framebuffer();
}
void* get_mem_page(void* addr) {
// Indexing bits:
// ---------------
// 47-39: PML4 (9 bits)
// 38-30: PDPT (9 bits)
// 29-21: PD (9 bits)
// 20-12: PT (9 bits)
// 0-11: The page itself (12 bits)
map_table* PML4 = (map_table*)(read_cr3() & 0xFFFFFFFFFFFFF000); // First 12 bits are to be ignored
ui64_t PML4_index = ((ui64_t)addr >> 39) & 0b111111111;
map_table* PDP = (map_table*)(PML4->entries[PML4_index] & PAGE_ADDR_MASK);
ui64_t PDP_index = ((ui64_t)addr >> 30) & 0b111111111;
void* page = NULL;
//ui8_t page_offset_width = 0;
if ((PDP->entries[PDP_index] >> 7) & 0x1) {
// Pages are 1 GiB (ignore PD)
page = &PDP->entries[PDP_index];
//page_offset_width = 30;
}
else {
map_table* PD = (map_table*)(PDP->entries[PDP_index] & PAGE_ADDR_MASK);
ui64_t PD_index = ((ui64_t)addr >> 21) & 0b111111111;
if ((PD->entries[PD_index] >> 7) & 0x1) {
// Pages are 2 Mib (ignore PT)
page = &PD->entries[PD_index];
//page_offset_width = 21;
}
else {
// Pages are 4 Kib (use PT)
map_table* PT = (map_table*)(PD->entries[PD_index] & PAGE_ADDR_MASK);
ui64_t PT_index = ((ui64_t)addr >> 12) & 0b111111111;
page = &PT->entries[PT_index];
//page_offset_width = 12;
}
}
return page;
}
Code: Select all
void initialize_video(BOOT_VIDEO_MODE_INFO* VMI) {
VideoModeInfo = VMI;
framebuffer_info.width = VideoModeInfo->PixelsPerScanline;
framebuffer_info.height = VideoModeInfo->VerticalResolution;
framebuffer_info.pitch = VideoModeInfo->PixelsPerScanline * 4;
framebuffer_info.depth = 32;
max_text_line = (framebuffer_info.height / font_size) - 1;
// Set framebuffer page tables to look to PAT PA4 (instead of memory default PA0)
// THIS SHOULD WORK AS IS RIGHT NOW AS THE MEMORY MODE IS NOT CHANGING (PAT modification commented out below) (WB -> WB)
for (ui64_t i = 0; i < (framebuffer_info.width * framebuffer_info.height * 4); i++) {
set_mem_page_flags(
(void*)((ui64_t)VideoModeInfo->FramebufferPointer + i),
PFlag_PAT);
}
// // Set PAT PA4 to Write-Combining mode (mode 001)
// ui32_t low,high;
// rdmsr(0x277, &low, &high);
// low |= 0b00100000000000000000000000000000000; // Set bit 32
// low &= ~0b11000000000000000000000000000000000; // Clear bits 33 and 34
// wrmsr(0x277, low, high);
blank_output();
}
----------------------------------------------
Videos of the code working as intended:
https://drive.google.com/file/d/1m8b0AH ... drive_link (Lenovo IdeaPad Z580)
https://drive.google.com/file/d/1aos8Fz ... drive_link (QEMU)
Videos of the system lockup:
https://drive.google.com/file/d/1q1CEm1 ... drive_link (VBox)
https://drive.google.com/file/d/1LJNwr1 ... drive_link (Lenovo Thinkpad P16s)