The BIOS provides a lot of standard interrupt routines for writing text to the display, which is useful. But unfortunately, you can’t really call any of them from protected mode. Since most modern programs spend most of their time in protected mode, this obviously poses a problem. The alternative explored in this article is to set the VGA card to a text mode and then poke values representing letters into the appropriate places in display memory, which will hopefully cause those letters to appear on the screen. Of course, writing to VGA memory directly poses problems of its own these days, but it works for the simulated VGA card used in this example. One decade at a time, I guess.
1. Follow the steps in the previous tutorial titled “Creating a Bootable Program in Assembly Language“, but replace the original text from HelloWorldBootable.asm with the code given below. The new code uses direct memory access to write text to the screen without using interrupts.
use16 ; 16-bit mode org 0x7C00 ; this is the address of the boot sector BootStageOne: ; mov ah,0x00 ; reset disk mov dl,0 ; drive number int 0x13 ; call BIOS interrupt routine ; ; load the sector from disk using BIOS interrupt 0x13 mov ah,0x02 ; read sectors into memory mov al,1 ; number of sectors to read mov dl,0 ; drive number mov ch,0 ; cylinder number mov dh,0 ; head number mov cl,2 ; starting sector number mov bx,Main ; memory location to load to int 0x13 ; call BIOS interrupt routine ; jmp Main ; now that it's been loaded ; PadOutSectorOneWithZeroes: ; pad out all but the last two bytes of the sector with zeroes times ((0x200 - 2) - ($ - $$)) db 0x00 BootSectorSignature: dw 0xAA55 ; these must be the last two bytes in the boot sector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x7E00 ; the address of the sector after the boot sector Main: mov ax,3 ; set VGA mode (text) int 0x10 mov dx,0xB800 ; beginning of display memory mov es,dx mov si,TextHelloWorld ; point si at the string mov cx,0 ForEachChar: ; begin loop lodsb ; load al with [si], increment si cmp al,0x00 ; if char is null... je EndForEachChar ; .. then break out of the loop mov di,cx ; offset of current character mov [es:di],al ; write the character to memory inc cx ; there are two bytes per character inc cx ; so increment cx twice jmp ForEachChar ; jump back to beginning of loop EndForEachChar: ; end of the loop ret ; quit the program ; data to display TextHelloWorld: db 'Hello, world!',0 PadOutSectorTwoWithZeroes: times ((0x200) - ($ - $$)) db 0x00