?? loader.asm
字號(hào):
;=============================================================================
; Kitnix ver 0.01
; Write by Kit
; 2008-10-31
;
; Loader.asm
; Show the menu
; Control the computer
; Open the user file
; Restart or Shutdown
;=============================================================================
;==============================================================================
;%define _BOOT_DEBUG_
org 0100h
BaseOfStack equ 0100h
BaseOfUserFile equ 08000h
OffsetOfUserFile equ 0100h
;==============================================================================
jmp LABEL_START
%include "fat12hdr.inc"
;==============================================================================
LABEL_START:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
again:
mov ax, RootDirSectors ; 還原 wRootDirSizeForLoop
mov [wRootDirSizeForLoop], ax ; Root Directory 占用的扇區(qū)數(shù), 在循環(huán)中會(huì)遞減至零.
mov ax, BootMessage
mov bp, ax
mov ax, ds
mov es, ax
mov cx, 086H
mov ax, 01301h
mov bx, 000Bh
mov dx, 0300H
int 10H
mov ah, 00H ; ┓
int 16H ; ┣ 鍵盤(pán)讀入 + 回顯
mov ah, 0EH ; ┃
int 10H ; ┛
n1:
cmp al, '1'
jnz n2
mov bx, FirstFileName
mov [choice], bx
jmp Find
n2:
cmp al, '2'
jnz n3
mov bx, SecondFileName
mov [choice], bx
jmp Find
n3:
cmp al, '3'
jnz n4
mov ax, 0600h ; AH = 6, AL = 0h
mov bx, 0700h ; 黑底白字(BL = 07h)
mov cx, 0 ; 左上角: (0, 0)
mov dx, 0184fh ; 右下角: (80, 50)
int 10h ; int 10h
jmp again
n4:
cmp al, '4'
jnz n5
jmp 0ffffh:0000h ; 重啟
n5:
cmp al, '5'
jnz again
%ifdef _BOOT_DEBUG_
mov ax, 4c00h
int 21h
%else
; 關(guān)機(jī)實(shí)現(xiàn)
mov ax,5301h ;Function 5301h: APM Connect real-mode interface
xor bx,bx ;Device ID: 0000h (=system BIOS)
int 15h ;Call interrupt: 15h
mov ax,530eh ;Function 530Eh: APM Driver version
mov cx,0102h ;Driver version: APM v1.2
int 15h ;Call interrupt: 15h
mov ax,5307h ;Function 5307h: APM Set system power state
mov bl,01h ;Device ID: 0001h (=All devices)
mov cx,0003h ;Power State: 0003h (=Off)
int 15h ;Call interrupt: 15h
%endif
;----------------------------------------------------------------------------
; 函數(shù)名: Find
;----------------------------------------------------------------------------
; 作用:
; 在軟盤(pán)中尋找 用戶(hù)文件
Find:
xor ah, ah ; ┓
xor dl, dl ; ┣ 軟驅(qū)復(fù)位
int 13h ; ┛
mov dh, 0
call DispStr
; 下面在 A 盤(pán)的根目錄尋找 用戶(hù)文件
mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
cmp word [wRootDirSizeForLoop], 0 ; ┓
jz LABEL_NO_LOADERBIN ; ┣ 判斷根目錄區(qū)是不是已經(jīng)讀完
dec word [wRootDirSizeForLoop] ; ┛ 如果讀完表示沒(méi)有找到 用戶(hù)文件
mov ax, BaseOfUserFile
mov es, ax ; es <- BaseOfUserFile
mov bx, OffsetOfUserFile ; bx <- OffsetOfUserFile 于是, es:bx = BaseOfUserFile:OffsetOfUserFile
mov ax, [wSectorNo] ; ax <- Root Directory 中的某 Sector 號(hào)
mov cl, 1
call ReadSector
mov si, [choice] ; ds:si -> 用戶(hù)文件名
mov di, OffsetOfUserFile ; es:di -> BaseOfUserFile:0100 = BaseOfUserFile*10h+100
cld
mov dx, 10h
LABEL_SEARCH_FOR_LOADERBIN:
cmp dx, 0 ; ┓循環(huán)次數(shù)控制,
jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR ; ┣如果已經(jīng)讀完了一個(gè) Sector,
dec dx ; ┛就跳到下一個(gè) Sector
mov cx, 11
LABEL_CMP_FILENAME:
cmp cx, 0
jz LABEL_FILENAME_FOUND ; 如果比較了 11 個(gè)字符都相等, 表示找到
dec cx
lodsb ; ds:si -> al
cmp al, byte [es:di]
jz LABEL_GO_ON
jmp LABEL_DIFFERENT ; 只要發(fā)現(xiàn)不一樣的字符就表明本 DirectoryEntry 不是我們要找的 用戶(hù)文件
LABEL_GO_ON:
inc di
jmp LABEL_CMP_FILENAME ; 繼續(xù)循環(huán)
LABEL_DIFFERENT:
and di, 0FFE0h ; else ┓ di &= E0 為了讓它指向本條目開(kāi)頭
add di, 20h ; ┃
mov si, [choice] ; ┣ di += 20h 下一個(gè)目錄條目
jmp LABEL_SEARCH_FOR_LOADERBIN ; ┛
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
add word [wSectorNo], 1
jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN
LABEL_NO_LOADERBIN:
mov dh, 2 ; "NO USER FILE."
call DispStr ; 顯示字符串
jmp again
LABEL_FILENAME_FOUND: ; 找到 用戶(hù)文件 后便來(lái)到這里繼續(xù)
mov ax, RootDirSectors
and di, 0FFE0h ; di -> 當(dāng)前條目的開(kāi)始
add di, 01Ah ; di -> 首 Sector
mov cx, word [es:di]
push cx ; 保存此 Sector 在 FAT 中的序號(hào)
add cx, ax
add cx, DeltaSectorNo ; 這句完成時(shí) cl 里面變成 用戶(hù)文件 的起始扇區(qū)號(hào) (從 0 開(kāi)始數(shù)的序號(hào))
mov ax, BaseOfUserFile
mov es, ax ; es <- BaseOfUserFile
mov bx, OffsetOfUserFile ; bx <- OffsetOfUserFile 于是, es:bx = BaseOfUserFile:OffsetOfUserFile = BaseOfUserFile * 10h + OffsetOfUserFile
mov ax, cx ; ax <- Sector 號(hào)
LABEL_GOON_LOADING_FILE:
push ax ; ┓
push bx ; ┃
mov ah, 0Eh ; ┃ 每讀一個(gè)扇區(qū)就在 "Loading " 后面打一個(gè)點(diǎn), 形成這樣的效果:
mov al, '.' ; ┃
mov bl, 0Fh ; ┃ Loading ......
int 10h ; ┃
pop bx ; ┃
pop ax ; ┛
mov cl, 1
call ReadSector
pop ax ; 取出此 Sector 在 FAT 中的序號(hào)
call GetFATEntry
cmp ax, 0FFFh
jz LABEL_FILE_LOADED
push ax ; 保存 Sector 在 FAT 中的序號(hào)
mov dx, RootDirSectors
add ax, dx
add ax, DeltaSectorNo
add bx, [BPB_BytsPerSec]
jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
mov dh, 1 ; "Ready."
call DispStr ; 顯示字符串
; *****************************************************************************************************
jmp BaseOfUserFile:OffsetOfUserFile ; 這一句正式跳轉(zhuǎn)到已加載到內(nèi)存中的 用戶(hù)文件的開(kāi)始處
; 開(kāi)始執(zhí)行 用戶(hù)文件 的代碼
; Find 的使命到此結(jié)束
; *****************************************************************************************************
ret
;----------------------------------------------------------------------------
; 函數(shù)名: DispStr
;----------------------------------------------------------------------------
; 作用:
; 顯示一個(gè)字符串
DispStr:
mov ax, MessageLength
mul dh
add ax, LoadMessage
mov bp, ax
mov ax, ds
mov es, ax
mov cx, MessageLength
mov ax, 01301h
mov bx, 000Bh
or dh, dh
jz prn
mov dh, 1
prn:
add dh, 10
xor dl, dl
int 10H
ret
;----------------------------------------------------------------------------
; 函數(shù)名: ReadSector
;----------------------------------------------------------------------------
; 作用:
; 從第 ax 個(gè) Sector 開(kāi)始, 將 cl 個(gè) Sector 讀入 es:bx 中
ReadSector:
; -----------------------------------------------------------------------
; 怎樣由扇區(qū)號(hào)求扇區(qū)在磁盤(pán)中的位置 (扇區(qū)號(hào) -> 柱面號(hào), 起始扇區(qū), 磁頭號(hào))
; -----------------------------------------------------------------------
; 設(shè)扇區(qū)號(hào)為 x
; ┌ 柱面號(hào) = y >> 1
; x ┌ 商 y ┤
; -------------- => ┤ └ 磁頭號(hào) = y & 1
; 每磁道扇區(qū)數(shù) │
; └ 余 z => 起始扇區(qū)號(hào) = z + 1
push bp
mov bp, sp
sub esp, 2 ; 辟出兩個(gè)字節(jié)的堆棧區(qū)域保存要讀的扇區(qū)數(shù): byte [bp-2]
mov byte [bp-2], cl
push bx ; 保存 bx
mov bl, [BPB_SecPerTrk] ; bl: 除數(shù)
div bl ; y 在 al 中, z 在 ah 中
inc ah ; z ++
mov cl, ah ; cl <- 起始扇區(qū)號(hào)
mov dh, al ; dh <- y
shr al, 1 ; y >> 1 (其實(shí)是 y/BPB_NumHeads, 這里BPB_NumHeads=2)
mov ch, al ; ch <- 柱面號(hào)
and dh, 1 ; dh & 1 = 磁頭號(hào)
pop bx ; 恢復(fù) bx
; 至此, "柱面號(hào), 起始扇區(qū), 磁頭號(hào)" 全部得到
mov dl, [BS_DrvNum] ; 驅(qū)動(dòng)器號(hào) (0 表示 A 盤(pán))
.GoOnReading:
mov ah, 2 ; 讀
mov al, byte [bp-2] ; 讀 al 個(gè)扇區(qū)
int 13h
jc .GoOnReading ; 如果讀取錯(cuò)誤 CF 會(huì)被置為 1, 這時(shí)就不停地讀, 直到正確為止
add esp, 2
pop bp
ret
;----------------------------------------------------------------------------
; 函數(shù)名: GetFATEntry
;----------------------------------------------------------------------------
; 作用:
; 找到序號(hào)為 ax 的 Sector 在 FAT 中的條目, 結(jié)果放在 ax 中
; 需要注意的是, 中間需要讀 FAT 的扇區(qū)到 es:bx 處, 所以函數(shù)一開(kāi)始保存了 es 和 bx
GetFATEntry:
push es
push bx
push ax
mov ax, BaseOfUserFile ; ┓
sub ax, 0100h ; ┣ 在 BaseOfUserFile 后面留出 4K 空間用于存放 FAT
mov es, ax ; ┛
pop ax
mov byte [bOdd], 0
mov bx, 3
mul bx ; dx:ax = ax * 3
mov bx, 2
div bx ; dx:ax / 2 ==> ax <- 商, dx <- 余數(shù)
cmp dx, 0
jz LABEL_EVEN
mov byte [bOdd], 1
LABEL_EVEN:;偶數(shù)
xor dx, dx ; 現(xiàn)在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面來(lái)計(jì)算 FATEntry 在哪個(gè)扇區(qū)中(FAT占用不止一個(gè)扇區(qū))
mov bx, [BPB_BytsPerSec]
div bx ; dx:ax / BPB_BytsPerSec ==> ax <- 商 (FATEntry 所在的扇區(qū)相對(duì)于 FAT 來(lái)說(shuō)的扇區(qū)號(hào))
; dx <- 余數(shù) (FATEntry 在扇區(qū)內(nèi)的偏移)。
push dx
mov bx, 0 ; bx <- 0 于是, es:bx = (BaseOfUserFile - 100):00 = (BaseOfUserFile - 100) * 10h
add ax, SectorNoOfFAT1 ; 此句執(zhí)行之后的 ax 就是 FATEntry 所在的扇區(qū)號(hào)
mov cl, 2
call ReadSector ; 讀取 FATEntry 所在的扇區(qū), 一次讀兩個(gè), 避免在邊界發(fā)生錯(cuò)誤, 因?yàn)橐粋€(gè) FATEntry 可能跨越兩個(gè)扇區(qū)
pop dx
add bx, dx
mov ax, [es:bx]
cmp byte [bOdd], 1
jnz LABEL_EVEN_2
shr ax, 4
LABEL_EVEN_2:
and ax, 0FFFh
LABEL_GET_FAT_ENRY_OK:
pop bx
pop es
ret
;============================================================================
;字符串
;----------------------------------------------------------------------------
BootMessage: db "Hello, this is Kit's World!", 13, 10
db "1. First Program", 13, 10
db "2. Second Program", 13, 10
db "3. Clean Screen", 13, 10
db "4. Restart", 13, 10
db "5. Shutdown", 13, 10
db "Please input your choose: "
FirstFileName db "FIRST BIN", 0 ; 用戶(hù)文件名1
SecondFileName db "SECOND BIN", 0 ; 用戶(hù)文件名2
LoadMessage: db "Loading "
SuccessMessage db "File Ready "
FailMessage db "NO USER FILE"
;============================================================================
;變量
;----------------------------------------------------------------------------
wRootDirSizeForLoop dw 0
wSectorNo dw 0 ; 要讀取的扇區(qū)號(hào)
bOdd db 0 ; 奇數(shù)還是偶數(shù)
choice dw 0
MessageLength equ 12
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -