Page 1 of 1

FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 7:31 am
by finarfin
I'm trying to implement a framebuffer on my 64bit kernel, i decided to use multiboot2 tags to enable it.

So far i managed to enable the framebuffer and get information back from it.

The multiboot header is the following:

Code: Select all

section .multiboot_header
header_start:
	align 8
    dd 0xe85250d6   ;magic_number
    dd 0            ;Protected mode
    dd header_end - header_start    ;Header length

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

framebuffer_tag_start:
    dw  0x05    ;Type: framebuffer
    dw  0x01    ;Optional tag
    dd  framebuffer_tag_end - framebuffer_tag_start ;size
    dd  0   ;Width - if 0 we let the bootloader decide
    dd  0   ;Height - same as above
    dd  0   ;Depth  - same as above
framebuffer_tag_end:

    ;here ends the required part of the multiboot header
	;The following is the end tag, must be always present
    ;end tag
    align 8
    dw 0    ;type
    dw 0    ;flags
    dd 8    ;size
header_end:
And when i boot into the kernel i can find a framebuffer_tag structure in the info passed by the bootloader. I also tried to print the information and they looks pretty accurate:
Found Multiboot framebuffer: 8
---framebuffer-type: 1
---framebuffer-width: 400
---framebuffer-height: 300
---framebuffer-address: FD000000
---framebuffer-bpp: 20
All numbers above are Hex numbers! :)

But now i wrote a small function that was just trying to put a pixel somewhere, but no matter what value i write in the video memory i always get the same error. The funcion is this one:

Code: Select all

void *FRAMEBUFFER_MEM = 0;
unsigned int FRAMEBUFFER_PITCH = 0;
unsigned int FRAMEBUFFER_POS_X = 0;
unsigned int FRAMEBUFFER_POS_Y = 0;
unsigned char FRAMEBUFFER_BPP = 0;


void set_fb_data(struct multiboot_tag_framebuffer *fbtag){
    FRAMEBUFFER_MEM = (void*)(unsigned long)fbtag->common.framebuffer_addr;
    FRAMEBUFFER_PITCH = fbtag->common.framebuffer_pitch;
    FRAMEBUFFER_BPP = fbtag->common.framebuffer_bpp;
    multiboot_uint32_t *pixel = FRAMEBUFFER_MEM + fbtag->common.framebuffer_pitch * 1 + 4 * 1;
                      *pixel = 0xFFFFFFFF;
    //*FRAMEBUFFER_MEM=4;
    //multiboot_uint16_t *pixel =
    //    unsigned int *px_addr = FRAMEBUFFER_MEM + 3 * FRAMEBUFFER_BPP + 10 * FRAMEBUFFER_BPP;
    //    *px_addr++ = 4;
}
I tried to write different value on pixel address and change values but whatever i try to write, or whatever position i try to get i always get a cpu reset (probably a triple fault)

So what can be the reason?

Actually i haven't implemente interrupt handling yet was trying to sortout basic screen i/o first.

I'm in 64bit long mode. So paging is already enabled (loaded in boot phase), gdt loaded.
I was wondering if the problem can be the address returned by the bootloader that is not mapped ?
But well why in the multiboot2 example should works properly?

Another thing that is not clear to me, while looking at different tutorials vesa mode and framebuffer are more or less the same thing? writing into both of them is done the same way? Becasue sometime i read of them like different options, but then thet tutorials mention the vesa driver as the same thing.

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 7:51 am
by thewrongchristian
finarfin wrote:I'm trying to implement a framebuffer on my 64bit kernel, i decided to use multiboot2 tags to enable it.

So far i managed to enable the framebuffer and get information back from it.

And when i boot into the kernel i can find a framebuffer_tag structure in the info passed by the bootloader. I also tried to print the information and they looks pretty accurate:
Found Multiboot framebuffer: 8
---framebuffer-address: FD000000
This is a physical address.
finarfin wrote:

Code: Select all

void *FRAMEBUFFER_MEM = 0;
...
   FRAMEBUFFER_MEM = (void*)(unsigned long)fbtag->common.framebuffer_addr;
This is a virtual address.

Do you identity map the entire physical address space? If not, using a physical address as a virtual address will result in a page fault.

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 8:46 am
by finarfin
That was my suspect, i have to admit i haven't checked it yet, i'll do it soon, but i'm just wondering is it possible that the framebuffer address is around 4gb?
The address returned is 0xFD000000 that in decimal is 4244635648, is that normal?

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 8:56 am
by austanss
finarfin wrote:I'm trying to implement a framebuffer on my 64bit kernel, i decided to use multiboot2 tags to enable it.

So far i managed to enable the framebuffer and get information back from it.

The multiboot header is the following:

Code: Select all

section .multiboot_header
header_start:
	align 8
    dd 0xe85250d6   ;magic_number
    dd 0            ;Protected mode
    dd header_end - header_start    ;Header length

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

framebuffer_tag_start:
    dw  0x05    ;Type: framebuffer
    dw  0x01    ;Optional tag
    dd  framebuffer_tag_end - framebuffer_tag_start ;size
    dd  0   ;Width - if 0 we let the bootloader decide
    dd  0   ;Height - same as above
    dd  0   ;Depth  - same as above
framebuffer_tag_end:

    ;here ends the required part of the multiboot header
	;The following is the end tag, must be always present
    ;end tag
    align 8
    dw 0    ;type
    dw 0    ;flags
    dd 8    ;size
header_end:
And when i boot into the kernel i can find a framebuffer_tag structure in the info passed by the bootloader. I also tried to print the information and they looks pretty accurate:
Found Multiboot framebuffer: 8
---framebuffer-type: 1
---framebuffer-width: 400
---framebuffer-height: 300
---framebuffer-address: FD000000
---framebuffer-bpp: 20
All numbers above are Hex numbers! :)

But now i wrote a small function that was just trying to put a pixel somewhere, but no matter what value i write in the video memory i always get the same error. The funcion is this one:

Code: Select all

void *FRAMEBUFFER_MEM = 0;
unsigned int FRAMEBUFFER_PITCH = 0;
unsigned int FRAMEBUFFER_POS_X = 0;
unsigned int FRAMEBUFFER_POS_Y = 0;
unsigned char FRAMEBUFFER_BPP = 0;


void set_fb_data(struct multiboot_tag_framebuffer *fbtag){
    FRAMEBUFFER_MEM = (void*)(unsigned long)fbtag->common.framebuffer_addr;
    FRAMEBUFFER_PITCH = fbtag->common.framebuffer_pitch;
    FRAMEBUFFER_BPP = fbtag->common.framebuffer_bpp;
    multiboot_uint32_t *pixel = FRAMEBUFFER_MEM + fbtag->common.framebuffer_pitch * 1 + 4 * 1;
                      *pixel = 0xFFFFFFFF;
    //*FRAMEBUFFER_MEM=4;
    //multiboot_uint16_t *pixel =
    //    unsigned int *px_addr = FRAMEBUFFER_MEM + 3 * FRAMEBUFFER_BPP + 10 * FRAMEBUFFER_BPP;
    //    *px_addr++ = 4;
}
I tried to write different value on pixel address and change values but whatever i try to write, or whatever position i try to get i always get a cpu reset (probably a triple fault)

So what can be the reason?

Actually i haven't implemente interrupt handling yet was trying to sortout basic screen i/o first.

I'm in 64bit long mode. So paging is already enabled (loaded in boot phase), gdt loaded.
I was wondering if the problem can be the address returned by the bootloader that is not mapped ?
But well why in the multiboot2 example should works properly?

Another thing that is not clear to me, while looking at different tutorials vesa mode and framebuffer are more or less the same thing? writing into both of them is done the same way? Becasue sometime i read of them like different options, but then thet tutorials mention the vesa driver as the same thing.
The reason you are resetting is because you are lacking an IDT, and when the system raises an interrupt, most likely a page fault, it triple faults because it can't find your #PF handler.

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 9:17 am
by finarfin
Ok so better implement Interrupt handling and basic paging first and then get back to framebuffer stuff probably.

Ok so now question about paging, when i did my 32bit kernel to handle pagefault and mapping of address i was used to access pagedir/tables having each tale last entry pointing to itself, in order to be able to build addresses to esaily map things, is this tecnique still valid or there are better way to achieve it in long mode?

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Tue Mar 02, 2021 2:05 pm
by Octocontrabass
Recursive mapping is still valid in long mode. However, using the last entry means you won't be able to map your kernel in the highest 2GiB of virtual addresses, so you'll have to compile with the large code model instead of the kernel code model.

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Wed Mar 03, 2021 9:39 am
by finarfin
Thanks @Octocontrabass!

So question: what are the alternatives, what is the best for page handling? (i honestly always used the recursive mapping, thinking it was the best/easiest way to cope with paging!)

Re: FrameBuffer cpu reset while trying to draw a pixel

Posted: Wed Mar 03, 2021 10:46 am
by Octocontrabass
  • Use a different entry instead of the last entry. Your kernel can be compiled with the kernel code model and you still get recursive mapping.
  • Map all physical memory to the higher half. Physical addresses can have up to 52 bits, so in the future you might need 5-level paging (with 57-bit virtual addresses) to do this.
  • Map memory for the page tables as you create them. This is probably the most difficult option since it's a circular dependency: you need to map the page tables before you can map the page tables!
There are probably other options that I haven't thought of as well. Which one is best depends on your design goals.