您的位置:首页 > 其它

操作系统u盘启动扇区

2012-07-12 00:00 267 查看
org 07c00h
; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行

BaseOfStack
equ
07c00h
; Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)

BaseOfLoader
equ
09000h
; LOADER.BIN 被加载到的位置 ---- 段地址

OffsetOfLoader
equ
0100h
; LOADER.BIN 被加载到的位置 ---- 偏移地址

RootDirSectors
equ
14
; 根目录占用空间

SectorNoOfRootDirectory
equ
19
; Root Directory 的第一个扇区号

SectorNoOfFAT1
equ
1
; FAT1 的第一个扇区号 = BPB_RsvdSecCnt

DeltaSectorNo
equ
17
; DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2

; 文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo

;================================================================================================

jmp short LABEL_START
; Start to boot.

nop
; 这个 nop 不可少

BP_OEMName
DB 'FXSTAR1 '

BPB_BytsPerSec
DW 512
; 每扇区字节数

BPB_SecPerClus
DB 1
; 每簇多少扇区

BPB_RsvdSecCnt
DW 1
; Boot 记录占用多少扇区

BPB_NumFATs
DB 2
; 共有多少 FAT 表

BPB_RootEntCnt
DW 224
; 根目录文件数最大值

BPB_TotSec16
DW 2880
; 逻辑扇区总数

BPB_Media
DB 0xF0
; 媒体描述符

BPB_FATSz16
DW 9
; 每FAT扇区数

BPB_SecPerTrk
DW 18
; 每磁道扇区数

BPB_NumHeads
DW 2
; 磁头数(面数)

BPB_HiddSec
DD 0
; 隐藏扇区数

BPB_TotSec32
DD 0
; 如果 wTotalSectorCount 是 0 由这个值记录扇区数

BS_DrvNum
DB 0
; 中断 13 的驱动器号

BS_Reserved1
DB 0
; 未使用

BS_BootSig
DB 29h
; 扩展引导标记 (29h)

BS_VolID
DD 0
; 卷序列号

BS_VolLab
DB 'AREA OS v01'; 卷标, 必须 11 个字节

BS_FileSysType
DB 'FAT12 '
; 文件系统类型, 必须 8个字节

LABEL_START:

mov
ax, cs

mov
ds, ax

mov
es, ax

mov
ss, ax

mov
sp, BaseOfStack

call
os_cls

call
os_searchfile

; *****************************************************************************************************

jmp
BaseOfLoader:OffsetOfLoader
; 这一句正式跳转到已加载到内

; 存中的 LOADER.BIN 的开始处,

; 开始执行 LOADER.BIN 的代码。

; Boot Sector 的使命到此结束。

; *****************************************************************************************************

;----------------------------------------------------------------------------

;AREA OS FUNCTION

os_cls:

mov
ax, 0600h

mov
bx, 0700h

mov
cx, 0000h

mov
dx, 184fh

int
10h

mov ah, 02h

mov bh, 00h

mov
dx, 00h

int 10h

mov
ax, 0

mov
[ds:position_x], al

mov
[ds:position_y], al

ret

os_message:
;输入参数:ax-数据起始地址

mov
bx, ax

add
ax, 2

mov bp, ax ; ES:BP = 串地址

mov cx, [es:bx]
; CX = 串长度

mov
ax, 0

mov ax, 1301h
; AH = 13, AL = 01h

mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)

mov
dl, [ds:position_x]
; 列

mov
dh, [ds:position_y]
; 行

int 10h ; int 10h

mov
bl, [ds:position_y]

add
bx, 1

mov
ax, cx

mov
dl, 80

div
dl

add
bx, ax

mov
[ds:position_y],bl

ret

os_getfatentry:

push
es

push
bx

push
ax

mov
ax, BaseOfLoader
; `.

sub
ax, 0100h
; | 在 BaseOfLoader 后面留出 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 <- 余数

cmp
dx, 0

jz
LABEL_EVEN

mov
byte [bOdd], 1

LABEL_EVEN:
;偶数

; 现在 ax 中是 FATEntry 在 FAT 中的偏移量,下面来

; 计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)

xor
dx, dx

mov
bx, [BPB_BytsPerSec]

div
bx
; dx:ax / BPB_BytsPerSec

; ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号)

; dx <- 余数 (FATEntry 在扇区内的偏移)。

push
dx

mov
bx, 0
; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00

add
ax, SectorNoOfFAT1
; 此句之后的 ax 就是 FATEntry 所在的扇区号

mov
cx, 2

call
os_readsector
; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界

; 发生错误, 因为一个 FATEntry 可能跨越两个扇区

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

os_readsector:
;输入参数:ax-起始扇区位置 es:bx-传输缓冲区地址 cx-传输扇区数

mov
[Data+8],ax

mov
[Data+6],es

mov
[Data+4],bx

mov
[Data+2],cx

.GoOnReading:

mov si,Data

mov dl,80h

mov ah,42h

int 13h

jc .GoOnReading ; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止

ret

os_searchfile:

mov
word [wSectorNo], SectorNoOfRootDirectory

LABEL_SEARCH_IN_ROOT_DIR_BEGIN:

cmp
word [wRootDirSizeForLoop], 0
; ┓

jz
LABEL_NO_LOADERBIN
; ┣ 判断根目录区是不是已经读完

dec
word [wRootDirSizeForLoop]
; ┛ 如果读完表示没有找到 LOADER.BIN

mov
ax, BaseOfLoader

mov
es, ax
; es <- BaseOfLoader

mov
bx, OffsetOfLoader
; bx <- OffsetOfLoader
于是, es:bx = BaseOfLoader:OffsetOfLoader

mov
ax, [wSectorNo]
; ax <- Root Directory 中的某 Sector 号

mov
cx, 1

call
os_readsector

mov
si, LoaderFileName
; ds:si -> "LOADER BIN"

mov
di, OffsetOfLoader
; es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100

cld

mov
dx, 10h

LABEL_SEARCH_FOR_LOADERBIN:

cmp
dx, 0
; ┓ 循环次数控制,

jz
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
; ┣ 如果已经读完了一个 Sector,

dec
dx
; ┛ 就跳到下一个 Sector

mov
cx, 11

LABEL_CMP_FILENAME:

cmp
cx, 0

jz
LABEL_FILENAME_FOUND
; 如果比较了 11 个字符都相等, 表示找到

dec
cx

lodsb
; ds:si -> al

cmp
al, byte [es:di]

jz
LABEL_GO_ON

jmp
LABEL_DIFFERENT
; 只要发现不一样的字符就表明本 DirectoryEntry 不是

; 我们要找的 LOADER.BIN

LABEL_GO_ON:

inc
di

jmp
LABEL_CMP_FILENAME
;
继续循环

LABEL_DIFFERENT:

and
di, 0FFE0h
; else ┓
di &= E0 为了让它指向本条目开头

add
di, 20h
; ┃

mov
si, LoaderFileName
; ┣ di += 20h 下一个目录条目

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
ax,0

mov
es,ax

mov
ax,Flag

call
os_message

jmp
$
; 没有找到 LOADER.BIN, 死循环在这里

LABEL_FILENAME_FOUND:
; 找到 LOADER.BIN 后便来到这里继续

mov
ax, RootDirSectors

and
di, 0FFE0h
; di -> 当前条目的开始

add
di, 01Ah
; di -> 首 Sector

mov
cx, word [es:di]

push
cx
; 保存此 Sector 在 FAT 中的序号

add
cx, ax

add
cx, DeltaSectorNo
; cl <- LOADER.BIN的起始扇区号(0-based)

mov
ax, BaseOfLoader

mov
es, ax
; es <- BaseOfLoader

mov
bx, OffsetOfLoader
; bx <- OffsetOfLoader

mov
ax, cx
; ax <- Sector 号

LABEL_GOON_LOADING_FILE:

mov
cx, 1

call
os_readsector

pop
ax
; 取出此 Sector 在 FAT 中的序号

call
os_getfatentry

cmp
ax, 0FFFh

jz
LABEL_FILE_LOADED

push
ax
; 保存 Sector 在 FAT 中的序号

mov
dx, RootDirSectors

add
ax, dx

add
ax, DeltaSectorNo

add
bx, [BPB_BytsPerSec]

jmp
LABEL_GOON_LOADING_FILE

LABEL_FILE_LOADED:

ret

;----------------------------------------------------------------------------

;BOOT DATA

LoaderFileName db "LOADER BIN", 0 ; LOADER.BIN 之文件名

BootMessage:
db
1,0

db
"Boot"

LoadMessage:
db
1,0

db
"Load"

Flag:
db
5,0

db
"Flag!"

position_x:
db
0h

position_y:
db
0h

wRootDirSizeForLoop dw RootDirSectors ; Root Directory 占用的扇区数, 在循环中会递减至零.

wSectorNo dw 0 ; 要读取的扇区号

bOdd db 0 ; 奇数还是偶数

Data:
db
10h

db
0

dw
01h

dd
00000100h

dd
0

dd
0

;----------------------------------------------------------------------------

times
510-($-$$)
db
0
; 填充剩下的空间,使生成的二进制代码恰好为512字节

dw
0xaa55
; 结束标志
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息