10 March 2004 VBE experiment 2 My first experiment with VBE was to get information about my Soyo's 800x600 high-color mode. Unfortunately, subsequent tests revealed that, while the Soyo's video card might be capable of 800x600 resolution, the built-in monitor would not display more than 640x480 pixels at a time. So the video mode 0x114 that I was hoping to use has proven useless, and I'm settling for video mode 0x111 (640x480 resolution, 65,536 colors) instead. Naturally, I wrote a boot sector to see if I could activate video mode 0x111 and put some color onto the screen. The purpose of the code is to cover the whole screen with six equal-sized horizontal bars of color — red on top, then green, blue, magenta, yellow, and cyan. The first thing the code does, as always, is to set up a stack so that BIOS routines can be called. main: ; ------ Set up real-mode stack for BIOS calls. cli in al, 0x70 ; Disable NMIs. or al, 0x80 out 0x70, al mov ax, 0x1000 mov ss, ax xor sp, sp in al, 0x70 ; Re-enable NMIs. and al, 0x7F out 0x70, al sti The next lines of code solve a small problem I was having with an earlier version of this boot sector. The code essentially halts execution for three seconds in order to give the BIOS floppy driver time to finish and to turn off the floppy drive's LED before I turn off interrupts and enter protected mode. Without this delay, I enter protected mode before the LED is turned off, and the LED stays on — which is not a huge problem here, because the color bars still show up on the screen, but it looks unprofessional to have the LED stay on. The floppy drive isn't doing anything, so the LED should be off. To delay for three seconds, I use the system timer. The timer "ticks" eighteen times per second, so I set the timer to zero, and I just keep reading the timer until its return value is 54. ; ------ Delay for three seconds. ; ------ (Gives floppy controller time to finish BEFORE ; ------ we clear interrupts and enter protected mode.) xor cx, cx xor dx, dx mov ah, 1 int 0x1A ; set system timer to zero .zz: xor ah, ah int 0x1A cmp dx, 54 jl .zz Now I activate the graphic mode. I pass the mode number in BX — bits 0..8 contain the mode number itself, bit 14 is set to enable a linear frame buffer, and bit 15 is cleared so that the video memory will be cleared. (The VBE 2.0 specification explains mode numbers. See also the VBE 3.0 specification.) ; ------ Set VBE mode: 800x600, 64K colors mov bx, 0x4111 ; mode 0x111, linear, clear memory mov ax, 0x4F02 int 0x10 Next, I enable the A20 line so that odd-numbered megabytes are accessible to the processor. I need access to high memory here because my code writes to a buffer in memory and then copies the buffer into the video memory. For 640x480 resolution and 16-bit color, I need a 600KB buffer. I could shoehorn the buffer into conventional memory if I had to, but Karig will put the buffer into high memory anyway (the kernel, editor, and working block buffers will go into conventional memory), so I might as well write the code to handle a high-memory buffer now. Note also that I won't be needing the BIOS services anymore, so I can shut off the interrupts and keep them off. ; ------ Shut off interrupts. cli in al, 0x70 or al, 0x80 out 0x70, al ; ------ Enable A20 line. (Method used in ColorForth) mov al, 0xD1 out 0x64, al .20: in al, 0x64 and al, 2 jnz .20 mov al, 0x4B out 0x60, al To use 32-bit code, I enter protected mode. ; ------ Load GDT and enter protected mode. lgdt [gdt] mov eax, cr0 or al, 1 mov cr0, eax jmp dword 8:pmstart [BITS 32] pmstart: mov eax, dseg-gdt mov ds, eax mov es, eax mov fs, eax mov gs, eax mov ss, eax Now I can draw pixels on the graphic screen. I draw the six color bands to a buffer in memory (at address 0x200000). Because each color band is going to be 640 pixels wide by (480/6) or 80 pixels high, I need to store the 16-bit (two-byte) color value 640*80 or 51,200 times. Storing two 16-bit values into EAX means that I need to write to memory only 51200/2 or 25,600 times for each of the six bands. ; ------ Draw color bands into screen buffer. cld mov edx, 6-1 ; six color bands to draw .d: mov ecx, 640*80/2 ; number of pixels to draw / 2 mov edi, [offsets+edx*4] mov eax, [colors+edx*4] rep stosd dec edx jns .d The color bands drawn, I copy them into video memory, which my previous experiment with VBE revealed to be at physical address 0xE0000000. (If the code were more general, it would have asked the BIOS for the location of the linear frame buffer, a procedure previously explained.) ; ------ Copy screen buffer into video memory. mov esi, [offsets] mov edi, 0xE0000000 mov ecx, 640 * 480 * 2 / 4 rep movsd The screen should immediately display the six horizontal bands of color, and the code simply halts here. ; ------ Hang computer. jmp $ I tested this code last night, and it works on my system. It might not work on yours if your system does not map its video memory to address 0xE0000000, or if it is very old and does not support video mode 0x111. Check the index for other entries. |