一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

linux 0.11 內(nèi)核學(xué)習(xí)

 android之情殤 2013-06-15

linux 0.11 內(nèi)核學(xué)習(xí) -- bootsect.s, 萬里長(zhǎng)征第一步

呵呵,終于將linux 0.11 下面的boot文件夾下的三個(gè)文件讀完,下面是相關(guān)注釋,沒有匯編基礎(chǔ)的人也是可以讀的。廢話少說,下面就是linux的源碼了。

參考資料 Linux內(nèi)核完全注釋.pdf

            網(wǎng)上相關(guān)資料

!時(shí)間  : 2010-1-14
!工作 : 閱讀linux 0.11 源碼中的bootsect.s

!總體linux啟動(dòng)過程如下:
!
!當(dāng)PC得電源打開之后,80x86結(jié)構(gòu)的CPU將自動(dòng)進(jìn)入實(shí)時(shí)模式,并且從0xFFFF0開始自動(dòng)執(zhí)行程序代碼,這個(gè)地址通常是
!ROM-BIOS的地址。PC機(jī)的BIOS將執(zhí)行系統(tǒng)的檢測(cè),并且在物理地址的0處開始初始化中斷向量。此后,它將可啟動(dòng)設(shè)備的第一
!扇區(qū)(512字節(jié))讀入內(nèi)存的絕對(duì)地址0x7c00處,并且跳轉(zhuǎn)到這個(gè)地方。啟動(dòng)設(shè)備通常是軟盤或者是硬盤。這里的敘述是很簡(jiǎn)單
!的,但是這已經(jīng)足夠理解內(nèi)核的初始化的工作過程。
!
!linux的0x9000由BIOS讀入到內(nèi)存的絕對(duì)地址0x7c00(31k)處,當(dāng)它被
!執(zhí)行時(shí)就會(huì)把自己移動(dòng)到絕對(duì)地址0x90000處,并把啟動(dòng)設(shè)備中后2kb字節(jié)代碼(boot/setup.s)讀入到內(nèi)存0x90200處,而內(nèi)核的
!其他部分則被讀入到從地址0x10000的開始處。在系統(tǒng)的加載期間顯示信息?Loading...",然后將控制權(quán)傳遞給boot/setup.s中
!的代碼.這是另一個(gè)實(shí)時(shí)模式匯編程序。
!
!系統(tǒng)啟動(dòng)部分識(shí)別主機(jī)的某些特性以及vga卡的類型。如果需要,它會(huì)要求用戶為控制臺(tái)選擇顯示模式。然后整個(gè)系統(tǒng)從地址
!0x10000移至0x0000處,進(jìn)入保護(hù)模式病跳轉(zhuǎn)至系統(tǒng)的余下部分。此時(shí)所有的32位運(yùn)行方式的設(shè)置啟動(dòng)被完成:idt,gdt,ldt被
!加載,處理器和協(xié)處理器也確認(rèn),分頁(yè)的工作也設(shè)置好了。最終將調(diào)用init/main.c中的main程序。上述的操作的源代碼是在
!boot/head.s中的。這可能是整個(gè)內(nèi)核中最有訣竅的代碼了。注意如果在上述任何一步中出現(xiàn)了一步錯(cuò)誤。計(jì)算機(jī)就會(huì)死鎖。在
!操作系統(tǒng)還沒有完全運(yùn)轉(zhuǎn)之前是處理不了錯(cuò)誤的。
!
!
!bootsec.s文件說明如下:
!bootsec.s代碼是磁盤的引導(dǎo)塊程序,駐留在磁盤的第一扇區(qū)。在PC機(jī)加電rom bios自檢之后,引導(dǎo)扇區(qū)由bios加載到內(nèi)存0x7c00
!處,然后將自己移動(dòng)到內(nèi)存0x90000處。該程序的主要作用是首先將setup模塊從磁盤加載到內(nèi)存中,緊接著bootsect的后面位置
!(0x90200),然后利用bios中斷0x13中斷去磁盤參數(shù)表中當(dāng)前引導(dǎo)盤的參數(shù),然后在屏幕上顯示"Loading system..."字符串。再者
!將system模塊從磁盤上加載到內(nèi)存0x10000開始的地方。隨后確定根文件系統(tǒng)的設(shè)備號(hào),如果沒有指定,則根據(jù)所保存的引導(dǎo)盤的每
!類型和種類,并保存設(shè)備號(hào)與boot_dev,最后長(zhǎng)跳轉(zhuǎn)到 setup程序開始處0x90200執(zhí)行setup程序。
!
!
!注釋如下:
!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000
!
!以下是這一段代碼的翻譯。
! bootsect.s
!bootsect.s被bios啟動(dòng)程序加載至0x7c00 31k處,并將自己移動(dòng)到地址0x90000 576k處,并跳轉(zhuǎn)到那里。
!
!它然后利用bios中斷將setup直接加載到自己后面0x90200 576.5k,并將system加載到地址0x10000處。
!
!注意 : 目前的內(nèi)核系統(tǒng)最大的長(zhǎng)度限制為8*65536 512k字節(jié),即使是在將來這也應(yīng)該沒有問題的。我想讓他保持簡(jiǎn)單明了,
!這樣512k的最大內(nèi)核長(zhǎng)度應(yīng)該足夠了,尤其是這里沒有向minix中一樣包含緩沖區(qū)高速緩沖。
!
!加載程序已經(jīng)做的足夠簡(jiǎn)單了,所以持續(xù)的獨(dú)處錯(cuò)誤將導(dǎo)致死循環(huán)。只能手工重啟。只要可能,通過一次取出所有的扇區(qū),加載的
!過程可以做的很快.
!
!
!
! bootsect.s  (C) 1991 Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200) 256b, and the system
! at 0x10000, using BIOS interrupts.
!
! NOTE! currently system is at most 8*65536 bytes long. This should be no
! problem, even in the future. I want to keep it simple. This 512 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible.

