我正在尝试使用USB上的引导加载程序加载一些数据,但显然int 13h不起作用!
引导器:
[bits 16]
[ORG 0x7c00]
jmp 0x0000:start
start:
cli
xor ax, ax
mov ss, ax
mov sp, 0x7c00
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
sti
mov [driveno], dl
reset:
;reset drive
xor ax, ax
mov dl, [driveno]
int 0x13
or ah, ah
jnz reset
mov ah, 0x02
mov al, 0x01
mov bx, 0x0000
mov es, bx
mov bx, 0x7e00
mov dl, [driveno]
xor dh, dh
mov cx, 0x0002
int 0x13
or ah, ah
jnz reset
mov dx, [0x7e00] ;So i can check and see if it has been loaded
call printhex
cli
hlt
jmp $
print:
loop:
lodsb
or al, al
jz done
mov ah, 0x0e
mov bx, 0x0003 ;page 0 and default color
int 0x10
jmp loop
done:
ret
printhex:
push bx
push si
mov si, hex_template
mov bx, dx
shr bx, 12
mov bx, [bx+hexabet]
mov [hex_template+2], bl
mov bx, dx
shr bx, 8
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+3], bl
mov bx, dx
shr bx, 4
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+4], bl
mov bx, dx
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+5], bl
call print
pop si
pop bx
ret
hex_template db '0x????',0
hexabet db '0123456789abcdef'
driveno db 0 ;Storing dl
times 510-($-$$) db 0
dw 0aa55h
dw 0x1234 ;This wont load!!!!
times 510 db 0
我希望我的十六进制转储方法将0x1234打印到屏幕,但它会打印0x0000而不是!我知道我的十六进制转储方法有效,问题是0x1234永远不会被加载到第一位。有什么想法吗?
我在Windows上运行。我编译并生成一个图像:
nasm -f bin -o boot.bin boot.asm
dd if=boot.bin of=\\.\e: bs=512 count=2
我正在使用chrysocome中的dd
。任何人都可以解释这种行为吗?
答案 0 :(得分:3)
虽然这个问题已经很久了,但它确实揭示了我所知道的其他人应该遇到的问题。
正如 Frank Kotler 指出你的代码看起来很好。我有几个小的挑剔:
问题是您使用 DD 程序。你这样做:
dd if=boot.bin of=\.\e: bs=512 count=2
通常,您使用of=\\.\e:
使用双反斜杠,但这不是问题的原因。 \.\e:
实际上并未指向磁盘(或USB驱动器)的开头。它指向 E:指向的分区的开头。因此,您在分区数据的开头编写了引导加载程序,而不是主引导记录(MBR)。较新版本的DD支持指定整个设备开头的选项(不仅仅是分区):
版本0.6beta1的变化
新功能id = / od =用于输入磁盘和输出磁盘。如果是磁盘上的唯一分区,则选择整个磁盘。例如:如果您插入一个USB磁盘并将其安装为f:那么' id = f:'将选择USB磁盘(不仅仅是if = \。\ f:将要执行的分区)
要写入USB驱动器的开头,分区 E:是其中的一部分,您可以这样做(我假设您以具有Admin的用户身份运行命令提示符权限):
dd if=boot.bin od=e: bs=512 count=2
注意我现在如何指定(od=e:
)。 od=
(输出设备)只是意味着我们要使用整个物理设备分区 E:。
可能感兴趣的是为什么你的bootloader似乎工作但打印出0x0000
。基于对Windows的了解,我会提出最佳猜测。
由于 DD 写入分区开头(而不是驱动器的开头)的问题,扇区#2(基于1)实际上并不包含我们的小内核。扇区#1甚至不包含我们编写的引导加载程序!
现在如果我们的代码是在分区中编写的,为什么我们的bootloader甚至会运行,为什么它会打印错误的值(0x0000)?
如果您使用Windows格式化USB驱动器,则会发生这种情况。您可能没有意识到的是,默认情况下,USB驱动器的格式类似于具有单个分区的硬盘驱动器,并且该一个分区被标记为可引导。 Microsoft在MBR(磁盘的第一个扇区)中安装引导加载程序。这个Microsoft引导加载程序是一个链式加载器,它通常具有这样的功能(一些细节可能会有所不同):
我们现在拥有的是Microsoft MBR引导加载程序读取USB驱动器上可引导分区的第一个扇区并执行它。分区的第一个扇区恰好是我们的引导加载程序,因为我们使用了dd if=boot.bin of=\.\e: bs=512 count=2
。我们实际上写了两个部门。 分区的第二个扇区(不是磁盘)包含我们的内核。所以我们的引导加载程序运行得很有效!
所以现在我们知道为什么我们的bootloader运行了,为什么它打印出错误的值?现在可能更清楚的是磁盘的第二个扇区没有我们的内核,分区包含它。磁盘读取( int 13h )代码执行此操作:
mov ah, 0x02 ; Disk Read
mov al, 0x01 ; Number of Sectors to read
mov bx, 0x0000
mov es, bx
mov bx, 0x7e00 ; ES:BX location to read to 0x0000:0x7E00
mov dl, [driveno]
xor dh, dh
mov cx, 0x0002 ; Read sector #2 (1-based, not 0-based)
int 0x13
我们只读取磁盘的第二个扇区,而不是分区。很可能第二个扇区被清零,因此我们的引导加载程序读取值为0x0000的原因。
如果我们正确地写了磁盘的前2个扇区(1024字节)( DD ),那么我们的引导加载程序和内核就能正常工作..
感谢Microsoft及其链式加载器 - 我们的引导加载程序运行但是内核位于磁盘上的错误位置,我们打印出一个可能充满零的扇区。这一系列事件恰好使我们的引导程序运行并使其看起来 int 13h 失败。它可能根本没有失败,它只是读取了一个没有包含我们内核的扇区。
注意:我使用单词kernel
,但在此问题的上下文中,它指的是存储在第二个扇区中的数据(0x1234
)。