System frozen after attempting to modify a page directory entry

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Spatialflunky1
Posts: 1
Joined: Fri Jul 26, 2024 12:23 am

System frozen after attempting to modify a page directory entry

Post by Spatialflunky1 »

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):

Code: Select all

(*page) |= flags;
The code that contains the above line (drivers/mem.c):

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;
}
The code that calls the above functions (drivers/vga.c):

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();
}
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)
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: System frozen after attempting to modify a page directory entry

Post by Octocontrabass »

Spatialflunky1 wrote: Fri Jul 26, 2024 1:09 amI 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.
You need to set up your own page tables instead of relying on the firmware's page tables. I'm not sure why it's freezing instead of giving you a page fault, though - unless perhaps your page fault handler is broken.
Spatialflunky1 wrote: Fri Jul 26, 2024 1:09 amVirtualBox
VirtualBox has a built-in debugger. That should help you figure out why it's freezing instead of calling one of your exception handlers.
Spatialflunky1 wrote: Fri Jul 26, 2024 1:09 am(drivers/vga.c)
This is a linear framebuffer driver, not a VGA driver.
Spatialflunky1 wrote: Fri Jul 26, 2024 1:09 am

Code: Select all

            PFlag_PAT);
It's a different bit for 4 kiB pages.
Post Reply