1.啟動(dòng)BIOS
加電瞬間強(qiáng)行將CS值設(shè)置為0xF000演熟,IP值置為0xFFF0. CS:IP=0xFFFF0,指向BIOS的地址范圍
BIOS在內(nèi)存最開始的位置(0x00000)用1KB構(gòu)建了中斷向量表区匣,后面緊接著256字節(jié)構(gòu)建BIOS數(shù)據(jù)區(qū)杨伙,大約57KB以后的位置加載了中斷服務(wù)程序
中斷向量表:256個(gè)中斷向量拳球,每個(gè)中斷4個(gè)字節(jié)舀瓢,2個(gè)是CS滞乙,2個(gè)是IP债蓝,每個(gè)向量指向一個(gè)中斷服務(wù)程序
2.把軟盤中的操作系統(tǒng)程序加載到內(nèi)存
2.1 BIOS中斷0x19把第一扇區(qū)bootsect內(nèi)容加載進(jìn)去
CPU接收到一個(gè)int 0x19中斷壳鹤,然后再去中斷向量表里找這個(gè)中斷向量。中斷向量指向0x0e6f2(中斷服務(wù)程序入口地址)饰迹,這個(gè)中斷服務(wù)程序的作用是把軟盤第一扇區(qū)中的程序(512B)加載到內(nèi)存中的指定位置芳誓,即將軟驅(qū)0號磁頭對應(yīng)盤面的0磁道1扇區(qū)的內(nèi)容復(fù)制到內(nèi)存0x7C00處。
2.2 把第二批和第三批程序加載到內(nèi)存
規(guī)劃內(nèi)存
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
!對后續(xù)操作涉及的內(nèi)存位置進(jìn)行設(shè)置
SETUPLEN = 4 ! nr of setup-sectors
BOOTSEG = 0x07c0 ! original address of boot-sector
INITSEG = 0x9000 ! we move boot here - out of the way
SETUPSEG = 0x9020 ! setup starts here
SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
復(fù)制bootsect
將源地址0x07C00的bootsect復(fù)制到目的地址0x90000
啊鸭!將源地址0x07C00的bootsect復(fù)制到目的地址0x90000
! 代碼主要設(shè)定源地址和目標(biāo)地址后锹淌,使用循環(huán)指令rep和移動(dòng)指令movw進(jìn)行移動(dòng)
entry start
start:
mov ax,#BOOTSEG !BOOTSEG = 0x07c0
mov ds,ax ! ds寄存器置為0x07c0
mov ax,#INITSEG 赠制!INITSEG = 0x9000
mov es,ax
mov cx,#256 赂摆!計(jì)數(shù)器,提供需要復(fù)制的字的數(shù)量 256字=512字節(jié)
sub si,si !sub是做減法操作钟些,此處將si烟号,di自己減自己,即置0政恍。
sub di,di
!移動(dòng)時(shí)源地址ds:si=0x07c0:0x0000汪拥,目的地址es:di=0x9000:0x0000
!即將BIOS移動(dòng)到0x9000(0x07c0用于放置bootsect.s)
rep !rep指令作用:重復(fù)執(zhí)行后面一句操作,并遞減cx的值篙耗,直到cx=0停止
movw !movw指令作用:這里從內(nèi)存[si]處移動(dòng)cx個(gè)字到[di]迫筑;注意一次的移動(dòng)單位是“字”, mov指令+w(word)是一次移動(dòng)一個(gè)字
jmpi go,INITSEG !將BIOS移動(dòng)到0x9000后宗弯,跳轉(zhuǎn)(go)到INITSEG(0x9000)脯燃,CS=0x90000
! 對ds,ex,ss,sp進(jìn)行調(diào)整
go: mov ax,cs
mov ds,ax
mov es,ax
! put stack at 0x9ff00. !下面兩條指令是將堆棧指針sp指向0x9ff00處(即0x9000:0xff00)
mov ss,ax
mov sp,#0xFF00 ! arbitrary value >>512
將setup程序加載到內(nèi)存
借助0x13中斷向量,從第二個(gè)扇區(qū)開始的4個(gè)扇區(qū)
!INT 0x13的使用方法:
!ah = 0x20-讀磁盤扇區(qū)到內(nèi)存罕伯; al = 需要讀出的扇區(qū)數(shù)量曲伊;
!ch=磁道(柱面)號的低8位; cl =開始扇區(qū)(位0-5)追他,磁道號高2位(位6-7);
!dh = 磁頭號岛蚤; dl = 驅(qū)動(dòng)器號邑狸;
!es:bx = 指向數(shù)據(jù)緩沖區(qū);
!如果出錯(cuò)則CF標(biāo)志置位涤妒,ah中是出錯(cuò)碼单雾。
load_setup:
mov dx,#0x0000 ! drive 0, head 0 磁頭號0,驅(qū)動(dòng)器號0
mov cx,#0x0002 ! sector 2, track 0,開始扇區(qū)2硅堆,磁道號0
mov bx,#0x0200 ! address = 512, in INITSEG es:bx=0x9000:0x0200 即數(shù)據(jù)緩沖區(qū)為0x90200
mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors,SETUPLEN初始設(shè)置為4,ax=0x0210,ah=0x02-讀磁盤扇區(qū)到內(nèi)存屿储,需要讀出的扇區(qū)數(shù)量-4
int 0x13 ! read it 打開中斷
jnc ok_load_setup ! ok - continue jnc指令:如果(上條指令)成功,則跳轉(zhuǎn)渐逃,即中斷INT 0x13成功够掠,則繼續(xù)執(zhí)行ok_load_setup
mov dx,#0x0000 ! 如果不成功,則復(fù)位驅(qū)動(dòng)器茄菊,并重試(重新跳轉(zhuǎn)函數(shù)load_setup)
mov ax,#0x0000 ! reset the diskette
int 0x13
j load_setup
ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track 利用BIOS中斷0x13取磁盤參數(shù)表中當(dāng)前啟動(dòng)引導(dǎo)盤的參數(shù)
! 這段代碼主要還是獲得每磁道的扇區(qū)數(shù)量疯潭,保存在了sectors中
mov dl,#0x00 !驅(qū)動(dòng)器號為0
mov ax,#0x0800 ! AH=8 is get drive parameters,AH=8,是INT 0x13取磁盤驅(qū)動(dòng)器的參數(shù)面殖,AL初始化0竖哩,作為返回值
int 0x13 ! 打開中斷
mov ch,#0x00
seg cs ! 此條指令表示下一條語句的操作數(shù)在cs段寄存器所指的段中
mov sectors,cx
mov ax,#INITSEG
mov es,ax
將system模塊加載到內(nèi)存,加載240個(gè)扇區(qū)
! Print some inane message
! 顯示信息:“Loading system ... 回車”脊僚,共顯示24個(gè)字符
! 使用BIOS中斷0x10功能號ah=0x03和ah=0x13實(shí)現(xiàn)
! BIOS中斷0x10功能號ah=0x03相叁,功能:讀光標(biāo)位置
! 輸入:bh=頁號
! 返回:ch=掃描開始線;cl=掃描結(jié)束線辽幌;dh=行號钝荡; dl=列號
! BIOS中斷0x10功能號ah=0x13,功能:顯示字符串
! 輸入:al=放置光標(biāo)方式及規(guī)定屬性舶衬。0x01表示使用bl中屬性值埠通,光標(biāo)停在字符串結(jié)尾處;
! es:bp 指向要顯示的字符串起始位置逛犹。 cx=顯示字符串個(gè)數(shù)端辱; bh=顯示頁面號
! bl=字符屬性; dh=行號虽画; dl=頁號
mov ah,#0x03 ! read cursor pos 讀光標(biāo)
xor bh,bh ! 將bh置為0
int 0x10
mov cx,#24 ! 24個(gè)字符
mov bx,#0x0007 ! page 0, attribute 7 (normal) bh=0,頁=0; bl=7,字符屬性=7
mov bp,#msg1 ! es:bp指向要顯示的字符串
mov ax,#0x1301 ! write string, move cursor ah=0x13使用中斷0x10功能號舞蔽;al=0x01,使用bl中屬性值
int 0x10 ! 打開中斷码撰,串口打印字符串
! 上面使用中斷0x10顯示字符渗柿,首先使用ah=0x03功能獲取光標(biāo)位置以及行號列號,作為ah=0x13中斷的入?yún)ⅲ?
! 而后使用ah=0x13中斷將存在es:bp寄存器的字符串打印在串口屏幕脖岛,只要在使用中斷時(shí)朵栖,將輸入設(shè)定好即可。
! ok, we've written the message, now
! we want to load the system (at 0x10000) 將system模塊加載到內(nèi)存0x10000往后的120KB中
mov ax,#SYSSEG !SYSSEG=0x10000
mov es,ax ! segment of 0x010000
call read_it
call kill_motor
此時(shí)整個(gè)操作系統(tǒng)的代碼已經(jīng)全部加載至內(nèi)存柴梆。
確定一下根設(shè)備號
! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.
! 確定根文件系統(tǒng)設(shè)備號并保存其設(shè)備號于root_dev
! Linux中陨溅,軟驅(qū)的主設(shè)備號是2,次設(shè)備號=type*4+nr绍在,其中nr為0-3分別對應(yīng)軟驅(qū)A门扇、B雹有、C和D;
! type是軟驅(qū)類型(2->1.2MB或7->1.44MB)臼寄。
! 因?yàn)?*4+0=28霸奕,所以/dev/PS0 (2,28)指1.44MB A驅(qū)動(dòng)器,其設(shè)備號是0x021c(2*256+28)
! 同理吉拳,/dev/at0 (2,8)值1.2MB A驅(qū)動(dòng)器质帅,設(shè)備號是0x0208
! 取上面獲得的每磁道扇區(qū)數(shù),如果sectors=15說明是1.2MB的驅(qū)動(dòng)器合武;如果sectors=18說明是1.44M軟驅(qū)(為什么临梗?);
! 因?yàn)槭强梢龑?dǎo)的驅(qū)動(dòng)器稼跳,所以肯定是A驅(qū)
seg cs
mov ax,root_dev
cmp ax,#0
jne root_defined ! 檢查root_dev是否是空盟庞,如果否,則說明其已經(jīng)存入根設(shè)備號汤善,直接跳轉(zhuǎn)后面
seg cs ! 此條指令表示下一條語句的操作數(shù)在cs段寄存器所指的段中如果以Masm語法寫什猖,
seg cs和mov bx,sectors兩句合起來,等價(jià)于mov bx, cs:[sectors], 這里使用了間接尋址方式红淡。
重復(fù)一下前面的解釋不狮,mov [sectors],ax表示將ax中的內(nèi)容存入ds:sectors內(nèi)存單元,而mov cs:[sectors],ax強(qiáng)制以cs作為段地址寄存器在旱,因此是將ax的內(nèi)容存入cs:sectors內(nèi)存單元
mov bx,sectors
mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
cmp bx,#15 ! 將sectors與15對比摇零,如果相同,則ax=0x0208桶蝎,最終賦值給root_defined
je root_defined
mov ax,#0x021c ! /dev/PS0 - 1.44Mb
cmp bx,#18 ! 將sectors與18對比驻仅,如果相同,則ax=0x021c登渣,最終賦值給root_defined
je root_defined
undef_root:
jmp undef_root
root_defined: !將獲取的驅(qū)動(dòng)設(shè)備號存入root_dev
seg cs
mov root_dev,ax
跳轉(zhuǎn)到setup的第一條指令
! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
jmpi 0,SETUPSEG ! 跳轉(zhuǎn)到setup程序開始處(即0x90200)執(zhí)行setup程序