⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat32.asm

📁 FAT32 文件格式的引导扇区汇编代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:

_REBOOT:       ; 重启
 MOV  SI,MessageRestart
 CALL ShowMessage
 
 ; 调用键盘中断,等待用户按键
 MOV  AH,00H
 INT  16H
 
 ; 重启计算机
 INT  19H 

 ; 死循环
 JMP  $


;====================================================================
; 
; 子过程
; 
;====================================================================

;====================================================================
; 
; 读取一个磁盘扇区
; 输入: 已经设置了DAP中相应的字段
; 限制: 不能读取超过一个簇的内容   
; 
;====================================================================
ReadSector:

 PUSHA  ; 保存寄存器
 
 ; 检查是否使用扩展方式
 CMP  BYTE [BP - DISK_EXT_SUPPORT],00H
 JZ  .NoDiskExtension
 
;====================================================================
; INT 13H  AH = 42H 扩展磁盘调用
;====================================================================
 ; 每次读取一个扇区
 MOV  AH,42H         ; 功能号 
 LEA  SI ,[BP - DAP_PACKET_SIZE]    ; 地址包地址

 ; 驱动器号
 MOV  DL ,[DriveNumber]      ; 驱动器号
 INT  13H
 JC   _DISK_ERROR        ; 读取失败
 JMP  _READ_SECTOR_OK       ; 读取成功

;====================================================================
; 
; INT 13H 
;  AH = 2        柱面号:0 - 1023
;  AL = 要读取的扇区数     磁头号:0 - 255    
;  CH = 柱面号低8位     扇区号:1 - 63  
;  CL = 柱面号高2位 : 6位扇区号  
;  DH = 磁头号 
;  DL = 驱动器号
;
; LBA = ( (cylinder * HeadsPerCylinder + heads ) * SectorsPerTrack ) + sector - 1
;
; Sector = LBA % SectorsPerTrack +1
; Head = (  LBA / SectorsPerTrack ) % HeadsPerCylinder
;   Cylinder= (  LBA / SectorsPerTrack ) / HeadsPerCylinder
;
;==================================================================== 
.NoDiskExtension:
  
 ;=================================================================== 
 ; 首先需要将扇区号转换为CHS地址
 ;===================================================================
 
 ; 首先计算扇区号
 MOV  AX,WORD [ BP - DAP_SECTOR_LOW   ]
 MOV  DX,WORD [ BP - DAP_SECTOR_LOW+2 ]
 DIV  WORD [SectorsPerTrack ] ; AX = LBA / SectorsPerTrack DX = LDA % SectorsPerTrack
 MOV  CX,DX
 INC  CX      ; CL = Sector
 AND  CL,3FH     ; 1-63

 ; 再计算磁头号和柱面号
 XOR  DX,DX     ; DX:AX = LBA / SectorsPerTrack
 DIV  WORD [HeadsPerCylinder] ; DX = ( LBA/SectorsPerTrack ) %  HeadsPerCylinder = Head
         ; AX = ( LBA/SectorsPerTrack ) /  HeadsPerCylinder = Cylinder
 MOV  CH,AL     ; 柱面号低8位
 SHL  AH,6
 OR  CL,AH     ; CL = 柱面号高2位:6位扇区号
 MOV  DH,DL     ; DL = 磁头号
         
 ; 准备读取磁盘          
 MOV  AX,WORD[ BP - DAP_BUFFER_SEG ]
 MOV  ES,AX
 MOV  BX,WORD[ BP - DAP_BUFFER_OFF ]
 MOV  AX ,0201H    ; 每次只读取一个扇区
 
 ; 驱动器号
 MOV  DL ,[DriveNumber]      ; 驱动器号
 INT  13H
 JC   _DISK_ERROR        ; 读取失败

_READ_SECTOR_OK:
 POPA       ; 恢复寄存器 
 RET 
    
;====================================================================
; 
; 显示一个字符串
; 输入:
;   DS:SI  = 字符串的起始地址(以NULL结束)
;   
;====================================================================
ShowMessage:
 LODSB    ; AL = DS:[SI] SI = SI+1
 OR  AL,AL    ; 检测是否遇到NULL字符串
 JZ  _SHOW_END
 MOV  AH,0EH
 MOV  BX,07H
 INT  10H
 JMP  ShowMessage

_SHOW_END:
 RET 

;====================================================================
; 数据区
;====================================================================
LoaderName     db "FDOSLDR BIN"       ; 第二阶段启动程序 FDOSLDR.BIN
MessageMissLoader   db "NO FDOSLDR.BIN.",0DH,0AH,00H   ; 没有找到装载程序
MessageDiskError   db  "Disk Error.",0DH,0AH,00    ; 磁盘错误消息
MessageRestart    db "Press any key to restart." ,0DH,0AH,00 ; 提示重启消息
;====================================================================
; 扇区最后的标记字节(NASM不支持重复ORG)
;====================================================================
Padding TIMES 510-($-$$) db  00H
SectorSignature    dw 0AA55H



;====================================================================
; 第二个扇区的代码(该代码位于分区的第四个扇区)
;====================================================================

;====================================================================
; 查找根目录,检查是否有 FDOSLDR.BIN文件
;====================================================================
_SEARCH_LOADER: 


 ; 设置缓冲区
 MOV  WORD [ BP - DAP_BUFFER_OFF  ], DATA_BUF_OFF ; 0000:1000H
 
 ; 根目录起始簇号
 MOV  EAX,DWORD[RootDirectoryStart]
 MOV  DWORD[ BP - CURRENT_CLUSTER ],EAX

; 检查下一个簇
_NEXT_ROOT_CLUSTER: 

 ; 根据簇号计算扇区号(EAX-2)*SectorsPerCluster+DATA_START_SECTOR
 DEC  EAX
 DEC  EAX  ; EAX = EAX - 2
 XOR  EBX,EBX 
 MOV  BL, BYTE[ SectorsPerCluster]
 MUL  EBX 
 ADD  EAX,DWORD[ BP- DATA_START_SECTOR]
 MOV  DWORD[ BP - DAP_SECTOR_LOW  ], EAX
 MOV  DL,[SectorsPerCluster]

; 检查下一个扇区
_NEXT_ROOT_SECTOR:
  
 ; 依次读取每个根目录扇区,检查是否存在FDOSLDR.BIN文件
 CALL ReadSector
 
 ; 检查该扇区内容
 MOV  DI,DATA_BUF_OFF
 MOV  BL,BYTE [ BP - DIR_PER_SECTOR]

; 检查每一个目录项
_NEXT_ROOT_ENTRY:
 CMP  BYTE [DI],DIR_NAME_FREE
 JZ  _MISSING_LOADER    ; NO MORE DIR ENTRY
 
 ; 检查是否装载程序
 PUSH  DI       ; 保存DI
 MOV  SI,LoaderName
 MOV  CX,11
 REPE  CMPSB 
 JCXZ  _FOUND_LOADER    ; 装载Loader并运行
  
 ; 是否还有下一个目录项(内层循环)
 POP  DI
 ADD   DI,DIR_ENTRY_SIZE
 DEC  BL 
 JNZ   _NEXT_ROOT_ENTRY
 
 ; 检查是否还有下一个扇区可读(外层循环)
 DEC  DL
 JZ  _CHECK_NEXT_ROOT_CLUSTER
 INC  DWORD [ BP - DAP_SECTOR_LOW ] ; 增加扇区号
 JMP  _NEXT_ROOT_SECTOR 
 
; 检查下一个簇
_CHECK_NEXT_ROOT_CLUSTER:

 ; 计算FAT所在的簇号和偏移 
 ; FatOffset = ClusterNum*4
 XOR  EDX,EDX
 MOV  EAX,DWORD[BP - CURRENT_CLUSTER]
 SHL  EAX,2
 XOR  ECX,ECX
 MOV  CX,WORD [ BytesPerSector ]
 DIV  ECX  ; EAX = Sector EDX = OFFSET
 ADD  EAX,DWORD [BP - FAT_START_SECTOR  ]
 MOV  DWORD [ BP - DAP_SECTOR_LOW ], EAX 
   
 ; 读取扇区
 CALL  ReadSector
  
 ; 检查下一个簇
 MOV  DI,DX
 ADD  DI,DATA_BUF_OFF
 MOV  EAX,DWORD[DI]  ; EAX = 下一个要读的簇号
 AND  EAX,CLUSTER_MASK
 MOV  DWORD[ BP - CURRENT_CLUSTER ],EAX
 CMP  EAX,CLUSTER_LAST  ; CX >= 0FFFFFF8H,则意味着没有更多的簇了
 JB  _NEXT_ROOT_CLUSTER
 JMP  _MISSING_LOADER

;====================================================================
; 装载FDOSLDR.BIN文件
;====================================================================
_FOUND_LOADER:
 ; 目录结构地址放在DI中
 POP  DI
 XOR  EAX,EAX
 MOV  AX,[DI+OFF_START_CLUSTER_HIGH] ; 起始簇号高32位
 SHL  AX,16
 MOV  AX,[DI+OFF_START_CLUSTER_LOW]  ; 起始簇号低32位
 MOV  DWORD[ BP - CURRENT_CLUSTER ],EAX
 MOV  CX, OSLOADER_SEG      ; CX  = 缓冲区段地址 
 
  
