如何使用 IBM/MS Int 13h 扩展读取 FAT32 RootDirectory?
How can I read the FAT32 RootDirectory using the IBM/MS Int 13h extensions?
我正在使用程序集为我的 OS 制作一个 BIOS 引导程序。我使用int 13h/ah=42h
通过LBA读取磁盘,但它总是抛出错误。
为什么会抛出这个错误?
我的代码:
; Bootloader stage 1
[BITS 16]
[ORG 0x0]
IMGADDR equ 0x60
[SECTION .text]
jmp _START
nop
bsOemName : DB 'OS ' ; 0x03
bpbBytesPerSector : DW '__' ; 0x0B
bpbSectorsPerCluster : DB 'e' ; 0x0D
bpbReservedSectors : DW 'xt' ; 0x0E
bpbNumberOfFATs : DB '~' ; 0x10
bpbRootEntries : DW 0x00 ; 0x11
bpbTotalSectors : DW 0x00 ; 0x13
bpbMedia : DB 0x00 ; 0x15
bpbSectorsPerFAT : DW 0x00 ; 0x16
bpbSectorsPerTrack : DW 0x00 ; 0x18
bpbHeadsPerCylinder : DW 0x00 ; 0x1A
bpbHiddenSectors : DD 0x00 ; 0x1C
bpbTotalSectorsBig : DD 0x00 ; 0x20
bsSectorsPerFAT32 : DD 0x00 ; 0x24
bsExtendedFlags : DW 0x00 ; 0x28
bsFSVersion : DW 0x00 ; 0x2A
bsRootDirectoryClusterNo : DD 0x00 ; 0x2C
bsFSInfoSectorNo : DW 0x00 ; 0x30
bsBackupBootSectorNo : DW 0x00 ; 0x32
bsreserved : times 12 DB 0x00 ; 0x34
bsDriveNumber : DB 0x00 ; 0x40
bsreserved1 : DB 0x00 ; 0x41
bsExtendedBootSignature : DB 0x00 ; 0x42
bsVolumeSerialNumber : DD 0x00 ; 0x43
bsVolumeLabel : DB ' ' ; 0x47
bsFileSystemName : DB ' ~' ; 0x52
_START:
cld
mov ax, 0x9000
mov es, ax
sub ax, 2048 / 16
mov ss, ax
mov sp, 2048
; Copy boot sector to top
mov cx, 256
mov si, 0x7C00
xor di, di
mov ds, di
rep movsw
jmp 0x9000:_ENTRY
_ENTRY:
push cs
pop ds
mov [ bsDriveNumber ], dl
and byte [ bsRootDirectoryClusterNo + 3 ], 0x0F
mov esi, [ bsRootDirectoryClusterNo ]
ReadRootDir:
push byte IMGADDR
pop es
xor bx, bx
call ReadCluster
push esi
pushf
push byte IMGADDR
pop es
xor di, di
mov si, ProgName
mov al, [ bpbSectorsPerCluster ]
cbw
mul word [ bpbBytesPerSector ]
shr ax, 5
mov dx, ax
FindName:
mov cx, 11
.FNAMELOOP:
cmp byte [es : di], ch
je .FNAMEERR
pusha
repe cmpsb
popa
je .FNAMEFOUND
add di, 32
dec dx
jnz .FNAMELOOP
popf
pop esi
jc ReadRootDir
jmp .FNAMEERR
.FNAMEFOUND:
push word [ es : di + 0x14 ]
push word [ es : di + 0x1A ]
pop esi
push byte IMGADDR
pop es
xor bx, bx
jmp ReadLoader
.FNAMEERR:
mov byte [ ErrorChar ], 'N'
jmp ShowError
ReadLoader:
call ReadCluster
jc ReadLoader
push byte IMGADDR
pop ds
mov ax, ds
sub ax, 0x10
mov es, ax
mov ds, ax
mov ss, ax
xor sp, sp
push es
push word 0x100
jmp short RunBinary
RunBinary:
mov dl, [ cs : bsDriveNumber ]
mov si, 16384 - 83
jmp 0x0060:0x0000
ReadCluster:
mov ax, [ bpbBytesPerSector ]
shr ax, 2
cwde
mov ebp, esi
xchg eax, esi
cdq
div esi
movzx edi, word [ bpbReservedSectors ]
add edi, [ bpbHiddenSectors ]
add eax, edi
push dx
mov cx, 1
call ReadSectorLBA
pop si
add si, si
add si, si
and byte [ es : si + 3 ], 0x0F
mov esi, [ es : si ]
lea eax, [ ebp - 2 ]
movzx ecx, byte [ bpbSectorsPerCluster ]
mul ecx
mov ebp, eax
movzx eax, byte [ bpbNumberOfFATs ]
mul dword [ bsSectorsPerFAT32 ]
add eax, ebp
add eax, edi
call ReadSectorLBA
mov ax, [ bpbBytesPerSector ]
shr ax, 4
mul cx
mov cx, es
add cx, ax
mov es, cx
cmp esi, 0x0FFFFFF8
ret
ReadSectorLBA:
pushad
.RSLBALOOP:
pusha
mov byte [ dapSize ] , 0x10
mov word [ dapReadSector ] , 0x0001
mov word [ dapDestOffset ] , bx
mov word [ dapDestSegment ] , es
mov dword [ dapReadStart ], eax
mov si, DAP
mov dl, [ bsDriveNumber ]
mov ax, 0x9000
mov ds, ax
mov ah, 0x42
int 0x13
push cs
pop ds
jc short .RSLBAERR
popa
dec cx
jz .RSLBAFIN
add bx, [ bpbBytesPerSector]
add eax, byte 1
jmp short .RSLBALOOP
.RSLBAFIN:
popad
ret
.RSLBAERR:
mov byte [ ErrorChar ], 'D'
jmp ShowError
ShowError:
mov ah, 0x0E
mov al, [ ErrorChar ]
mov bx, 7
int 10h
jmp $
ProgName: db "STARTUP BIN"
ErrorChar : db ' '
DAP:
dapSize : db 0x10;
dapReserved : db 0x00;
dapReadSector : dw 0x01;
dapDestOffset : dw 0x00;
dapDestSegment : dw 0x00;
dapReadStart : dq 0x00;
times 510 - ( $ - $$ ) db 0
dw 0xAA55
这是 GDB 寄存器信息和 DAP(磁盘地址包)内存转储:
eax 0xe44 3652
ecx 0x1 1
edx 0x80 128
ebx 0x7 7
esp 0x7ca 0x7ca
ebp 0x2 0x2
esi 0x1d3 467
edi 0x20 32
eip 0x1c5 0x1c5
eflags 0x203 [ IOPL=0 IF CF ]
cs 0x9000 36864
ss 0x8f80 36736
ds 0x9000 36864
es 0x60 96
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0x0 0
k_gs_base 0x0 0
cr0 0x10 [ ET ]
cr2 0x0 0
cr3 0x0 [ PDBR=0 PCID=0 ]
cr4 0x0 [ ]
cr8 0x0 0
efer 0x0 [ ]
0x901d3: 0x10 0x00 0x01 0x00 0x00 0x00 0x60 0x00
0x901db: 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
我认为我的代码生成了正确的 DAP 并传递了正确的 DAP 地址。我的代码中出现此问题的原因可能是什么?
[编辑]
为了回应 Michael Petch 的评论,我已经将 mov ah, 0x42
int 0x13
放在 mov ax, 0x9000
mov ds, ax
之后。
FAT32数据扇区号计算错误
以下是将数据簇号 N 转换为扇区号(该簇中的第一个扇区)的计算:
bpbHiddenSectors + bpbReservedSectors + bpbNumberOfFATs * bsSectorsPerFAT32 + (N - 2) * bpbSectorsPerCluster
因此我们编码:
; IN (es:bx is DestinationBuffer, esi is ClusterNumber)
ReadCluster:
lea edi, [esi-2]
mov eax, byte [ bpbSectorsPerCluster ]
imul edi, eax
movzx eax, byte [ bpbNumberOfFATs ]
imul eax, [ bsSectorsPerFAT32 ]
add edi, eax
movzx eax, word [ bpbReservedSectors ]
add eax, edi
add eax, [ bpbHiddenSectors ]
push dx
mov cx, 1 ; Read 1x one sector
call ReadSectorLBA
...
mov dl, [ bsDriveNumber ] <<< already requires DS=0x9000
mov ax, 0x9000 <<< redundant
mov ds, ax <<< redundant
mov ah, 0x42 ; BIOS.ExtendedRead
在 ReadSectorLBA 中,您可以安全地删除 DS
设置,因为如果 DS
在那个时候不等于 0x9000,none 的内存访问是正确的。
最后但可能太明显了:
- 明显的第 1 个,IBM/MS INT 13 扩展对您可用吗?
- 明显的 n°2,谁填写了 bpb 和 bs 字段?
- 很明显n°3,驱动器编号在80h-FFh范围内吗?
我正在使用程序集为我的 OS 制作一个 BIOS 引导程序。我使用int 13h/ah=42h
通过LBA读取磁盘,但它总是抛出错误。
为什么会抛出这个错误?
我的代码:
; Bootloader stage 1
[BITS 16]
[ORG 0x0]
IMGADDR equ 0x60
[SECTION .text]
jmp _START
nop
bsOemName : DB 'OS ' ; 0x03
bpbBytesPerSector : DW '__' ; 0x0B
bpbSectorsPerCluster : DB 'e' ; 0x0D
bpbReservedSectors : DW 'xt' ; 0x0E
bpbNumberOfFATs : DB '~' ; 0x10
bpbRootEntries : DW 0x00 ; 0x11
bpbTotalSectors : DW 0x00 ; 0x13
bpbMedia : DB 0x00 ; 0x15
bpbSectorsPerFAT : DW 0x00 ; 0x16
bpbSectorsPerTrack : DW 0x00 ; 0x18
bpbHeadsPerCylinder : DW 0x00 ; 0x1A
bpbHiddenSectors : DD 0x00 ; 0x1C
bpbTotalSectorsBig : DD 0x00 ; 0x20
bsSectorsPerFAT32 : DD 0x00 ; 0x24
bsExtendedFlags : DW 0x00 ; 0x28
bsFSVersion : DW 0x00 ; 0x2A
bsRootDirectoryClusterNo : DD 0x00 ; 0x2C
bsFSInfoSectorNo : DW 0x00 ; 0x30
bsBackupBootSectorNo : DW 0x00 ; 0x32
bsreserved : times 12 DB 0x00 ; 0x34
bsDriveNumber : DB 0x00 ; 0x40
bsreserved1 : DB 0x00 ; 0x41
bsExtendedBootSignature : DB 0x00 ; 0x42
bsVolumeSerialNumber : DD 0x00 ; 0x43
bsVolumeLabel : DB ' ' ; 0x47
bsFileSystemName : DB ' ~' ; 0x52
_START:
cld
mov ax, 0x9000
mov es, ax
sub ax, 2048 / 16
mov ss, ax
mov sp, 2048
; Copy boot sector to top
mov cx, 256
mov si, 0x7C00
xor di, di
mov ds, di
rep movsw
jmp 0x9000:_ENTRY
_ENTRY:
push cs
pop ds
mov [ bsDriveNumber ], dl
and byte [ bsRootDirectoryClusterNo + 3 ], 0x0F
mov esi, [ bsRootDirectoryClusterNo ]
ReadRootDir:
push byte IMGADDR
pop es
xor bx, bx
call ReadCluster
push esi
pushf
push byte IMGADDR
pop es
xor di, di
mov si, ProgName
mov al, [ bpbSectorsPerCluster ]
cbw
mul word [ bpbBytesPerSector ]
shr ax, 5
mov dx, ax
FindName:
mov cx, 11
.FNAMELOOP:
cmp byte [es : di], ch
je .FNAMEERR
pusha
repe cmpsb
popa
je .FNAMEFOUND
add di, 32
dec dx
jnz .FNAMELOOP
popf
pop esi
jc ReadRootDir
jmp .FNAMEERR
.FNAMEFOUND:
push word [ es : di + 0x14 ]
push word [ es : di + 0x1A ]
pop esi
push byte IMGADDR
pop es
xor bx, bx
jmp ReadLoader
.FNAMEERR:
mov byte [ ErrorChar ], 'N'
jmp ShowError
ReadLoader:
call ReadCluster
jc ReadLoader
push byte IMGADDR
pop ds
mov ax, ds
sub ax, 0x10
mov es, ax
mov ds, ax
mov ss, ax
xor sp, sp
push es
push word 0x100
jmp short RunBinary
RunBinary:
mov dl, [ cs : bsDriveNumber ]
mov si, 16384 - 83
jmp 0x0060:0x0000
ReadCluster:
mov ax, [ bpbBytesPerSector ]
shr ax, 2
cwde
mov ebp, esi
xchg eax, esi
cdq
div esi
movzx edi, word [ bpbReservedSectors ]
add edi, [ bpbHiddenSectors ]
add eax, edi
push dx
mov cx, 1
call ReadSectorLBA
pop si
add si, si
add si, si
and byte [ es : si + 3 ], 0x0F
mov esi, [ es : si ]
lea eax, [ ebp - 2 ]
movzx ecx, byte [ bpbSectorsPerCluster ]
mul ecx
mov ebp, eax
movzx eax, byte [ bpbNumberOfFATs ]
mul dword [ bsSectorsPerFAT32 ]
add eax, ebp
add eax, edi
call ReadSectorLBA
mov ax, [ bpbBytesPerSector ]
shr ax, 4
mul cx
mov cx, es
add cx, ax
mov es, cx
cmp esi, 0x0FFFFFF8
ret
ReadSectorLBA:
pushad
.RSLBALOOP:
pusha
mov byte [ dapSize ] , 0x10
mov word [ dapReadSector ] , 0x0001
mov word [ dapDestOffset ] , bx
mov word [ dapDestSegment ] , es
mov dword [ dapReadStart ], eax
mov si, DAP
mov dl, [ bsDriveNumber ]
mov ax, 0x9000
mov ds, ax
mov ah, 0x42
int 0x13
push cs
pop ds
jc short .RSLBAERR
popa
dec cx
jz .RSLBAFIN
add bx, [ bpbBytesPerSector]
add eax, byte 1
jmp short .RSLBALOOP
.RSLBAFIN:
popad
ret
.RSLBAERR:
mov byte [ ErrorChar ], 'D'
jmp ShowError
ShowError:
mov ah, 0x0E
mov al, [ ErrorChar ]
mov bx, 7
int 10h
jmp $
ProgName: db "STARTUP BIN"
ErrorChar : db ' '
DAP:
dapSize : db 0x10;
dapReserved : db 0x00;
dapReadSector : dw 0x01;
dapDestOffset : dw 0x00;
dapDestSegment : dw 0x00;
dapReadStart : dq 0x00;
times 510 - ( $ - $$ ) db 0
dw 0xAA55
这是 GDB 寄存器信息和 DAP(磁盘地址包)内存转储:
eax 0xe44 3652
ecx 0x1 1
edx 0x80 128
ebx 0x7 7
esp 0x7ca 0x7ca
ebp 0x2 0x2
esi 0x1d3 467
edi 0x20 32
eip 0x1c5 0x1c5
eflags 0x203 [ IOPL=0 IF CF ]
cs 0x9000 36864
ss 0x8f80 36736
ds 0x9000 36864
es 0x60 96
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0x0 0
k_gs_base 0x0 0
cr0 0x10 [ ET ]
cr2 0x0 0
cr3 0x0 [ PDBR=0 PCID=0 ]
cr4 0x0 [ ]
cr8 0x0 0
efer 0x0 [ ]
0x901d3: 0x10 0x00 0x01 0x00 0x00 0x00 0x60 0x00
0x901db: 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
我认为我的代码生成了正确的 DAP 并传递了正确的 DAP 地址。我的代码中出现此问题的原因可能是什么?
[编辑]
为了回应 Michael Petch 的评论,我已经将 mov ah, 0x42
int 0x13
放在 mov ax, 0x9000
mov ds, ax
之后。
FAT32数据扇区号计算错误
以下是将数据簇号 N 转换为扇区号(该簇中的第一个扇区)的计算:
bpbHiddenSectors + bpbReservedSectors + bpbNumberOfFATs * bsSectorsPerFAT32 + (N - 2) * bpbSectorsPerCluster
因此我们编码:
; IN (es:bx is DestinationBuffer, esi is ClusterNumber)
ReadCluster:
lea edi, [esi-2]
mov eax, byte [ bpbSectorsPerCluster ]
imul edi, eax
movzx eax, byte [ bpbNumberOfFATs ]
imul eax, [ bsSectorsPerFAT32 ]
add edi, eax
movzx eax, word [ bpbReservedSectors ]
add eax, edi
add eax, [ bpbHiddenSectors ]
push dx
mov cx, 1 ; Read 1x one sector
call ReadSectorLBA
...
mov dl, [ bsDriveNumber ] <<< already requires DS=0x9000 mov ax, 0x9000 <<< redundant mov ds, ax <<< redundant mov ah, 0x42 ; BIOS.ExtendedRead
在 ReadSectorLBA 中,您可以安全地删除 DS
设置,因为如果 DS
在那个时候不等于 0x9000,none 的内存访问是正确的。
最后但可能太明显了:
- 明显的第 1 个,IBM/MS INT 13 扩展对您可用吗?
- 明显的 n°2,谁填写了 bpb 和 bs 字段?
- 很明显n°3,驱动器编号在80h-FFh范围内吗?