!六個(gè)全局標(biāo)示符
.globl begtext, begdata, begbss, endtext, enddata, endbss
!文本段
.text
begtext:
!數(shù)據(jù)段
.data
begdata:
!堆棧段
.bss
begbss:

!文本段
.text
SETUPLEN = 4    ! nr of setup-sectors setup程序的扇區(qū)數(shù)(setup-sectors)值
BOOTSEG  = 0x07c0   ! original address of boot-sector bootsect的原始地址
INITSEG  = 0x9000   ! we move boot here - out of the way 將bootsect移動(dòng)到這里
SETUPSEG = 0x9020   ! setup starts here setup程序開始地址
SYSSEG   = 0x1000   ! system loaded at 0x10000 (65536). 將system模塊加載到的地址
ENDSEG   = SYSSEG + SYSSIZE  ! where to stop loading 停止加載的地址

! ROOT_DEV: 0x000 - same type of floppy as boot.
!  0x301 - first partition on first drive etc
ROOT_DEV = 0x306 !根文件系統(tǒng)設(shè)備是第二硬盤的第一個(gè)分區(qū)
   !0x300 -- /dev/hd0
   !0x301 -- /dev/hd1
   !...
   !0x309 -- /dev/hd9

entry start 告知連接程序,程序充start標(biāo)號(hào)開始。
start:
////////////////////////////////////////////////////////////////////////////////////////////////////////////
!下面的代碼是將自身bootsect從目前位置0x07c0 31k移動(dòng)到0x9000 576k處,然后跳轉(zhuǎn)到本程序的下一條語句處。
 !
 !此時(shí)(在實(shí)時(shí)模式下)內(nèi)存使用如下的分布 :
 !0      0x7c00(bootsect.s)
 !--------++++++++++---------------------------
 !ds = 0x7c00
 !         <-
 mov ax,#BOOTSEG
 mov ds,ax

 !es = 0x9000
 mov ax,#INITSEG
 mov es,ax

 !移動(dòng)計(jì)數(shù)的值 256
 !啟動(dòng)代碼是512kb
 mov cx,#256

 !源地址 ds : si = 0x07co : 0x0000
 sub si,si
 !目的地址 es : di = 0x9000 : 0x0000
 sub di,di
 !重復(fù)執(zhí)行知道cx = 0。循環(huán)程序?qū)崿F(xiàn)的另一種方法是利用串操作處理的重復(fù)指令rep。rep指令以cx為重復(fù)次數(shù),
 !當(dāng)指令被重復(fù)執(zhí)行完一次,那么cx的值會(huì)自動(dòng)減一。rep指令和串操作指令movs,stos配合使用,它將這兩條指令
 !重復(fù)執(zhí)行cx次。
 rep
 !移動(dòng)一個(gè)字
 movw

 !此時(shí)的內(nèi)存使用情況如下 :
 !0         0x7c00            0x9000
 !----------+++++++++---------+++++++++---------
 !兩個(gè)使用中的內(nèi)存是相同的

 !在匯編中的段的使用
 !
 !間接跳轉(zhuǎn)。這里INITSEG指出跳轉(zhuǎn)到的地址。
 !其格式為:jmpi offset(標(biāo)號(hào)), segment selector
 jmpi go,INITSEG -- 0x9000
