开发语言:汇编
编译工具:NASM for Win
1、BOOT.ASM
编译工具:NASM for Win
1、BOOT.ASM
;************************************************************************************************
;
; Name........... Noah system boot program
; File........... BOOT.ASM
; Version........ 1.0.0
; Dependencies... x86
; Description.... for Noah system startup loader program
; Author......... 周文星 ( Zhou Wen Xing )
; CSDN Accounts.. SupermanKing
; Date........... Jan, 05nd 2011
; UpdateURL...... http://noah.rljy.com/
; QQ Codeing..... 44068232
; TEL............ +86.015677228819
; E-Mail......... humanhome@126.com
;
; Copyright (c) 2004-2011 by www.rljy.com
; LiuZhou city, China
;
;************************************************************************************************
;================================================================================================
; Program Description ( 程序描述 )
;================================================================================================
; 本程序在16位的实时模式下运行,目的为实现加载并执行 Loader 程序做启动处理
; 支持 FAT12 文件系统的文件检索识别处理
;
;================================================================================================
; Constant defining ( 常数定义 )
;================================================================================================
%INCLUDE "NS_CONSTANT.INC"
BOOT_MODE EQU FD_FAT12 ; Fat12:
; Floppy installation can be used as such.
;
; Fat32:
; Harddisk installation requires modification
; of the Fat32 header, or you'll lose everything
; on the target partition.
;
; Debug:
; No Header. Use for debugging with floppy only !!
; Messages at low left corner during boot:
; 1 : bootsector loaded
; 2 : file not found
; 3 : file found - load starts
; 4 : jump to kernel
BOOT_DRV EQU FD_DISK1
;================================================================================================
; Program start ( 程序开始 )
;================================================================================================
$START:
ORG ORIGIN ; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
;==================== 初始化 MBR( Master Boot Record 主引导记录 ) 表 ====================
;---------- BS_jmpBoot 节点 ( 3 BYTE ) ----------
JMP MAIN ; ( 2 BYTE )跳转到执行程序段落
NOP ; ( 1 BYTE )这个 nop 不可少
%IF BOOT_MODE == FD_FAT12
; 下面是 FAT12 磁盘的头
BS_OEMName DB 'NOAH 1.0' ; ( 8 BYTE )厂商名, 必须 8 个字节 ( 这里标注为诺亚系统 )
;---------- BPB 节点( 53 BYTE ) ----------
; BIOS Parameter Block
BPB_BytsPerSec DW 512 ; ( 2 BYTE )每扇区字节数 512 个字节
BPB_SecPerClus DB 0x01 ; ( 1 BYTE )每扇区分配单位 ( MS DOS5.0 设置其值为 8 )
BPB_RsvdSecCnt DW 0x0001 ; ( 2 BYTE )Boot 记录占用多少扇区 ( MS DOS5.0 标注为保留的意思,但设置其值为 1 )
BPB_NumFATs DB 0x02 ; ( 1 BYTE )共有多少 FAT 表 ( 如果出现磁盘坏道,两个 FAT 表的价值才有体现 )
BPB_RootEntCnt DW 0x00E0 ; ( 2 BYTE )根目录文件数最大值
BPB_TotSec16 DW 0x0B40 ; ( 2 BYTE )逻辑扇区总数 ( 高密3.5英寸软盘最高密度支持:2面×每面80磁道×每磁道18扇区 = 2880扇区 )
BPB_Media DB 0xF0 ; ( 1 BYTE )媒体描述符( 软盘类型,高密3.5英寸软盘,双面 )
BPB_FATSz16 DW 0x0009 ; ( 2 BYTE )每FAT扇区数
BPB_SecPerTrk DW 0x0012 ; ( 2 BYTE )每磁道扇区数
BPB_NumHeads DW 0x0002 ; ( 2 BYTE )磁头数(面数)
BPB_HiddSec DD 0x00000000 ; ( 4 BYTE )隐藏扇区数
BPB_TotSec32 DD 0x00000000 ; ( 4 BYTE )如果 wTotalSectorCount 是 0 由这个值记录扇区数
BS_DrvNum DB BOOT_DRV ; ( 1 BYTE )中断 13 的驱动器号
BS_Reserved1 DB 0x00 ; ( 1 BYTE )未使用
BS_BootSig DB 0x29 ; ( 1 BYTE )扩展引导标记 (29h)
BS_VolID DD 0x18073C0B ; ( 4 BYTE )卷序列号
BS_VolLab DB 'NOAH SYSTEM' ; ( 11 BYTE )卷标, 必须 11 个字节(虽然Windows读卷标具体的是在 FDT 表里)
BS_FileSysType DB 'FAT12 ' ; ( 8 BYTE )文件系统类型, 必须 8个字节
%ELSE
%IF BOOT_MODE == HD_FAT16
%ELSE
%IF BOOT_MODE == HD_FAT32
%ELSE
%IF BOOT_MODE == HD_NTFS
%ENDIF
%ENDIF
%ENDIF
%ENDIF
;---------- 引导程序代码( 420 BYTE ) ----------
MAIN:
;==================== 初始化寄存器 ====================
CLI ; 停止堆栈中以前的中断
CLD;
XOR AX, AX ; 将 AX 寄存器清零
MOV SS, AX ; 在堆栈的工作只在下面的程序
MOV AX, CS ; CS 代码段寄存器
MOV DS, AX ; DS 数据段寄存器
MOV ES, AX ; ES 补助段寄存器
MOV SS, AX ; SS 堆栈段寄存器
MOV SP, ORIGIN
;------------------------------------------------------------
; 加载 Loader 程序
;------------------------------------------------------------
%INCLUDE "NSRDLM.INC"
JMP$
;================================================================================================
; Public function defining ( 公共的函数定义 )
;================================================================================================
%INCLUDE "NS_VARIABLE.INC"
%INCLUDE "NS_FUNCTION.INC"
Diskformat:
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
;---------- 有效结束标志( 2 BYTE ) ----------
dw 0xAA55 ; 结束标志
2、NS_CONSTANT.INC
;================================================================================================
; Constant defining ( 常数定义 )
;================================================================================================
ORIGIN EQU 7C00H ; 把 Boot Sector 加载到的起始地址
MEMADDR EQU 0400H ; 内存起始偏移地址
LOADERADDR EQU 09000H ; Loader 载入内存起始地址
; 以下为编译条件
DEBUG EQU 0 ; 设置程序为调试模式
FD_FAT12 EQU 1 ; 设置程序为软盘的 FAT12 文件系统
HD_FAT16 EQU 2 ; 设置程序为硬盘的 FAT16 文件系统
HD_FAT32 EQU 3 ; 设置程序为硬盘的 FAT32 文件系统
HD_NTFS EQU 4 ; 设置程序为硬盘的 NTFS 文件系统
; 最多支持 2 个软驱设备
FD_DISK1 EQU 00h
FD_DISK2 EQU 01h
; 最多支持 8 块硬盘
HD_DISK1 EQU 80h
HD_DISK2 EQU 81h
HD_DISK3 EQU 82h
HD_DISK4 EQU 83h
HD_DISK5 EQU 84h
HD_DISK6 EQU 85h
HD_DISK7 EQU 86h
HD_DISK8 EQU 87h
3、NSRDLM.INC
;****************************************************************************************************
;
; Name........... NSRDLM for FAT12/FAT16/FAT32/NTFS
; File........... NSRDLM.INC
; Version........ 1.0.0
; Dependencies... x86
; Description.... Read disk loader file module
; Author......... 周文星 ( Zhou Wen Xing )
; CSDN Accounts.. SupermanKing
; Date........... Jan, 05nd 2011
; UpdateURL...... http://noah.rljy.com/
; QQ Codeing..... 44068232
; TEL............ +86.015677228819
; E-Mail......... humanhome@126.com
;
; Copyright (c) 2004-2011 by www.rljy.com
; LiuZhou city, China
;
;****************************************************************************************************
%IF BOOT_MODE == FD_FAT12
%INCLUDE "NSRDLM_FAT12.INC"
%ELSE
%IF BOOT_MODE == HD_FAT16
%INCLUDE "NSRDLM_FAT16.INC"
%ELSE
%IF BOOT_MODE == HD_FAT32
%INCLUDE "NSRDLM_FAT32.INC"
%ELSE
%IF BOOT_MODE == HD_NTFS
%INCLUDE "NSRDLM_NTFS.INC"
%ENDIF
%ENDIF
%ENDIF
%ENDIF
;****************************************************************************************************
;
; Name........... NS_VARIABLE
; File........... NS_VARIABLE.INC
; Version........ 1.0.0
; Dependencies... x86
; Description.... Set static variable
; Author......... 周文星 ( Zhou Wen Xing )
; CSDN Accounts.. SupermanKing
; Date........... Jan, 05nd 2011
; UpdateURL...... http://noah.rljy.com/
; QQ Codeing..... 44068232
; TEL............ +86.015677228819
; E-Mail......... humanhome@126.com
;
; Copyright (c) 2004-2011 by www.rljy.com
; LiuZhou city, China
;
;****************************************************************************************************
;================================================================================================
; Public variable defining ( 全局变量定义 )
;================================================================================================
READ_COUNT: db 0 ; 要读取的扇区数量
BOOTFILE: db "KERNEL BIN", 0x00
TMPSTR: db "."
SHOWSTR: db "CBCDEFGH", 0x00
;----------------------------------------------------------------------------------------------------
;※※※※※※※※※※※※※ 全局变量定义 ( Public variable defining ) ※※※※※※※※※※※※※
;----------------------------------------------------------------------------------------------------
FDT_TYPE: db 0 ; 文件类型,0为文件,1为目录,2为卷标
FDT_ATTRIB: db 0 ; 文件属性
FDT_SECADDR: dw 0 ; 文件数据起始扇区号
FDT_SIZE: dd 0 ; 文件大小
READ_SECTOR: dw 0xFFFF ; 读磁盘的扇区号
READ_TRACK: db 0 ; 读磁盘的磁道(柱面)号
READ_HEADS: db 0 ; 读磁盘的磁头(面)号
READ_SECSIZE: dd 0 ; 要读取的扇区数量
;==================================================================================
; 字符串对比函数(NASM没有 cmps 函数)
; 输入参数: AX 要对比的串地址
; BX 要对比的串地址
; CX
; 返回参数: ZF = 1 相等, ZF = 0 不想等
;==================================================================================
;----------------------------------------------------------------------------------------------------
; Function Name: cmps
; Input Parameter: AX - 要对比的串地址
; : BX - 要对比的串地址
; : CX - 要对比的字符串长度
; Return Value: ZF - 1为不想等,0为相等
; Description : 字符串对比函数(NASM没有 cmps 函数)
;----------------------------------------------------------------------------------------------------
cmps:
PUSH SI ; 将 DS:SI 放入栈
PUSH DI ; 将 ES:DI 放入栈
CLD
MOV SI, AX
MOV DI, BX
;========== 字符串自动长度判断对比过程 ==========
cmps_loop:
LODSB ; ds:si -> al
CMP AL, byte [ES:DI] ; 判断 al 与当前的 di 是否相等
JNZ cmps_out ; al 与 di 不匹配结束判断过程
INC DI ; di 地址偏移一个字节
DEC CX ; CX--
CMP CX, 0 ; 判断 al 与当前的 di 是否相等
JZ cmps_out ;
JMP cmps_loop ; 继续判断下一个字符
cmps_out:
POP DI ; 将 DI 移出栈
POP SI ; 将 SI 移出栈
RET
;----------------------------------------------------------------------------------------------------
; Function Name: FindSectorFDT
; Input Parameter: AX - 扇区数据地址
; : BX - 要搜索的文件名地址
; Return Value: ZF - 0 为不想等,1为相等
; : AX - 返回找到的文件数据起始扇区号
; Description : 在FDT表中寻找指定文件名的文件并取得文件数据区的起始扇区号
;----------------------------------------------------------------------------------------------------
FindSectorFDT:
PUSH SI ; 将 DS:SI 放入栈
PUSH DI ; 将 ES:DI 放入栈
PUSH CX ; 将 CX 放入栈
MOV SI, BX
MOV DI, AX
MOV CX, 16 ; 设置循环搜索 16 个 FDT 表
fsfdt_loop:
CMP CX, 0
JZ fsfdt_over ; 循环已结束
PUSH CX ; 将 CX 放入栈
MOV AX, DI
MOV BX, SI
MOV CX, 11
CALL cmps ; 调用 cmps 函数对比字符串
POP CX ; 将 CX 移出栈
JZ fsfdt_ok ; 如果文件名相等结束循环并做载入处理
; 文件名不等的情况如下处理
ADD DI, 32 ; 让 ES:DI 向后偏移 32 个字节(到下一个 FDT 处)
DEC CX ; CX--; 将 FDT 循环数减一
JMP fsfdt_loop ; 继续循环
fsfdt_ok:
ADD DI, 26 ; 移动 FDT 到数组族所在地址
MOV AX, word [ES:DI]
ADD AX, 31
MOV word [FILE_ADDRESS], AX
fsfdt_over:
POP CX ; 将 CX 移出栈
POP DI ; 将 DI 移出栈
POP SI ; 将 SI 移出栈
RET
;----------------------------------------------------------------------------------------------------
; 16 位实时模式下直接通过调用 BIOS 中断 13h 实现磁盘读写操作
;----------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------
; Function Name: RDSector
; Input Parameter: AX - 读取磁盘扇区的缓冲区地址
; : CL - 要读磁盘扇区的起始扇号
; : CH - 要读磁盘扇区的磁道(柱面)号
; : DL - 要读磁盘扇区的驱动器号( 00H-7FH 表示软驱 00h是第一个软驱,01h是第二个软驱..., 80H-0FFH 表示硬盘 )
; : DH - 要读磁盘扇区的磁头(面)号
; Return Value: AX - 将读到的扇区数据返回到 AX 指定的缓冲区中
; Description : Read Disk Sector.( 读取磁盘扇区, )
;----------------------------------------------------------------------------------------------------
RDSector:
; 磁盘复位
;XOR AH, 00h ; 通过功能 00H 设置为磁盘系统复位功能
;XOR DL, BOOT_DRV ; 设置要处理的驱动器号( 00H-7FH 表示软驱 00h是第一个软驱,01h是第二个软驱..., 80H-0FFH 表示硬盘 )
;INT 13h ; 调用 BIOS 中断开始处理
; 开始读取磁盘扇区
PUSH BX ; 将 es:bx 放入栈
MOV BX, AX ; 设置缓冲区的地址
PUSH AX ; 将 AX 放入栈
MOV AH, 02h ; 通过功能 02H 设置为读扇区功能
MOV AL, 1 ; 设置要读的扇区数
INT 13h ; 调用 BIOS 中断开始处理
POP AX ; 将 AX 移出栈
POP BX ; 将 es:bx 移出栈
RET
;----------------------------------------------------------------------------------------------------
; Function Name: LoaderFile
; Input Parameter: AX - 要搜索的文件名串地址
; : BL - 要搜索的磁盘驱动器号
; ; DX - 指定加载到内存的内存地址
; Return Value: AX - 0 为加载成功,非零表示失败
; Description : Search Disk File.( 搜索指定磁盘文件 )
;----------------------------------------------------------------------------------------------------
; FDT 表起始位置计算公式:
; FDT 起始扇区号 = BPB_FATSz16(FAT扇区数) * BPB_NumFATs(FAT表数) + 1(引导扇区)
; FDT 表扇区总数:
; FDT 表扇区总数 = BPB_RootEntCnt(最大文件数) / 32(FDT表大小)
LoaderFile:
; 先搜索 FDT 表,找到数据起始地址后,再根据 FAT 表读数据
; ---------- 搜索 FDT 表 ----------
PUSH DI ; 将 ES:DI 放入栈
PUSH SI ; 将 DS:SI 放入栈
PUSH CX ; 将 CX 放入栈
MOV SI, AX
XOR CX, CX ; 将计数器 CX 清零
MOV CL, byte [FDT_BEGINSEC] ; 初始化计数器为 FDT 开始扇区号
; 开始循环 FDT 表寻找指定文件的过程
FindFile_NextSector:
MOV AL, byte [FDT_SECCOUNT] ; 设置 AX 寄存器为 FDT 表扇区总数
ADD AL, byte [FDT_BEGINSEC] ; 然后在 FDT 表扇区总数加上 FDT 开始扇区号
CMP CX, AX ; 判断 CX 与 AX 是否相等,如果两数相等,表示超出边界,
; ZF 会设置为 1
JZ FindFile_Over ; 根据 ZF 状态决定是否跳转到 FindFile_Over 位置
; ---------- 读 FDT 表所在扇区数据到 LOADERADDR 的内存地址处 ----------
MOV AX, CX ; 先将 当前计数器中的扇区号传递到 AX 作为参数
CALL GetPDI ; 调用 GetPDI 函数转换逻辑扇区号为物理扇区号
; ---------- 开始读取指定物理扇区的整个扇区内容到 LOADERADDR 的内存地址处 ----------
MOV AX, LOADERADDR ; 设置数据缓冲区到 LOADERADDR 地址上
MOV DL, BOOT_DRV ; 设置设备号为启动盘的设备号
CALL RDSector ; 调用 RDSector 函数开始读取扇区内容
INC CX ; CX++(自动添加预读取的 FDT 逻辑扇区号码)
; ---------- 开始在读取的扇区数据循环读取每一个 FDT 表数据,同时判断是否有指定的文件存在 ----------
MOV AX, LOADERADDR ; 设置比对用的数据源地址
MOV BX, SI ; 设置要对比的文件名地址(因为上面先把AX参数存入了 SI 里)
CALL FindSectorFDT ; 开始搜索扇区中的 FDT 信息是否存在指定文件信息
JNZ FindFile_NextSector ; 判断 FindSectorFDT 返回参数是否找到了指定文件,如果
; 没有找到,就继续循环读取下一个扇区进行查找
; 开始根据 FAT 数据表加载数据
FindFile_Read:
XOR CX, CX ; CX 计数器清零
INC CX ; CX+1
; 读取一个扇区的 FAT 内容
MOV AX, CX ; 先将 当前计数器中的扇区号传递到 AX 作为参数
CALL GetPDI ; 调用 GetPDI 函数转换逻辑扇区号为物理扇区号
MOV AX, LOADERADDR ; 设置数据缓冲区到 LOADERADDR 地址上
MOV DL, BOOT_DRV ; 设置设备号为启动盘的设备号
CALL RDSector ; 调用 RDSector 函数开始读取扇区内容
MOV DI, LOADERADDR
FindFile_FAT_Loop:
MOV AX, DI
ROR AX, 8 ; AX>>8 向右偏移 8 个二进制位
AND AX, 0xFFF ; 取后 12 个二进制位
CMP AX, FILE_ADDRESS ; 对比 数据地址是否与找到的数据地址相同
JZ FindFile_READ_FAT ; 找到FAT数据开始处
; 没有找到与 FDT 对应的 FAT 地址处
INC DI ; 让 ES:DI 向后偏移 1 个字节(到下一个 FDT 处)
INC CX ; CX 计数器加一
JMP FindFile_FAT_Loop
FindFile_READ_FAT:
XOR AX, AX ; AX 清零,表示成功
FindFile_Over:
POP CX ; 讲影响了的 CX 寄存器出栈(恢复入栈时的值)
POP SI ; 讲影响了的 SI 寄存器出栈(恢复入栈时的值)
POP DI ; 讲影响了的 DI 寄存器出栈(恢复入栈时的值)
RET
;==================================================================================
; 调用 BIOS 中断 int 10h 的 13H 功能 在 Teletype 模式下显示字符串
;==================================================================================
;----------------------------------------------------------------------------------------------------
; Function Name: Print
; Input Parameter: AX - 要输出字符串的地址
; : CX - 要输出字符串的字节长度
; Description : Print string to screen.( 输出字符串到屏幕 )
;----------------------------------------------------------------------------------------------------
Print:
PUSH BP
PUSH BX
MOV BP, AX
PUSH AX
; 设置功能号 AH = 13 同时设置 AL = 01h(配合 BL 参数设置属性)
; AL = 显示输出方式
; 0 字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
; 1 字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
; 2 字符串中含显示字符和显示属性。显示后,光标位置不变
; 3 字符串中含显示字符和显示属性。显示后,光标位置改变
MOV AX, 1301h ; AH = 13, AL = 01h
MOV BX, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h,高亮)
INC DL ; 行号
INT 10h ; 10h 号中断
POP AX
POP BX
POP BP
RET
;----------------------------------------------------------------------------------------------------
; Function Name: GetPDI
; Input Parameter: AX - 要换算的逻辑扇区号
; Return Value: CL - 磁盘扇区号
; : CH - 磁盘磁道(柱面)号
; : DL - 驱动器号
; : DH - 磁盘磁头(面)号
; Description : 将逻辑扇区号换算成物理扇区信息
;----------------------------------------------------------------------------------------------------
; 换算物理磁头、磁道、扇区的方法如下:
; 扇区 = (逻辑扇区号 MOD 每道扇区数) + 1
; 磁道 = (逻辑扇区号 / 每道扇区数) / 磁头数
; 磁头 = (逻辑扇区号 / 每道扇区数) MOD 磁头数
;----------------------------------------------------------------------------------------------------
GetPDI:
PUSH BX ; 将 BX 放入栈
;---------- 计算磁头和磁道号 ----------
;公式:LBA(逻辑扇区号-1) / BPB_SecPerTrk(每磁道扇区数)
MOV BX, word [BPB_SecPerTrk] ; 设置被除数
DIV BL ; 开始除法运算:逻辑扇区号 / BPB_SecPerTrk
INC AH ; 得到物理扇区号
MOV CL, AH ; 将余数设置到 CL 寄存器
XOR AH, AH ; 清楚余数结果,只要 AL 中的整除结果
MOV BX, word [BPB_NumHeads] ; 设置磁头数为被除数
DIV BL ; 开始除法运算:(LBA / BPB_SecPerTrk) MOD BPB_NumHead
MOV DH, AH ; 得到磁头号,将余数设置到 DH 寄存器
MOV CH, AL ; 得到磁道号,将余数设置到 CH 寄存器
POP BX ; 将 BX 移出栈,同时恢复 BX 原始的内容
RET
6、NSRDLM_FAT12.INC
;****************************************************************************************************
;
; Name........... NSRDLM for FAT12
; File........... NSRDLM_FAT12.INC
; Version........ 1.0.0
; Dependencies... x86
; Description.... Read disk loader file module for FAT12
; Author......... 周文星 ( Zhou Wen Xing )
; CSDN Accounts.. SupermanKing
; Date........... Jan, 05nd 2011
; UpdateURL...... http://noah.rljy.com/
; QQ Codeing..... 44068232
; TEL............ +86.015677228819
; E-Mail......... humanhome@126.com
;
; Copyright (c) 2004-2011 by www.rljy.com
; LiuZhou city, China
;
;****************************************************************************************************
;----------------------------------------------------------------------------------------------------
;※※※※※※※※※※※※※※※※※※ FAT12 分区表结构说明 ※※※※※※※※※※※※※※※※※※
;----------------------------------------------------------------------------------------------------
;┌───────┬────────────┬────────────┬───────────────┬──────┐
;│ (1扇区)MBR表 │(BPB_FATSz16扇区)FAT表1 │(BPB_FATSz16扇区)FAT表2 │(BPB_RootEntCnt/32)扇区)FTD表 │FAT12 数据区│
;└───────┴────────────┴────────────┴───────────────┴──────┘
; [FAT 表数据区格式]
;┌────┬──────┬───────────────┐
;│ 0F │ FF FF │ 12个二进制位的数据扇区地址表 │
;└────┴──────┴───────────────┘
; 存储介质 系统固定值 详细参考 FAT 数据表说明
;
; ------------------------------ 详细参考 FAT 数据表说明 ------------------------------
; 000 - 表示此簇未用
; FF0 - FF7 - 表示此簇为坏,不可用
; FF8 - FFF - 表示该簇为文件的最后一簇
; 其它值表示文件下一簇的簇号
; 簇的逻辑位置为 簇号+31
; 这个31是由 保留扇区数 + 隐藏扇区数 + FAT数×每个FAT所占扇区数 + FDT所占扇区数 - 2
; 公式为:1 + 0 + 2*18 + 14 - 2
; 二进制位合成为后一个字节的低 4 位累加到第一个字节的高8位之上
; 如:数据为 05 60 00 表示连续的两个簇
; 第一个簇位置为:
; 0x60 0x05
; 01100000 00000101 将数据换算成二进制
; 0110 0000 00000101 划分出12个二进制位作为要取得的值
; 0110 000000000101 演变成这样的数据
; 取低 12 位,取得 5 这个值
; 将 5+31 = 36 ,表示下一个簇的数据在 36 簇上
; 同理的,再下一的族的数据这样计算
; 0x00 0x60
; 00000000 01100000 将数据换算成二进制
; 00000000 0110 0000 划分出12个二进制位作为要取得的值
; 000000000110 0000 演变成这样的数据
; 取高12位,取得 6 这个值
; 将 6+31 = 37 ,表示下一个簇的数据在 37 簇上
;----------------------------------------------------------------------------------------------------
; 换算物理磁头、磁道、扇区的方法如下:
; LBA = 逻辑扇区号 - 1
; 扇区 = (LBA MOD 每道扇区数) + 1
; 磁道 = (LBA / 每道扇区数) / 磁头数
; 磁头 = (LBA / 每道扇区数) MOD 磁头数
;====================================================================================================
; ----------------------------------- 数 据 表 范 例 -----------------------------------
; 0F FF FF 11 12 22 33 3F FF ...
; 0F FF FF .................. 为 FAT12 固定格式
; 11 1 .................. 为 12 个二进制位的数据扇区数
; 2 22 .................. 为下一个数据扇区数
; 33 3 .................. 为下一个数据扇区数
; F FF .................. 为最后一簇
;----------------------------------------------------------------------------------------------------
; [FDT 表数据区格式]
;┌────┬────┬───┬───────┬────────┬────────┬──────────┬────┐
;│ 文件名 │ 扩展名 │ 属性 │ 系统保留段落 │最后一次写入时间│最后一次写入日期│此条目对应的开始族号│文件大小│
;├────┼────┼───┼───────┼────────┼────────┼──────────┼────┤
;│ 8 字节 │ 3 字节 │1 字节│ 10 字节 │ 2 字节 │ 2 字节 │ 2 字节 │ 4 字节 │
;└────┴────┴───┴───────┴────────┴────────┴──────────┴────┘
;
; [系统保留段落数据区格式]
;┌─────┬─────────┬──────┬──────┬────────┬─────────┐
;│ 系统保留 │创建时间的10毫秒位│文件创建时间│文件创建日期│文件最后访问日期│文件起始簇的高16位│
;├─────┼─────────┼──────┼──────┼────────┼─────────┤
;│ 1 字节 │ 1 字节 │ 2 字节 │ 2 字节 │ 2 字节 │ 2 字节 │
;└─────┴─────────┴──────┴──────┴────────┴─────────┘
;
;----------------------------------------------------------------------------------------------------
; [时间格式]
;----------------------------------------------------------------------------------------------------
; 换算公式:小时*2048+分钟*32+秒/2
; 二进制位说明:0-4 bit 2秒为单位
; 5-10 bit 为分钟
; 11-15 bit 为小时
; 转换时间数据范例:
; ----- ------- -----
; 时 分 秒
; ----- ------- -----
; 05 24 32 未转换的时间信息
; 05 24 16 已转换的时间信息
; 00101 011000 10000 将时间分析成二进制
; 0010101100010000 组合所有二进制位
; 2B 10 转换二进制为16进制( 得到以下结果 )
;
;----------------------------------------------------------------------------------------------------
; [日期格式]
;----------------------------------------------------------------------------------------------------
; 换算公式:(年份-1980)*512+月份*32+日
; 二进制位说明:0-4 bit 为日期
; 5-8 bit 为月份
; 9-15 bit 为年份 范围 0-127 表示 1980-2107年
; 转换日期数据范例:
; ------------- ------- ----
; 年 月 日
; ------------- ------- ----
; 2011 10 11 未转换的日期信息
; 31 10 11 已转换的日期信息
; 0011111 1010 01011 将日期分析成二进制
; 0011111101001011 组合所有二进制位
; 3F 4B 转换二进制为16进制( 得到以下结果 )
;----------------------------------------------------------------------------------------------------
;※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
;----------------------------------------------------------------------------------------------------
;====================================================================================================
; Public variable defining ( 全局变量定义 )
;====================================================================================================
FDT_SECCOUNT db 0 ; FDT 表扇区总数
FDT_SECSIZE db 0 ; FDT 表每扇区数量
FDT_BEGINSEC db 0 ; FDT 开始扇区号
FILE_ADDRESS dw 0
; 尝试输出文件名数据
; Input Parameter: AX - 读取磁盘扇区的缓冲区地址
; : CL - 要读磁盘扇区的起始扇号
; : CH - 要读磁盘扇区的磁道(柱面)号
; : DL - 要读磁盘扇区的驱动器号( 00H-7FH 表示软驱 00h是第一个软驱,01h是第二个软驱..., 80H-0FFH 表示硬盘 )
; : DH - 要读磁盘扇区的磁头(面)号
; LBA = 逻辑扇区号 - 1
; 扇区 = (LBA MOD 每道扇区数) + 1
; 磁道 = (LBA / 每道扇区数) / 磁头数
; 磁头 = (LBA / 每道扇区数) MOD 磁头数
; ---------- 计算 FDT 开始扇区号 ----------
; 公式:FDT_BEGINSEC(FDT 开始扇区号) = BPB_FATSz16(FAT扇区数) * BPB_NumFATs(FAT表数) + 1(引导扇区)
XOR AX, AX
XOR BX, BX
MOV AL, byte [BPB_FATSz16] ; 设置乘数为 BPB_FATSz16(FAT扇区数)
MOV BL, byte [BPB_NumFATs]
MUL BL ; 乘法运算:BPB_FATSz16(FAT扇区数) * BPB_NumFATs(FAT表数)
ADD AX, 1 ; 加法运算:相乘结果 + 1(引导扇区)
MOV byte [FDT_BEGINSEC], AL ; 将运算结果放入 FDT_BEGINSEC 变量
; ---------- 计算 FDT 每扇区数 ----------
; 公式:FDT_SECSIZE(FDT 表每扇区数量) = BPB_BytsPerSec(每扇区字节数) / 32(FDT 表的字节大小)
MOV AX, word [BPB_BytsPerSec] ; 设置 16 位的除数
MOV BX, 32 ; 设置被除数 (32 为 FDT 表的字节大小)
DIV BL ; 开始除法运算: BPB_RootEntCnt(每扇区字节数) / 32(FDT表大小)
MOV byte [FDT_SECSIZE], AL ; 将运算结果放入 FDT_SECSIZE 变量
; ---------- 计算 FDT 扇区总数 ----------
; 公式:FDT_SECCOUNT(FDT 表扇区总数) = BPB_RootEntCnt(最大文件数) / FDT_SECSIZE(FDT 每扇区数)
MOV AX, word [BPB_RootEntCnt] ; 设置16位的除数
XOR BX, BX ; BX 清零
MOV BL, byte [FDT_SECSIZE] ; 设置被除数
DIV BL ; 开始除法运算: BPB_RootEntCnt(最大文件数) / FDT_SECSIZE(FDT 表每扇区数量)
MOV byte [FDT_SECCOUNT], AL ; 将运算结果放入 FDT_SECCOUNT 变量
; ---------- 设置要读取的扇区信息 ----------
;MOV AX, ReadFDT
;MOV CX, 3
;XOR AX, AX
;MOV AL, byte [FDT_BEGINSEC]
;MOV BX, SHOWSTR
;CALL IntToStr
;MOV AL, SHOWSTR
;CALL Print
;PUSH DI ; 将 DI 放入栈
;MOV DI, SHOWSTR
;MOV AX, word [FILE_ADDRESS]
;MOV byte [ES:DI], AH
;INC DI
;MOV byte [ES:DI], AL
;POP DI
; 先查询 FDT 表文件是否存在,如果存在,则取得FDT表中的文件数据起始扇区号到 FILE_ADDRESS 变量里
MOV AX, BOOTFILE ; 设置要查询的文件名缓冲区地址
MOV DX, LOADERADDR
CALL LoaderFile
MOV AX, word [FILE_ADDRESS] ; 设置 AX 寄存器为读到的文件起始扇区数
CALL GetPDI ; 将逻辑扇区号换算成物理扇区信息
MOV AX, LOADERADDR ; 设置要读取磁盘扇区的缓冲区地址
MOV DL, BOOT_DRV ; 设置要要读磁盘扇区的驱动器
CALL RDSector ; 开始读取指定磁盘扇区内容
;MOV AX, LOADERADDR ; 设置要显示数据的缓冲区地址
;MOV CX, 512 ; 设置要显示数据的缓冲区大小
;CALL BuffToHexStr ; 开始以十六进制字符形式显示指定缓冲区的数据