;************************************************************************************************ ; ; 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......... [email protected] ; ; 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 ; 结束标志
;================================================================================================ ; 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
;**************************************************************************************************** ; ; 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......... [email protected] ; ; 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......... [email protected] ; ; 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
;**************************************************************************************************** ; ; 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......... [email protected] ; ; 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 ; 开始以十六进制字符形式显示指定缓冲区的数据