boot

在Ubuntu下要安裝bin86軟件包,只需要在終端中輸入命令 sudo apt-get install bin86 即可。

 

下面是我們的代碼:

複製代碼
1 entry start
2 start:
3 mov ax,#0xb800
4 mov ds,ax
5 mov byte[0],#0x41
6 mov byte[1],#0x1f
7 hlt
8
複製代碼

上面這段就是我們需要的as86彙編代碼。在linux下將它保存爲boot.s文件。

entry start 這一句正如字面意思所言,我們的程序就從start這裏開始。

代碼的意義等我們講完windows版本的彙編代碼再在步驟二解釋,我們先在linux終端中輸入命令把代碼彙編成機器指令:

as86 -o boot.o boot.s

ld86 -o boot boot.o

 

這樣我們就在linux中得到了我們接下來要寫入U盤的文件boot,

我們在前面的導言中說了,現階段編寫的代碼是用於讓BIOS從U盤中讀出,然後放入內存中執行的。

 

這個階段,CPU並沒有發揮它最大的威力。

這個一方面是CPU的內存還處於未管理的狀態,還可以由我們自己自由使用,還沒有確定堆棧的位置等等。

另一方面,更強大,而且也是windows xp等系統和linux系統共同使用的,CPU的保護模式還有待我們啓動。

(你可能已經猜到,啓動保護模式這部分內容將會出現在未來的幾篇教程中。)

而在保護模式啓動之前我們處於所謂的實地址模式,這個時候我們總是先設定數據段段寄存器的地址,

然後我們的地址就可以用一個16位的地址來訪問內存開頭的1M空間了。

這裏的gas版本的彙編程序中,.code16這一句聲明就是爲了讓gas瞭解到這段程序是爲實模式編寫的(也即是此時還不能使用保護模式下專有的指令)

 

我們把數據段寄存器設置成0xb800,這樣,地址0就會指向PC的CPU中用來顯示屏幕的一段內存的開頭。

寫入這些地址,屏幕上就會輸出latin-1字符(也就是我們常說的ascii字符的8位拓展)。

在這個CPU的最初的階段,一般屏幕有80行,25列,而當我們把數據段寄存器賦予值0xb800,

地址0所指向的字節就代表第一行第一個字符,這裏是ascii碼中的大寫字母A,0x41。

地址1現在指向的字節代表了第一行第一個字符的字體顏色和背景顏色,格式與windows命令行解釋器的color命令一樣。

具體如下:

複製代碼
顏色設置
顏色屬性由兩個十六進制數字指定 -- 第一個爲背景,第二個則爲
前景。每個數字可以爲以下任何值之一:

0 = 黑色 8 = 灰色
1 = 藍色 9 = 淡藍色
2 = 綠色 A = 淡綠色
3 = 淺綠色 B = 淡淺綠色
4 = 紅色 C = 淡紅色
5 = 紫色 D = 淡紫色
6 = 黃色 E = 淡黃色
7 = 白色 F = 亮白色
複製代碼

 

這裏我們用0x1f這個值,也就是字符是白色的而背景顏色是藍色的。

 

按我的電腦的情況舉例,我的電腦主板使用的是Award公司出產的BIOS,它在運行載入器程序的前一刻顯示的是計算機中已經接入的磁盤的列表,

以及一個框顯示了USB控制器等各種設備的狀態。而且它的文字是白色的而背景是黑色的(注意,也就是顏色屬性是0f)。並且可以看出可以容納80個文字一行共25行。

 

我們的程序就將在BIOS這最後一個畫面的基礎上輸出顯示畫面。

 

可以看出在這個時候,段0xb800開頭的這段內存有80x25x2字節的內存用於設置屏幕的文字。

也就是內存地址160的字節的值就代表第2行第一個字符。

 

在我們上面的彙編程序中,我們把0x41也就是大寫字母A的ascii值寫入內存地址0,將顏色屬性0x1f寫入內存地址1。

