操作系統篇-hello world(免系統運行程序)


 || 版權聲明:本文為博主原創文章,未經博主允許不得轉載。

  一、前言

    今天起開始分享關於操作系統的相關知識,本人也是菜鳥一個,正處於學習階段,這整個操作系統篇也是我邊學習邊總結的一些結果,希望能給正在學習或者有意向學習操作系統的童鞋帶來幫助。
    二、有關知識
    在進入代碼之前,先給大家普及一些硬件知識,如果你已經具備了這方面的知識,可以直接略過這部份。
    1.計算機怎么啟動操作系統的?
    首先,我們思考一個問題,為什么一個硬盤安裝系統之后打開計算機電源之后就能正常加載啟動呢?這看起來似乎很智能,似乎計算機像活的一樣會自動去硬盤中找系統代碼並自行加載。其實不然,在計算機的世界里一切也都是離不開規則的。而基於這些硬件所定的規則或者協議,我們將啟動代碼放到協議規定的地方,這時候啟動就會加載這部分代碼。聽起來好像有點亂,我們繼續看。
    2.主引導扇區
    很多安裝過系統的童鞋都應該知道引導盤這個東西,就是在我們啟動電腦的時候可以通過bios來設定是通過U盤啟動還是通過硬盤啟動。對於硬盤來說,硬盤的第一個扇區是 0 面 0 道 1 扇區,或者說是 0 頭 0 柱 1 扇區,這個扇區稱為主引導扇區。如果計算機的設置是從硬盤啟動,那么, ROM-BIOS 將讀取硬盤主引導扇區的內容,將它加載到內 存地址 0x0000:0x7c00 處(也就是物理地址 0x07C00),然后 jmp 跳到那里接着執行:
jmp 0x0000:0x7c00

  為什么偏偏是 0x7c00 這個地方?還不太清楚。反正當初定下這個方案的家伙已經被人說了很多壞話!!

  通常,主引導扇區的功能是繼續從硬盤的其他部分讀取更多的內容加以執行。像 Windows 這樣的操作系統,就是采用這種接力的方法一步一步把自己運行起來的。

說到這里,我們可以想象,如果我們把自己編譯好的程序寫到主引導扇區,不也能夠讓處理器執行嗎?    
其實這就是我們尋找的答案,這幾乎是在不依賴操作系統的情況下,讓我們的程序可以執行的唯一方法。但這里要注意可別拿自己的電腦亂試,系統一下就癱瘓了,我們可以通過虛擬機來進行我們的代碼運行與調試。
  三、配置
   1.nasm
    首先安裝nasm,方便編譯我們的代碼,為了大家方便,本文后面會附上相關的下載地址。
    安裝過程是直接安裝,一直next:
  
  
  安裝完成之后,我們可以啟動nasm的shell,通過該shell進行相關編譯工作。
   2.bochs
    該軟件可用於創建硬盤或軟盤,同時也可模擬計算機啟動,可以加載我們寫好的啟動盤。
 
  點擊I Agree進入下面的界面:
 
  這個界面,大家看自己的需求選擇,然后點擊next:
 
  
  這里DLX Linux Demo是默認沒選上的,安裝Bochs時不妨選中“DLX Linux Demo”,便可直接參考它的配置文件。
  繼續next:
 
選擇好安裝位置,install就行了。
    3.dd
    該工具用於將我們編譯后的機器碼寫入到啟動扇區中。我這里用的是dd-0.6beta3,將附件下載后解壓,拿到里面的exe文件,在cmd下cd到該目錄就可以使用dd命令進行寫入操作。
  四、程序
    說了這么多,還沒見到代碼,下面我們就一段代碼了實現字符串的顯示,由於代碼是用匯編寫的,所以沒有匯編基礎的童鞋可能需要先看看匯編的語法。
廢話不多說了,直接上代碼:
 1 org 07c00h ;告訴計算機將代碼加載到內存的07c00h
 2 mov ax, cs 
 3 mov ds, ax ;初始化數據段ds
 4 mov es, ax ;初始化附加段寄存器
 5 call DispStr ;調用DispStr來顯示字符串
 6 jmp $  ;無限循環
 7 DispStr:
 8   mov ax, BootMessage ;將字符串地址傳給寄存器ax
 9   mov bp, ax ; 通過ES:BP來指向顯示的字符串
10   mov cx, 16 ; 表示字符串的長度
11   mov ax, 01301h ;10h的13號中斷,此時通過AH=13傳入,AL=1,表示目標字符串僅僅包含字符,屬性在BL中包含,移動光標
12   mov bx, 000ch  ;BH表示視頻區頁數
13   mov dl, 0 ;DL表示在第幾列顯示(0為第一列)
14   int 10h ;10H中斷
15   ret
16 BootMessage:  db "Hello,OS World!"
17 times 510-($-$$) db 0  ;用times來創建字節0
18 dw 0xaa55 ;扇區結尾,寫入引導程序標志位
  上面的代碼注釋比較清晰的解釋了程序的意思,這里我們在詳細分析一下。
  在前面我們講到因為硬件設計的原因,在充電的時候,回去內存的07c00h處讀取指令,因此,我們通過org 0700ch來講程序加載到該地址。接着初始化了段寄存器,然后調用字符串的顯示的代碼部分從而將字符串顯示在顯示器上面。
  在DispStr中,相關寄存器的操作都是為了后面的10H中斷做准備,int 10h這條指令的觸發將會使得ES:BP所指向的字符串進行顯示。
  顯示完成后,原則上整個程序就結束了,但對處理器來說,它並不知道。對它來說,取指令、執行是永無止境的。程序有大小,執行無停息,它這么做的結果,就是會執行到后面非指令的數據上,然后……
  問題在於我們現在的確無事可做。為避免發生問題,源程序第 6 行,安排了一個無限循環:jmp $。其中$等同於標號,你可以把它看成是一個隱藏在當前行行首的標號。
     說到這里就只剩下最后兩行代碼了,其實這里也是可以算是一個協議來的。因為主引導扇區在系統啟動過程中扮演着承上啟下的角色,但並非是唯一的選擇。如果硬盤的主引導扇區不可用,系統還有其他選擇,比如可以從光盤和 U 盤啟動。
     然而,如果不試試水的深淺就一個猛子扎下池塘,這並非一個明智之舉。同樣地,如果主引導扇區是無效的,上面並非是一些處理器可以識別的指令,而處理器又不加鑒別地執行了它, 其結果是陷入宕機狀態,更不要提從其他設備啟動了。
     為此,計算機的設計者們決定,一個有效的主引導扇區,其最后兩個字節的數據必須是 0x55和 0xAA。否則,這個扇區里保存的就不是一些有意而為的數據。這就是最后一行代碼的解釋:dw 0xaa55。
  根據上面的說法,這里還要解決另外的一個問題,就是如何使這兩個字節正好位於 512 字節的最后。前面的代碼有多少個字節我們不知道,那是由 NASM 編譯器計算和跟蹤的。這時倒數第二行代碼就起作用了,這里通過創建數值為0的字節來補充余下的空間,其中$$是 NASM編譯器提供的另一個標記,代表當前匯編節(段)的起始匯編地址
    到此,我們對於代碼的分析完畢了。
  五、編譯與運行
      這時候打開我們前面安裝好的nasm shell,cd定位到我們的boot.asm的位置,然后執行nasm boot.asm -o boot.bin

 

  然后,我們通過bochs來創建一個軟盤,通過軟盤來做啟動盤從而啟動執行我們的程序。
  首先,打開bochs安裝目錄的bximage.exe文件

  下面是打開后的界面:

  然后輸入1並回車,選擇創建一個軟盤或硬盤,進入下面的界面:

 
  這時候會詢問要創建的類型是hd還是fd,我們輸入fd回車,進入下面的界面

 

這個提示是要我們選擇要創建的盤符的大小,我們直接回車選擇默認的1.44M就行了:

  到這里可以為創建的鏡像輸入名稱,也可以用a.img作為默認名。回車后,這時會在bochs安裝的目錄下面多了一個a.img的文件,這個就是我們剛剛創建的鏡像文件:

  到此,我們創建好了軟盤,下面就是將程序寫入到軟盤的第一個扇區,這時,我們dd工具就派上用場了,我們啟動命令行,cd到dd的根目錄,然后執行寫入的命令:
dd  if=boot.bin  of=a.img  bs=512  count=1  conv=notrunc

  注意這里我把編譯好的boot.bin文件與鏡像a.img跟dd放在同一目錄,不是同一目錄的同學請自行修改路徑。

  執行完后,a.img就是我們要的啟動盤了。
  六、運行
     運行的時候是肯定不能在真機上面運行的,這時就要用到虛擬機了,我用的是vm ware。
     首先,我們需要創建一個新的虛擬機,主要的步驟如下:

  

  選擇自定義,單擊下一步進入下一個界面:

  

  

  這里默認就可以了,直接單擊下一步:

  

  這里選擇稍后安裝操作系統,下一步:

  

  這里選擇其他,然后下一步:

  

  這里是處理器的配置,因為我們的程序都很簡單,而不是玩游戲,所以選擇最低配置就可以了:

  

  選擇好內存,單擊下一步:

  

  關於網絡就隨意選都行,反正我們暫時不會涉及網絡方面的東西,單擊下一步:

  

  IO控制器,直接默認就行,下一步:

   

  虛擬磁盤類型,選擇IDE,單擊下一步:

  

  創建磁盤,單擊下一步:

  

  這里盡量選小一點的磁盤,因為我們用不上的,我們這里是通過軟盤來啟動的:

  

  選擇磁盤文件的位置,然后單擊下一步:

  

  單擊完成,此時我們的虛擬機就創建好了。

     這個時候不要急於去啟動它,因為我們還有將我們剛剛做好的啟動盤配置進來,作為虛擬機的啟動盤。下面我們繼續通過截圖來說明,這樣會直觀一些:

   

  這里我們選擇圖中紅色圈住的地方,來我們剛剛創建好的虛擬機:

  

  選擇添加,來添加我們剛剛制作好的軟盤:

  

  選擇軟盤驅動器,單擊下一步:

  

  選擇使用軟盤鏡像,單擊下一步:

   

  選擇我們剛剛的a.img,並勾選啟動時連接,單擊完成。

  這時候我們的准備工作就結束了,可以啟動虛擬機來看看我們的工作成果了:

  

  

   可以看到我們字符串Hello,OS World!顯示在上面。
  這個時候,心細的同學可能有疑問了,為什么顯示的字符串是紅色的,為什么不是白色或者其他顏色呢?要顯示其他顏色也是可以的,這其實是我們寫在了程序里面的,這其實是有AL與BL寄存器來決定的。
  如果AL的BIT1為1,則BL表示顯示屬性。屬性為:
  |BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0| BL
  BIT7:背景是否閃爍。0不閃爍,1閃爍
  BIT6~BIT4為背景色,分別為RGB,000為黑色,111為白色
  BIT3為1,則前景色加亮,為0則不加亮
  BIT2-BIT0為前景色,意義同背景色
  有興趣的同學可以嘗試修改代碼運行試試,這里就不一一列舉 了。
   七、總結
    回顧上面所講的內容,我們主要講解了以下幾點的內容:
    1.如何免系統運行程序:由於硬件設計的原因,在計算機充電啟動的時候會去內存的0x07c00h處讀取指令,因此我們通過指令org 0x07c00h將代碼加載到內存的該位置。
    2.計算機如何知道要我們制作的軟盤就是啟動盤呢?因為在軟盤的第一扇區最后的兩個字節是計算機識別啟動盤的位置,我們通過將這兩個字節設置成0xaa55,從而告訴計算機,該軟盤就是啟動盤。
    3.如何通過代碼將字符串顯示到顯示器上?我們利用10H中斷,該中斷會去ES:BP所指向的內存地址讀取內容並顯示。
    4.顯示是樣式如何設定?將AX的低八位AL的BIT1設置為1,表示要顯示的是字符串,而且樣式包含在BL中,而在BL中我們設置的值為0x0c,也就是二進制的0000_1100,從上面 對BL的各個位的講解,我們知道該內容是將字符串設置為紅色。
    5.同時,我們也學會了利用bochs來制作鏡像,另外bochs也可以用來調試,以后的文章也會用到,希望大家多多關注。
    6.通過dd工具將程序寫入鏡像。

  下面是本文中用到的相關工具的下載地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM