cassemblyx86kernelvesa

VESA skipping "blocks" of video memory when trying to fill the screen


I'm developing a simple OS' kernel and I am trying to make a working video library so I can use it later. (VBE version 3.0, 1920 * 1080px, 32bpp).
I wrote a pixel plotting function in C which seems to be working fine:

void putPixelRGB(struct MODEINFOBLOCK mib, short x, short y, int color) {
   int *pos = (char *)mib.framebuffer + x * 4 + y * 7680;
       *pos = color;
}

Then I tried to fill the whole screen using this function and two for loops:

for(int i = 0; i < 1920; i++) {
   for(int j = 0; j < 1080; j++) {
      putPixelRGB(mib, i, j, 0xFFFFFF);
   }
}

This is the result that I ended up with so far:

enter image description here


(I even tried to fill each single byte in the video memory with 0xFF to make sure that I'm not altering other pixels or stuff :P... and, uhh.. I got the same result.)

dloop:
   mov byte[eax], 0xFF           ;eax contains the address of the FB memory.
   inc eax
   cmp eax, 829440               ;829440 = 1920 * 1080 * 4
   jg done
   jmp dloop

done:
   hlt

Any idea why this doesn't work? Did I access memory the wrong way?


EDIT:

The MODEINFOBLOCK structure:

struct MODEINFOBLOCK {
    int attributes;
    char windowA, windowB;
    int granularity;
    int windowSize;
    int segmentA, segmentB;
    long winFuncPtr;
    int pitch;      

    int resolutionX, resolutionY;
    char wChar, yChar, planes, bpp, banks;
    char memoryModel, bankSize, imagePages;
    char reserved0;

    char readMask, redPosition;           
    char greenMask, greenPosition; 
    char blueMask, bluePosition;
    char reservedMask, reservedPosition;
    char directColorAttributes;

    char* framebuffer;                     
    long offScreenMemOff;
    int offScreenMemSize;
    char  reserved1 [206];
};

Solution

  • You probably didn't enable the A20 gate.

    With A20 gate disabled, the 21st bit of physical addresses is ignored/masked to zero (to help emulate an old 8086 CPU where there were only 20 address lines). The result is that when you try to fill the frame buffer; the first 1 MiB of pixels works, then the second 1 MiB of pixels overwrites the first 1 MiB of pixels (leaving an unfilled black band), then the third 1 MiB of pixels works but gets overwritten by the fourth 1 MiB of pixels, and so on.

    This creates "filled and not filled" horizontal bands. If you do the math, ("1 MiB / 1920 / 4") you'd expect the horizontal bands to be about 136.5 pixels tall; so there'd be slightly more than 7 bands ("1000 / 136.5"); which is what you're getting.

    To enable the A20 gate; see https://wiki.osdev.org/A20_Line .