Page 1 of 1
VBE Linear framebuffer - not very linear at all!
Posted: Wed Aug 22, 2018 6:36 pm
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)
Re: VBE Linear framebuffer - not very linear at all!
Posted: Wed Aug 22, 2018 8:22 pm
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
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 12:28 am
by Octocontrabass
It looks an awful lot like you didn't enable the
A20 line.
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 12:39 am
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.
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 6:28 am
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.
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 6:30 am
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.
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 5:39 pm
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.
Re: VBE Linear framebuffer - not very linear at all!
Posted: Thu Aug 23, 2018 8:05 pm
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.
.