上一期,我講述了如何在軟盤的啟動扇區寫一些代碼,然后再從軟盤啟動的過程。制作好一個啟動扇區,在切換到保護模式之前,我們還應該知道如何使用BIOS中斷。BIOS中斷是一些由BIOS提供的、為了使操作系統的創建更輕易的低級程序。在本文中,我們將學習處理BIOS的中斷。
為什么要用BIOS
BIOS會把啟動扇區拷貝至RAM中,并且執行這些代碼。除此之外,BIOS還要做很多其它的事情。當一個操作系統剛開始啟動時,系統中并沒有顯卡驅動、軟盤驅動等任何驅動程序。因此,啟動扇區中不可能包含任何一個驅動程序,我們要采取其它的途徑。這個時候,BIOS就可以幫助我們了。BIOS中包含有各種可以使用的程序,包括檢測安裝的設備、控制打印機、計算內存大小等用于各種目的的程序。這些程序就是所說的BIOS中斷。
如何調用BIOS中斷
在一般的程序設計語言中,函數的調用是一件非常輕易的事情。比如在C語言中,假如有一個名為display的程序,它帶有兩個參數,其中參數noofchar表示顯示的字符數,參數attr表示顯示字符的屬性。那么要調用它,只需給出程序的名稱即可。對于中斷的調用,我們使用的是匯編語言中的int指令。
比如,在C語言中要顯示一些東西時,使用的指令如下所示:
display(nofchar,attr);
而使用BIOS時,要實現相同功能使用的指令如下:
int 0x10
如何傳遞參數
在調用BIOS中斷之前,我們需要先往寄存器中送一些特定的值。假設要使用BIOS的中斷13h,該中斷的功能是把數據從軟盤傳送至內存之中。在調用該中斷之前,要先指定拷貝數據的段地址,指定驅動器號、磁道號、扇區號,以及要傳送的扇區數等等。然后,就要往相應的寄存器送入相應的值。在進行下面的步驟前,讀者有必要對這一點有比較明確地熟悉。
此外,一個比較重要的事實是同一個中斷往往可以實現各種不同的功能。中斷所實現的確切功能取決于所選擇的功能號,功能號一般都存在ah寄存器之中。比如中斷13h可以用于讀磁盤、寫磁盤等功能,假如把3送入ah寄存器中,那么中斷選擇的功能就是寫磁盤;假如把2送入ah寄存器中,選擇的功能則是讀磁盤等。
我們要做的事情
這次我們的源代碼由兩個匯編語言程序和一個C程序組成。第一個匯編文件是引導扇區的代碼。在引導扇區中,我們寫的代碼是要把軟盤中第二扇區拷貝至內存段的0x500處(地址是0x5000,即偏移地址為0)。這時我們需要使用BIOS的中斷13h。這時啟動扇區的代碼就會把控制權轉移至0x500處。在第二個匯編文件中,代碼會使用BIOS中斷10h在屏幕上顯示一個信息。C程序實現的功能則是把可執行的文件1拷貝至啟動扇區,把可執行的文件2拷貝至軟盤的第二扇區。
啟動扇區代碼
使用中斷13h,啟動扇區把軟盤第二扇區里的內容加載至內存的0x5000處(段地址為0x500)。下面的代碼是用于實現這一目的的代碼,將其保存至文件sbect.s中。
LOC1=0x500
entry start
start:
mov ax,#LOC1
mov es,ax
mov bx,#0
mov dl,#0
mov dh,#0
mov ch,#0
mov cl,#2
mov al,#1
mov ah,#2
int 0x13
jmpi 0,#LOC1
上面代碼第一行類似于一個宏。接下去的兩行則是把值0x500加載至es寄存器中,這是軟盤上第二扇區代碼將拷貝到的地方(第一扇區是啟動扇區)。這時,把段內的偏移設為0。
接下來把驅動器號送入dl寄存器中,其中磁頭號送入dl寄存器中,磁道號送入ch寄存器中,扇區號送入cl寄存器中,扇區數送入al寄存器之中。我們想要實現的功能是把扇區2、磁道號為0、驅動器號為0的內容送至段地址0x500處。所有這些參數都和1.44MB的軟盤相對應。
把2送入ah寄存器中,是選擇了由中斷13h提供的相應功能,即實現從軟驅轉移數據的功能。
最后調用中斷13h,并且轉至偏移為0的段地址0x500處。
第二個扇區的代碼
第二個扇區中的代碼如下所示(把這些代碼保存至文件sbect2.s之中):
entry start
start:
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#26
mov bx,#0x0007
mov bp,#mymsg
mov ax,#0x1301
int 0x10
loop1: jmp loop1
mymsg:
.byte 13,10
.ascii “Operating System is Loading......”
上面代碼將被加載至段地址為0x500處,并且被執行。
在這段代碼中,使用了中斷10h來獲取目前的光標位置,然后顯示信息。
從第3行到第5行用于得到目前光標的位置,在此中斷10h選用的是功能3。然后,清除了bh寄存器的內容,并把字符串送至ch寄存器中。在bx中,我們送入了頁碼及顯示的屬性。此處,我們想要在黑背景上顯示白色的字符。然后,把要顯示字符的地址送到bp之中,信息由兩個字節組成,其值分別為13的10,它們分別對應回車和LF(換行)的ASCⅡ值。接下來是一個由29個字符組成的串;在下面實現的功能是輸出字符串然后移動光標;最后是調用中斷,然后進入循環。
C程序代碼
C程序的源代碼如下所示,將其存儲為write.c文件。
#include /* unistd.h needs this */
#include /* contains read/write */
#include
int main()
{
char boot_buf[512];
int floppy_desc, file_desc;
file_desc = open(“./bsect”, O_RDONLY);
read(file_desc, boot_buf, 510);
close(file_desc);
boot_buf[510] = 0x55;
boot_buf[511] = 0xaa;
floppy_desc = open(“/dev/fd0”, O_RDWR);
lseek(floppy_desc, 0, SEEK_SET);
write(floppy_desc, boot_buf, 512);
file_desc = open(“./sect2”, O_RDONLY);
read(file_desc, boot_buf, 512);
close(file_desc);
lseek(floppy_desc, 512, SEEK_SET);
write(floppy_desc, boot_buf, 512);
close(floppy_desc);
}
在上一期中,我曾經介紹過如何操作能啟動的軟盤。現在這一個過程稍微有點不同,首先把由bsect.s編譯出來的可執行文件bsect拷貝至軟盤的啟動扇區。然后再把由sect2.s產生的可執行文件sect2拷貝至軟盤的第二個扇區。
把上述文件置于同一目錄之下,然后分別對其進行編譯,方法如下所示:
as86 bsect.s -o bsect.o
ld86 -d bsect.o -o bsect
對sect2.s文件重復以上的操作,得出可執行文件sect2。編譯write.c,插入軟盤后執行write文件,命令如下所示:
cc write.c -o write
./write
下一步我們要做的事情
從軟盤啟動以后,可以看到顯示出來的字符串。這是使用了BIOS中斷來完成的。下一期要做的事情是在這個操作系統中實現實模式向保護模式的轉換。