⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 anosboot.asm

📁 一个关于系统启动代码的各种版本的打包机和
💻 ASM
字号:
; boot.asm boot.asm : ANOS fat12 软盘启动代码
; Larry Li, 2005.2.25
; 2005.3.19
;  整理注释

PosBuf equ 0700h
StackTop equ 07BF0h
BootStart equ 07C00h
SegKernel equ 0800h

RootBufEnd equ 02h
DataStart equ 04h
CursorPos equ 10h

; BOOT 会被 BIOS 载入到 00007C00h 处
org 7C00h

; 代码段
segment .text
; 16 位代码
bits 16

; start: 首先是跳过必须的 FAT 信息表执行后面的程序
Start:
	jmp short Main
	; 补一个字节的空指令
	nop

; FAT12 信息
; 只是文件系统的描述信息
OEMName         db 'ANOSDISK'
; 扇区大小(字节),应为 512
BytesPerSector  dw 512
; 簇的扇区数,应为 2 的幂,FAT12 为 1
SectsPerCluster db 1
; 保留扇区,FAT12/16 应为 1
ReservedSectors dw 1
; FAT 结构数目,一般为 2
NumberOfFats    db 2
; 根目录项目数,FAT12 为 224
MaxRootEntries  dw 224
; 扇区总数,1.44M 软盘为 2880
TotalSectors    dw 2880
; 设备类型,1.44M 软盘为 F0h
MediaDescriptor db 0f0h
; FAT 占用扇区数,9
SectorsPerFat   dw 9
; 磁道扇区数,18
SectorsPerTrack dw 18
; 磁头数,2
NumberOfHeads   dw 2
; 隐藏扇区,默认为 0
HiddenSectors   dd 0
; FAT32 使用,0
TotalSectorsBig dd 0
;; 下面的内容为 FAT12/16 所有,和 FAT32 不同
; MS-DOS 使用,0
BootDrive       db 0
; Windows NT 使用,0
Reserved        db 0
; 附加的可启动标志,29h
ExtendSig       db 029h
; 卷标序列号,00000000h
SerialNumber    dd 00000000h
; 卷标,11 字节,必须用空格( 20h )补齐
VolumeLabel     db 'ANOS FLOPPY'
; 文件系统标志,
FileSystem      db 'FAT12   '

; Main: BOOT 主程序
Main:
	; 初始化运行环境
	xor ax,ax
	mov ss,ax
	mov bp,BootStart
	mov sp,StackTop
	push ss
	pop ds

; LoadRootDirSector: 读取 FAT12 根目录项目扇区
LoadRootDirSector:
	push ss
	pop es

	; 计算 ROOT 启始逻辑扇区
	mov al,[BYTE bp+NumberOfFats]
	; FAT 表数目
	mul WORD [BYTE bp+SectorsPerFat]
	; 乘上一个 FAT 表占用的扇区数
	add ax,WORD [BYTE bp+HiddenSectors]
	; 加上隐藏的扇区数
	add ax,WORD [BYTE bp+ReservedSectors]
	; 加上保留的扇区数
	push ax
	mov WORD [BYTE bp-DataStart],ax
	; AX ROOT 项目的启始逻辑扇区, 保存

	; 计算 ROOT 扇区数
	mov ax,20h
	mov cx,WORD [BYTE bp+MaxRootEntries]
	mul cx
	mov bx,WORD [BYTE bp+BytesPerSector]
	add ax,bx
	dec ax
	div bx
	mov cx,ax
	; CX ROOT 扇区大小
	add WORD [BYTE bp-DataStart],ax
	; 更新数据区启始逻辑扇区
	mul bx
	; AX ROOT 总扇区字节大小
	mov bx,PosBuf
	; BX 缓存启始地址
	add ax,bx
	; AX 缓存尾地址
	mov WORD [BYTE bp-RootBufEnd],ax
	; 保存尾地址

	pop ax
	; 取出 ROOT 项目启始逻辑扇区
	call ReadSectors
	mov si,bx
	; [ES:SI] 根目录内容

; SearchRootDirSector: 在根目录项目中搜索内核文件
SearchRootDirSector:
	; [ES:SI] 为当前目录项
	; 其头 11 个字节为文件名称
	cmp [es:di],ch
	; 如果目录项的第一个字节是0,这就是最后一个目录项
	jz NotFound
	push si
	; 保存 SI rep cmpsb 时 SI 会改变
	mov cx,11
	; 比较前 11 个字节
	mov di,FileName
	; [DS:DI] 要载入的内核名称
	rep cmpsb
	; 比较 [ES:SI] [DS:DI]
	pop si
	; 恢复 [ES:SI] 为当前查对的目录项
	je FoundKernel
	add si,32
	; [ES:SI] 指向下一个目录项
	; 每个目录项 32 字节
	cmp si,WORD [BYTE bp-RootBufEnd]
	; 是否到根目录项目尾
	jb SearchRootDirSector

; NotFound: 没有发现内核的处理
NotFound:
	mov si,msgNotFound
	call PutChars
	jmp ReBoot

; FoundKernel: 发现内核后处理
FoundKernel:
	; [ES:SI] 内核文件目录项
	mov ax,[si+01ah]
	push ax
	; 内核文件启始簇(低)地址
	; 目录项偏移 26(1ah) 为文件项目启始簇低地址
	; 偏移 20(14h) 为高地址
	; 由 FAT12 只是 12 位簇地址, 低地址 16 位足以

	xor dx,dx
	mov es,dx
	mov ax,WORD [BYTE bp+ReservedSectors]
	; DX:AX 第一个 FAT 表的启始逻辑扇区
	mov bx,PosBuf
	; [ES:BX] 读盘缓存
	mov cx,WORD [BYTE bp+SectorsPerFat]
	; CX FAT 表扇区数
	call ReadSectors

	pusha
	mov si,msgLoadKernel
	call PutChars
	popa

	mov ax,SegKernel
	mov es,ax
	xor bx,bx
	; [ES:BX] 读盘缓存, 内核载入地址

	pop ax
	push ax
	; 文件的第一个簇

; LoadKernel: 载入内核
LoadKernel:
	; AX 当前簇
	call ReadCluster
	pop ax
	; 取当前簇
	add bx,0200h
	; [ES:BX] 缓存地址增加 512 字节(1 个扇区)
	; 下面开始查 FAT12 表项目
	; 所以对于簇 n 其项目位于 n / 2 * 3 处
	; n / 2 * 3 = n / 2 + n
	; n 为偶, 在低 12 位
	; n 为奇, 在高 12 位
	mov di,ax
	; BP DI 文件簇 n
	shr di,01h
	; DI n / 2
	pushf
	; 保存标志位, 供以后奇偶处理
	add di,ax
	; DI n / 2 + n
	add di,PosBuf
	; DI 加上 FAT12 表的启始地址
	mov ax,[di]
	; AX 一个 FAT12 组, 两个簇号
	popf
	; 根据 n / 2 奇偶判定
	jc ShiftRight4
	and ax,0fffh
	; 取低 12 位
	jmp IsTheEnd
ShiftRight4:
	mov cl,4
	shr ax,cl
	; 高 12 位, 所以右移 4 位
IsTheEnd:
	cmp ax,0ff8h
	; 比较, ff8h - fffh 表示簇链末尾
	jae ExecKernel
	; 载入完毕, 跳转到内核地址
	push ax
	; 复制下一簇号
	jmp LoadKernel

; ExecKernel: 运行内核
ExecKernel:
	pusha
	mov si,msgLoadKernelOK
	call PutChars
	popa

	mov ah,3
	xor bh,bh
	int 10h
	mov WORD [BYTE bp-CursorPos],dx
	; 将当前光标位置写入 7df0h 7df1h
;
	push word SegKernel
	push word 00h
	; 入栈供返回指令跳转
	retf

; BadDisk: 显示错误启动信息,然后重启
BadDisk:
	mov si,msgDiskError
	call PutChars
; ReBoot: 重启
ReBoot:
	mov si,msgAnyKey
	call PutChars
	xor ax,ax
	int 16h
	; 等待键盘按键
	int 19h
	; 重启

; ReadCluster: 读磁盘文件簇
; 读数据簇 AX 到 [ES:BX]
; CarryFlag == 1 错误
ReadCluster:
	; 显示一个 .
	push ax
	mov ax,0e2eh
	int 10h
	pop ax

	dec ax
	dec ax
	; 修正, 簇号 - 2
	add ax, WORD [BYTE bp-DataStart]
	; AX 数据的启始逻辑扇区
	xor dx,dx
	mov cx,01h

; ReadSectors: 读磁盘扇区
; 读 CX 个逻辑扇区(地址 DX:AX)到 [ES:BX]
; CarryFlag == 1 错误
ReadSectors:
	pusha
	push cx	; 保存读取扇区数
	; 首先要将 DX:AX 逻辑扇区号转换为[驱动器号][磁头号][磁道号][扇区号]
	; 根据:磁盘总扇区 = 磁道数 * 磁头数 * 扇区数
	; 逻辑扇区 = (磁道号 * 磁头数 + 磁头号) * 扇区数 + 扇区号 - 1
	; (注意:实际在磁道的扇区号是从 1 开始计数的,其他号从 0 开始)
	; 那么:扇区号 = 逻辑扇区 % 磁道的扇区数 + 1
	; 同样:含磁头计算的磁道号 = 逻辑扇区 / 磁道的扇区数
	; 除掉磁头数,就是:磁道号 = 含磁头计算的磁道号 / 磁头数
	; 所以:磁头号 = 含磁头计算的磁道号 % 磁头数
	xchg ax,cx	; AX <=> CX
	xchg ax,dx	; AX <=> DX
	; AX:CX 逻辑扇区
	xor dx,dx	; DX 清零
	div WORD [BYTE bp+SectorsPerTrack]	; 除高位
	; 计算得含磁头计算的磁道号的高位
	xchg ax,cx	; 临时保存到 CX
	; 此时余数 DX 与 AX 组成新数继续低位除
	div WORD [BYTE bp+SectorsPerTrack]	; 除低位
	; 余数 DX 为 0 开的扇区号
	inc dx	; 修正为 1 开
	xchg cx,dx	; CX <=> DX
	; CX 为扇区号
	; DX:AX 为含磁头计算的磁道号
	div WORD [BYTE bp+NumberOfHeads]	; 继续除
	; AX 为磁道号
	; DX(DL) 为磁头号
	mov dh,dl
	; DH 磁头号
	mov dl,[BYTE bp+BootDrive]
	; DL 驱动器号
	mov ch,al
	; CX bit 8-15(CH) 磁道低 8 位
	ror ah,2
	; CX bit 6-7(AH bit 6-7) 磁道高 2 位
	or cl,ah
	; CX bit 0-5 扇区
	pop ax
	; AL 操作扇区数目
	mov ah,02h
	; AH 02h 读磁盘扇区
	int 13h
	; BIOS 13h 调用
; int 13h BIOS 功能
; 参数
; AH = 0x02 读磁盘扇区到内存
; AL 需要读出的扇区数量
; CH 磁道(柱面)号的低 8 位
; CL 开始扇区(0-5位),磁道号高 2 位(6-7)
; DH 磁头号
; DL 驱动器号
; ES:BX 指向数据缓存
; 返回
; 出错置 CF 标志位
; AH 状态 = 0x01
; AL 读取的扇区数
	jc BadDisk

	popa
	ret

; PutChars: 打印字符串
; 入口参数 si
PutChars:
	lodsb
	or al,al
	jz short Done
	mov ah,0eh
	mov bx,07h
	int 10h
	jmp short PutChars
Done:
	retn

TheEnd:
	db 0

msgLoadKernel db 'Loading ANOS',0
msgLoadKernelOK db 'OK!',0Dh,0Ah,0
msgNotFound db 'Cannot found ANOS kernel!',0Dh,0Ah,0
msgDiskError db 'Disk Error!',0Dh,0Ah,0
msgAnyKey db 'Press any key to reboot...',0Dh,0Ah,0

; 将 BOOT 映象对齐到 512 个字节
times 496-($-$$) db 0

FileName db 'ANOS    SYS',0,0

BootPartition:
	db 0

; 启动标志
BootSignature dw 0AA55h	; BootSector signature

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -