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


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
代码部分来自Google的重建IBMPC BIOS项目(https://sites.google.com/site/pcdosretro/ibmpcbios),其中的BIOS镜像(*.rom)可用于各种IBM PC模拟器,可按情况使用。源代码可以用masm编译,站内英文说明文件如下: IBM PC BIOS source code reconstruction This is a reconstruction of the IBM PC, PC XT, PC AT and PC XT 286 BIOS source code using scanning and transcription of the BIOS listings found in the IBM Technical Reference manuals. This historically relevant source code is presented here for software preservation. The following BIOS source code has been reconstructed: IBM PC version 1 04/21/81 IBM PC version 2 10/19/81 IBM PC version 3 10/27/82 IBM PC XT version 1 11/08/82 (also used on the Portable PC) IBM PC XT version 2 01/10/86 IBM PC XT version 3 05/09/86 IBM PC AT version 1 01/10/84 IBM PC AT version 2 06/10/85 IBM PC AT version 3 11/15/85 (used on the PC AT models 319 and 339) IBM PC XT 286 04/21/86 Notes: • All 3 versions of the IBM PC BIOS and the first version of the IBM PC XT BIOS were built using Intel ASM86 on an Intel development system. In each case the BIOS source code is a single large file and the BIOS code is 8KB which resides at F000:E000 • The IBM PC AT version 1 BIOS was built using IBM MASM 1.0 on DOS. This is the first IBM BIOS which uses multiple source files. Since IBM MASM 1.0 did not support the 80286 there is a macro file (IAPX286.MAC) which is used to generate the necessary opcodes. This is also the first BIOS to be split into two parts: the main BIOS code resides at F000:0000 and the compatibility section (ORGS.ASM) resides at F000:E000. An additional file FILL.ASM has been added to define the area between the end of the main BIOS code and the compatibility section to allow the BIOS to be linked properly. It is currently unknown how this was originally handled. • The IBM PC AT version 2 and 3 BIOS and the IBM PC XT 286 BIOS were built using IBM MASM 2.0 on DOS. These are similar to the PC AT version 1 BIOS but there are fewer source files as some files were combined and a bit of cleanup was done. IAPX286.INC is used to generate the protected-mode 80286 opcodes which IBM MASM 2.0 did not support. FILL.ASM serves the same purpose as it does for the PC AT version 1 BIOS though in each case the file is specific to the particular BIOS being built. • The IBM PC XT version 2 and 3 BIOS were built using IBM MASM 2.0 on DOS. The later PC XT BIOS code was restructured to be similar to the PC AT BIOS code so there are multiple source files. Like the PC AT BIOS the code is split into two parts though the compatibility section is in the file POST.ASM. Again the additional file FILL.ASM is used to define the area between the end of the main BIOS code and the compatibility section. • The following code is present in all versions of the PC AT BIOS and the PC XT 286 BIOS but does not appear in the published listings. It is inferred from the public symbols in ORGS.ASM and code disassembly. It is unknown what purpose this code serves. .XLIST ;;- ORG 0FF5AH ORG 01F5AH HRD PROC FAR CALL DISK_SETUP RET HRD ENDP FLOPPY PROC FAR CALL DSKETTE_SETUP RET FLOPPY ENDP SEEKS_1 PROC FAR CALL SEEK RET SEEKS_1 ENDP TUTOR: JMP K16 .LIST • In all cases the 32KB ROM BASIC code which resides at F6000 is not available as its source code was never published. • Versions of MASM later than 4.0 cannot be used to build the IBM BIOS source code since older constructs and macros are used. More information about functionality changes in the IBM PC BIOS code is listed here: IBM PC BIOS version history
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值