_NEXT_DATA_CLUSTER:
 
 ; 根据簇号计算扇区号
 DEC  EAX
 DEC  EAX  ; EAX = EAX - 2
 XOR  EBX,EBX 
 MOV  BL, BYTE[ SectorsPerCluster]
 MUL  EBX 
 ADD  EAX,DWORD[ BP- DATA_START_SECTOR]
 MOV  DWORD[ BP - DAP_SECTOR_LOW  ], EAX
 MOV  DL,[SectorsPerCluster]

 ; 设置缓冲区
 MOV  WORD [ BP - DAP_BUFFER_SEG   ],CX
 MOV  WORD [ BP - DAP_BUFFER_OFF   ],00H
   
 ; 每个簇需要读取的扇区数
 MOV  BL , BYTE [SectorsPerCluster]

_NEXT_DATA_SECTOR:
 ; 读取簇中的每个扇区(内层循环)
 ; 注意 : 通过检查文件大小,可以避免读取最后一个不满簇的所有大小
 ; 读取数据扇区
 CALL  ReadSector
 
 ; 更新地址,继续读取
 MOV  AX, WORD [BytesPerSector]
 ADD  WORD  [BP - DAP_BUFFER_OFF],AX 
 INC  DWORD [BP - DAP_SECTOR_LOW]  ; 递增扇区号
 DEC  BL        ; 内层循环计数
 JNZ  _NEXT_DATA_SECTOR
  
 
 ; 检查下一个簇
  
 ; 更新读取下一个簇的缓冲区地址
 MOV  CL,BYTE [ SectorsPerCluster ]
 MOV  AX ,WORD [BytesPerSector]
 SHR  AX ,4
 MUL  CL
 ADD  AX ,WORD [ BP - DAP_BUFFER_SEG ] 
 MOV  CX,AX ; 保存下一个簇的缓冲区段地址
 
 ;====================================================================
 ;
 ; 检查是否还有下一个簇(读取FAT表的相关信息)
 ;  LET   N = 数据簇号
 ;  THUS FAT_BYTES  = N*4  (FAT32)
 ;      FAT_SECTOR = FAT_BYTES / BytesPerSector
 ;    FAT_OFFSET = FAT_BYTES % BytesPerSector
 ;
 ;====================================================================
 
 ; 计算FAT所在的簇号和偏移 
 MOV  EAX,DWORD [BP - CURRENT_CLUSTER]
 XOR  EDX,EDX
 SHL  EAX,2
 XOR  EBX,EBX
 MOV  BX,WORD [ BytesPerSector ]
 DIV  EBX   ; EAX = Sector  EDX = Offset
 
 ; 设置缓冲区地址
 ADD  EAX,DWORD [BP - FAT_START_SECTOR  ]
 MOV  DWORD [ BP - DAP_SECTOR_LOW ], EAX 
 MOV   WORD [BP - DAP_BUFFER_SEG  ], 00H 
 MOV  WORD [BP - DAP_BUFFER_OFF  ], DATA_BUF_OFF ; 0000:1000H

 ; 读取扇区
 CALL  ReadSector
  
 ; 检查下一个簇
 MOV  DI,DX
 ADD  DI,DATA_BUF_OFF
 MOV  EAX,DWORD[DI]  ; EAX = 下一个要读的簇号
 AND  EAX,CLUSTER_MASK
 MOV  DWORD[ BP - CURRENT_CLUSTER ],EAX
 CMP  EAX,CLUSTER_LAST  ; CX >= 0FFFFFF8H,则意味着没有更多的簇了
 JB  _NEXT_DATA_CLUSTER

;读取完毕
_RUN_LOADER: 

 ; 运行FDOSLDR.BIN
 MOV  DL,[DriveNumber]
 jmp 800h:0100h;JMP  00:OSLOADER_ADDR

;====================================================================
; 调试例程
;====================================================================
%IFDEF DEBUG
;====================================================================

;====================================================================
; 
; 显示一个字符
; 输入: AL = 待显示字符
;
;====================================================================
PrintChar:
 PUSH BX
 MOV  AH,0EH
 MOV  BX,7
 INT  10H
 POP  BX
 RET
 
;====================================================================
%ENDIF ; DEBUG
;====================================================================


;====================================================================
; 扇区最后的标记字节(NASM不支持重复ORG)
;====================================================================
SecondPadding  TIMES 1022-($-$$) db  00H
SecondSignature  DW 0AA55H

;====================================================================
; 代码结束
;====================================================================

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -