FrameBuffer cpu reset while trying to draw a pixel

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
User avatar
finarfin
Member
Member
Posts: 106
Joined: Fri Feb 23, 2007 1:41 am
Location: Italy & Ireland
Contact:

FrameBuffer cpu reset while trying to draw a pixel

Post 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.
Elen síla lúmenn' omentielvo
- DreamOS64 - My latest attempt with osdev: https://github.com/dreamos82/Dreamos64
- Osdev Notes - My notes about osdeving! https://github.com/dreamos82/Osdev-Notes
- My old Os Project: https://github.com/dreamos82/DreamOs
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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.
User avatar
finarfin
Member
Member
Posts: 106
Joined: Fri Feb 23, 2007 1:41 am
Location: Italy & Ireland
Contact:

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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?
Elen síla lúmenn' omentielvo
- DreamOS64 - My latest attempt with osdev: https://github.com/dreamos82/Dreamos64
- Osdev Notes - My notes about osdeving! https://github.com/dreamos82/Osdev-Notes
- My old Os Project: https://github.com/dreamos82/DreamOs
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
User avatar
finarfin
Member
Member
Posts: 106
Joined: Fri Feb 23, 2007 1:41 am
Location: Italy & Ireland
Contact:

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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?
Elen síla lúmenn' omentielvo
- DreamOS64 - My latest attempt with osdev: https://github.com/dreamos82/Dreamos64
- Osdev Notes - My notes about osdeving! https://github.com/dreamos82/Osdev-Notes
- My old Os Project: https://github.com/dreamos82/DreamOs
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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.
User avatar
finarfin
Member
Member
Posts: 106
Joined: Fri Feb 23, 2007 1:41 am
Location: Italy & Ireland
Contact:

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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!)
Elen síla lúmenn' omentielvo
- DreamOS64 - My latest attempt with osdev: https://github.com/dreamos82/Dreamos64
- Osdev Notes - My notes about osdeving! https://github.com/dreamos82/Osdev-Notes
- My old Os Project: https://github.com/dreamos82/DreamOs
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: FrameBuffer cpu reset while trying to draw a pixel

Post 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.
Post Reply