Page 1 of 1

Unable to Write/Read from Framebuffer multiboot2

Posted: Sun Jan 19, 2025 7:28 am
by MrGoblings
Hello,
I've encountered a problem when trying to access the framebuffer address `0xFD000000`, which is parsed from the boot_info from the EBX register.

My OS seems to halt when trying to execute a read/write operation on the pointer.
(referenced from here - https://github.com/Mrgoblings/AnasOS/bl ... in.rs#L172)

Code: Select all

    unsafe { // halts on the first println
        println!("Pixel value before: {:#x}", *(framebuffer_virt_addr.as_mut_ptr::<u32>()));
        *(framebuffer_virt_addr.as_mut_ptr::<u32>()) = 0x00FF00; // Set to green
        println!("Pixel value after: {:#x}", *(framebuffer_virt_addr.as_mut_ptr::<u32>()));
    }
I've identity mapped the whole framebuffer to virtual addresses in a manner like this:
(referenced from here - https://github.com/Mrgoblings/AnasOS/bl ... fer.rs#L95)

Code: Select all

pub fn map_framebuffer(
    framebuffer_phys_addr: PhysAddr,
    framebuffer_size: u64,
    framebuffer_virt_addr: VirtAddr,
    mapper: &mut OffsetPageTable,
    frame_allocator: &mut BootInfoFrameAllocator,
) -> Result<(), &'static str> {
    if framebuffer_phys_addr.as_u64() % 4096 != 0 || framebuffer_virt_addr.as_u64() % 4096 != 0 {
        panic!("Framebuffer addresses must be 4KiB aligned.");
    }


    let framebuffer_start_page: Page<Size4KiB> = Page::containing_address(framebuffer_virt_addr);
    let framebuffer_end_page: Page<Size4KiB> = Page::containing_address(
        framebuffer_virt_addr + framebuffer_size as u64 - 1u64
    );

    let mut current_page = framebuffer_start_page;

    while current_page <= framebuffer_end_page {
        let frame = PhysFrame::containing_address(framebuffer_phys_addr + (current_page.start_address().as_u64() - framebuffer_virt_addr.as_u64()));
        let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_CACHE;

        unsafe {
            mapper.map_to(current_page, frame, flags, frame_allocator)
                  .expect("Frame allocation failed in map_framebuffer")
                  .flush();
        }

        current_page += 1;
    }

    Ok(())
}
As of my research, the multiboot2 is responsible for allocating the physical memory. Mapping it to virtual should be enough to access it accordingly.

My header.asm file:
(referenced from here - https://github.com/Mrgoblings/AnasOS/bl ... header.asm)

Code: Select all

SECTION .multiboot_header
ALIGN 8
header_start:
    ; Multiboot2 magic number
    DD 0xE85250D6            ; Magic number
    ; Architecture (protected mode i386)
    DD 0
    ; Header length
    DD header_end - header_start
    ; Checksum
    DD -(0xE85250D6 + 0 + (header_end - header_start))

    ; Console Flags Tag
    ALIGN 8
    DW 4                     ; Tag type: Console flags
    DW 0                     ; Flags: Optional
    DD 12                    ; Size of this tag
    DD 1                     ; Console flags (Bit 0 set)

    ; Framebuffer Tag
    ALIGN 8
    DW 5                     ; Tag type: Framebuffer
    DW 0                     ; Flags: Optional
    DD 20                    ; Size of this tag
    DD 1280                  ; Preferred framebuffer width
    DD 720                   ; Preferred framebuffer height
    DD 32                    ; Preferred bits per pixel

    ; End Tag
    ALIGN 8
    DD 0                     ; Tag type: End tag
    DD 8                     ; Size of end tag
header_end:

At some point while testing with the embedded_graphics framebuffer i managed to get a PageFault like this:
(referenced from here - https://github.com/Mrgoblings/AnasOS/bl ... in.rs#L198)

Code: Select all

EXCEPTION: PAGE FAULT
Accessed Address: VirtAddr(0xfd0466e0)
Error Code: PageFaultErrorCode(CAUSED_BY_WRITE)
InterruptStackFrame {
    instruction_pointer: VirtAddr(
        0x12122c,
    ),
    code_segment: 8,
    cpu_flags: 0x200206,
    stack_pointer: VirtAddr(
        0x12e648,
    ),
    stack_segment: 0,
}

Any comments on the topic would be highly appreciated,
Thank you in advanced!

Re: Unable to Write/Read from Framebuffer multiboot2

Posted: Sun Jan 19, 2025 5:58 pm
by Octocontrabass
I would guess something is going wrong in the code that actually manipulates the page tables, but I'm not familiar enough with Rust to spot any bugs.

I suggest attaching a debugger to QEMU and using it to examine the contents of your page tables before and after each attempt to modify them. You can also use the QEMU monitor to decode the current page tables ("info mem" and "info tlb"), which should be much faster than decoding them by hand.