组装 Fat32 引导
Posted
技术标签:
【中文标题】组装 Fat32 引导【英文标题】:Assembly Fat32 Booting 【发布时间】:2013-12-16 21:08:44 【问题描述】:所以经过几个小时的挣扎,我现在完全迷失了。 我要做的基本上是将第一个根目录条目加载到内存中,但它似乎在读取部分失败了。我正在使用 virtualbox 来模拟!
这是孔代码:
[BITS 16]
[ORG 0x7C00]
jmp START
nop
OEM_ID db "APACU-OS"
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x227E
TotalFATs db 0x02
MaxRootEntries dw 0x0000
NumberOfSectors dw 0x0000
MediaDescriptor db 0xF8
SectorsPerFAT dw 0x0000
SectorsPerTrack dw 0x003D
SectorsPerHead dw 0x0002
HiddenSectors dd 0x00000001
TotalSectors dd 0x00200000
BigSectorsPerFAT dd 0x00003EC1
Flags dw 0x0000
FSVersion dw 0x0000
RootDirectoryStart dd 0x00000002
FSInfoSector dw 0x0001
BackupBootSector dw 0x0006
times 12 db 0
DriveNumber db 0x80
db 0x00
Signature db 0x29
VolumeID dd 0xFFFFFFFF
VolumeLabel db "APACU BOOT "
SystemID db "FAT32 "
START:
mov Byte[DriveNumber], dl
; code located at 0000:7C00, adjust segment registers
cli
mov ax, 0x7C00
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
mov ax, 0x7C00
mov ss, ax
mov sp, 0xFFFF
sti
mov ah, 0x41
mov dl, [DriveNumber]
mov bx, 0x55AA
int 0x13
jnc continue
mov ah, 0x0E
mov al, "N"
int 0x10
;int 0x18
; No Support For Extended Reading
continue:
; size of a cluster in sectors is stored in cx
mov cx, WORD[SectorsPerCluster]
; compute location of the begining of the Data area and store in ax
mov al, BYTE [TotalFATs] ; Total number of FATs
mul WORD[BigSectorsPerFAT] ; Number of sectors for a FAT
add ax, WORD [ReservedSectors] ; Find the start of the Data area
mov WORD [datasector], ax ; Store the begining of the Data area
; read 1st data cluster into memory (7C00:0200)
mov ax, WORD[RootDirectoryStart]
call ClusterLBA
mov bx, 0x0200 ; copy 1st data cluter above bootcode
call ReadSectors
; Point Index register to 1st File Entry
mov di, 0x0200 + 0x20
mov si, msgCRLF
call DisplayMessage
;Point to the offset where the file location information contains
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx
;Set up the segments where the kernel needs to be loaded
mov ax, 0100h ; set ES:BX = 0100:0000
mov es, ax
mov bx, 0
;Read the cluster which contains the kernel
mov cx, 0x0008
mov ax, WORD[cluster]
call ClusterLBA
call ReadSectors
mov si, msgCRLF
call DisplayMessage
;Jump to the location where the kernel was loded
push WORD 0x0100
push WORD 0x0000
retf
;An error has occured if this part is executed
mov si, msgFailure
call DisplayMessage
mov ah, 0x00
int 0x16 ; await keypress
int 0x19 ; warm boot computer
;*************************************************************************
; PROCEDURE ReadSectors
; reads cx sectors from disk starting at ax into
;memory location es:bx
;*************************************************************************
ReadSectors:
.MAIN:
mov di, 0x0005 ; five retries for error
.SECTORLOOP:
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; Bios read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .SECTORLOOP ; attempt to read again
int 0x18
.SUCCESS:
mov si, msgProgress
call DisplayMessage
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
;*************************************************************************
; PROCEDURE DisplayMessage
; display ASCIIZ string at ds:si via BIOS
;*************************************************************************
DisplayMessage:
lodsb ; load next character
or al, al ; test for NUL character
jz .DONE
mov ah, 0x0E ; BIOS teletype
mov bh, 0x00 ; display page 0
mov bl, 0x07 ; text attribute
int 0x10 ; invoke BIOS
jmp DisplayMessage
.DONE:
ret
;*************************************************************************
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; FileStartSector = ((X - 2) * SectorsPerCluster(0x08))
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert ax LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
mov word[SectorsPerTrack], 0x003D
mov word[SectorsPerHead], 0x0002
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerHead] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
;************************************************************************
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
cluster dw 0x0000
datasector dw 0x0000
;*******************************************************************************
;messages that needs to be shown
msgProgress db ".", 0x00
msgFailure db 0x0D, 0x0A, "Kernel loading failed...", 0x0D, 0x0A, 0x00
msgCRLF db 0x0D, 0x0A, 0x00
TIMES 510-($-$$) DB 0
DW 0xAA55
;*************************************************************************
我知道它失败了,因为它在读取扇区循环中触发了 int 0x18。
所以我的问题是:为什么会失败?我将如何解决它?并且我还需要使用 BIOS 扩展读取驱动器吗?
【问题讨论】:
代码很多;你能指出你需要帮助的具体部分吗?此外,你怎么知道你的内核失败了? VirtualBox 的输出是什么? 它在 ReadSectors 中失败,因为它在它的末尾触发了 int 0x18。 甚至没有关闭。在设置隔离之前尝试保存dl
是错误的,对于org 0x7C00
,您希望隔离为零。可能还有其他问题。
我在使用 VirtualBox 时遇到了问题,后来一位当时的 Sun 工程师在现实生活中向我证实了这些问题。请使用其他任何东西,即使 BOCHS 更好更可靠,但由于能够为此附加 gdb 和 b *0x7C00,我现在特别关注 qemu。另外,@FrankKotler 所说的。
您在 int 0x13 中检测到驱动器扩展,那么您为什么不使用它们来执行读取呢?通过使用 CHS 而不是 LBA,您并没有节省时间;事实上,你在浪费代码空间。正如弗兰克所说,可能还有其他问题,我认为你的 BPB 是有问题的。您是否使用磁盘编辑器在 USB 密钥上对其进行了测试?
【参考方案1】:
我认为你不能像这样使用引导挂钩中断(int 0x18)。而且我认为那不是你自己的代码。如果你想使用清晰的引导加载程序,你必须使用二进制文件(在其他操作中使用系统)。如果要制作自己的引导加载程序,则必须浪费大量时间进行编码和编译和放置。
【讨论】:
【参考方案2】:对于 [Segment:Offset] RealMemory = Segment * 16 + Offset
引导扇区在实际内存中的 0x07C00 处加载。这相当于 07C0:0000 或 0000:7C00。因此,首先,您需要决定要在哪个空间中引用变量。看起来您已将原点设置为 0x7C00。
但是,您将段寄存器设置为 7C00。对于您选择的原点,段值将为 0。如果您选择 [org 0],则段值为 0x07C0。 此外,您必须将 CS:IP 与您为代码选择的地址空间对齐。
如果原点是 0x7c00:
xor ax, ax
mov ds, ax
push word RealignmentPoint
retf
RealignmentPoint:
;variable addresses are mapped into 'usable' memory locations.
这仍然不是最佳做法。将原点设置为0,段寄存器设置为0x07C0,我们可以用一个字节来引用near变量,重对齐代码如下。
mov ax, 0x07C0
mov ds, ax
push ax
push word RealignmentPoint
retf
RealignmentPoint:
;variable addresses are mapped into acceptable memory locations
该技术是 NTFS 引导扇区反汇编的一部分(该死的小字)。但是您需要做更多的研究并更好地计划事情,否则您尝试编写的其他 98% 的代码将无法工作,因为它基于已弃用的功能或不完整的逻辑。
【讨论】:
以上是关于组装 Fat32 引导的主要内容,如果未能解决你的问题,请参考以下文章