運行起來之後,我們就會看到屏幕的左上角是一個藍色底白色字的大寫字母A!

 

最後的hlt指令讓CPU停住不動,這樣我們就可以靜靜觀察屏幕上的變化了~

 

不到10行的程序就是我們將來完善的操作系統的第一個版本,不賴吧~~

 

不過這個時候我們只是把程序的匯編出來了,還沒有寫入U盤並運行,下面我們就來完成這一步。

教程第三步我們也是分成了linux版和windows版。

可惜的是,無論是linux還是windows,都沒有常見程序可以幫我們把文件寫入磁盤,所以我們這裏還需要寫C程序自己實現這個功能。



 

步驟三:將程序寫入U盤並運行(linux版)

想要在linux中把數據寫入U盤,首先要知道linux中怎表示U盤。

linux中,U盤的表示方法和硬盤是一致的,它們都是 /dev/sd開頭,接着用小寫字母做標號。

第一塊磁盤就是/dev/sda,第二塊磁盤就是/dev/sdb

我的電腦上裝了2塊硬盤,這時候再插上一個U盤,那就是總共3個磁盤了。

這個時候U盤就表示爲/dev/sdc

在Ubuntu中,可以在菜單中找一找,有一項叫“磁盤實用工具”的,可以查看U盤和硬盤設備的設備名。

 

再不確定,可以使用linux中的fdisk -l命令,在某些系統中要訪問設備可能需要超級權限。

以Ubuntu爲例,需要使用sudo超級權限。

輸入sudo fdisk -l /dev/sda可以查看第一塊磁盤的信息。(-l代表list,列表)

 

插入U盤之後,分別查看/dev/sdb,/dev/sdc等磁盤,通過磁盤的大小和分區情況可以判斷哪個是你的U盤。

一般來說命令得出的U盤的分區情況是混亂的,那麼對U盤做fdisk命令通常提示不合理的磁盤分區,

這也可以幫助判斷哪個設備是U盤。

這個一定要判斷正確了,至少你不能把一個總容量幾百G或者1T,2T大小的磁盤設備辨認成U盤吧。(這麼大U盤,你哪買的?)

 

下面這個C程序把我們前面在linux下用as86處理出的程序寫入設備/dev/sdc(如果你的U盤是設備/dev/sdb或是其他的,那麼就需要相應修改程序)

 

複製代碼
代碼
1 #include <fcntl.h>
2 #include <stdio.h>
3 int main(int argc,char*argv[]){
4 int dev_desc,file_desc;
5 unsigned char buffer[512];
6 file_desc = open("./boot",O_RDONLY);
7 if(file_desc ==-1){
8 perror("failed to read file boot");
9 return-1;
10 }
11 read(file_desc,buffer,510);
12 close(file_desc);
13 buffer[510] =0x55;
14 buffer[511] =0xaa;
15 dev_desc = open("/dev/sdc",O_RDWR);
16 if(dev_desc ==-1){
17 perror("failed to open device /dev/sdc");
18 return-1;
19 }
20 write(dev_desc,buffer,512);
21 close(dev_desc);
22 puts("done.");
23 return0
24 }
複製代碼

 

這裏我們只是簡單的用linux下的api,聲明在fcntl.h裏的open函數和close函數讀取文件,並把內容寫入U盤的起始數據。

這裏我們並不是直接寫入512個字節,而是寫510個字節,並填上55和aa這2個字節,才把510字節的文件內容和2字節的結尾標識一起寫入U盤。

 

我們把它保存成linux-write-mbr.c,然後編譯:

cc -o linux-write-mbr linux-write-mbr.c

插入U盤,然後用超級權限執行我們的linux-write-mbr程序。(其他linux系統可能需要把sudo改成別的什麼。)

這是因爲訪問設備還是需要比較高權限才能做的:-)

sudo ./linux-write-mbr


發佈了121 篇原創文章 · 獲贊 2 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章