VBE Linear framebuffer - not very linear at all!

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
scdown
Posts: 13
Joined: Tue Jun 05, 2018 4:43 pm
Libera.chat IRC: stephennnnn

VBE Linear framebuffer - not very linear at all!

Post by scdown »

Hi all,

I've started to write a very basic OS. I'm having some trouble with the linear framebuffer, however. It works fine in Qemu, but in virtualbox, or on real hardware, I can only write to the first 2MB of it. Past that point, things start to get weird - the screen wraps around back to the top, but offset to the right - and then eventually jumps to the bottom of the screen. The framebuffer address is about 10 times bigger on virtualbox/bare metal (About 0xE000000) so I wonder if it's related to an integer overflow of some sort.

Source code: https://git.scd31.com/laptopdude90/SteveOS/

VIdeo is first set up in boot/video.asm
The offending function is in drivers/screen.c (fillrect() - which generates the background)

I have tried a memcpy and memset directly to the framebuffer - both suffer from the same issues. At this point I have no idea how to debug further.

Screenshots:
https://img.scd31.com/up/15349708260cf53f6.png <- shows how screen wraps back up
https://img.scd31.com/up/1534971984396f61e.png <- shows how text wraps

Could it possibly have something to do with the GDT? (boot/gdt.asm)
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: VBE Linear framebuffer - not very linear at all!

Post by Brendan »

Hi,
scdown wrote:The offending function is in drivers/screen.c (fillrect() - which generates the background)
On line 25 and 29 in "putpixel()", and on lines 35, 42 and 43 of "filrect()"; you're doing calculations wrong. Specifically, you're doing "COLOR_BITS/8" to calculate how many bytes a pixel takes up, but (for 15-bpp video mode) with integer arithmetic "15/8 = 1" which is wrong. You need something more like "(COLOR_BITS+7)/8" so that it rounds up and you get the correct result (2 bytes per pixel, not one byte per pixel); or even better you could do a "bytes_per_pixel = (COLOR_BITS+7)/8;" once in "setup_video()" so that you don't have to repeatedly calculate it everywhere.

This bug means that every time you write a pixel it gets put at the wrong place; and I suspect that all of the other code relies on either "putpixel()" (which is very bad for performance) or "fillrect()", so everything gets drawn at the wrong place. I'd also assume that on Qemu you got a 16-bpp video mode (where "16/8 = 2") so it was right and worked by accident.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Octocontrabass
Member
Member
Posts: 5586
Joined: Mon Mar 25, 2013 7:01 pm

Re: VBE Linear framebuffer - not very linear at all!

Post by Octocontrabass »

It looks an awful lot like you didn't enable the A20 line.
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: VBE Linear framebuffer - not very linear at all!

Post by MichaelPetch »

Octocontrabass is exactly right.You haven't enabled A20 so all the odd megabyte memory areas are mapped to the even numbered megabyte memory region just below it. On some system A20 is enabled and some it isn't. So it depends on the emulator or the hardware as to what state it is in. You should always enable it. See this OSDev article on enabling A20 line

As well you should really consider creating a linker script and create a BSS section that you can get the beginning and the end - and then initialize that memory to 0 rather than relying on being lucky that the memory is zeroed out. GRUB does the zeroing for you, but since you are using your own bootloader that job is left to you.

Since you are using x87 for floating point to keep BOCHS happy you should consider using the finit instruction to initialize the FPU before calling into your kernel.
scdown
Posts: 13
Joined: Tue Jun 05, 2018 4:43 pm
Libera.chat IRC: stephennnnn

Re: VBE Linear framebuffer - not very linear at all!

Post by scdown »

Brendan wrote:Hi,
scdown wrote:The offending function is in drivers/screen.c (fillrect() - which generates the background)
On line 25 and 29 in "putpixel()", and on lines 35, 42 and 43 of "filrect()"; you're doing calculations wrong. Specifically, you're doing "COLOR_BITS/8" to calculate how many bytes a pixel takes up, but (for 15-bpp video mode) with integer arithmetic "15/8 = 1" which is wrong. You need something more like "(COLOR_BITS+7)/8" so that it rounds up and you get the correct result (2 bytes per pixel, not one byte per pixel); or even better you could do a "bytes_per_pixel = (COLOR_BITS+7)/8;" once in "setup_video()" so that you don't have to repeatedly calculate it everywhere.

This bug means that every time you write a pixel it gets put at the wrong place; and I suspect that all of the other code relies on either "putpixel()" (which is very bad for performance) or "fillrect()", so everything gets drawn at the wrong place. I'd also assume that on Qemu you got a 16-bpp video mode (where "16/8 = 2") so it was right and worked by accident.


Cheers,

Brendan
Thanks! I'll keep this in mind if I switch to a 15 bit colour mode in the future. I'll probably implement it sooner than that anyway, because why not?

Also, the putpixel() function isn't being used too much as it is, I've been working to make it obsolete.
scdown
Posts: 13
Joined: Tue Jun 05, 2018 4:43 pm
Libera.chat IRC: stephennnnn

Re: VBE Linear framebuffer - not very linear at all!

Post by scdown »

Octocontrabass wrote:It looks an awful lot like you didn't enable the A20 line.
MichaelPetch wrote:Octocontrabass is exactly right.You haven't enabled A20 so all the odd megabyte memory areas are mapped to the even numbered megabyte memory region just below it. On some system A20 is enabled and some it isn't. So it depends on the emulator or the hardware as to what state it is in. You should always enable it. See this OSDev article on enabling A20 line

As well you should really consider creating a linker script and create a BSS section that you can get the beginning and the end - and then initialize that memory to 0 rather than relying on being lucky that the memory is zeroed out. GRUB does the zeroing for you, but since you are using your own bootloader that job is left to you.

Since you are using x87 for floating point to keep BOCHS happy you should consider using the finit instruction to initialize the FPU before calling into your kernel.
THANK YOU BOTH SO MUCH! I'd never even heard of the A20 line, but setting this immediately fixed the issue.
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

Re: VBE Linear framebuffer - not very linear at all!

Post by azblue »

MichaelPetch wrote:Octocontrabass is exactly right.You haven't enabled A20 so all the odd megabyte memory areas are mapped to the even numbered megabyte memory region just below it. On some system A20 is enabled and some it isn't. So it depends on the emulator or the hardware as to what state it is in. You should always enable it. See this OSDev article on enabling A20 line
If I'm not mistaken a Mac will freak out if you try to enable A20 (it's already enabled). To work on Macs and PCs you should first check to see if it's already enabled, and then enable it only if it isn't already.
MichaelPetch
Member
Member
Posts: 799
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: VBE Linear framebuffer - not very linear at all!

Post by MichaelPetch »

azblue wrote: If I'm not mistaken a Mac will freak out if you try to enable A20 (it's already enabled). To work on Macs and PCs you should first check to see if it's already enabled, and then enable it only if it isn't already.
The OSDev article we linked to discuss that as well.
.
Post Reply