04 print Hello through BIOS

我們要利用 BIOS 提供的功能來在螢幕上印出 Hello World。(如果沒有 BIOS,這個工作會變得很困難,因為有很多種不同的螢幕,每個螢幕的硬體跟 interface 都不相同…)

那我們要怎麼使用 BIOS 的功能呢?

這就要說到 interrupt。

Interrupt

interrupt 是個讓 CPU 暫時停下手上正在做的事、轉去做比較優先的事再回來繼續的機制。interrupt 可以由 software 發出,也可由 hardware device 發出。

每個 interrupt 以一個數字表示,這個數字是 interrupt vector 的 index。interrupt vector 是個由 BIOS 初始化的 table,裡面記錄著指向 interrupt service routine (ISR) 的 address pointer。一個 ISR 就是一段處理特定 interrupt 的 machine code。

那麼,BIOS 在 interrupt vector 中放了一些 ISR,每個 ISR 表示某些部份的功能,例如 0x10 跟螢幕有關、0x13 則跟 disk 有關。

如果為每個 BIOS routine 都指定一個 interrupt,有點浪費,而且 interrupt vector 的大小也是有限的,所以會透過 interrupt 配合 register ax 的值來決定執行哪個 BIOS routine。

印出 Hello

印字的方式是使用 INT 0x10(video service 的 interrupt)配合 ALAH register 內的值。register AL 裡放要印的 character,AH 則是放 0x0eALAX 的 lower part、AH 則是 higher part)。AH0x0e 表示要 call「將 AL 內容寫到在 tty mode 下寫到螢幕上」的 function。

在這個例子裡,我們只需要設定一次 AH0x0e,因為只有一個 process 在 CPU 上跑,AH 的值不會被亂改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mov ah, 0x0e ; tty mode
mov al, 'H'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
int 0x10 ; al is still 'l'
mov al, 'o'
int 0x10

jmp $ ; jump to current address = infinite loop

; padding and magic number
times 510 - ($-$$) db 0
dw 0xaa55

一樣的組譯並執行:

1
2
$ nasm -f bin boot_sect_hello.asm -o boot_sect_hello.bin
$ qemu-system-x86_64 boot_sect_hello.bin

會看到像這樣的畫面: