我写了一个引导加载程序,它应该加载我的KRNLDR。SYS在FAT12格式的img文件上。但它不起作用
我用来创建它的命令:
nasm -fbin -o boot.bin boot.asm
dd if=/dev/zero of=test.img bs=512 count=2880
sudo losetup /dev/loop0 test.img
sudo mkdosfs -F 12 /dev/loop0
现在,我的系统识别并安装了设备,然后我放上了KRNLDR。上的SYS
然后我执行:
sudo dd if=boot.bin of=/dev/loop0 bs=512 count=1 conv=notrunc
sudo umount /dev/loop0
sudo losetup -d /dev/loop0
现在,该文件看起来像FAT12软盘,带有引导扇区和文件KRNLDR。系统
现在我在QEMU:中执行它
qemu-system-i386 -device format=raw,file=test.img
输出:
Operating System not found
Press any key to reboot
如果文件KRNLDR,这是我的引导加载程序打印到屏幕上的输出。我的引导程序找不到SYS
我的代码:
org 0x0
bits 16
jmp word loader
bsOEMName: db "TestOS "
bpbBytesPerSector: dw 512
bpbSectorsPerCluster: db 1
bpbReservedSectors: dw 1
bpbNumberOfFATs: db 2
bpbNumberOfRootEntries: dw 224
bpbTotalSectors: dw 2880
bpbMedia: db 0xf0
bpbSectorsPerFAT: dw 9
bpbSectorsPerTrack: dw 18
bpbNumberOfHeads: dw 2
bpbHiddenSectors: dd 0
bpbTotalSectorsBig: dd 0
bsDriveNumber: db 0
bsReserved: db 0
bsExtendedBootSignature: db 0x29
bsVolumeID: dd 0x12345678
bsVolumeLabel: db "TestOS "
bsFileSystem: db "FAT12 "
;-------------------------------------------------------------------------------
; SI = Zero terminated string to print
;-------------------------------------------------------------------------------
printMsg:
push ax
.printStart:
lodsb
or al, al
jz .printEnd
mov ah, 0x0e
int 0x10
jmp .printStart
.printEnd:
pop ax
ret
;-------------------------------------------------------------------------------
; AX = Starting sector
; CX = Number of sectors to read
; ES:BX = Buffer
;-------------------------------------------------------------------------------
readSectors:
mov di, 0x0005
.readLoop:
push ax
push bx
push cx
call lbaToChs
mov ah, 0x02
mov al, 0x01
mov ch, byte [track]
mov cl, byte [sector]
mov dh, byte [head]
mov dl, byte [bsDriveNumber]
int 0x13
jnc .success
dec di
pop cx
pop bx
pop ax
jnz .readLoop
.success:
pop cx
pop bx
pop ax
inc ax
add bx, word [bpbBytesPerSector]
loop readSectors
ret
track: db 0
head: db 0
sector: db 0
;-------------------------------------------------------------------------------
; AX = Logical sector
;-------------------------------------------------------------------------------
lbaToChs:
xor dx, dx
div word [bpbSectorsPerTrack]
inc dl
mov byte [sector], dl
xor dx, dx
div word [bpbNumberOfHeads]
mov byte [head], dl
mov byte [track], al
ret
;-------------------------------------------------------------------------------
; AX = Cluster number
;-------------------------------------------------------------------------------
clusterToLba:
sub ax, 0x0002
xor cx, cx
mov cl, byte [bpbSectorsPerCluster]
mul cx
ret
;-------------------------------------------------------------------------------
loader:
cli
mov ax, 0x07c0
mov es, ax
mov gs, ax
mov fs, ax
mov ds, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xffff
sti
mov byte [bsDriveNumber], dl
xor dx, dx
xor cx, cx
mov ax, 0x0020
mul word [bpbNumberOfRootEntries]
div word [bpbBytesPerSector]
xchg cx, ax ; Number of sectors of the root directory
mov al, byte [bpbNumberOfFATs]
mul word [bpbSectorsPerFAT]
add ax, word [bpbReservedSectors] ; Starting sector of the root directory
mov bx, 0x0200
call readSectors
mov cx, word [bpbNumberOfRootEntries]
mov di, 0x0200
searchRoot:
push cx
mov cx, 0x000b
mov si, stage2
push di
rep cmpsb
pop di
je loadFat
pop cx
add di, 0x0020
loop searchRoot
jmp failure
loadFat:
mov dx, [di + 26] ; Starting address of entry
xor ax, ax
mov al, byte [bpbNumberOfFATs]
mul word [bpbSectorsPerFAT] ; Number of sectors used by the FATs
mov word [cluster], dx
mov cx, ax
mov ax, word [bpbReservedSectors]
mov bx, 0x0200
call readSectors
mov ax, 0x0050
mov es, ax
mov bx, 0x0000
push bx
loadFile:
mov ax, word [cluster]
pop bx
call clusterToLba
xor cx, cx
mov cl, byte [bpbSectorsPerCluster]
call readSectors
push bx
mov ax, word [cluster]
mov cx, ax
mov dx, ax
shr dx, 1
add cx, dx
mov bx, 0x0200
add bx, cx
mov dx, [bx]
test ax, 1
jnz oddCluster
evenCluster:
and dx, 0b0000111111111111
jmp next
oddCluster:
shr dx, 4
next:
mov word [cluster], dx
cmp dx, 0x0ff0
jb loadFile
jmp 0x0050:0 ; Far jmp to KRNLDR.SYS
failure:
mov si, fail
call printMsg
mov si, anykey
call printMsg
mov ah, 0x00
int 0x16 ; Await key press
jmp 0xffff:0 ; Reboot with far jmp to BIOS
stage2: db "KRNLDR SYS"
fail: db "Operating system not found", 0xd, 0xa, 0x0
anykey: db "Press any key to reboot", 0xd, 0xa, 0x0
cluster: dw 0
times 510 - ($ - $$) db 0
dw 0xaa55
我能做什么?感谢的帮助
loadFat:
mov dx, [di + 26] ; Starting address of entry
xor ax, ax
mov al, byte [bpbNumberOfFATs]
mul word [bpbSectorsPerFAT] ; Number of sectors used by the FATs
mov word [cluster], dx
这里的一个问题是具有字操作数的mul
将该字乘以ax
,并将结果留在寄存器对dx:ax
中。因此,在使用零来初始化名为cluster的变量之前,您将用零覆盖dx
。当将FAT条目索引转换为扇区号时,从零减去2会得到非常高的扇区号。
这就引出了我发现的第二期。通常,[集群]中的零应该减去2,其结果乘以1(每个集群的扇区数量(,然后添加"第一个数据扇区",这将再次导致一个非常低的数字,这将导致故障,但可能会有所不同。然而,您的clusterToLba实际上并没有转换为该集群数据的LBA起始扇区,因为它没有添加"第一个数据扇区"(即第一个集群的第一个扇区的LBA编号(。这需要由加载程序进行计算。它是根目录的起始扇区加上根目录扇区的数量。