Search code examples
user-interfaceoperating-systemosdev

How to draw pixel on screen without BIOS?


I am writing an OS and want to have GUI. I can't find good tutorial for drawing pixels on the screen.

I'd like to have some assembly + C example which I can build and run on some emulator like BOCHS or v86


Solution

  • Top answer did a very good job of explaining. You did ask for some example code, so here's a code snippet from my GitHub, and a detailed explanation will follow.

    1. bios_setup:
    2.  mov ah, 00h     ; tell the bios we'll be in graphics mode
    3.  mov al, 13h
    4.  int 10h         ; call the BIOS
    
    5.  mov ah, 0Ch     ; set video mode
    6.  mov bh, 0       ; set output vga
    7.  mov al, 0       ; set initial color
    8.  mov cx, 0       ; x = 0
    9.  mov dx, 0       ; y = 0
    
    10. int 10h         ; BIOS interrupt
    

    Line 2 is where the fun begins. Firstly, we move the value 0 into the ah register. At line 3, we move 13 hex into al - now we're ready for our BIOS call. Line 4 calls the bios with interrupt vector 10 hex. BIOS now checks in ah and al.

    AH:
     - tells BIOS to set video mode
    AL:
     - tells BIOS to enter write string mode.
    

    Now that we called the interrupt on line 4, we're ready to move new values into some registers. At line 5, we put 0C hex into the ah register. This tells BIOS that we want to write a graphics pixel. At line 6, we throw 0 into the bh register, which tells BIOS that we'll be either using a CGA, EGA, MCGA, or VGA adapter to output. So output mode 0 basically. And next all we have to do is set our color. So lets start at 0, which is black. That's all nice, but where do we want to actually draw this black pixel to? That's where lines 8-9 come in, where registers cx and dx store the x,y coordinates of the pixel to draw, respectively. Once they are set, we call the BIOS with interrupt 10 hex. And the pixel in drawn.

    After reading Brendan's elaborate and informative answer, this code will make much more sense. Certain values must be in certain registers before calling the BIOS simply because those are the registers in which the according interrupt will check. Everything else is pretty straight forward. If you want another color, simply change the value in al. You want to blit your pixel somewhere else? Mess around with the x and y values in cx and dx. Again, this isn't very efficient for graphics intensive programs as it is pretty slow. For educational purposes, however, it beats writing your own graphics driver ;)

    You can still get some efficiency by drawing everything in a buffer in RAM before blitting to the screen, as Brendan said, but I'd much rather keep it simple in my example.

    Check out the full - free - example on my GitHub. I've also included a README and a Makefile, but they are Linux exclusive. If you're running on Windows, some googling will yield any information necessary to assembling the OS to a bootable floppy, and just about any virtual machine host will do. Also, feel free to ask me about anything that's unclear. Cheers!

    Ps: I did not write a tool, simply a small script in NASM that is meant to be assembled to a floppy and ran as a kernel (in a VM if you will)