線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2363
推到 Plurk!
推到 Facebook!

FREEDOS 的BOOT.ASM文件詳細說明

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-04-09 15:29:33 IP:61.221.xxx.xxx 未訂閱
此為轉貼資料 http://depos.patching.net/showart.asp?art_id=82&cat_id=5 FREEDOS 的BOOT.ASM文件詳細說明 本文件主要用來寫引導磁區程式。這個程式引導了整個DOS系統到記憶體。 ; ; file: ; boot.asm ; Description: ; DOS-C boot ; ; Copyright (c) 1997; ; Svante Frey ; All Rights Reserved ; ; ;Þfine ISFAT12 1 ;Þfine ISFAT16 1 ;Þfine CALCPARAMS 1 ;Þfine MULTI_SEC_READ 1 ;代碼段開始。 segment .text ;巨集定義,指向基底位址 Þfine BASE 7c00h ;定義執行文件開始運行的位置. org BASE ;程式的入口,然後跳到real_start開始運行. Entry: jmp short real_start ;一條空指令 nop ; ;初始化基址寄存器指標BP指向地址:7c00h ;巨集定義參數表。因爲JMP指令佔用兩個位元組,NOP指令佔用一個位元組。 ;所以偏移地址就從BP 3開始,就是從0000:7C03開始。 Þfine bsOemName bp 3 ; OEM標置. Þfine bsBytesPerSec bp 0bh ; 每磁區位元組數. Þfine bsSecPerClust bp 0dh ; 每簇磁區數 Þfine bsResSectors bp 0eh ; 保留磁區數。 Þfine bsFATs bp 10h ; FAT數目。 Þfine bsRootDirEnts bp 11h ; 根目錄登記項數。 Þfine bsSectors bp 13h ; 總磁區數 Þfine bsMedia bp 15h ; 磁片介質描標誌: fd=2side9sec, etc... Þfine sectPerFat bp 16h ; 每個FAT的磁區數。 Þfine sectPerTrack bp 18h ; 每道磁區數 Þfine nHeads bp 1ah ; 磁頭數 Þfine nHidden bp 1ch ; 隱藏磁區數 Þfine nSectorHuge bp 20h ; 磁片磁區數# sectors if > 65536 Þfine drive bp 24h ;驅動器的數位 Þfine extBoot bp 26h ; 擴展引導的標誌。 Þfine volid bp 27h ;卷ID。 Þfine vollabel bp 2bh ;卷標。 Þfine filesys bp 36h ;文件系統。 Þfine LOADSEG 0060h Þfine FATBUF 4000h ; offset of temporary buffer for FAT ; chain ; Some extra variables ;臨時變數保存位置。 Þfine StoreSI bp 3h ;temp store ; To save space, functions that are just called once are ; implemented as macros instead. Four bytes are saved by ; avoiding the call / ret instructions. ; GETDRIVEPARMS: Calculate start of some disk areas. ; 計算磁片區的開始位置,主要根據下面的公式來算。。 ; 文件起始區磁區號 = 隱藏磁區數 保留磁區數 每個FAT的磁區數X FAT數目 ; 根目錄登記專案/( 每磁區位元組數/32)。 ; ;巨集定義開始。 %macro GETDRIVEPARMS 0 ;算出:隱藏磁區數 保留磁區數 ;得到隱藏磁區數。 ;低字送到SI。 mov si, word [nHidden] ;高字送到DI。 mov di, word [nHidden 2] ;加保留磁區數到SI。 add si, word [bsResSectors] ;調整DI進位元標誌。DI:SI爲每個FAT開始位置磁區。 adc di, byte 0 ; DI:SI = first FAT sector ;保存FAT表的開始位置。 mov word [fat_start], si mov word [fat_start 2], di ;算出:每個FAT的磁區數X FAT數目 ; ;得到FAT的數目。用來 mov al, [bsFATs] ;清空AH。 xor ah, ah ;算出總共有多少個磁區。 mul word [sectPerFat] ; DX:AX = total number of FAT sectors ;算出第一個根目錄DI:SI位置。 add si, ax adc di, dx ; DI:SI = first root directory sector ;保存根目錄的位置。 mov word [root_dir_start], si mov word [root_dir_start 2], di ; Calculate how many sectors the root directory occupies. ;計算根目錄總共有多少磁區。 ;得到每磁區有多少位元組。 mov bx, [bsBytesPerSec] ;設置CL = 5。 mov cl, 5 ; divide BX by 32 ;BX除以32,因爲DOS目錄是32位元組長, ;BX就是每個磁區有多少個目錄。 shr bx, cl ; BX = directory entries per sector ;得到根目錄有多少個入口 mov ax, [bsRootDirEnts] xor dx, dx div bx ;得到每個根目錄的磁區數。 mov word [RootDirSecs], ax ; AX = sectors per root directory ;得到DI:SI爲指向第一個資料磁區。 add si, ax adc di, byte 0 ; DI:SI = first data sector ;保存第一個資料磁區的位置。 mov [data_start], si mov [data_start 2], di %endmacro ;----------------------------------------------------------------------- times 3Eh-$ $$ db 0 Þfine tempbuf bp 3Eh dw LOADSEG %ifdef CALCPARAMS Þfine RootDirSecs bp 27h ; # of sectors root dir uses Þfine fat_start bp 29h ; first FAT sector Þfine root_dir_start bp 2Dh ; first root directory sector Þfine data_start bp 31h ; first data sector %else Þfine RootDirSecs bp 40h ; # of sectors root dir uses dw 0 Þfine fat_start bp 42h ; first FAT sector dd 0 Þfine root_dir_start bp 46h ; first root directory sector dd 0 Þfine data_start bp 4Ah ; first data sector dd 0 %endif ;----------------------------------------------------------------------- ; 程式入口處 ;----------------------------------------------------------------------- real_start: ;清中斷 cli ;清爲DF標置爲0,執行串操作時,使地址按遞增方向變化 cld ; mov ax, cs ;清ax爲0. xor ax, ax ; 初始化堆疊段,ss爲0. mov ss, ax ;清ds爲0. mov ds, ax ;指向地址0000:7c00h處. mov bp, 7c00h ;把7BE0H的所在的地址送給sp.0000:7BE0H作爲棧區開始位置。 lea sp, [bp-20h] ;使開中斷. Sti ; int 13h ; 重定驅動器. ; int 12h ; get memory available in AX ;設置AX = 480,爲1E0H。 mov ax, 480 ;計算要把自己移動高端記憶體的位址。 ;設置CL= 6,移位6次。 mov cl, 6 ;左移6位.結果AX = 7800H shl ax, cl ;AX = 7020H sub ax, 07e0h ;設置ES = 7020H mov es, ax ;設置SI=7C00H mov si, bp ;設置DI = 7C00H mov di, bp ;移動256個字,就是說512位元組. mov cx, 256 ;開始移動,從0000:7C000移到7020:7C00. rep movsw ;保存ES=7020H到棧區。 push es ;得到cont偏移地址 mov bx, cont ;保存到棧區 push bx ;調用一條段間返回指令,結果是IP = cont的位址,CS = ES = 7020H, ;然後跳到7020:cont地方執行,就是剛才的代碼移動到的新地方繼續運 ;行原來的程式。 retf ;下面是繼續執行原來的程式。 ;設置資料段DS = 7020H,爲現在代碼所在的資料段地址。 cont: mov ds, ax; ;設置SS = AX = 7020爲棧段地址。 mov ss, ax ;因爲BIOS保存總共有多少個驅動器數目在DL中,所以保存BP 24H處。 mov [drive], dl ; BIOS passes drive number in DL ;調用螢幕輸出子過程。 call print db "Loading FreeDOS...",13,10,"ROOT",0 ;如果定義了計算參數,就包含進來。 %ifdef CALCPARAMS ;計算資料磁區的開始位置。 GETDRIVEPARMS %endif ; 搜索根目錄下的文件。 ; FINDfile: Searches for the file in the root directory. ; ; 返回Returns: ; AX = first cluster of file ; First, read the whole root directory ; into the temporary buffer. ;得到根目錄開始磁區。 mov ax, word [root_dir_start] mov dx, word [root_dir_start 2] ;得到根目錄的磁區數。 mov di, word [RootDirSecs] xor bx, bx ;得到臨時目錄地址。 mov es, [tempbuf] ;調用讀磁片子過程。 call readDisk ;如果出錯就跳到出錯處理。 jc jmp_boot_error xor di, di ;比較檔案名"KERNEL SYS", next_entry: mov cx, 11 mov si, filename push di repe cmpsb pop di mov ax, [es:di 1ah] ; get cluster number from directory entry ;如檔案名相等就跳走。 je ffDone ;如果第一個不是KERNEL.SYS就到下一個目錄入口。 add di, byte 20h ; go to next directory entry cmp byte [es:di], 0 ; if the first byte of the name is 0, jnz next_entry ; there is no more files in the directory ;讀KERNEL.SYS出錯。 jc boot_error ; fail if not found ffDone: ;如果找到KERNEL.SYS目錄, call print db " FAT",0 ; 下面得到FAT鏈表。 ; GETFATCHAIN: ; ; Reads the FAT chain and stores it in a temporary buffer in the first ; 64 kb. The FAT chain is stored an array of 16-bit cluster numbers, ; ending with 0. ; ; The file must fit in conventional memory, so it cant be larger than ; 640 kb. The sector size must be at least 512 bytes, so the FAT chain ; cant be larger than around 3 kb. ; ; Call with: AX = first cluster in chain push ax ; store first cluster number ; Load the complete FAT into memory. The FAT cant be larger ; than 128 kb, so it should fit in the temporary buffer. mov es, [tempbuf] xor bx, bx mov di, [sectPerFat] mov ax, word [fat_start] mov dx, word [fat_start 2] call readDisk pop ax ; restore first cluster number jmp_boot_error: jc boot_error ; Set ES:DI to the temporary storage for the FAT chain. push ds push es pop ds pop es mov di, FATBUF next_clust: stosw ; store cluster number mov si, ax ; SI = cluster number ; cmp byte ptr extBoot, 29h ; jne fat_12 ; cmp byte ptr filesys[4], 6 ; check for FAT-16 system ; je fat_16 ;如果是FAT12處理。 %ifdef ISFAT12 ; This is a FAT-12 disk. fat_12: add si, si ; multiply cluster number by 3... add si, ax shr si, 1 ; ...and divide by 2 lodsw ; If the cluster number was even, the cluster value is now in ; bits 0-11 of AX. If the cluster number was odd, the cluster ; value is in bits 4-15, and must be shifted right 4 bits. If ; the number was odd, CF was set in the last shift instruction. jnc fat_even mov cl, 4 shr ax, cl ; shift the cluster number fat_even: and ah, 0fh ; mask off the highest 4 bits cmp ax, 0fffh ; check for EOF jb next_clust ; continue if not EOF %endif ;如果是FAT16處理。 %ifdef ISFAT16 ; This is a FAT-16 disk. The maximal size of a 16-bit FAT ; is 128 kb, so it may not fit within a single 64 kb segment. fat_16: mov dx, [tempbuf] add si, si ; multiply cluster number by two jnc first_half ; if overflow... add dh, 10h ; ...add 64 kb to segment value first_half: mov ds, dx ; DS:SI = pointer to next cluster lodsw ; AX = next cluster cmp ax, 0fff8h ; >= FFF8 = 16-bit EOF jb next_clust ; continue if not EOF %endif finished: ; Mark end of FAT chain with 0, so we have a single ; EOF marker for both FAT-12 and FAT-16 systems. xor ax, ax stosw push cs pop ds call print db " KERNEL",0 ; loadfile: Loads the file into memory, one cluster at a time. ; 讀文件進入記憶體,一次讀一簇。 mov es, [tempbuf] ; set ES:BX to load address xor bx, bx mov si, FATBUF ; set DS:SI to the FAT chain ; cluster_next: lodsw ; AX = next cluster to read or ax, ax ; if EOF... je boot_success ; ...boot was successful dec ax ; cluster numbers start with 2 dec ax mov di, word [bsSecPerClust] and di, 0ffh ; DI = sectors per cluster mul di add ax, [data_start] adc dx, [data_start 2] ; DX:AX = first sector to read call readDisk jnc cluster_next boot_error: call print db 13,10,"BOOT error!",0 jmp short $ ; sleep boot_success: call print db " GO!",13,10,0 mov bl, [drive] ;跳到 0000:0060執行。???? jmp word LOADSEG:0 ;調用這個子過程來從螢幕輸出文字提示資訊。 ; ;保存SI 到 StoreSI = BP 3. print: mov [StoreSI], si ;得到字串的首位址,因用CALL指令調用時,把下一條指令壓入棧, ;就是說這個位址就是指跟在CALL PRINT後面的字串位址。 pop si ;保存返回段地址 。 push ax ;保存返回的指令開始執行的位址。 push bx ;保存基址指標。 push di ;清空BX爲0 。 xor bx, bx ; video page 0 ;調用BIOS顯示中斷10H中的功能0EH。 mov ah, 0Eh ; else print it ;裝入顯示的字串。把位元組送到 AL = 要示的位元組,SI增加1。 print1: lodsb ; get token ;比較是否到了字串的結束位置。 cmp al, 0 ; end of string? ;如果是字串結束就跳到print2運行。 je print2 ; if so, exit ;如果沒有結束就繼續調用BIOS中斷10H顯示。 int 10h ; via TTY mode ;直到顯示完成。 jmp short print1 ; until done ;設置返回的地址。 print2: pop di pop bx pop ax ;由於執行完LODSB指令後,SI就指向字串後面的指令。 ;所以把它壓入棧區,以便返回時執行下條指令。 push si ; stack up return address ;取回原來的SI。 mov si, [StoreSI] ;跳到字串後面的指令 ret ; and jump to it ; ;讀磁片磁區資料到記憶體。 ; readDisk: Reads a number of sectors into memory. ; ; Call with: DX:AX = 32-bit DOS 邏輯磁區號。 ; DI = 要讀幾個磁區數。 ; ES:BX = 讀出的資料放到的緩衝區位址。 ; ES 必需是 64k 爲邊界(1000h, 2000h etc). ; ; Returns: CF set on error ; ES:BX points one byte after the last byte read. ;保存SI。 readDisk: push si ;保存DX read_next: push dx ;保存AX push ax ; ;轉換DOS邏輯磁區參數爲BIOS參數的形式。 ; ; ;絕對磁區號 = 物理磁區號 ; 物理磁頭號 * 每道磁區數 ; 物理磁軌號 * 每道磁區數 * 磁頭數 ;所以算出BIOS參數用下面的公式: ;(絕對磁區號 - 物理磁區號)/每道磁區數 = 物理磁頭號 ; 物理磁軌號 * 磁頭數 ;(絕對磁區號 / 每道磁區數)的 商 等於 ;物理磁頭號 物理磁軌號 * 磁頭數,(商在AX中)。 ;絕對磁區號 mod 每道磁區數 等於 物理磁區號,(餘數在DX中)。 div word [sectPerTrack] mov cx, dx ; ; (AX) = 物理磁頭號 物理磁軌號 * 磁頭數 ; ;AX中有除法後商,DX中有除法後的餘數。 ; 物理磁軌號 = (AX) / 磁頭數 (ax has track) ; 物理磁頭號 = (AX) mod磁頭數 (dl has head) ; xor dx, dx div word [nHeads] ; the following manipulations are necessary in order to ; properly place parameters into registers. ;下面處理合適參數到寄存器。 ; ch = 磁片柱面號的低 8 位。 ; cl = 7-6: 磁片柱面號的高 2 位 ; 5-0: sector mov dh, dl ; 磁頭號。 ror ah, 1 ; move track high bits into ror ah, 1 ; bits 7-6 (assumes top = 0) xchg al, ah ; swap for later mov dl, byte [sectPerTrack] sub dl, cl inc cl ; 起始的磁區號。 or cx, ax ; merge cylinder into sector mov al, dl ; al has # of sectors left %ifdef MULTI_SEC_READ ;如果定義讀多磁區 ;計算有多少磁區能傳輸,因爲DMA存邊界限制。 ; Calculate how many sectors can be transfered in this read ; due to dma boundary conditions. push dx mov si, di ; temp register save ; this computes remaining bytes because of modulo 65536 ; nature of dma boundary condition mov ax, bx ; get offset pointer neg ax ; and convert to bytes jz ax_min_1 ; started at seg:0, skip ahead xor dx, dx ; convert to sectors div word [bsBytesPerSec] cmp ax, di ; check remainder vs. asked jb ax_min_1 ; less, skip ahead mov si, ax ; transfer only what we can ax_min_1: pop dx ; Check that request sectors do not exceed track boundary mov si, [sectPerTrack] inc si mov ax, cx ; get the sector/cyl byte and ax, 03fh ; and mask out sector sub si, ax ; si has how many we can read mov ax, di cmp si, di ; see if asked <= available jge ax_min_2 mov ax, si ; get what can be xfered ;ax_min_2: mov ah, 2 ax_min_2: push ax mov ah, 2 mov dl, [drive] int 13h pop ax %else ;讀入一個磁區。 ;調用BIOS中斷 13h讀功能。 mov ax, 0201h mov dl, [drive] int 13h %endif jnc read_ok ; 如果沒有錯就跳到讀完。 xor ah, ah ; 否則就重定軟盤機 int 13h pop ax pop dx ; 試著再讀一次這個磁區。 jmp short read_next ; read_ok: %ifdef MULTI_SEC_READ ; cbw ; mov si, ax ; mul word ptr bsBytesPerSec ; add number of bytes read to BX mul word [bsBytesPerSec] ; add number of bytes read to BX add bx, ax %else add bx, word [bsBytesPerSec] %endif jnc no_incr_es ; if overflow... mov ax, es add ah, 10h ; ...add 1000h to ES mov es, ax no_incr_es: pop ax pop dx ; DX:AX = last sector number ; call print ; db ".",0 %ifdef MULTI_SEC_READ add ax, si adc dx, byte 0 ; DX:AX = next sector to read sub di,si ; if there is anything left to read, jg read_next ; continue %else add ax, 1 adc dx, byte 0 ; DX:AX = next sector to read dec di ; if there is anything left to read, jnz read_next ; continue %endif clc pop si ret ;要讀入內核的檔案名。 filename db "KERNEL SYS" times 01feh-$ $$ db 0 sign dw 0aa55h ********************************************************* 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together! 希望能大家敞開心胸,將知識寶庫結合一起
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-11-21 23:51:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!