//////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////
!在將自己成功移動(dòng)之后,下面的幾步是為下面加載setup程序做準(zhǔn)備。
!
!在執(zhí)行jmpi指令時(shí),cs段會(huì)被自動(dòng)更新。注意的是cs寄存器在call或者是jmp指令時(shí)會(huì)自動(dòng)更新。將 ds es ss都設(shè)置成代碼所
!在的段。
go: mov ax,cs
 mov ds,ax
 mov es,ax
!將堆棧指針sp指向0x9ff00 (0x9000 : 0xff00)
! put stack at 0x9ff00.
 !SS被成為堆棧段寄存器,用于存放堆棧段的基值.
 mov ss,ax

 !代碼段的移動(dòng),需要重新設(shè)置堆棧段的位置。sp只要指向遠(yuǎn)大于512便宜處都可以。
 mov sp,#0xFF00  ! arbitrary value >>512
!//////////////////////////////////////////////////////////////////////////////////////////////////////////

!在bootsect程序塊后緊隨著加載setup模塊。注意es已經(jīng)設(shè)置好了。es是指附加段寄存器。附加段寄存器是es,它的作用是很大的.
!因?yàn)槲覀冊(cè)谔幚頂?shù)據(jù)的時(shí)候,往往需要用到兩個(gè)數(shù)據(jù)段,特別是在字符串的處理方面,使用兩個(gè)數(shù)據(jù)段簡(jiǎn)便了許多的操作.
!
! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.
!
!下面的這段代碼的主要作用是使用int 0x13把磁盤上的setup模塊加載到內(nèi)存中,位置在bootsect.s (0x90000 + 512字節(jié))之后,
!真?zhèn)€過程主要是操作寄存器ax,bx,cx,dx等四個(gè)寄存器。
!
!
!///////////////////////////////////////////////////////////////////////////////////////////////////////
!設(shè)置load_setup標(biāo)號(hào),是為了執(zhí)行j load_setup語句。
load_setup:

 mov dx,#0x0000  ! drive 0, head 0 
 mov cx,#0x0002  ! sector 2, track 0
 mov bx,#0x0200  ! address = 512, in INITSEG
 mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
 int 0x13   ! read it 調(diào)用中斷信號(hào),開始讀取。
     !進(jìn)位操作標(biāo)示符cf = 0表示操作成功。

 jnc ok_load_setup  ! ok - continue·如果成功就跳轉(zhuǎn)到下面的ok_load_setup
     !否則執(zhí)行下面的代碼,復(fù)位磁盤再次執(zhí)行這段代碼
 mov dx,#0x0000
 mov ax,#0x0000  ! reset the diskette 磁盤復(fù)位
 int 0x13   !ld86中就有j這條指令,等價(jià)于jmp。這條語句的含義是 :
     !跳轉(zhuǎn)回去繼續(xù)執(zhí)行,如果總是失敗系統(tǒng),將總執(zhí)行這段代碼
 j load_setup
!//////////////////////////////////////////////////////////////////////////////////////////////////////

!時(shí)間 : 2010-1-15
!工作量  : 繼續(xù)閱讀linux 0.11 源碼
!時(shí)間 : 2010-1-17
!工作量 : 繼續(xù)閱讀linux源碼。
!
!如果上面講setup模塊順利讀入到內(nèi)存中,那么執(zhí)行下面的ok_load_setup代碼。
!
ok_load_setup:

! Get disk drive parameters, specifically nr of sectors/track
!取得磁盤驅(qū)動(dòng)器的參數(shù),特別是沒道的扇區(qū)數(shù)量。
!取得磁盤的參數(shù)使用的是int 0x13中斷來實(shí)現(xiàn),其調(diào)用格式如下 :
!ah = 0x08 dl = 啟動(dòng)器號(hào)
!返回信息如下 :
!如果出錯(cuò)的話cf置位,并且ah = 狀態(tài)碼
!ah = 0, al = 0 bl = 驅(qū)動(dòng)器類型(at/ps2)
!ch = 最大磁盤號(hào)的低8位, cl = 每磁盤的最大扇區(qū)數(shù)(位0-5),最大磁道號(hào)高2位(位6-7)
!dh = 最大磁道數(shù) dl = 驅(qū)動(dòng)器數(shù)量
!es : di = 軟驅(qū)磁盤參數(shù)表
!
!調(diào)用中斷0x13
 mov dl,#0x00  !清空dl,以獲得驅(qū)動(dòng)器號(hào)
 mov ax,#0x0800  ! AH=8 is get drive parameters
 int 0x13
 
 mov ch,#0x00
 ///////////////////////////////////////////////////////////
 !先講一下寄存器的默認(rèn)組合問題,比如指令mov [si], ax表示將ax中的內(nèi)容存入ds:si指向的內(nèi)存單元,也就是說在寄存器間
 !接尋址的情況下,以si間接尋址時(shí)總是默認(rèn)以ds為相應(yīng)的段地址寄存器。同樣di是以es為默認(rèn)的段地址寄存器。
 !第二個(gè)要了解的是“段超越”的問題,就是在某些時(shí)候你不想使用默認(rèn)的段地址寄存器,那
 !么你可以強(qiáng)制指定一個(gè)段地址寄存器(當(dāng)然這種強(qiáng)制是在允許的情況下,建議看一下匯編
 !教材上的說明),同上例mov [si],ax表示存入ds:si中,但如果你想存入cs指向的段中可
 !以這樣mov cs:[si],ax, 這樣就強(qiáng)制指定將ax中的內(nèi)容存入cs:si的內(nèi)存單元。
 !第三個(gè)要明白的是seg cs這樣的語句只影響到它下一條指令,比如在linux啟動(dòng)代碼中的一段:
      !seg cs
      !mov sectors,ax
      !mov ax,#INITSEG
 !要說明兩點(diǎn):
     !第一,seg cs 只影響到mov sectors,ax而不影響mov ax,#INITSEG
     !第二,如果以Masm語法寫,seg cs和mov sectors,ax兩句合起來等
        !  價(jià)于mov cs:[sectors],ax,這里使用了間接尋址方式。
        !  重復(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)存
        !  單元,一般來說cs與ds的值是不同的,如果cs和ds的值一樣,
        !  那兩條指令的運(yùn)行結(jié)果會(huì)是一樣的。(編譯后的指令后者比前
        !  者一般長(zhǎng)一個(gè)字節(jié),多了一個(gè)前綴。)
     !結(jié)論,seg cs只是表明緊跟它的下一條語句將使用段超越,因?yàn)樵诰?br>        !  譯后的代碼中可以清楚的看出段超越本質(zhì)上就是加了一個(gè)字節(jié)
        !  的指令前綴,因此as86把它單獨(dú)作為一條指令來寫也是合理的。
        !
        !mov cs:[sectors],ax
 !
 !下面的代碼在linux 2.6.x的內(nèi)核中可能改變。沒有查證。網(wǎng)上有關(guān)于其的討論,認(rèn)為其中含有錯(cuò)誤。
 seg cs
 mov sectors,cx  !sectors在下面定義,保存每個(gè)磁道扇區(qū)數(shù)
 ///////////////////////////////////////////////////////////
 
 mov ax,#INITSEG
 mov es,ax   !INITSEG = 0x90000 恢復(fù)es值

! Print some inane message 在顯示一些信息("Loading system...\n"回車換行。共24個(gè)字符)
 !//////////////////////////////////////////////////
 !讀取光標(biāo)位置
 mov ah,#0x03  ! read cursor pos
 xor bh,bh   ! bh = 0,使用xor指令將bh清0,但是速度比賦值快
 int 0x10
 !//////////////////////////////////////////////////

 !//////////////////////////////////////////////////
 !利用int 0x10來實(shí)現(xiàn)將移動(dòng)光標(biāo),并寫字符創(chuàng)
 mov cx,#24   ! 共24個(gè)字符
 mov bx,#0x0007  ! page 0, attribute 7 (normal)
 mov bp,#msg1  ! msgl下面定義,指向要顯示的字符串
 mov ax,#0x1301  ! write string, move cursor
 int 0x10   !寫字符串并且移動(dòng)光標(biāo)
 !//////////////////////////////////////////////////

! ok, we've written the message, now
! we want to load the system (at 0x10000)
! 現(xiàn)在開始將system模塊加載到內(nèi)存0x10000(64k)處。
 !/////////////////////////////////////////////////
 mov ax,#SYSSEG
 mov es,ax  ! segment of 0x010000,現(xiàn)在es就是存放system的段地址
 !/////////////////////////////////////////////////

 !//////////////////////////////////////////////////
 ! 調(diào)用邋read_it來實(shí)現(xiàn)讀取磁盤上的system模塊,其中es為輸入?yún)?shù)。
 call read_it
 !//////////////////////////////////////////////////
 !關(guān)閉驅(qū)動(dòng)器馬達(dá),這樣就知道驅(qū)動(dòng)器的狀態(tài)了。
 call kill_motor
 !/////////////////////////////////////////////////
 
! 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.
! 此后,我們檢查使用哪個(gè)根文件系統(tǒng)設(shè)備。如果已經(jīng)指定了設(shè)備,就直接使用給定的設(shè)備,
! 否則就需要根據(jù)bios的報(bào)告的每磁道扇區(qū)數(shù)來確定到底是使用/dev/ps0還是/dev/at0
 ! 上面一行中的兩個(gè)設(shè)備文件的含義 :
 ! 在linux中軟驅(qū)的主設(shè)備號(hào)是2,次設(shè)備號(hào) = type * 4 + nr,其中nr 為0-3分別
 ! 對(duì)應(yīng)軟驅(qū)的abcd;type是軟驅(qū)的類型(2->1.2m 7->1.44m等)。因?yàn)?*4+0=28,所
 ! 以/dev/ps0指的是1.44m a驅(qū)動(dòng)器,起設(shè)備號(hào)是0x021c,同理/dev/at0(2,8)指的是1.2
 ! m a的驅(qū)動(dòng)器,其設(shè)備號(hào)是0x0208

 seg cs
 mov ax,root_dev  ! 根設(shè)備號(hào)
 !////////////////////////////////////////////////////
 ! 使用cmp和jne指令來實(shí)現(xiàn)條件轉(zhuǎn)移。在匯編語句中的跳轉(zhuǎn)指令分為有條件跳轉(zhuǎn)和
 ! 無條件跳轉(zhuǎn),jne可解釋為如下:jump not equal
 !
 cmp ax,#0
 jne root_defined
 !////////////////////////////////////////////////////
 
 seg cs
 mov bx,sectors  ! 取上面保存的sectors。如果sectors=15,則說明是
     ! 1.2mb的驅(qū)動(dòng)器;如果sectors=18,則說明是1.44mb
     ! 軟驅(qū)。因?yàn)槭强梢龑?dǎo)的驅(qū)動(dòng)器,所以肯定是a驅(qū)。
     
 !////////////////////////////////////////////////////
 ! 如果跳轉(zhuǎn)到root_defined,則使用ax作為參數(shù)來傳遞。
 mov ax,#0x0208  ! /dev/ps0 - 1.2Mb
 cmp bx,#15   ! 判斷每磁道扇區(qū)數(shù)是否是15
 je root_defined  ! 如果等于,則ax中就是引導(dǎo)驅(qū)動(dòng)器的設(shè)備號(hào)
 !///////////////////////////////////////////////////

 !//////////////////////////////////////////////////////
 ! 如果跳轉(zhuǎn)到root_defined,使用ax來作為參數(shù)傳遞。
 mov ax,#0x021c  ! /dev/PS0 - 1.44Mb
 !/////////////////////////////////////////////////////
 ! 使用cmp和je指令來實(shí)現(xiàn),助記符je的含義是jump equal
 cmp bx,#18
 je root_defined
 !/////////////////////////////////////////////////////

////////////////////////////////////////////////////////
undef_root:    ! 死循環(huán) - 死機(jī)
 jmp undef_root
////////////////////////////////////////////////////////

////////////////////////////////////////////////////////
root_defined:
 seg cs
 mov root_dev,ax  ! ax = 0x0208,將檢查的設(shè)備號(hào)保存。
///////////////////////////////////////////////////////

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:
! 到此,所有的程序都加在完畢,我們就跳轉(zhuǎn)到被加載在bootsect后面的setup程序去。
!
 jmpi 0,SETUPSEG  ! 跳轉(zhuǎn)到0x9020 : 0000(setup.s的開始處)。
     ! 本程序到此結(jié)束。呵呵終于結(jié)束了。

