Problem parsing Multiboot2 struct

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
spyder23
Posts: 3
Joined: Sat Jun 04, 2022 1:29 am

Problem parsing Multiboot2 struct

Post by spyder23 »

Following the wiki and tutorials I've successfully managed to boot my kernel and print using BIOS in long mode, however now I want to use a GOP framebuffer. I'm stuck trying to draw anything.
This is how my multiboot_header looks like:

Code: Select all

section .multiboot_header
align 8
header_start:
    dd 0xe85250d6                ; magic
    dd 0
    dd header_end - header_start

    dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) ; checksum

    ; framebuffer
    dw 5
    dw 0
    dd 20
    dd 640
    dd 480
    dd 32


    dw 0    ; end tag
    dw 0   ; flags
    dd 8    ; required
header_end:
This works, as the QEMU window resizes to 640x480.
Since I'm using long mode, I pass rbx to rdi before calling the kernel function:

Code: Select all

global long_mode_start
section .text
bits 64
long_mode_start:
    mov ax, 0
    mov ss, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov rdi, rbx
    extern kernel_main
    call kernel_main
    hlt
And this is how I try to parse the struct, adapting a minimal version from the Multiboot2 specification example (I also dropped in multiboot2.h) and using a method from the wiki to draw a pixel:

Code: Select all

#include <stdint.h>
#include "multiboot2.h"

extern "C" void kernel_main(unsigned long mbi_addr) {
    auto addr = mbi_addr;
    for (auto tag = (struct multiboot_tag *) ((uint8_t *) addr + 8);
         tag->type != MULTIBOOT_TAG_TYPE_END;
         tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7))) {

        switch (tag->type) {
            case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: {
                auto *tagfb = (struct multiboot_tag_framebuffer *) tag;
                auto *fb = (multiboot_uint64_t *) (unsigned long) tagfb->common.framebuffer_addr;
                *((uint32_t *) (fb + 4 * tagfb->common.framebuffer_pitch * 100 + 4 * 100)) = 0xFFFFFFFF;
                break;
            }
        }
    }
}

The pixel isn't drawn and QEMU restarts after a while. Please help

EDIT: After going back to BIOS output and trying to just parse the multiboot header, the problem seems to occur when updating the tag value in the for loop. It enters the loop once and then triple faults.
davmac314
Member
Member
Posts: 121
Joined: Mon Jul 05, 2021 6:57 pm

Re: Problem parsing Multiboot2 struct

Post by davmac314 »

Is it possible your ebx value has been lost (overwritten) before you jump to long mode?

(You really should just attach a debugger and single-step through. You're almost certainly going to have to do that at a later stage anyway, may as well get used to it now.)

Edit: also, what do you mean by this?
and print using BIOS in long mode
You can't use the BIOS in long mode.
spyder23
Posts: 3
Joined: Sat Jun 04, 2022 1:29 am

Re: Problem parsing Multiboot2 struct

Post by spyder23 »

davmac314 wrote:Is it possible your ebx value has been lost (overwritten) before you jump to long mode?

(You really should just attach a debugger and single-step through. You're almost certainly going to have to do that at a later stage anyway, may as well get used to it now.)
I'm not touching ebx anywhere in the boot process, is there something else that could affect it?
I'll try to attach a debugger and go from there. I thought that since I managed to print text, drawing a few pixels would be easy :P
You can't use the BIOS in long mode.
I got a little confused. I am not using the BIOS I was just printing to 0xB8000.
davmac314
Member
Member
Posts: 121
Joined: Mon Jul 05, 2021 6:57 pm

Re: Problem parsing Multiboot2 struct

Post by davmac314 »

I'm not touching ebx anywhere in the boot process, is there something else that could affect it?
I mean generally not, but one thought I just had: are you sure the framebuffer, and also the multiboot information structure, are mapped into memory? I.e. how have you set up the paging for long mode?
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Problem parsing Multiboot2 struct

Post by kzinti »

spyder23 wrote:

Code: Select all

                auto *fb = (multiboot_uint64_t *) (unsigned long) tagfb->common.framebuffer_addr;
                *((uint32_t *) (fb + 4 * tagfb->common.framebuffer_pitch * 100 + 4 * 100)) = 0xFFFFFFFF;
The pixel isn't drawn and QEMU restarts after a while. Please help
1) I am not sure what a "multiboot_uint64_t" is, but if this is a uint64_t, it means you are doing your framebuffer calculations using 8 bytes entities. It's probably better to use uintptr_t (or a uint8_t*) for calculations to avoid such problems. This could explain the crash / not seeing the pixel. Also do not multiple the pitch by 4! The size of pixels is already taken into account in the pitch.

Code: Select all

auto fb = (uintptr_t)tagfb->common.framebuffer_addr;
auto pixel = (uint32_t*)(fb + tagfb->common.framebuffer_pitch * 100 + 4 * 100);
*pixel = 0xFFFFFFFF;
2) Are you sure the framebuffer is 32 bits? - This probably would not explain the crash.
Last edited by kzinti on Mon Jun 06, 2022 10:14 am, edited 2 times in total.
spyder23
Posts: 3
Joined: Sat Jun 04, 2022 1:29 am

Re: Problem parsing Multiboot2 struct

Post by spyder23 »

davmac314 wrote:
I'm not touching ebx anywhere in the boot process, is there something else that could affect it?
I mean generally not, but one thought I just had: are you sure the framebuffer, and also the multiboot information structure, are mapped into memory? I.e. how have you set up the paging for long mode?
Even though I went through the code several times, this magically made me see the issues.

1. I forgot to loop when setting up identity paging
2. I didn't have KEEP for the multiboot_header in the linker file
3. ebx was actually changed somehow, so I moved it into rdi at the very beginning instead of right before calling kernel_main
4. The tags themselves were not aligned properly (I was getting unsupported tag 0x8)

I can now parse the multiboot information struct without triple faulting so I guess the problem in the title is solved.
I still triple fault when trying to write to the framebuffer but that's probably because it's not in the first 2MB that I have mapped. I'll continue without it for now and set up IDT & serial and try to understand what I'm doing without just blindly following tutorials.

I appreciate both of you for your help.
Post Reply