1. 程式人生 > >自制操作系統-使用匯編顯示 hello world

自制操作系統-使用匯編顯示 hello world

number initial 整體 重寫 ber mage 意思 pro ots

Windows (開機)讀軟盤第一個扇區的讀法的具體表格

技術分享圖片

Hello World匯編版

就是將16進制編寫的代碼使用匯編語言編寫出來

; cherry-os
ORG 0x7c00 ;指定程序裝載的位置

;下面用於描述FAT12格式的軟盤
JMP entry
DB 0x90
DB "CHRRYIPL" ;啟動區的名稱可以是任意的字符串,但長度必須是8字節
DW 512; 每一個扇區的大小,必須是512字節
DB 1 ;簇的大小(必須為1個扇區)
DW 1 ;FAT的起始位置(一般從第一個扇區開始)
DB 2 ;FAT的個數 必須是2
DW 224;根目錄的大小 一般是224項
DW 
2880; 該磁盤的大小 必須是2880扇區 DB 0xf0;磁盤的種類 必須是0xf0 DW 9;FAT的長度 必須是9扇區 DW 18;1個磁道(track) 有幾個扇區 必須是18 DW 2; 磁頭個數 必須是2 DD 0; 不使用分區,必須是0 DD 2880; 重寫一次磁盤大小 DB 0,0,0x29 ;擴展引導標記 固定0x29 DD 0xffffffff ;卷列序號 DB "CHERRY-OS " ;磁盤的名稱(11個字節) DB "FAT12 " ;磁盤的格式名稱(8字節) TIMES 18 DB 0; 先空出18字節 這裏與原文寫法不同 ;程序核心 entry: MOV AX,
0 ;初始化寄存器 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 CMP AL,0 JE fin MOV AH,0x0e ;顯示一個文字 MOV BX,15 ;指定字符的顏色 INT 0x10 ;調用顯卡BIOS JMP putloop fin: HLT ;CPU停止,等待指令 JMP fin ;無限循環 msg: DB 0x0a
, 0x0a ;換行兩次 DB "hello, cherryOS" DB 0x0a DB 0 TIMES 0x1fe-($-$$) DB 0 ;填寫0x00,直到0x001fe DB 0x55, 0xaa

將這個文件保存為cherryOS.asm,使用nasm生成cherryOS.img

nasm cherryOS.asm -o cherryOS.img

使用QEMU運行我們的系統

qemu-system-i386 cherryOS.img

效果圖:

技術分享圖片

代碼說明

書中使用的是NASK,我們使用的是NASM,部分語法不同,這裏總結一下。

1 2 3 4 5 NASK代碼 NASM代碼 JMP entry -> JMP SHORT entry RESB <填充字節數> -> TIMES <填充字節數> DB <填充數據> RESB 0x7dfe-$ -> TIMES 0x1fe-($-$$) DB 0 ALIGNB 16 -> ALIGN 16, DB 0

下面對一個語句做專門說明

1 TIMES 0x1fe-($-$$) DB 0

這一句其中出現了$與$$這樣的符號。
$ 是當前位置
$$ 是段開始位置
$ - $$ 是當前位置在段內的偏移
比如我們前面輸入了130個字節,那麽$ - $$就是130,使用0x1fe-($ - $$)就可以計算出到達0x1fe還需要多少個字節。
這樣就保證了我們循環填充後所停在的位置是0x1fe

上面的代碼中出現了FAT12格式,IPL這樣的詞語。這裏簡要說明。

FAT12: Windows MS-DOS所采用的軟盤格式。後面我們將使用FAT32作為我們系統的格式。
啟動區: 軟盤的第一個扇區成為啟動區。
扇區: 計算機讀寫軟盤的過程中不是一個字節一個字節的讀寫,而是以512字節為一個單位進行讀寫的。因此,軟盤的512個字節就是一個扇區。扇區就是最小的讀寫單元。
IPL:initial program loader的縮寫。啟動程序加載器,啟動區只有區區512字節,實在是太小了。所以我們需要一個專門的程序IPL去啟動操作系統
bootsrap:鞋帶。操作系統的啟動就是操作系統的一個自救過程,我們一般將操作系統的啟動機制叫做bootstrap。

幾個語句:
ORG:這個指令將告訴編譯器,在代碼開始執行的時候,這些代碼將被裝載到哪個地址中,比如我們在這裏指定的地址是0x7c00。(為什麽是0x7c00,IBM的大佬們當年規定的就是這個數字,我也沒辦法)
JMP:JMP,跳轉,轉到對應的語句。
MOV:這個不多說了,相當於賦值語句。MOV AX,0 就是將0賦值給AX
HLT:讓CPU停止動作的指令,並不是完全的停止,只是讓CPU進入等待狀態。
INT:BIOS中斷指令,這裏我們用到INT0x10調用顯卡,更多的有關BIOS的中斷可以自行百度。

四個代碼塊:
entry:程序的開始,主要用來初始化寄存器和將msg的地址放入SI
putloop:用於顯示一個字符,整個流程就是這個代碼段所表示的過程,AH默認0x0e,AL表示字符,BH默認為0,BL表示顏色。具體參考INT0x10中斷內容。
fin:讓CPU進行等待。這個代碼段要在代碼中看,我們是這麽寫的CMP AL,0 JE fin。JE表示 jump if equal。所以這句話的意思是,如果AL==0 那麽跳轉到fin。也就是說我們msg中的信息顯示完成後,就讓CPU進入無限等待狀態。
msg:用於顯示我們的內容

幾個寄存器:
雖然這都是基礎了,但是還是寫一下,省的大家百度了
AX 累加寄存器 BX 基址寄存器 CX計數寄存器 DX數據寄存器
SP 棧指針寄存器 BP 基址指針寄存器 SI 源變址寄存器 DI 目的變址寄存器
ES 附加段寄存器 CS 代碼段寄存器 SS 堆棧段寄存器 DS 數據段寄存器
L與H:H表示高位,L表示地位,AL表示AX寄存器低位,AH表示AX寄存器的高位

整體流程:

    • 首先進入entry,entry中完成了對寄存器的初始化,並且將msg的地址放到SI中,此時可以將SI理解成一個在msg數據中滑動的指針。
    • msg內部是我們需要顯示的字符串
    • 進入putloop,這個循環用於將msg的字符一個一個打印出來。如果AH = 0時,進入fin。
    • 進入fin,程序變為無限等待狀態。

參考:

http://blackblog.tech/2018/07/18/CreateOSDay2/

自制操作系統-使用匯編顯示 hello world