! 下面是兩個(gè)子程序。
! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in: es - starting address segment (normally 0x1000)
!
! 該子程序?qū)⑾到y(tǒng)模塊加載到內(nèi)存地址0x10000處,并確定沒有跨越64kb內(nèi)存邊界,我們?cè)噲D盡快的
! 進(jìn)行加載,只要可能,就每次加載整條磁道的數(shù)據(jù)。
! 輸入es : -- 開始內(nèi)存地址段值 (通常是0x1000)
!
sread: .word 1+SETUPLEN ! sectors read of current track
    ! 定義變量sread,表示當(dāng)前磁道中以讀的扇區(qū)數(shù)。開始時(shí)已經(jīng)讀
    ! 進(jìn)1扇區(qū)的引導(dǎo)扇區(qū),bootsect和setup程序所占的扇區(qū)數(shù)SETUPLEN.
    !
head: .word 0   ! current head,當(dāng)前磁頭號(hào)。
track: .word 0   ! current track,當(dāng)前磁道號(hào)。

read_it:
! 測(cè)試輸入的段值。必須位于內(nèi)存地址64kb邊界處,否則進(jìn)入死循環(huán)。清bx寄存器,用于表示當(dāng)前段內(nèi)
! 存放數(shù)據(jù)的開始位置。
!
! es = 0x1000
 mov ax,es
 !//////////////////////////////////////////////
 ! test指令,實(shí)現(xiàn)將原操作數(shù)用于和目的操作數(shù)按位"與"運(yùn)算,但是結(jié)果并不放在目的地址。
 ! test指令會(huì)影響到ZF的標(biāo)志位。如果"與"的結(jié)果為0,那么zf=1。
 test ax,#0x0fff
 !/////////////////////////////////////////////
 
die: jne die   ! es must be at 64kB boundary
    ! es的值必須是位于64k地址的邊界,否則進(jìn)入死循環(huán)。
 xor bx,bx  ! bx is starting address within segment
    ! bx是段內(nèi)偏移地址。
rp_read:
! 判斷是否已經(jīng)全部讀入數(shù)據(jù)。比較當(dāng)前所讀段是否就是系統(tǒng)數(shù)據(jù)的末端所處的段(endseg),
!如果不是,跳轉(zhuǎn)到下面的ok1_read標(biāo)號(hào)處繼續(xù)讀取數(shù)據(jù)。否則退出子程序返回。
!
!
 mov ax,es
 cmp ax,#ENDSEG  ! have we loaded all yet?
 jb ok1_read
 ret
 
ok1_read:
! 計(jì)算和驗(yàn)證當(dāng)前的磁道需要讀取的扇區(qū)數(shù),放在ax寄存器中。
! 根據(jù)當(dāng)前磁道還未讀取的扇區(qū)數(shù)以及段內(nèi)數(shù)據(jù)字節(jié)的開始偏
! 移量,計(jì)算如果全部讀取這些未讀扇區(qū),所讀總字節(jié)數(shù)是否
! 會(huì)超過64kb段長(zhǎng)度限制。若會(huì)超過,則根據(jù)此次最多能讀入
! 的字節(jié)數(shù)(64kb - 段內(nèi)偏移量),反算出此次需要讀取的扇區(qū)數(shù)。
!
 seg cs
 mov ax,sectors  ! 取出每個(gè)磁道扇區(qū)數(shù)
 sub ax,sread  ! 減去當(dāng)前磁道中已經(jīng)讀取的扇區(qū)數(shù)
 mov cx,ax  ! cx = ax = 當(dāng)前磁道未讀的扇區(qū)數(shù)
 shl cx,#9  ! cx = cx * 512
 add cx,bx  ! cx = cx + 段內(nèi)當(dāng)前的偏移量
    !  = 此次讀操作后,段內(nèi)共讀入的字節(jié)數(shù)。
    ! CF是進(jìn)位標(biāo)志,就是說當(dāng)執(zhí)行一個(gè)加法或減
    ! 法時(shí),最高位產(chǎn)生進(jìn)位或借位時(shí),CF就為1,否則為0.
    ! ADD它的功能是將源操作數(shù)與目標(biāo)操作數(shù)相加,
    ! 結(jié)果保存在目標(biāo)操作數(shù)中,并根據(jù)結(jié)果置標(biāo)志位.
    ! 例如:MOV?。模蹋保玻?!將12H放到數(shù)據(jù)寄存器低8位中,即DL
       ! add dl,34H 將34H和12H相加,結(jié)果保存在DL中,運(yùn)行后DL為46H
    ! 他們相加后最高位沒有進(jìn)位,所以CF=0,它們是這樣相加的
    ! 12H對(duì)應(yīng)的二進(jìn)制   00010010
                ! 34H對(duì)應(yīng)的二進(jìn)制?。。埃埃保保埃保埃?br>                !               ?。?br>                !                 01000110
    !最高位是第8位,0+0沒有進(jìn)位,所以CF=0

 jnc ok2_read  ! 如果沒有超過64kb字節(jié),則跳轉(zhuǎn)到ok2_read
    ! 進(jìn)位時(shí)轉(zhuǎn)移 jnc, cf = 0時(shí)跳轉(zhuǎn)。
 je ok2_read  !
 xor ax,ax  ! 若加上此次將讀磁道上所未讀扇區(qū)時(shí)會(huì)超過64kb
 sub ax,bx  ! 那么計(jì)算此時(shí)最多能讀入的字節(jié)數(shù)64kb - 段內(nèi)讀偏移量
 shr ax,#9  ! 再轉(zhuǎn)換成需要讀取的扇區(qū)數(shù)。
 
ok2_read:
 call read_track
 mov cx,ax  ! cx = 該次操作已讀取的扇區(qū)數(shù)
 add ax,sread  ! 當(dāng)前磁道上已經(jīng)讀取的扇區(qū)數(shù)。
 
 seg cs
 cmp ax,sectors  ! 如果當(dāng)前磁道上還有扇區(qū)未讀,則跳轉(zhuǎn)到ok3_read
 jne ok3_read
!讀該磁道的下一個(gè)磁頭面上的數(shù)據(jù)。如果已經(jīng)完成,則去讀下一個(gè)磁道。
 mov ax,#1
 sub ax,head  ! 判斷當(dāng)前的磁頭號(hào)
 
 jne ok4_read  ! 如果是0磁頭,則再去讀1磁頭面上的數(shù)據(jù)。
 inc track  ! 否則去讀取下一個(gè)磁道。
 
ok4_read:
 mov head,ax  ! 保存當(dāng)前磁道已讀扇區(qū)數(shù)
 xor ax,ax  ! 清空前磁道已讀扇區(qū)數(shù)
 
ok3_read:
 mov sread,ax  ! 保存當(dāng)前磁道已讀扇區(qū)數(shù)。
 shl cx,#9  ! 上次已讀扇區(qū)數(shù) * 512字節(jié)
 add bx,cx  ! 調(diào)整當(dāng)前段內(nèi)數(shù)據(jù)開始位置
 
 jnc rp_read  ! 如果小于64kb邊界值,則跳轉(zhuǎn)到邋rp_read處,繼續(xù)

 ! 讀取數(shù)據(jù)。否則調(diào)整當(dāng)前段,為下一個(gè)段數(shù)據(jù)做準(zhǔn)備。
 ///////////////////////////////////////////////////
 ! 將段基址調(diào)整為指向下一個(gè)64kb段內(nèi)存。
 mov ax,es
 add ax,#0x1000
 mov es,ax
 ///////////////////////////////////////////////////
 xor bx,bx  ! 清段內(nèi)數(shù)據(jù)開始偏移量
 //////////////////////////////////////////////////

 jmp rp_read

read_track:
! 讀取當(dāng)前磁道上制定開始的扇區(qū)和需要讀取的扇區(qū)數(shù)的數(shù)據(jù)到es:bx處。
! al - 需要讀取的扇區(qū)數(shù)
! es : bx - 緩沖區(qū)的位置
!
 !/////////////////////////////////////////////////
 ! 信息保護(hù)
 push ax
 push bx
 push cx
 push dx
 !/////////////////////////////////////////////////

 !////////////////////////////////////////////////
 ! 調(diào)用中斷前的準(zhǔn)備工作
 mov dx,track  ! 當(dāng)前的磁道號(hào)
 mov cx,sread  ! 去當(dāng)前磁道上已讀的扇區(qū)數(shù)
 inc cx   ! cl = 開始讀扇區(qū)
 mov ch,dl  ! ch = 當(dāng)前磁道號(hào)
 mov dx,head
 mov dh,dl
 mov dl,#0
 and dx,#0x0100
 mov ah,#2
 int 0x13
 !//////////////////////////////////////////////////
 
 jc bad_rt  ! 如果出錯(cuò)的話,跳轉(zhuǎn)到bad_rt
    ! 否則執(zhí)行下面的代碼,回復(fù)現(xiàn)場(chǎng)
 pop dx
 pop cx
 pop bx
 pop ax
 ret
! 執(zhí)行驅(qū)動(dòng)器的復(fù)位操作,在跳轉(zhuǎn)到read_track處重試
bad_rt: mov ax,#0
 mov dx,#0
 int 0x13

 ! 回復(fù)現(xiàn)場(chǎng)
 pop dx
 pop cx
 pop bx
 pop ax

 ! 重新在讀
 jmp read_track

/*
 * This procedure turns off the floppy drive motor, so
 * that we enter the kernel in a known state, and
 * don't have to worry about it later.
 */
 ! 這個(gè)子程序關(guān)閉軟驅(qū)的馬達(dá),這樣我們進(jìn)入內(nèi)核之后它處于已知的狀態(tài),所以以后也就
 ! 無需擔(dān)心了。
kill_motor:
 push dx
 mov dx,#0x3f2  ! 軟驅(qū)控制卡的驅(qū)動(dòng)端口,只寫
 mov al,#0  ! 關(guān)閉馬達(dá)
 outb   ! 將al中的內(nèi)容傳輸?shù)絛x指定的端口上去
 pop dx
 ret

sectors:   ! 存放的是當(dāng)前啟動(dòng)軟盤每磁道的扇區(qū)數(shù)
 .word 0

msg1:
 .byte 13,10
 .ascii "Loading system ..."
 .byte 13,10,13,10

.org 508   ! 標(biāo)示下面的語句從地址508開始,所以邋root_dev
    ! 在啟動(dòng)扇區(qū)的第508開始的2個(gè)字節(jié)中。
root_dev:   ! 這里存放的是根文件系統(tǒng)所在的設(shè)備號(hào),
    ! 在init/main.c中會(huì)使用。
 .word ROOT_DEV
boot_flag:   ! 硬盤的有效標(biāo)示
 .word 0xAA55

.text
endtext:
.data
enddata:
.bss
endbss:

1. 本博客中的文章均是個(gè)人在學(xué)習(xí)和項(xiàng)目開發(fā)中總結(jié)。其中難免存在不足之處 ,歡迎留言指正。 2. 本文版權(quán)歸作者和博客園共有,轉(zhuǎn)載時(shí),請(qǐng)保留本文鏈接。

2
0
(請(qǐng)您對(duì)文章做出評(píng)價(jià))
上一篇:linux下內(nèi)存管理簡(jiǎn)介
下一篇:linux 0.11 內(nèi)核學(xué)習(xí) -- setup.s

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    亚洲男人的天堂久久a| 五月婷日韩中文字幕四虎| 国产欧美高清精品一区| 自拍偷拍一区二区三区| 国产女高清在线看免费观看| 亚洲日本加勒比在线播放| 99免费人成看国产片| 欧美国产日本高清在线| 又大又紧又硬又湿又爽又猛| 欧美日韩国产精品黄片| 美女黄色三级深夜福利| 精品少妇一区二区视频| 91福利免费一区二区三区| 久久机热频这里只精品| 日韩欧美国产三级在线观看| 精品亚洲av一区二区三区| 91人人妻人人爽人人狠狠| 91人妻人人澡人人人人精品| 国产不卡免费高清视频| 日系韩系还是欧美久久| 欧美日韩一区二区三区色拉拉 | 搡老熟女老女人一区二区| 久久永久免费一区二区| 东京干男人都知道的天堂| 亚洲精品偷拍视频免费观看| 人妻一区二区三区多毛女| 日韩少妇人妻中文字幕| 日韩精品少妇人妻一区二区| 好东西一起分享老鸭窝| 狠狠做五月深爱婷婷综合| 国产欧美一区二区久久| 国内九一激情白浆发布| 日韩丝袜诱惑一区二区| 在线欧美精品二区三区| 国产精品美女午夜福利| 丁香七月啪啪激情综合| 人妻精品一区二区三区视频免精| 草草视频福利在线观看| 欧美一级内射一色桃子| 免费在线播放一区二区| 五月激情婷婷丁香六月网|