Search (using Google):  Web Karig

 

7 March 2004

Experimenting with VBE

I decided to see what video resolutions my Soyo laptop offers, so I wrote a boot sector to find out. The boot sector does not access the hard disk; it simply calls the BIOS to retrieve data about the video card and dumps the data to the screen.

There are two functions that I use here:

  • INT 10h, AX=4F00: Return VBE Controller Information. This writes into memory a 512-byte block of data about the video card, such as the amount of memory on the video card and a list of video modes that the card supports.
  • INT 10h, AX=4F01: Return VBE Mode Information. This writes into memory a 256-byte block of data about a particular video mode, such as the video resolution, the number of bits per pixel (and therefore the number of colors supported), whether the mode is text or graphics, whether the mode is color or monochrome, how the bits representing a pixel must be laid out, and whether the mode supports a linear frame buffer (a single large chunk of memory representing all of the screen display).

(Online references: The VESA VBE 3.0 Standard (PDF). Here I link to pages in an online version of the VBE 2.0 Standard for convenience.)

Note that there are different versions of VBE. The most recent as of this writing is 3.0; the earliest public standard was 1.0. I need at least Version 2.0, because that was when VESA introduced support for linear frame buffers. A linear frame buffer is a single large chunk of memory representing the entire screen display. If the current graphics mode provides a linear frame buffer, any pixel on the screen can be changed at any time. If the current graphics mode does not provide a linear frame buffer, then you could change only some of the pixels on the screen, and if you wanted to change pixels on another part of the screen, you'd have to change the current "bank" first. Using a linear frame buffer is simpler and requires less code.

Code and results

Here is the boot-sector source code.

After setting up the segment registers and stack and clearing the screen, the code calls function 0x4F00 to get the video card information. The buffer into which this data is saved begins right after the boot-sector code, at address 0x7E00. Note that the first four bytes in the buffer must contain the characters "VBE2". This tells the function to return information relevant to VBE 2.0.

		mov	ax, 0x4F00
		mov	di, 0x7E00 ; 512-byte buffer
		mov	ebx, "VBE2"
		mov	[di], ebx
		int	0x10

This done, I then dump the first 32 bytes of the data to the screen.

		mov	bx, 0x7E00
		call	dump_16
		call	dump_16

This part of the code prints the following two lines on the screen:

0000:7E00: 56 45 53 41 00 02 22 7F 00 00 00 00 00 00 22 7E | VESA  ".      "~
0000:7E10: 00 00 10 00 02 01 00 7F 00 00 09 7F 00 00 1D 7F |        .   .   .

There are a number of fields here, but I care only about the following:

  • VbeSignature (7E00..7E03): 56 45 53 41
    The letters here need to be, and are, "VESA".
  • VbeVersion (7E04..7E05): 00 02
    The version needs to be, and is, 0x0200 (2.0).
  • VideoModePtr (7E0E..7E11): 22 7E 00 00
    This is a real-mode far pointer (0:0x7E22) to the array of video-mode numbers supported by the video card in my laptop.
  • TotalMemory (7E12..7E13): 10 00
    This is the number of 64KB blocks of memory on the video card. Divide this by sixteen to get the number of megabytes of video memory. The number 0x0010 is 16, so the video card in my laptop has just one megabyte of video memory.

Next, I want to display a list of the video modes that my laptop supports. I'm hoping to find the mode 0x114 listed. The VBE standard states that this mode usually offers (though apparently is not guaranteed to offer) 800x600 resolution and 65,536 colors. I'd go for a higher resolution or more colors, except that the video card has only one megabyte of memory. If I were to try for 1024x768 resolution, for example, I'd have to settle for a palette of only 256 colors. If I wanted more colors, I'd have to settle for a smaller video resolution. So in this case, 800x600 resolution with 65,536 colors is a decent tradeoff.

So I load the VideoModePtr from address 0x7E0E and dump the first 32 bytes pointed to.

		mov	bx, [0x7E0E]
		call	dump_16
		call	dump_16

The list turns out to contain fifteen video-mode numbers (in hex): 100, 101, 102, 103, 104, 105, 10D, 10E, 110, 111, 112, 113, 114, 120, and 121. (The last value, FFFF, signals the end of the list.)

0000:7E22: 00 01 01 01 02 01 03 01 04 01 05 01 0D 01 0E 01 |
0000:7E32: 10 01 11 01 12 01 13 01 14 01 20 01 21 01 FF FF |             ! ..

So mode 0x114 is supported. Let's see if this video card's mode 0x114 is indeed 800x600 with 65,536 colors.

To do this, I use function 0x4F01. I pass in CX the number of the video mode I want to investigate, and I pass in DI the address to which the data should be saved.

		mov	ax, 0x4F01
		mov	cx, 0x114
		mov	di, 0x7F00 ; ModeInfoBlock is 256 bytes long
		int	0x10

This function returns quite a bit more information that I'm interested in than does 0x4F00, so I dump more bytes to the screen:

		mov	bx, 0x7F00
		call	dump_16
		call	dump_16
		call	dump_16
		call	dump_16

These are the bytes dumped:

0000:7F00: 9F 00 07 00 40 00 40 00 00 A0 00 00 A5 1F 00 C0 | .   @ @  .  .  .
0000:7F10: 40 06 20 03 58 02 08 10 01 10 01 06 00 00 01 05 | @   X           
0000:7F20: 0B 06 05 05 00 00 00 00 00 00 00 E0 00 A8 0E 00 |            . .
0000:7F30: 94 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | .

There are more fields in this data than I discuss here. The fields I care about are the following:

  • ModeAttributes (7F00..7F01): 9F 00
    I only care about the bits in the first byte (0x9F in hex is 10011111 in binary):
    • bit 0 = 1. This means that the video card supports mode 0x114.
    • bit 3 = 1. This means that this mode offers color (it isn't a monochrome mode).
    • bit 4 = 1. This means that this mode is a graphics mode (you don't print with predesigned characters; you draw with pixels).
    • bit 5 = 0. This means that I can use the standard VGA I/O ports to draw if I want to.
    • bit 7 = 1. This is the biggie. This tells me that this mode does indeed offer a linear frame buffer, so that I can draw the whole screen in memory and then have the screen image copied into the video memory all at once. Woohoo!
  • BytesPerScanLine (7F10..7F11): 40 06
    0x0640 is 1600, which of course is the number of pixels in a line (800) times the number of bytes per pixel (2).
  • XResolution (7F12..7F13): 20 03
    YResolution (7F14..7F15): 58 02
    0x0320 is 800, the number of pixels in a scanline. 0x258 is 600, the number of scanlines on the screen. So the resolution is indeed 800x600.
  • BitsPerPixel (7F19): 10
    0x10 is 16, which means that mode 0x114 does offer 16-bit color.
  • MemoryModel (7F1B): 06
    -- direct color -- see MaskSize and FieldPosition fields below --
  • RedMaskSize (7F1F): 05
    RedFieldPosition (7F20): 0B
    GreenMaskSize (7F21): 06
    GreenFieldPosition (7F22): 05
    BlueMaskSize (7F23): 05
    BlueFieldPosition (7F24): 00
    These six fields, taken together, indicate the layout of bits in a word that represents a screen pixel. The bits in the word are thus rrrr rggg gggb bbbb, with bit 15 coming first and bit 0 coming last, and 'r', 'g', and 'b' indicating 'red', 'green', and 'blue' respectively.
  • PhysBasePtr (7F28): 00 00 00 E0
    This is the 32-bit physical memory address (0xE0000000) that corresponds to the video card memory. If I'm using an 800x600, 16-bit color bitmap in memory to represent the screen, I'd copy the bitmap to this address to update the screen. (Note that I have no plans to include hardware memory paging or address translation in Karig, so I'd be able to address the video memory directly.)

Modes 0x120 and 0x121?

Curiosity led me to investigate the modes 0x120 and 0x121 that my Soyo offers. Neither are improvements over my chosen mode 0x114 for my purposes, for both modes offer only 320x240 resolution.

How will I use this information?

I suspect that I won't include in Karig the code to do all of this investigating. I'll probably just write code that expects mode 0x114 and a linear frame buffer to be available and complains if they aren't. If my code expects a certain video resolution and color depth, then I don't have to write code to support other video resolutions or color depths. I also don't plan on writing code to support "banking" video modes that can't use a linear frame buffer. Video mode 0x114 is apparently a standard, and the VBE 2.0 standard is now years old, so there is a good chance that Karig will work on most recent computers.

I probably will have to write code to get the address of video memory, though. The video memory on my laptop is at physical address 0xE0000000, while Chuck Moore's ColorForth source code lists two other possible physical addresses: 0xF0000000, apparently the video address used in Fujitsu computers; and 0xF2000000, apparently the video address used by the NVIDIA video card inside an eMonster PC. So there doesn't seem to be any standard on exactly where video card manufacturers should make the video card memory "appear" within the main memory space.

Update — 2004-03-09

Disappointment! It turns out that, while the Soyo's video card supports 800x600 resolution, the built-in monitor only supports 640x480!

How did I find out? Well, as it turns out, the Windows 2000 OS that came with the Soyo was not destroyed by my MBR experiments as I had thought. I booted my Soyo to see if my new MBR-modifying code had worked properly, and lo and behold, Windows starts booting. So I let it finish booting, loaded up Control Panel, and decided to see what the screen looked like in 800x600 resolution.

Well, 800x600 resolution looked a lot like 640x480 resolution — except that when you moved the mouse to the edge of the screen, the screen scrolled so that you could see another part of the 800x600 virtual screen show up on the 640x480 real screen. Ugh. This was not a good sign.

Sure enough, when I ran some experimental boot code to set graphic mode 0x114 and to cover the 800x600 screen with six color bars (each 100 scanlines high), the screen showed only five bars, and the bar on the bottom looked a little shorter than the others.

So that's how I know that my Soyo is stuck with 640x480 resolution. Still, it's not a total loss. I have been working on a font to use in 800x600 resolution, with each character 8 pixels wide and 16 pixels high. If the resolution is 640x480, I can still display 80 characters on a line (the same as in text mode) and 30 lines on the screen (an improvement over text mode's 25 lines).

Check the index for other entries.