开源个我的 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......... [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                              ; 结束标志

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......... [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

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......... [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			; 要读取的扇区数量

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......... [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			; 开始以十六进制字符形式显示指定缓冲区的数据


 

你可能感兴趣的:(操作系统)