- 作業系統,啟動!
- 大致過程
- 重要程式
- bootsect.s
- setup.s
- head.s
作業系統,啟動!
大致過程
計算機的工作方式是取指執行,而執行其的前提是記憶體中有程式碼。作業系統剛開始並不是在記憶體中,而是在磁碟上,因此第一步需要將其以一定的方式從磁碟讀入記憶體。
(1)x86PC剛開機時CPU處於真實模式(和保護模式對應),定址方式為CS左移四位+IP
(2)開機時,CS = 0xFFFF;IP = 0X0000
(3)定址0xFFFF0(ROM BIOS對映區)
開機時記憶體中唯一有程式碼的地方
(4)檢查RAM,鍵盤,顯示器,軟硬磁碟
(5)將磁碟0磁軌0扇區(引導扇區,作業系統的第一段程式碼bootsect.s)讀入0x7c00處
一個扇區512位元組
.s 彙編程式碼
(6)設定cs = 0x7c0,ip = 0x0000
以下摘自《Linux核心完全註釋》
這裡先總的說明一下 Linux 作業系統啟動部分的主要執行流程。當 PC 的電源開啟後,80x86 結構的 CPU 將自動進入真實模式,並從地址 0xFFFF0 開始自動執行程式程式碼,這個地址通常是 ROM-BIOS 中的 地址。PC 機的 BIOS 將執行某些系統的檢測,並在實體地址 0 處開始初始化中斷向量。此後,它將可啟 動裝置的第一個扇區(磁碟引導扇區,512 位元組)讀入記憶體絕對地址 0x7C00 處,並跳轉到這個地方。啟 動裝置通常是軟碟機或是硬碟。這裡的敘述是非常簡單的,但這已經足夠理解核心初始化的工作過程了。
Linux 的最最前面部分是用 8086 組合語言編寫的(boot/bootsect.s),它將由 BIOS 讀入到記憶體絕對地 址 0x7C00(31KB)處,當它被執行時就會把自己移到絕對地址 0x90000(576KB)處,並把啟動裝置中後 2kB 位元組程式碼(boot/setup.s)讀入到記憶體 0x90200 處,而核心的其它部分(system 模組)則被讀入到從地址 0x10000 開始處,因為當時 system 模組的長度不會超過 0x80000 位元組大小(即 512KB),所以它不會覆 蓋在 0x90000 處開始的 bootsect 和 setup 模組。後面 setup 程式將會把 system 模組移動到記憶體起始處,這 樣 system 模組中程式碼的地址也即等於實際的實體地址,便於對核心程式碼和資料的操作。圖 3-1 清晰地顯 示出 Linux 系統啟動時這幾個程式或模組在記憶體中的動態位置。其中,每一豎條框代表某一時刻記憶體中各程式的映像位置圖。在系統載入期間將顯示資訊"Loading..."。然後控制權將傳遞給 boot/setup.s 中的代 碼,這是另一個真實模式組合語言程式。
重要程式
bootsect.s
.globl begtext,begdata,begbss,endtext,enddata,endbss
.text //文字段
begtext:
.data //資料段
begdata:
.bss //未初始化資料段
begbss:
entry start //關鍵字entry告知連結器,程式從start標號開始執行
start:
mov ax, #BOOTSEG //將ds段暫存器置為0x07c0
mov ds, ax
mov ax, #INITSEG //將es段暫存器置為0x9000
mov es, ax
mov cx, #256 //移動計數值=256字
sub si, si //源地址 ds:di = 0x07c0:0x0000
sub di, di //目標地址 es:si = 0x9000:0x0000
rep
movw
jmpi go, INITSEG //間接跳轉,cs=0x9000,ip=go
go: mov ax, cs //cs=0x9000
mov ds, ax
mov es, ax
mov ss, ax
mov sp, #0xFF00 //由於程式碼移動過了,所以要重新設定堆疊段的位置。sp只要指向遠大於512偏移(即地址0x90200)處都可以。因為從0x90200地址開始處還要放置setup程式,而此時setup程式大約為4個扇區,因此sp要指向大於(0x200+0x200*4+堆疊大小)處
load_setup:
mov dx, #0x0000
mov cx, #0x0002
mov bx, #0x0200
mov ax, #0x0200+SETUPLEN
int 0x13 //利用BIOS中斷INT 0x13將setup模組從磁碟第二個扇區開始讀到0X90200處,共讀4個扇區。如果讀出錯,則復位驅動器,並重試
jnc ok_load_setup
mov dx, #0x0000
mov ax, #0x0000 //復位
int 0x13
j load_setup //重讀
ok_load_setup:
mov dl, #0x00
mov ax, #0x0800
int 0x13
mov ch, #0x00
seg cs
mov sectors, cx
mov ah, #0x03 //顯示一些資訊('Loading system...'共24個字元)
xor bh, bh //讀游標位置
int 0x10
mov cx, #24 //共24個字元
mov bx, #0x0007 //顯示屬性
mov bp, #msg1 //指向要顯示的字串
mov ax, #0x1301
int 0x10 //顯示字元
mov ax, #STSSEG //0x1000
mov es, ax
call read_it //讀入system模組
jmpi 0, SETUPSEG //跳轉到0x9020:0000(setup.s程式的開始處)