VESA graphics page flipping in protected mode

568 views Asked by At

I am trying to figure out how the page flip in 32-bit protected mode. I run 0x4F0A and store the output table at 0x00008100. Would I be correct that the command to set the LFB location should be located at 0x00008102? Knowing this is the location for that command, how would I change the location of the LFB in c then without returning to real mode?

void main() {
    char vmem_back_buffer0[3932160];
    char vmem_back_buffer1[3932160];
    char* prot_mode_desc  = (char*)0x00008102;

    /* ... code to file those buffers with data is removed for brevity ... */

    // Here I change the LFB location to vmem_back_buffer0
    // Here I change the LFB location to vmem_back_buffer1

    while (TRUE);
}
1

There are 1 answers

0
Brendan On

I am trying to figure out how the page flip in 32-bit protected mode. I run 0x4F0A and store the output table at 0x00008100. Would I be correct that the command to set the LFB location should be located at 0x00008102?

The 16-bit value at 0x00008102 may contain the offset (in VBE's code segment) of the "Set/Get Display Start" function. If it does, you'd need to set up various descriptors in your GDT (e.g. "32-bit code segment for VBE", "data segment for VBE") and use a 32-bit far call to load CS with "32-bit code segment for VBE" while also loading EIP with the (zero extended to 32-bit) "value at 0x00008102" after you've loaded DS and/or ES with whatever VBE needed.

However; for VBE 3.0 (the latest version and the most likely VBE version for computers that aren't 20+ years old) the function is optional and might not exist. Instead; VBE 3.0 added a "VBE 3.0 protected mode interface" (which is 16-bit code for protected mode, allowing video ROM to recycle existing code and worry less about running out of space in the tiny 64 KiB ROM).

Of course for very old video cards (before VBE 2.0) the "VBE 3.0 protected mode interface" will never exist.

This means that to support "all VBE" you have to use either real mode, virtual8086 mode or an interpreter for VBE 1.2 and older; and may use the same "real mode, virtual8086 mode or an interpreter" for both VBE 2.0 and VBE 3.0 (to avoid extra hassle dealing with both "VBE 2.0 protected mode interface" and "VBE 3.0 protected mode interface").

There are also other problems; mainly, VBE doesn't provide any "IRQ on vertical sync", if you use the "set display start on vertical sync" option (in VBE's "Set/Get Display Start" function) it will waste a huge amount of CPU time polling to detect if/when vertical sync has started, and if you don't do that you'll end up with tearing (and avoiding tearing is the entire point of doing "page flip" in the first place). It is possible to fix that by using a timer to emulate "IRQ on vertical sync" (specifically, call "Set/Get Display Start" when the timer expires and then use how long it takes "Set/Get Display Start" to return to adjust when the timer will expire next, so that you know the timer will expire just before the vertical sync happens).

The other thing to worry about is bugs in the VBE's code. In general frequently used code (e.g. to set a video mode) is more heavily tested and less likely to have bugs, and rarely used code (e.g. to set the display start) is more likely to have bugs (and crash, and ruin everything). I'm not sure, but I think it is possible to mitigate some of the risk by isolating VBE's code (executed via. either "VBE protected mode interface") inside a "CPL=3 sandbox" (like a process).

Of course for modern computers (with UEFI) VBE itself doesn't exist at all; and UEFI doesn't provide any alternative way to do page flipping. This means that (if you use VBE and page flipping) it will be hard to port the OS to hardware that is still relevant later.

For all of these reason; it's better to use "boot loader sets up a frame buffer using whatever firmware provides, and kernel/OS only uses the frame buffer and nothing else (until/unless it starts native video driver/s)"; and avoid a huge amount of work for something that (at best) can't work well.

Knowing this is the location for that command, how would I change the location of the LFB in c then without returning to real mode?

Most C compilers don't support segmentation; which means that you'd have to use an assembly language stub to load VBE's segments (including a "far call" that loads VBE's code segment) and restore your normal segments afterwards.

You'd also need to worry about what happens if an IRQ occurs while VBE's code is running. You really don't want to disable IRQs (because there's no guarantee that VBE's function will be fast and no guarantee that disabling IRQs wile VBE's code is running won't ruin IRQ latency for all of your device drivers, especially for the "waste lots of CPU time while waiting for vertical sync" case); so all interrupt handlers will want to be able to handle interrupting VBE's code.

Apart from that; you can think of "display start" as the offset in the LFB where the first pixel sent to the monitor will be (note that "display start" can also be used for smooth scrolling - e.g. move "display start" one row of pixels only to scroll vertically one pixel at a time). You'll also need some safeguards (e.g. fall back to "no page flipping" if the LFB isn't large enough for 2 frames, based on the "TotalMemory (in 64 KiB chunks)" field of the structure returned by VBE's "Return Controller Information" and the vertical resolution and "bytesPerLine" taken from the structure returned by VBE's "Get Mode Information").