預(yù)備知識(shí): 匯編語(yǔ)言、能讀懂NASM語(yǔ)法、了解BIOS 中斷INT0x10, INT 0x16,虛擬機(jī)的使用
涉及工具: NASM,一個(gè)文本編輯器(我用的是ConText + NASM語(yǔ)法高亮)
前言: 第一次寫教程,不知道能拿多少分。
“怎樣開始寫自己的操作系統(tǒng)”可能是不少有“非分想法”的愛(ài)好者來(lái)說(shuō)是一個(gè)難題,在我的大學(xué)課程《計(jì)算機(jī)操作系統(tǒng)教程》以教程的形式充分說(shuō)明了操作系統(tǒng)的原理,這本書會(huì)告訴你各個(gè)環(huán)節(jié)的原語(yǔ);所謂“原理”就指理論上的東西,實(shí)際上我們并不知道操作系統(tǒng)是如何工作的。為了不至于讓有這個(gè)非分想法的朋友不至于放棄,這篇日志就帶你走進(jìn)操作系統(tǒng)開發(fā)的殿堂。
一、操作系統(tǒng)是如何啟動(dòng)的?
首先讓我們來(lái)看看計(jì)算機(jī)的啟動(dòng)過(guò)程,這里我摘抄了一些東西:
“首先讓我們來(lái)了解一些基本概念。第一個(gè)是大家非常熟悉的BIOS(基本輸入輸出系統(tǒng)),BIOS是直接與硬件打交道的底層代碼,它為操作系統(tǒng)提供了控制硬件設(shè)備的基本功能。BIOS包括有系統(tǒng)BIOS(即常說(shuō)的主板BIOS)、顯卡BIOS和其它設(shè)備(例如IDE控制器、SCSI卡或網(wǎng)卡等)的BIOS,其中系統(tǒng)BIOS是本文要討論的主角,因?yàn)橛?jì)算機(jī)的啟動(dòng)過(guò)程正是在它的控制下進(jìn)行的。BIOS一般被存放在ROM(只讀存儲(chǔ)芯片)之中,即使在關(guān)機(jī)或掉電以后,這些代碼也不會(huì)消失。
“第二個(gè)基本概念是內(nèi)存的地址,我們的機(jī)器中一般安裝有32MB、64MB或128MB內(nèi)存,這些內(nèi)存的每一個(gè)字節(jié)都被賦予了一個(gè)地址,以便CPU訪問(wèn)內(nèi)存。32MB的地址范圍用十六進(jìn)制數(shù)表示就是0~1FFFFFFH,其中0~FFFFFH的低端1MB內(nèi)存非常特殊,因?yàn)樽畛醯?086處理器能夠訪問(wèn)的內(nèi)存最大只有1MB,這1MB的低端640KB被稱為基本內(nèi)存,而A0000H~BFFFFH要保留給顯示卡的顯存使用,C0000H~FFFFFH則被保留給BIOS使用,其中系統(tǒng)BIOS一般占用了最后的64KB或更多一點(diǎn)的空間,顯卡BIOS一般在C0000H~C7FFFH處,IDE控制器的BIOS在C8000H~CBFFFH處。”
(以上引自:http://article.pchome.net/2003/09/25/13022.htm)
二、進(jìn)一步了解引導(dǎo)的關(guān)鍵所在
計(jì)算機(jī)啟動(dòng)的第一個(gè)過(guò)程由BIOS完成,它做了什么工作是不我們不必理會(huì)的,我們也管不了那它;關(guān)鍵在于:BIOS完成設(shè)備檢查、初始化、更新之后,根據(jù)預(yù)先設(shè)定的引導(dǎo)設(shè)備順序檢查可以引導(dǎo)的設(shè)備,比如我們?cè)O(shè)置啟動(dòng)順序?yàn)?:Floppy(軟驅(qū))2:HDD1(硬盤1) 3:CD-ROM(光驅(qū)),那么,BIOS會(huì)從軟驅(qū)開始查找是否可以啟動(dòng),如果軟驅(qū)失敗,則會(huì)去找HDD1,...... 那么,BIOS如何知道軟盤或硬盤能不能引導(dǎo)呢?這個(gè)把戲的關(guān)鍵在于:每個(gè)可引導(dǎo)設(shè)備都有一個(gè)512字節(jié)的設(shè)備頭,如果這個(gè)設(shè)備可引導(dǎo),最后兩個(gè)字節(jié)必須為0x55(低),0xAA(高),如果BIOS找到這個(gè)標(biāo)志,就會(huì)將這512字節(jié)(注意:只有512字節(jié))讀到內(nèi)存的0x0000:0x7C00,然后將控制權(quán)轉(zhuǎn)交給(跳到)0x0000:0x7C00的程序,這就意味著:如果我們將軟盤的第一個(gè)扇區(qū)最后兩個(gè)字節(jié)打上"0x55,0xAA"的標(biāo)志,這個(gè)軟盤就可以啟動(dòng)了!當(dāng)然,BIOS不會(huì)知道你這個(gè)引導(dǎo)程序是不是有效的,它只認(rèn)0x55,0xAA。
好了,我們知道寫自己第一個(gè)引導(dǎo)程序的關(guān)鍵在于: 1. 一個(gè)兩字節(jié)(一個(gè)字長(zhǎng))的引導(dǎo)標(biāo)志 0x55,0xAA 2. 引導(dǎo)程序必須占512字節(jié)
三、看看實(shí)例
代碼用NASM編譯:nasmw -f bin boot.asm -o boot.bin 解釋一下上面的命令:在M$命令提示行下編譯,-f bin 表示編譯為純二進(jìn)制文件(我們不需要任何文件頭),-o boot.bin 編譯。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; boot.asm ; A demo to show how bootsect works ; Last modified:2005-4-3 10:57:45 ; Copyright (c) 2005,E-mean X. ; ; This program is released under GPL,See document for details ; You can use this code anywhere you want in condition keep autor's info ; original ; ; Author: E-mean X. ; Contact: xemean@sina.com ; Website: http://www.xemean.net/ ; April,02,2005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; bits 16 ; 偽指令,告訴編譯器這是 16位代碼 org 0x7C00 ; 偽指令,告訴編譯器這段代碼由0x0:0x7C00開始 ;=========================================================================== ; 程序執(zhí)行的第一條指令必須是跳轉(zhuǎn)(如果你想使用FAT12這類文件系統(tǒng)的磁盤) ; 必須占用3字節(jié) ;=========================================================================== jmp SHORT main ; 2 bits,跳轉(zhuǎn)到主程序執(zhí)行 nop ; 1 bit ;=========================================================================== ; FAT12 文件系統(tǒng)頭,從NYAOS 借過(guò)來(lái)的,可以參考相關(guān)的文檔以獲得更多細(xì)節(jié) ; 這個(gè)塊會(huì)讓 Winimage 認(rèn)出編譯后的二進(jìn)制文件為有效的引導(dǎo)文件 ; 如果不使用這個(gè)塊,Winimage將不會(huì)將其作為引導(dǎo)程序處理 ; 但我們可以借助其它方法和工具處理,比如DEBUG ;=========================================================================== bsOEM db "ExOS0.01" ; OEM String,任意你喜歡的8字節(jié)ASCII碼 bsSectSize dw 512 ; Bytes per sector bsClustSize db 1 ; Sectors per cluster bsRessect dw 1 ; # of reserved sectors bsFatCnt db 2 ; # of fat copies bsRootSize dw 224 ; size of root directory bsTotalSect dw 2880 ; total # of sectors if < 32 meg bsMedia db 0xF0 ; Media Descriptor bsFatSize dw 9 ; Size of each FAT bsTrackSect dw 18 ; Sectors per track bsHeadCnt dw 2 ; number of read-write heads bsHidenSect dd 0 ; number of hidden sectors bsHugeSect dd 0 ; if bsTotalSect is 0 this value is ; the number of sectors bsBootDrv db 0 ; holds drive that the bs came from bsReserv db 0 ; not used for anything bsBootSign db 29h ; boot signature 29h bsVolID dd 0 ; Disk volume ID also used for temp ; sector # / # sectors to load bsVoLabel db "NO NAME " ; Volume Label bsFSType db "FAT12 " ; File System type <- FAT 12文件系統(tǒng) ;=========================================================================== ; Main start here ;=========================================================================== main: cli ; 關(guān)閉可屏蔽中斷,以備我們接下來(lái)初始化寄存器的工作 mov ax,cs ; 將代碼段傳給ax,實(shí)模式下,代碼段與數(shù)據(jù)段沒(méi)什么分別 mov ds,ax ; 數(shù)據(jù)段寄存器,實(shí)際上都是0 mov es,ax ; 附加段 mov ax,ss ; 堆棧段 mov sp,0x7C00-1 ; 堆棧指針,指向0x7BFF sti ; 基本工作已經(jīng)完成,開放中斷
; mov si,msgHello ; 使 si指向 "Hello World!"字符串 call printStr ; 調(diào)用顯示子程序 mov si,fixLine ; 回車換行 call printStr mov si,msgMore ; 顯示更多信息 call printStr
; Mission complete,take a break .loop: xor ax,ax ; ax 清0 int 0x16 ; 調(diào)用int 16h 讀取鍵盤輸入
; 重啟計(jì)算機(jī) ; mov ax,0x40 ; mov ds,ax ; xor ax,ax ; mov [0x0072],ax ; 向 0x40:0x72寫0后再跳到_ ; jmp 0xFFFF:0x0 ; 0xFFFF:0x0 可以實(shí)現(xiàn)重啟
jmp .loop ; 跳轉(zhuǎn)到 .loop,什么也不做了
;------- END OF MAIN ----------------
;=========================================================================== ; printStr ; sub function for print a string to screen by INT 10H ; 入口:ds:si = 指向目標(biāo)字符串 ; 返回:無(wú) ;=========================================================================== printStr: push si ; 保護(hù)寄存器 push ax push bx
cld ; 清除進(jìn)位標(biāo)志位,這個(gè)標(biāo)志位會(huì)影響 si 的遞增方向 mov ah,0x0E ; int 0x10 子功能號(hào),顯示字符,參看相關(guān)資料以獲得細(xì)節(jié) mov bx,0x0007 ; 頁(yè)號(hào)0,字符前景色 7,淺灰色,試著改變這個(gè)數(shù)值 ; 會(huì)給你的文字增添色彩 .nextChar: lodsb ; [si] -> al,取一個(gè)字節(jié)碼 or al,al ; 如果取得的字節(jié)是0,則表示字符串結(jié)束 jz .OK ; 退出 int 0x10 ; 調(diào)用BIOS int 10h 中斷 jmp .nextChar ; 繼續(xù)下一個(gè)字符,直到遇到0 .OK: pop bx ; 恢復(fù)寄存器 pop ax pop si ret ; 返回調(diào)用程序 ;------- END OF printStr --------------
; data area
msgHello db 'Hello World!',0 ; 以物理 0結(jié)束 msgMore db 'Wow,my FIRST boot sector!',0 fixLine db 13,10,0 ; 回車,換行的ASCII碼
; 引導(dǎo)程序必須為512字節(jié),不用的地方以0填充 times 510-($-$$) db 0 ; $表示程序當(dāng)前位置,$$表示程序開始位置,由編譯器自動(dòng)計(jì)算 BOOT_SIGN DW 0xAA55 ; 最后兩個(gè)字節(jié)為引導(dǎo)標(biāo)志55AA
;--------------------------- End of this programme --------------------------------------
編譯成功之后,會(huì)生成一個(gè)512字節(jié)的boot.bin,用Winimage創(chuàng)建一個(gè)新的軟盤,在“Options(選項(xiàng))”菜單里,"Winimage mode selection ..." 選擇“WinImage Professional mode(專家模式)”(如果不選專家模式,將不能進(jìn)行引導(dǎo)扇區(qū)的編輯),之后,"Image-> Boot Sector Properties"(映像->引導(dǎo)扇區(qū)屬性)中,將引導(dǎo)扇區(qū)改為你剛才編譯的程序,保存,用Vmware/Qemu/Bochs之類的虛擬機(jī)工具試試你的啟動(dòng)盤吧!
發(fā)揮你的想像力,讓你的引導(dǎo)程序?qū)崿F(xiàn)更多的功能!
-----------------------------------------------------------
E-mean X. April,03,2005
轉(zhuǎn)載請(qǐng)說(shuō)明作者及出處 |