从 FAT 软盘映像读取第二阶段引导加载程序
Reading second stage bootloader from FAT floppy image
我正在尝试开发一个带有自定义引导加载程序的小型 OS。我在 OSDEV 方面有一点经验,但不是很多......我的问题是第一阶段引导加载程序不会从磁盘加载秒数。这是 boot.asm 文件:
org 0
bits 16
jmp boot
%include "include/fat12.inc"
%include "include/io.inc"
Mem.Loader1 equ 0x00007c00
Mem.Loader1.Size equ 0x00000200
Mem.Loader1.Segment equ Mem.Loader1 >> 4
Mem.Stack.Top equ 0x00007c00
boot: jmp Mem.Loader1.Segment : .init
.init:
cli
; adjust segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
xor ax, ax
mov ss, ax
mov sp, Mem.Stack.Top
sti
call LoadRoot
xor ebx, ebx
mov bp, secondStage
mov si, ImageName
call LoadFile
cmp ax, 0
je secondStage
BiosPrint msgBooting
jmp $
msgBooting db "E", 0
ImageName db "loader bin"
times 510-($-$$) db 0
dw 0xAA55
secondStage:
您可能认得 MonkOS and Brokenthorn since all my knowledge comes from them and OSDevWiki 中的一些代码。
引导加载程序无法找到 loader.bin 文件并打印“E”。
我绝对确定 LoadRoot
和 LoadFile
可以正常工作,因为我从上一个项目中复制了它,它运行良好,但如果需要,我会在此处添加它们。
用 nasm 组装文件后,我创建了一个软盘映像:
dd if=/dev/zero of=BonsOS.img bs=1024 count=1440
/sbin/mkfs.msdos BonsOS.img
mcopy -i BonsOS.img ./bin/boot/loader.bin ::/
dd if=./bin/boot/boot.bin of=BonsOS.img seek=0 count=1 conv=notrunc
最后 运行
qemu-system-x86_64 -fda BonsOS.img -m 512M -no-reboot -no-shutdown
如何解决找不到文件的问题?
编辑
fat12.inc:
;*******************************************************
;
; Fat12.inc
; FAT12 filesystem for 3-1/2 floppies
;
; OS Development Series
;*******************************************************
%ifndef __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
%define __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
%include "include/floppy16.inc" ; the erm.. floppy driver
%define ROOT_OFFSET 0x2e00
%define FAT_SEG 0x2c0
%define ROOT_SEG 0x2e0
;*******************************************
; LoadRoot ()
; - Load Root Directory Table to 0x7e00
;*******************************************
LoadRoot:
pusha ; store registers
push es
; compute size of root directory and store in "cx"
xor cx, cx ; clear registers
xor dx, dx
mov ax, 32 ; 32 byte directory entry
mul WORD [bpbRootEntries] ; total size of directory
div WORD [bpbBytesPerSector] ; sectors used by directory
xchg ax, cx ; move into AX
; compute location of root directory and store in "ax"
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
add ax, WORD [bpbReservedSectors]
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
; read root directory into 0x7e00
push word ROOT_SEG
pop es
mov bx, 0 ; copy root dir
call ReadSectors ; read in directory table
pop es
popa ; restore registers and return
ret
;*******************************************
; LoadFAT ()
; - Loads FAT table to 0x7c00
;
; Parm/ ES:DI => Root Directory Table
;*******************************************
LoadFAT:
pusha ; store registers
push es
; compute size of FAT and store in "cx"
xor ax, ax
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in "ax"
mov ax, WORD [bpbReservedSectors]
; read FAT into memory (Overwrite our bootloader at 0x7c00)
push word FAT_SEG
pop es
xor bx, bx
call ReadSectors
pop es
popa ; restore registers and return
ret
;*******************************************
; FindFile ()
; - Search for filename in root table
;
; parm/ DS:SI => File name
; ret/ AX => File index number in directory table. -1 if error
;*******************************************
FindFile:
push cx ; store registers
push dx
push bx
mov bx, si ; copy filename for later
; browse root directory for binary image
mov cx, WORD [bpbRootEntries] ; load loop counter
mov di, ROOT_OFFSET ; locate first root entry at 1 MB mark
cld ; clear direction flag
.LOOP:
push cx
mov cx, 11 ; eleven character name. Image name is in SI
mov si, bx ; image name is in BX
push di
rep cmpsb ; test for entry match
pop di
je .Found
pop cx
add di, 32 ; queue next directory entry
loop .LOOP
.NotFound:
pop bx ; restore registers and return
pop dx
pop cx
mov ax, -1 ; set error code
ret
.Found:
pop ax ; return value into AX contains entry of file
pop bx ; restore registers and return
pop dx
pop cx
ret
;*******************************************
; LoadFile ()
; - Load file
; parm/ ES:SI => File to load
; parm/ EBX:BP => Buffer to load file to
; ret/ AX => -1 on error, 0 on success
; ret/ CX => number of sectors read
;*******************************************
LoadFile:
xor ecx, ecx ; size of file in sectors
push ecx
.FIND_FILE:
push bx ; BX=>BP points to buffer to write to; store it for later
push bp
call FindFile ; find our file. ES:SI contains our filename
cmp ax, -1
jne .LOAD_IMAGE_PRE
pop bp
pop bx
pop ecx
mov ax, -1
ret
.LOAD_IMAGE_PRE:
sub edi, ROOT_OFFSET
sub eax, ROOT_OFFSET
; get starting cluster
push word ROOT_SEG ;root segment loc
pop es
mov dx, WORD [es:di + 0x001A]; DI points to file entry in root directory table. Refrence the table...
mov WORD [cluster], dx ; file's first cluster
pop bx ; get location to write to so we dont screw up the stack
pop es
push bx ; store location for later again
push es
call LoadFAT
.LOAD_IMAGE:
; load the cluster
mov ax, WORD [cluster] ; cluster to read
pop es ; bx:bp=es:bx
pop bx
call ClusterLBA
xor cx, cx
mov cl, BYTE [bpbSectorsPerCluster]
call ReadSectors
pop ecx
inc ecx ; add one more sector to counter
push ecx
push bx
push es
mov ax, FAT_SEG ;start reading from fat
mov es, ax
xor bx, bx
; get next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0 ;location of fat in memory
add bx, cx
mov dx, WORD [es:bx]
test ax, 0x0001 ; test for odd or even cluster
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low 12 bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high 12 bits
.DONE:
mov WORD [cluster], dx
cmp dx, 0x0ff0 ; test for end of file marker
jb .LOAD_IMAGE
.SUCCESS:
pop es
pop bx
pop ecx
xor ax, ax
ret
%endif ;__FAT12_INC_67343546FDCC56AAB872_INCLUDED__
依赖于floppy16.inc:
;*******************************************************
;
; Floppy16.inc
; Floppy drive interface routines
;
; OS Development Series
;*******************************************************
%ifndef __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
%define __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
bpbOEM db "My OS "
bpbBytesPerSector: DW 512
bpbSectorsPerCluster: DB 1
bpbReservedSectors: DW 1
bpbNumberOfFATs: DB 2
bpbRootEntries: DW 224
bpbTotalSectors: DW 2880
bpbMedia: DB 0xf0 ;; 0xF1
bpbSectorsPerFAT: DW 9
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
bpbHiddenSectors: DD 0
bpbTotalSectorsBig: DD 0
bsDriveNumber: DB 0
bsUnused: DB 0
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "MOS FLOPPY "
bsFileSystem: DB "FAT12 "
datasector dw 0x0000
cluster dw 0x0000
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
;************************************************;
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;************************************************;
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;************************************************;
; Convert LBA to CHS
; AX=>LBA Address to convert
;
; 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:
xor dx, dx ; prepare dx:ax for operation
div WORD [bpbSectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [bpbHeadsPerCylinder] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
;************************************************;
; Reads a series of sectors
; CX=>Number of sectors to read
; AX=>Starting sector
; ES:EBX=>Buffer to read to
;************************************************;
ReadSectors:
.MAIN
mov di, 0x0005 ; five retries for error
.SECTORLOOP
push ax
push bx
push cx
call LBACHS ; convert starting sector to CHS
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 [bsDriveNumber] ; 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
pop cx
pop bx
pop ax
add bx, WORD [bpbBytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
%endif ;__FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
这两个文件不是我的代码,它们取自 Brokenthorn 说明。
终于io.inc:
;************************;
; Parameters: ;
; si => string pointer ;
;************************;
bits 16
%macro BiosPrint 1
mov si, word %1
call _BiosPrint
%endmacro
_BiosPrint:
pusha
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
popa
ret
EDIT2
这是组织的完整项目的回购:https://github.com/Bonfra04/BonsOS
使用像 BOCHS 这样的调试器
我强烈建议使用 BOCHS 调试实模式代码,尤其是引导加载程序和内核开发的早期阶段。在 *nix 类型的系统上,您可以使用以下命令启动 BOCHS:
bochs -f /dev/null 'floppya: 1_44=BonsOS.img, status=inserted' 'boot: a'
然后在bootloader开始处设置断点,开始执行:
b 0x7c00
c
BOCHS步进使用说明;追踪;显示段寄存器;显示通用寄存器等可以在 BOCHS documentation.
中找到
问题
您似乎在某些时候更改了代码以不同方式处理段并引入了一些错误。您也在搜索错误的文件名。 FAT12 文件名全部以大写形式存储,长度为 11 个字节(文件名用空格填充 8 个字符)后跟 3 个字母的扩展名。您的代码正在寻找:
ImageName db "loader bin"
什么时候应该是:
ImageName db "LOADER BIN" ; 2 spaces between LOADER and BIN
调用 LoadFile
时,您可以这样设置调用:
xor ebx, ebx
mov bp, secondStage
mov si, ImageName
call LoadFile
BX:BP 应该是要将 stage2 读入内存的 segment:offset 地址。应该是:
mov bx, Mem.Loader1.Segment
mov bp, secondStage
mov si, ImageName
call LoadFile
您似乎将 FindFile
修改为使用 ROOT_OFFSET
,而 LoadFat
和 LoadRoot
您使用 ROOT_SEG
。您的代码最终为 CMPSB
指令提供了不正确的 DS:SI 和 ES:DI 值,因此您最终从错误的内存地址。我修改了您的 FindFile
代码以使用 ROOT_SEG
并最终得到如下内容:
FindFile:
push es ; Save ES
push cx ; store registers
push dx
push bx
mov bx, si ; copy filename for later
; browse root directory for binary image
mov ax, ROOT_SEG ; Set ES to ROOT_SEG not 0
mov es, ax
mov cx, WORD [bpbRootEntries] ; load loop counter
xor di, di ; Start at 0 offset from ES (ROOT_SEG)
; Remove mov di, ROOT_OFFSET ; locate first root entry
cld ; clear direction flag
.LOOP:
push cx
mov cx, 11 ; eleven character name. Image name is in SI
mov si, bx ; image name is in BX
push di
rep cmpsb ; test for entry match
pop di
je .Found
pop cx
add di, 32 ; queue next directory entry
loop .LOOP
.NotFound:
pop bx ; restore registers and return
pop dx
pop cx
pop es ; Restore ES
mov ax, -1 ; set error code
ret
.Found:
pop ax ; return value into AX contains entry of file
pop bx ; restore registers and return
pop dx
pop cx
pop es ; Restore ES
ret
然后你需要从 .LOAD_IMAGE_PRE
的开头删除调整 EDI 和 EAX 的 2 行,所以它应该以:
开头
.LOAD_IMAGE_PRE:
; get starting cluster
push word ROOT_SEG ; root segment loc
您没有提供 loader.asm
文件,所以作为示例,我使用它进行测试:
org 0x200
bits 16
jmp start
%include "include/io.inc"
start:
BiosPrint hello
jmp $
hello: db "Hello, world!", 0
我使用了 org 0x200
因为你使用了从你的引导加载程序的近跳转来达到这个并且你的引导加载程序使用的是 0x07c0 的 CS。这意味着 stage2 所需的偏移量 (ORG) 仍然相对于 0x07c0,这就是我使用 0x200 的原因。 0x07c0:0x0200 是物理地址 0x07e00,它是引导加载程序之后的物理地址。
当我在 BOCHS 中 运行 它时,我得到这个输出:
我正在尝试开发一个带有自定义引导加载程序的小型 OS。我在 OSDEV 方面有一点经验,但不是很多......我的问题是第一阶段引导加载程序不会从磁盘加载秒数。这是 boot.asm 文件:
org 0
bits 16
jmp boot
%include "include/fat12.inc"
%include "include/io.inc"
Mem.Loader1 equ 0x00007c00
Mem.Loader1.Size equ 0x00000200
Mem.Loader1.Segment equ Mem.Loader1 >> 4
Mem.Stack.Top equ 0x00007c00
boot: jmp Mem.Loader1.Segment : .init
.init:
cli
; adjust segment registers
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; create stack
xor ax, ax
mov ss, ax
mov sp, Mem.Stack.Top
sti
call LoadRoot
xor ebx, ebx
mov bp, secondStage
mov si, ImageName
call LoadFile
cmp ax, 0
je secondStage
BiosPrint msgBooting
jmp $
msgBooting db "E", 0
ImageName db "loader bin"
times 510-($-$$) db 0
dw 0xAA55
secondStage:
您可能认得 MonkOS and Brokenthorn since all my knowledge comes from them and OSDevWiki 中的一些代码。
引导加载程序无法找到 loader.bin 文件并打印“E”。
我绝对确定 LoadRoot
和 LoadFile
可以正常工作,因为我从上一个项目中复制了它,它运行良好,但如果需要,我会在此处添加它们。
用 nasm 组装文件后,我创建了一个软盘映像:
dd if=/dev/zero of=BonsOS.img bs=1024 count=1440
/sbin/mkfs.msdos BonsOS.img
mcopy -i BonsOS.img ./bin/boot/loader.bin ::/
dd if=./bin/boot/boot.bin of=BonsOS.img seek=0 count=1 conv=notrunc
最后 运行
qemu-system-x86_64 -fda BonsOS.img -m 512M -no-reboot -no-shutdown
如何解决找不到文件的问题?
编辑
fat12.inc:
;*******************************************************
;
; Fat12.inc
; FAT12 filesystem for 3-1/2 floppies
;
; OS Development Series
;*******************************************************
%ifndef __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
%define __FAT12_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
%include "include/floppy16.inc" ; the erm.. floppy driver
%define ROOT_OFFSET 0x2e00
%define FAT_SEG 0x2c0
%define ROOT_SEG 0x2e0
;*******************************************
; LoadRoot ()
; - Load Root Directory Table to 0x7e00
;*******************************************
LoadRoot:
pusha ; store registers
push es
; compute size of root directory and store in "cx"
xor cx, cx ; clear registers
xor dx, dx
mov ax, 32 ; 32 byte directory entry
mul WORD [bpbRootEntries] ; total size of directory
div WORD [bpbBytesPerSector] ; sectors used by directory
xchg ax, cx ; move into AX
; compute location of root directory and store in "ax"
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
add ax, WORD [bpbReservedSectors]
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx
; read root directory into 0x7e00
push word ROOT_SEG
pop es
mov bx, 0 ; copy root dir
call ReadSectors ; read in directory table
pop es
popa ; restore registers and return
ret
;*******************************************
; LoadFAT ()
; - Loads FAT table to 0x7c00
;
; Parm/ ES:DI => Root Directory Table
;*******************************************
LoadFAT:
pusha ; store registers
push es
; compute size of FAT and store in "cx"
xor ax, ax
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in "ax"
mov ax, WORD [bpbReservedSectors]
; read FAT into memory (Overwrite our bootloader at 0x7c00)
push word FAT_SEG
pop es
xor bx, bx
call ReadSectors
pop es
popa ; restore registers and return
ret
;*******************************************
; FindFile ()
; - Search for filename in root table
;
; parm/ DS:SI => File name
; ret/ AX => File index number in directory table. -1 if error
;*******************************************
FindFile:
push cx ; store registers
push dx
push bx
mov bx, si ; copy filename for later
; browse root directory for binary image
mov cx, WORD [bpbRootEntries] ; load loop counter
mov di, ROOT_OFFSET ; locate first root entry at 1 MB mark
cld ; clear direction flag
.LOOP:
push cx
mov cx, 11 ; eleven character name. Image name is in SI
mov si, bx ; image name is in BX
push di
rep cmpsb ; test for entry match
pop di
je .Found
pop cx
add di, 32 ; queue next directory entry
loop .LOOP
.NotFound:
pop bx ; restore registers and return
pop dx
pop cx
mov ax, -1 ; set error code
ret
.Found:
pop ax ; return value into AX contains entry of file
pop bx ; restore registers and return
pop dx
pop cx
ret
;*******************************************
; LoadFile ()
; - Load file
; parm/ ES:SI => File to load
; parm/ EBX:BP => Buffer to load file to
; ret/ AX => -1 on error, 0 on success
; ret/ CX => number of sectors read
;*******************************************
LoadFile:
xor ecx, ecx ; size of file in sectors
push ecx
.FIND_FILE:
push bx ; BX=>BP points to buffer to write to; store it for later
push bp
call FindFile ; find our file. ES:SI contains our filename
cmp ax, -1
jne .LOAD_IMAGE_PRE
pop bp
pop bx
pop ecx
mov ax, -1
ret
.LOAD_IMAGE_PRE:
sub edi, ROOT_OFFSET
sub eax, ROOT_OFFSET
; get starting cluster
push word ROOT_SEG ;root segment loc
pop es
mov dx, WORD [es:di + 0x001A]; DI points to file entry in root directory table. Refrence the table...
mov WORD [cluster], dx ; file's first cluster
pop bx ; get location to write to so we dont screw up the stack
pop es
push bx ; store location for later again
push es
call LoadFAT
.LOAD_IMAGE:
; load the cluster
mov ax, WORD [cluster] ; cluster to read
pop es ; bx:bp=es:bx
pop bx
call ClusterLBA
xor cx, cx
mov cl, BYTE [bpbSectorsPerCluster]
call ReadSectors
pop ecx
inc ecx ; add one more sector to counter
push ecx
push bx
push es
mov ax, FAT_SEG ;start reading from fat
mov es, ax
xor bx, bx
; get next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0 ;location of fat in memory
add bx, cx
mov dx, WORD [es:bx]
test ax, 0x0001 ; test for odd or even cluster
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low 12 bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high 12 bits
.DONE:
mov WORD [cluster], dx
cmp dx, 0x0ff0 ; test for end of file marker
jb .LOAD_IMAGE
.SUCCESS:
pop es
pop bx
pop ecx
xor ax, ax
ret
%endif ;__FAT12_INC_67343546FDCC56AAB872_INCLUDED__
依赖于floppy16.inc:
;*******************************************************
;
; Floppy16.inc
; Floppy drive interface routines
;
; OS Development Series
;*******************************************************
%ifndef __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
%define __FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
bits 16
bpbOEM db "My OS "
bpbBytesPerSector: DW 512
bpbSectorsPerCluster: DB 1
bpbReservedSectors: DW 1
bpbNumberOfFATs: DB 2
bpbRootEntries: DW 224
bpbTotalSectors: DW 2880
bpbMedia: DB 0xf0 ;; 0xF1
bpbSectorsPerFAT: DW 9
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
bpbHiddenSectors: DD 0
bpbTotalSectorsBig: DD 0
bsDriveNumber: DB 0
bsUnused: DB 0
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "MOS FLOPPY "
bsFileSystem: DB "FAT12 "
datasector dw 0x0000
cluster dw 0x0000
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
;************************************************;
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;************************************************;
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;************************************************;
; Convert LBA to CHS
; AX=>LBA Address to convert
;
; 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:
xor dx, dx ; prepare dx:ax for operation
div WORD [bpbSectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [bpbHeadsPerCylinder] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
;************************************************;
; Reads a series of sectors
; CX=>Number of sectors to read
; AX=>Starting sector
; ES:EBX=>Buffer to read to
;************************************************;
ReadSectors:
.MAIN
mov di, 0x0005 ; five retries for error
.SECTORLOOP
push ax
push bx
push cx
call LBACHS ; convert starting sector to CHS
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 [bsDriveNumber] ; 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
pop cx
pop bx
pop ax
add bx, WORD [bpbBytesPerSector] ; queue next buffer
inc ax ; queue next sector
loop .MAIN ; read next sector
ret
%endif ;__FLOPPY16_INC_67343546FDCC56AAB872_INCLUDED__
这两个文件不是我的代码,它们取自 Brokenthorn 说明。
终于io.inc:
;************************;
; Parameters: ;
; si => string pointer ;
;************************;
bits 16
%macro BiosPrint 1
mov si, word %1
call _BiosPrint
%endmacro
_BiosPrint:
pusha
.loop:
lodsb
or al, al
jz .done
mov ah, 0x0E
int 0x10
jmp .loop
.done:
popa
ret
EDIT2 这是组织的完整项目的回购:https://github.com/Bonfra04/BonsOS
使用像 BOCHS 这样的调试器
我强烈建议使用 BOCHS 调试实模式代码,尤其是引导加载程序和内核开发的早期阶段。在 *nix 类型的系统上,您可以使用以下命令启动 BOCHS:
bochs -f /dev/null 'floppya: 1_44=BonsOS.img, status=inserted' 'boot: a'
然后在bootloader开始处设置断点,开始执行:
b 0x7c00
c
BOCHS步进使用说明;追踪;显示段寄存器;显示通用寄存器等可以在 BOCHS documentation.
中找到问题
您似乎在某些时候更改了代码以不同方式处理段并引入了一些错误。您也在搜索错误的文件名。 FAT12 文件名全部以大写形式存储,长度为 11 个字节(文件名用空格填充 8 个字符)后跟 3 个字母的扩展名。您的代码正在寻找:
ImageName db "loader bin"
什么时候应该是:
ImageName db "LOADER BIN" ; 2 spaces between LOADER and BIN
调用 LoadFile
时,您可以这样设置调用:
xor ebx, ebx
mov bp, secondStage
mov si, ImageName
call LoadFile
BX:BP 应该是要将 stage2 读入内存的 segment:offset 地址。应该是:
mov bx, Mem.Loader1.Segment
mov bp, secondStage
mov si, ImageName
call LoadFile
您似乎将 FindFile
修改为使用 ROOT_OFFSET
,而 LoadFat
和 LoadRoot
您使用 ROOT_SEG
。您的代码最终为 CMPSB
指令提供了不正确的 DS:SI 和 ES:DI 值,因此您最终从错误的内存地址。我修改了您的 FindFile
代码以使用 ROOT_SEG
并最终得到如下内容:
FindFile:
push es ; Save ES
push cx ; store registers
push dx
push bx
mov bx, si ; copy filename for later
; browse root directory for binary image
mov ax, ROOT_SEG ; Set ES to ROOT_SEG not 0
mov es, ax
mov cx, WORD [bpbRootEntries] ; load loop counter
xor di, di ; Start at 0 offset from ES (ROOT_SEG)
; Remove mov di, ROOT_OFFSET ; locate first root entry
cld ; clear direction flag
.LOOP:
push cx
mov cx, 11 ; eleven character name. Image name is in SI
mov si, bx ; image name is in BX
push di
rep cmpsb ; test for entry match
pop di
je .Found
pop cx
add di, 32 ; queue next directory entry
loop .LOOP
.NotFound:
pop bx ; restore registers and return
pop dx
pop cx
pop es ; Restore ES
mov ax, -1 ; set error code
ret
.Found:
pop ax ; return value into AX contains entry of file
pop bx ; restore registers and return
pop dx
pop cx
pop es ; Restore ES
ret
然后你需要从 .LOAD_IMAGE_PRE
的开头删除调整 EDI 和 EAX 的 2 行,所以它应该以:
.LOAD_IMAGE_PRE:
; get starting cluster
push word ROOT_SEG ; root segment loc
您没有提供 loader.asm
文件,所以作为示例,我使用它进行测试:
org 0x200
bits 16
jmp start
%include "include/io.inc"
start:
BiosPrint hello
jmp $
hello: db "Hello, world!", 0
我使用了 org 0x200
因为你使用了从你的引导加载程序的近跳转来达到这个并且你的引导加载程序使用的是 0x07c0 的 CS。这意味着 stage2 所需的偏移量 (ORG) 仍然相对于 0x07c0,这就是我使用 0x200 的原因。 0x07c0:0x0200 是物理地址 0x07e00,它是引导加载程序之后的物理地址。
当我在 BOCHS 中 运行 它时,我得到这个输出: