您的代码假定DS设置为 0。您不能这样假设。如果您使用org 0x7c00
.
您应该认真考虑通过设置SS:SP来定义您的堆栈。您不知道现有的在哪里,也不知道它是否足够大以处理您打算做的事情。
就在调用引导加载程序之前,BIOS 将使用引导设备编号设置DL寄存器。从引导驱动器发出驱动器请求时,不应在代码中将DL设置为 0。调用引导加载程序时,您应该使用DL中存在的值。
您应该使用CLD指令来清除方向标志,因为您正在使用LODSB指令,希望在内存中向前移动。不能保证正确设置方向标志,因此您应该使用CLD(向前)或STD(向后)将其明确设置为您需要的方向。
我在 StackOverflow 的General Bootloader Tips回答中提供了有关上述问题的更多信息。
由于您没有使用BPB,因此我强烈建议您删除jmp start
引导加载程序的第一条指令。而是在代码之后、引导扇区签名 ( 0xAA55
) 之前移动数据。原因是某些 BIOS 将尝试根据作为引导加载程序的第一条指令出现的JMP指令来查找BPB ,如果找到,则会覆盖内存中引导加载程序的部分内容,从而导致潜在的未定义行为。
您的引导加载程序使用此指令启动从第二个扇区加载的第二阶段:
jmp 0x0:0x1000
问题是,当您以这种方式读取设置ES:BX的扇区时:
read_sector:
mov ax, 0x0
mov es, ax
xor bx, bx
这会将ES:BX设置为 0x0000:0x0000,这显然不是您的JMP期望代码所在的位置。您需要将ES:BX设置为您希望INT 13/AH=02h读取磁盘扇区的内存位置。
INT 13h/AH=02h需要正确设置Cylinder/Head/Sector 编号。扇区从 1 开始编号,但气缸和气缸盖从零开始。磁盘的第二个扇区位于 Cylinder 0、Head 0、Sector 2。您的代码将 Cylinder 设置为 1 而不是 0。此代码是错误的,因为您确实应该将其设置为 0:
mov ch, 01
在您的第二阶段,您创建print
为一个函数,因为它以RET
指令结束。 jmp print
应改为call print
.
通过上面推荐的所有更改,包括我的一般引导加载程序提示中的更改,您的代码可以修改为:
引导程序
[bits 16]
[org 0x7c00]
; Use the boot drive number passed to us by BIOS in register DL
start:
xor ax,ax ; We want a segment of 0 for DS for this question
mov ds,ax ; Set AX to appropriate segment value for your situation
mov es,ax ; In this case we'll default to ES=DS
mov bx,0x8000 ; Stack segment can be any usable memory
mov ss,bx ; This places it with the top of the stack @ 0x80000.
mov sp,ax ; Set SP=0 so the bottom of stack will be @ 0x8FFFF
cld ; Set the direction flag to be positive direction
mov si, wolf_wel_msg
call wolf_print
mov si, wolf_kernel_load
call wolf_print
pushf
stc
mov ah,00
int 13h
read_sector:
mov ax, 0x0
mov es, ax ; ES = 0
mov bx, 0x1000 ; BX = 0x1000. ES:BX=0x0:0x1000
; ES:BX = starting address to read sector(s) into
mov ah, 02 ; Int 13h/AH=2 = Read Sectors From Drive
mov al, 01 ; Sectors to read = 1
mov ch, 00 ; CH=Cylinder. Second sector of disk
; is at Cylinder 0 not 1
mov cl, 02 ; Sector to read = 2
mov dh, 00 ; Head to read = 0
; DL hasn't been destroyed by our bootloader code and still
; contains boot drive # passed to our bootloader by the BIOS
int 13h
jc wolf_error
popf
jmp 0x0:0x1000
cli
hlt
wolf_error:
mov si, wolf_error_msg
call wolf_print
mov si, wolf_error_msg1
call wolf_print
mov ah,00
int 16h
xor ax,ax
int 19h
wolf_print:
lodsb
or al,al
jz exit
mov ah,0x0e
int 10h
jmp wolf_print
exit:
ret
; Moved the data before the boot signature but after the code
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
wolf_error_msg1 db 'Press any key to restart..',0
times 510-($-$$) db 0
dw 0xAA55
你好.asm
[org 0x1000]
jmp start
data:
msg db 'Hello',0
start:
mov si, msg
call print ; print is a function, use CALL instead of JMP
cli
hlt
print:
lodsb
or al, al
jz exit
mov ah,0x0e
int 10h
jmp print
exit:
ret
由于根据DD命令中给出的信息,您似乎正在使用 Windows ,因此您可能遇到了另一个问题。我不知道您使用的是哪个DDof=\\.\d:
,但不会写入磁盘(USB 驱动器)的开头,它会写入 D: 所在的分区,而不是磁盘本身的开头。
我建议您使用Chrysocome的最新DD。截至今天,最新的是0.6beta3。我推荐这个版本,因为它允许您正确访问相对于驱动器开头的磁盘(或 USB 记忆棒),而不是相对于特定分区的开头。这可能会导致尝试正确存储第 1 和第 2 扇区时出现严重问题。使用最新版本,我将使用这些具有管理员权限的命令来写入 USB 驱动器:
dd if=f:\boot.bin od=d: bs=512 count=1
dd if=f:\hello.bin od=d: bs=512 seek=1 count=1
这假设您的USB驱动器位于 Drive D: 上,如您的问题中所建议的那样。警告:未能使用正确的驱动器可能会导致其他设备上的数据丢失和损坏!!
如果这些命令正常工作,输出应该类似于:
dd if=boot.bin od=d: bs=512 count=1
rawwrite dd for windows version 0.6beta3.
Written by John Newbigin <jn@it.swin.edu.au>
This program is covered by terms of the GPL Version 2.
Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1
512 100%
1+0 records in
1+0 records out
dd if=hello.bin od=d: bs=512 seek=1 count=1
rawwrite dd for windows version 0.6beta3.
Written by John Newbigin <jn@it.swin.edu.au>
This program is covered by terms of the GPL Version 2.
Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1
28 5%
0+1 records in
0+1 records out
发出这些命令后,Windows 可能会自动检测到驱动器不再正确格式化。不允许 Windows 格式化驱动器。如果您确实允许它格式化驱动器,它将重新分区并格式化它。这样做会破坏你写的引导扇区。出现提示时,只需取消可能出现的格式对话框即可。
请记住在从系统中删除 USB 驱动器之前正确卸载/弹出 USB 驱动器。未能正确卸载可能会导致数据无法正确/完全写入驱动器。
如果您希望为 Bochs、QEMU、DOSbox 等创建磁盘映像,您可以在命令提示符下使用以下命令创建 720k 软盘:
dd if=/dev/zero of=disk.img bs=1024 count=720
dd if=f:\boot.bin of=disk.img bs=512 count=1 conv=notrunc
dd if=f:\hello.bin of=disk.img bs=512 seek=1 count=1 conv=notrunc
映像文件disk.img
应可供 Bochs、QEMU、DOSbox 等使用,或写入 720k 软盘以在真实计算机上使用。
/dev/zero
看起来像一个典型的 Unix/Linux 设备。我建议您使用的Windows DD/dev/zero
命令理解为一种特殊的输入设备,它只生成零。Windows 没有/dev/zero
设备,但DD将其视为特殊的内部设备并对其进行模拟。
在 MS Windows 上使用 Bochs 2.6.8 运行时,我看到的是:
在我的带有 16GB USB 记忆棒的联想 L520 笔记本电脑(非 EFI BIOS)上,这是我看到的: