目錄操作系統,啟動!大致過程重要程式bootsect.ssetup.shead.s 操作系統,啟動! 大致過程 電腦的工作方式是取指執行,而執行其的前提是記憶體中有代碼。操作系統剛開始並不是在記憶體中,而是在磁碟上,因此第一步需要將其以一定的方式從磁碟讀入記憶體。 (1)x86PC剛開機時CPU處於 ...
目錄
操作系統,啟動!
大致過程
電腦的工作方式是取指執行,而執行其的前提是記憶體中有代碼。操作系統剛開始並不是在記憶體中,而是在磁碟上,因此第一步需要將其以一定的方式從磁碟讀入記憶體。
(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程式的開始處)