读取磁盘时出现奇怪的错误
Weird Errors While Reading Disk
所以,我一直在从事一个业余爱好项目。创建我自己的操作系统。我开始有一段时间了,但直到几天前才放弃。我只是修复了一个疏忽,导致无法从我想读取的扇区读取任何内容。排除了那个错误,又出现了一个新错误,老实说,我什至不知道从哪里开始调试这个错误。
我正在编写主引导记录并使用 GDB 和 QEMU 对其进行调试,这是我的主引导记录的代码(它是使用 YASM 组装的)
抱歉,如果我的代码不是很好。我不是汇编语言专家...
; yasm boot.asm -fbin
bits 16
%define part(n,l) section n vstart=l align=1
%define rpart(n,l) section n start=l align=1
; ----------------------- ;
part(entry, 0x7c00) ;
; --ENTRY---------------- ;
_start:
mov [boot_drive+0x7c00], dl
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
mov sp, _start
mov bp, _start
mov cx, 512
mov si, _start
mov di, _strap
rep movsb
jmp 0:_strap+(b_boot_strapper-$$)
b_boot_strapper:
; ----------------------- ;
part(strap, 0x0600) ;
; --BOOT STRAPPER-------- ;
_strap:
xor cx, cx
.find_active_part:
cmp cl, 4
jge .no_active_part
xor ax, ax
mov ah, cl
mov bl, 16
mul bl
mov bx, ax
inc cl
mov al, (1 << 7)
mov ah, [partition_1+0x600+bx]
and ah, al
jnz .load_active_part
jmp .find_active_part
.load_active_part:
xor ax, ax
mov ds, ax
mov ah, 42h
mov dl, [boot_drive+0x600]
mov si, dap+0x600
push bx
mov bx, dap+0x600
mov es, bx
pop bx
mov cx, [partition_1+0x600+bx+8]
mov [dap_startlba+0x600], cx
mov cx, [partition_1+0x600+bx+12]
mov [dap_sectors+0x600], cx
int 13h
jc .disk_error
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, _start
mov bp, _start
mov dl, [boot_drive+0x600]
jmp 0:0x7c00
.no_active_part:
mov si, msg_no_part
call print
jmp halt
.disk_error:
mov si, msg_er_read
call print
jmp halt
print:
mov dx, ax
mov ah, 0Eh
xor bh, bh
mov bl, 0Fh
.rep:
lodsb
or al, al
jz .done
int 10h
jmp .rep
.done:
ret
halt:
cli
hlt
jmp halt
msg_er_read db 'Disk Read Error....', 0
msg_no_part db 'No Active Partition....', 0
; ----------------------- ;
rpart(variables, 300) ;
; --VARIABLES------------ ;
boot_drive db 0
dap: ; Disk Address Packet
db 16, 0
dap_sectors dw 0
dap_offset dw 0x7c00
dap_segment dw 0
dap_startlba dq 0
dap_end:
; ----------------------- ;
rpart(partitions, 446) ;
; --VARIABLES------------ ;
partition_1: ; This file has the following 16 bytes:
; 0x80, 0x01, 0x00, 0x05, 0x17, 0x01, x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
%include "part_n1.asm"
partition_2: ; The rest of these files are just 16 null bytes.
%include "part_n2.asm"
partition_3:
%include "part_n3.asm"
partition_4:
%include "part_n4.asm"
; ------------------------------- ;
rpart(signature, 510) ;
db 0x55, 0xAA ;
; ------------------------------- ;
此代码有效!但是,我不知道这是否是 QEMU 的问题,但是当它从扇区读取时它有一点损坏或数据丢失......
这些是预期位于 0x7c00 的字节
EB 1B B4 0E 30 FF B3 0F
AC 74 04 CD 10 EB F9 C3
48 65 6C 6C 6F 20 57 6F
72 6C 64 21 00 BE 10 7C
E8 DF FF F4
(打印"Hello World!"的基本函数)
这就是最终实际存在于该位置的内存中的内容:
EB 1B B4 0E 30 FF B3 0F
AC 74 04 CD 10 EB F9 C3
48 65 6C 6C 6F 20 57 6F
72 6C 64 21 00 BE 10 7C
F0 DF FF F4
如果你仔细观察,倒数第 4 个字节从 E8 变成了 F0,我不知道为什么会这样。在上一个 运行 中 "Hello World" 中的 "E" 也被更改,但它不在这个调试 运行.
中
我需要帮助甚至从哪里开始调试...
编辑 1
我意识到我打印 hello world 的函数有一些问题,天气是否与这件奇怪的事情有关,我真的不知道。在打印功能的重复部分(我正在加载的代码中的那个,而不是上面的 mbr 代码中的部分)我忘记在 lodsb
之后和 [=15= 之前添加 or al, al
] 这可能一直在干扰事情,我不完全确定,但在我更新了代码和 运行 几个调试会话之后,似乎这个问题不再发生了......
您的代码有很多问题,但问题很可能出在您没有显示的卷引导记录中。 MBR中的一些需要解决的问题:
- 在SS之后设置SP,保证SS[设置之间不会出现中断=82=] 和 SP,这将破坏由未知的旧 SP 和新 SS[ 形成的地址处的内存=82=](反之亦然)。 CPU 在设置 SS 后自动关闭中断,并在 以下指令后重新启用它们。
- 发出一条CLD指令来清除方向标志(DF),这样字符串指令如MOVSB和LODSB 使用向前移动。
- 当使用 Int 13h/ah=42h 时,有些 BIOS 需要 ES:BX 在磁盘地址包 (DAP) 中设置相同的值。您的代码未正确设置 ES。它应该被设置为零。
- 当从活动分区条目中的值填充 DAP 中的起始 LBA 时,您的代码仅复制 32 位值的低 16 位。这将您限制为 <= 32MiB (512*65536) 的媒体。您应该将起始 LBA 的下半部分和上半部分从分区 table 复制到 DAP。
- 进行磁盘读取或写入操作时,您应该在失败之前再重试 3 次。这在使用实际软盘和硬盘驱动器的实际硬件上可能是必需的。
- 您应该通过检查值是否为 0x80 而不仅仅是最高位来检查活动分区。唯一的有效值是 0x00 或 0x80。
- 您从分区加载的卷引导记录(VBR)通常是一个扇区。如果是一个扇区,则读取一个扇区,而不是整个分区。
- 您的代码在设置部分的方式上过于复杂。如果您要将引导加载程序重新定位到 0x0600,则使用 0x0600 的 ORG。只需确保将引导扇区从 0x0000:0x7c00 重定位到 0x0000:0x0600 的代码不依赖于任何与 0x7c00.
相关的标签
您的代码中有些东西很不错:
- 清除如何循环遍历分区 table 搜索 active/bootable 分区。
- 如果您想与某些古老的操作系统保持兼容,请在跳转到卷引导之前传递 DS:SI 中 bootable 分区条目的地址记录你读入内存。这不是必需的
- 不是必需的,这只是一个注意事项:如果您想保持与 MS-DOS 的兼容性,硬盘驱动器上的分区应始终位于 cylinder boundary 上,最好以柱面结尾边界。
其中一些技巧可以在我的 Whosebug 中找到 。
你的 relocatable 链加载卷引导记录 (VBR) 的引导加载程序的修改版本可以编码为:
boot.asm:
DISK_RETRY EQU 3
BOOT_ORG_RELOC EQU 0x0600
BOOT_ORG EQU 0x7c00
MBR_SIZE EQU 512
%define SECTION(n,l) section n start=l+BOOT_ORG_RELOC align=1
ORG BOOT_ORG_RELOC
_start:
; This code occurs before relocation so can't rely on any labels relative to
; BOOT_ORG_RELOC
xor ax, ax
mov es, ax
mov ds, ax
mov ss, ax
mov sp, BOOT_ORG ; Place stack at 0x0000:0x7c00 below bootloader
cld ; DF=0 for forward direction of string instructions
mov cx, MBR_SIZE/2 ; MBR Size to copy in bytes
mov si, BOOT_ORG ; Source address = DS:SI (0x0000:0x7c00)
mov di, BOOT_ORG_RELOC ; Destination address = ES:DI (0x0000:0x0600)
rep movsw
jmp 0x0000:.reloc_start ; Set CS:IP to continue at the next instruction but in
; the relocated boot sector
.reloc_start:
; Start at end of partition table and search to beginning looking for active
; boot partition.
mov si, partition_start ; SI = base of partition table
mov bx, PARTITION_SIZE ; Set the offset to search at to end of partition table
.active_search_loop:
sub bx, 16 ; Go to previous partition entry
jl .no_active ; If BX is neg we have passed beginning of partition table
cmp byte [si + bx], 0x80 ; Is partition bootable?
jnz .active_search_loop ; If not bootable go back and search again
.fnd_active:
lea di, [si + bx] ; Save offset of active partition to DI
mov ax, [si + bx + 8] ; Copy partition start LBA to DAP structure (lower 16-bits)
mov [dap + 8], ax
mov ax, [si + bx + 10] ; Copy partition start LBA to DAP structure (upper 16-bits)
mov [dap + 10], ax
mov cx, DISK_RETRY
; DL contains boot drive passed by BIOS
; ES was previously set to 0
mov bx, BOOT_ORG ; ES:BX needs to be same values as the DAP for some BIOSes
mov si, dap ; DS:SI = beginning of DAP structure
.disk_retry:
mov ah, 0x42 ; BIOS call for extended disk read
int 0x13 ; Read boot sector to 0x0000:0x7c00
jnc .vbr_loaded ; If int 0x13 succeeded (CF=0), run the loaded VBR
dec cx ; Lower retry count by 1
jge .disk_retry ; If retry count >= 0 go back and try again
.disk_error:
mov si, msg_er_read ; Print disk error and halt
call print
jmp halt
.no_active:
mov si, msg_no_part ; Print no active partition error and halt
call print
jmp halt
.vbr_loaded:
; DL is still same value oeiginally passed by BIOS
mov si, di ; DS:SI=address of active partition for some old OSes
jmp 0x0000:BOOT_ORG ; Execute the chain loaded VBR
halt: ; Infinite HLT loop with interrupts off to end bootloader
cli
.halt_loop:
hlt
jmp .halt_loop
; Print function
print:
mov ah, 0x0e
xor bh, bh
.rep:
lodsb
or al, al
jz .done
int 0x10
jmp .rep
.done:
ret
dap: ; Disk Address Packet
db 16, 0 ; DAP size, second byte always 0
dap_sectors dw 1 ; Read VBR (1 sector)
dap_offset dw BOOT_ORG ; Read to 0x0000:0x7c00
dap_segment dw 0
dap_startlba dq 0 ; To be filled in at runtime
dap_end:
msg_er_read: db 'Disk Read Error....', 0
msg_no_part: db 'No Active Partition....', 0
SECTION(parttbl, 446)
partition_start:
partition_1:
%include "part_n1.asm"
partition_2:
%include "part_n2.asm"
partition_3:
%include "part_n3.asm"
partition_4:
%include "part_n4.asm"
partition_end:
PARTITION_SIZE EQU partition_end - partition_start
SECTION(bootsig, 510)
dw 0xaa55
part_n1.asm:
db 0x80, 0x01, 0x00, 0x05, 0x17, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
part_n2.asm:
dq 0, 0
part_n3.asm:
dq 0, 0
part_n4.asm:
dq 0, 0
要测试的简单卷引导记录 (VBR) 可以是:
BOOT_ORG EQU 0x7c00
%define SECTION(n,l) section n start=l+BOOT_ORG align=1
ORG BOOT_ORG
vbr_start:
xor ax, ax ; ES=DS=SS=0
mov es, ax
mov ds, ax
mov ss, ax
mov sp, BOOT_ORG ; Place stack at 0x0000:0x7c00 below bootloader
cld ; DF=0 is forward direction for string instructions
mov si, vbr_run_msg ; Print a message that the VBR is running
call print
halt:
cli
.halt_loop:
hlt
jmp .halt_loop
; print function
print:
mov ah, 0x0e
xor bh, bh
.rep:
lodsb
or al, al
jz .done
int 0x10
jmp .rep
.done:
ret
vbr_run_msg: db "VBR running", 0x0d, 0x0a, 0
SECTION(bootsig, 510)
dw 0xaa55
您可以使用以下命令将此代码构建并运行为 10 兆字节的磁盘映像:
nasm -f bin boot.asm -o boot.bin
nasm -f bin vbr.asm -o vbr.bin
# create 10MiB disk image
dd if=/dev/zero of=disk.img bs=10M count=1
# place boot sector at LBA=0 without truncating the disk image
dd if=boot.bin of=disk.img conv=notrunc seek=0
# place vbr at LBA=4 without truncating the disk image
dd if=vbr.bin of=disk.img conv=notrunc seek=4
在 QEMU 中,您可以 运行 使用以下命令:
qemu-system-i386 -hda disk.img
如果有效,输出应类似于:
所以,我一直在从事一个业余爱好项目。创建我自己的操作系统。我开始有一段时间了,但直到几天前才放弃。我只是修复了一个疏忽,导致无法从我想读取的扇区读取任何内容。排除了那个错误,又出现了一个新错误,老实说,我什至不知道从哪里开始调试这个错误。
我正在编写主引导记录并使用 GDB 和 QEMU 对其进行调试,这是我的主引导记录的代码(它是使用 YASM 组装的)
抱歉,如果我的代码不是很好。我不是汇编语言专家...
; yasm boot.asm -fbin
bits 16
%define part(n,l) section n vstart=l align=1
%define rpart(n,l) section n start=l align=1
; ----------------------- ;
part(entry, 0x7c00) ;
; --ENTRY---------------- ;
_start:
mov [boot_drive+0x7c00], dl
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
mov sp, _start
mov bp, _start
mov cx, 512
mov si, _start
mov di, _strap
rep movsb
jmp 0:_strap+(b_boot_strapper-$$)
b_boot_strapper:
; ----------------------- ;
part(strap, 0x0600) ;
; --BOOT STRAPPER-------- ;
_strap:
xor cx, cx
.find_active_part:
cmp cl, 4
jge .no_active_part
xor ax, ax
mov ah, cl
mov bl, 16
mul bl
mov bx, ax
inc cl
mov al, (1 << 7)
mov ah, [partition_1+0x600+bx]
and ah, al
jnz .load_active_part
jmp .find_active_part
.load_active_part:
xor ax, ax
mov ds, ax
mov ah, 42h
mov dl, [boot_drive+0x600]
mov si, dap+0x600
push bx
mov bx, dap+0x600
mov es, bx
pop bx
mov cx, [partition_1+0x600+bx+8]
mov [dap_startlba+0x600], cx
mov cx, [partition_1+0x600+bx+12]
mov [dap_sectors+0x600], cx
int 13h
jc .disk_error
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, _start
mov bp, _start
mov dl, [boot_drive+0x600]
jmp 0:0x7c00
.no_active_part:
mov si, msg_no_part
call print
jmp halt
.disk_error:
mov si, msg_er_read
call print
jmp halt
print:
mov dx, ax
mov ah, 0Eh
xor bh, bh
mov bl, 0Fh
.rep:
lodsb
or al, al
jz .done
int 10h
jmp .rep
.done:
ret
halt:
cli
hlt
jmp halt
msg_er_read db 'Disk Read Error....', 0
msg_no_part db 'No Active Partition....', 0
; ----------------------- ;
rpart(variables, 300) ;
; --VARIABLES------------ ;
boot_drive db 0
dap: ; Disk Address Packet
db 16, 0
dap_sectors dw 0
dap_offset dw 0x7c00
dap_segment dw 0
dap_startlba dq 0
dap_end:
; ----------------------- ;
rpart(partitions, 446) ;
; --VARIABLES------------ ;
partition_1: ; This file has the following 16 bytes:
; 0x80, 0x01, 0x00, 0x05, 0x17, 0x01, x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
%include "part_n1.asm"
partition_2: ; The rest of these files are just 16 null bytes.
%include "part_n2.asm"
partition_3:
%include "part_n3.asm"
partition_4:
%include "part_n4.asm"
; ------------------------------- ;
rpart(signature, 510) ;
db 0x55, 0xAA ;
; ------------------------------- ;
此代码有效!但是,我不知道这是否是 QEMU 的问题,但是当它从扇区读取时它有一点损坏或数据丢失......
这些是预期位于 0x7c00 的字节
EB 1B B4 0E 30 FF B3 0F
AC 74 04 CD 10 EB F9 C3
48 65 6C 6C 6F 20 57 6F
72 6C 64 21 00 BE 10 7C
E8 DF FF F4
(打印"Hello World!"的基本函数)
这就是最终实际存在于该位置的内存中的内容:
EB 1B B4 0E 30 FF B3 0F
AC 74 04 CD 10 EB F9 C3
48 65 6C 6C 6F 20 57 6F
72 6C 64 21 00 BE 10 7C
F0 DF FF F4
如果你仔细观察,倒数第 4 个字节从 E8 变成了 F0,我不知道为什么会这样。在上一个 运行 中 "Hello World" 中的 "E" 也被更改,但它不在这个调试 运行.
中我需要帮助甚至从哪里开始调试...
编辑 1
我意识到我打印 hello world 的函数有一些问题,天气是否与这件奇怪的事情有关,我真的不知道。在打印功能的重复部分(我正在加载的代码中的那个,而不是上面的 mbr 代码中的部分)我忘记在 lodsb
之后和 [=15= 之前添加 or al, al
] 这可能一直在干扰事情,我不完全确定,但在我更新了代码和 运行 几个调试会话之后,似乎这个问题不再发生了......
您的代码有很多问题,但问题很可能出在您没有显示的卷引导记录中。 MBR中的一些需要解决的问题:
- 在SS之后设置SP,保证SS[设置之间不会出现中断=82=] 和 SP,这将破坏由未知的旧 SP 和新 SS[ 形成的地址处的内存=82=](反之亦然)。 CPU 在设置 SS 后自动关闭中断,并在 以下指令后重新启用它们。
- 发出一条CLD指令来清除方向标志(DF),这样字符串指令如MOVSB和LODSB 使用向前移动。
- 当使用 Int 13h/ah=42h 时,有些 BIOS 需要 ES:BX 在磁盘地址包 (DAP) 中设置相同的值。您的代码未正确设置 ES。它应该被设置为零。
- 当从活动分区条目中的值填充 DAP 中的起始 LBA 时,您的代码仅复制 32 位值的低 16 位。这将您限制为 <= 32MiB (512*65536) 的媒体。您应该将起始 LBA 的下半部分和上半部分从分区 table 复制到 DAP。
- 进行磁盘读取或写入操作时,您应该在失败之前再重试 3 次。这在使用实际软盘和硬盘驱动器的实际硬件上可能是必需的。
- 您应该通过检查值是否为 0x80 而不仅仅是最高位来检查活动分区。唯一的有效值是 0x00 或 0x80。
- 您从分区加载的卷引导记录(VBR)通常是一个扇区。如果是一个扇区,则读取一个扇区,而不是整个分区。
- 您的代码在设置部分的方式上过于复杂。如果您要将引导加载程序重新定位到 0x0600,则使用 0x0600 的 ORG。只需确保将引导扇区从 0x0000:0x7c00 重定位到 0x0000:0x0600 的代码不依赖于任何与 0x7c00. 相关的标签
您的代码中有些东西很不错:
- 清除如何循环遍历分区 table 搜索 active/bootable 分区。
- 如果您想与某些古老的操作系统保持兼容,请在跳转到卷引导之前传递 DS:SI 中 bootable 分区条目的地址记录你读入内存。这不是必需的
- 不是必需的,这只是一个注意事项:如果您想保持与 MS-DOS 的兼容性,硬盘驱动器上的分区应始终位于 cylinder boundary 上,最好以柱面结尾边界。
其中一些技巧可以在我的 Whosebug 中找到
你的 relocatable 链加载卷引导记录 (VBR) 的引导加载程序的修改版本可以编码为:
boot.asm:
DISK_RETRY EQU 3
BOOT_ORG_RELOC EQU 0x0600
BOOT_ORG EQU 0x7c00
MBR_SIZE EQU 512
%define SECTION(n,l) section n start=l+BOOT_ORG_RELOC align=1
ORG BOOT_ORG_RELOC
_start:
; This code occurs before relocation so can't rely on any labels relative to
; BOOT_ORG_RELOC
xor ax, ax
mov es, ax
mov ds, ax
mov ss, ax
mov sp, BOOT_ORG ; Place stack at 0x0000:0x7c00 below bootloader
cld ; DF=0 for forward direction of string instructions
mov cx, MBR_SIZE/2 ; MBR Size to copy in bytes
mov si, BOOT_ORG ; Source address = DS:SI (0x0000:0x7c00)
mov di, BOOT_ORG_RELOC ; Destination address = ES:DI (0x0000:0x0600)
rep movsw
jmp 0x0000:.reloc_start ; Set CS:IP to continue at the next instruction but in
; the relocated boot sector
.reloc_start:
; Start at end of partition table and search to beginning looking for active
; boot partition.
mov si, partition_start ; SI = base of partition table
mov bx, PARTITION_SIZE ; Set the offset to search at to end of partition table
.active_search_loop:
sub bx, 16 ; Go to previous partition entry
jl .no_active ; If BX is neg we have passed beginning of partition table
cmp byte [si + bx], 0x80 ; Is partition bootable?
jnz .active_search_loop ; If not bootable go back and search again
.fnd_active:
lea di, [si + bx] ; Save offset of active partition to DI
mov ax, [si + bx + 8] ; Copy partition start LBA to DAP structure (lower 16-bits)
mov [dap + 8], ax
mov ax, [si + bx + 10] ; Copy partition start LBA to DAP structure (upper 16-bits)
mov [dap + 10], ax
mov cx, DISK_RETRY
; DL contains boot drive passed by BIOS
; ES was previously set to 0
mov bx, BOOT_ORG ; ES:BX needs to be same values as the DAP for some BIOSes
mov si, dap ; DS:SI = beginning of DAP structure
.disk_retry:
mov ah, 0x42 ; BIOS call for extended disk read
int 0x13 ; Read boot sector to 0x0000:0x7c00
jnc .vbr_loaded ; If int 0x13 succeeded (CF=0), run the loaded VBR
dec cx ; Lower retry count by 1
jge .disk_retry ; If retry count >= 0 go back and try again
.disk_error:
mov si, msg_er_read ; Print disk error and halt
call print
jmp halt
.no_active:
mov si, msg_no_part ; Print no active partition error and halt
call print
jmp halt
.vbr_loaded:
; DL is still same value oeiginally passed by BIOS
mov si, di ; DS:SI=address of active partition for some old OSes
jmp 0x0000:BOOT_ORG ; Execute the chain loaded VBR
halt: ; Infinite HLT loop with interrupts off to end bootloader
cli
.halt_loop:
hlt
jmp .halt_loop
; Print function
print:
mov ah, 0x0e
xor bh, bh
.rep:
lodsb
or al, al
jz .done
int 0x10
jmp .rep
.done:
ret
dap: ; Disk Address Packet
db 16, 0 ; DAP size, second byte always 0
dap_sectors dw 1 ; Read VBR (1 sector)
dap_offset dw BOOT_ORG ; Read to 0x0000:0x7c00
dap_segment dw 0
dap_startlba dq 0 ; To be filled in at runtime
dap_end:
msg_er_read: db 'Disk Read Error....', 0
msg_no_part: db 'No Active Partition....', 0
SECTION(parttbl, 446)
partition_start:
partition_1:
%include "part_n1.asm"
partition_2:
%include "part_n2.asm"
partition_3:
%include "part_n3.asm"
partition_4:
%include "part_n4.asm"
partition_end:
PARTITION_SIZE EQU partition_end - partition_start
SECTION(bootsig, 510)
dw 0xaa55
part_n1.asm:
db 0x80, 0x01, 0x00, 0x05, 0x17, 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
part_n2.asm:
dq 0, 0
part_n3.asm:
dq 0, 0
part_n4.asm:
dq 0, 0
要测试的简单卷引导记录 (VBR) 可以是:
BOOT_ORG EQU 0x7c00
%define SECTION(n,l) section n start=l+BOOT_ORG align=1
ORG BOOT_ORG
vbr_start:
xor ax, ax ; ES=DS=SS=0
mov es, ax
mov ds, ax
mov ss, ax
mov sp, BOOT_ORG ; Place stack at 0x0000:0x7c00 below bootloader
cld ; DF=0 is forward direction for string instructions
mov si, vbr_run_msg ; Print a message that the VBR is running
call print
halt:
cli
.halt_loop:
hlt
jmp .halt_loop
; print function
print:
mov ah, 0x0e
xor bh, bh
.rep:
lodsb
or al, al
jz .done
int 0x10
jmp .rep
.done:
ret
vbr_run_msg: db "VBR running", 0x0d, 0x0a, 0
SECTION(bootsig, 510)
dw 0xaa55
您可以使用以下命令将此代码构建并运行为 10 兆字节的磁盘映像:
nasm -f bin boot.asm -o boot.bin
nasm -f bin vbr.asm -o vbr.bin
# create 10MiB disk image
dd if=/dev/zero of=disk.img bs=10M count=1
# place boot sector at LBA=0 without truncating the disk image
dd if=boot.bin of=disk.img conv=notrunc seek=0
# place vbr at LBA=4 without truncating the disk image
dd if=vbr.bin of=disk.img conv=notrunc seek=4
在 QEMU 中,您可以 运行 使用以下命令:
qemu-system-i386 -hda disk.img
如果有效,输出应类似于: