开源个我的 x86 架构操作系统的 boot 程序

开发语言:汇编
编译工具: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

4、NS_VARIABLE.INC
;****************************************************************************************************
;
; 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			; 要读取的扇区数量

5、NS_FUNCTION.INC 
;==================================================================================
; 字符串对比函数(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			; 开始以十六进制字符形式显示指定缓冲区的数据


 

posted @ 2013-03-31 19:03  xinyuyuanm  阅读(645)  评论(0编辑  收藏  举报