X86 int 13h 42h不';不要把任何东西装在箱子里
我将引导加载程序从CHS更改为LBA,因此我将X86 int 13h 42h不';不要把任何东西装在箱子里,x86,nasm,bootloader,bios,bochs,X86,Nasm,Bootloader,Bios,Bochs,我将引导加载程序从CHS更改为LBA,因此我将int13h02h替换为int13h42h。它在QEMU中正常工作,但是,我用Bochs和我的笔记本电脑运行它时遇到问题 我使用ddif=main.bin of=/dev/sdb bs=512将引导加载程序写入USB闪存驱动器。笔记本电脑加载Intel UNDI并显示以下错误:无可引导设备-插入引导盘并按任意键 所以我试着用Bochs调试它,注意到Bochs将这个二进制文件识别为可引导文件。但是,在执行int13h后,没有加载任何内容 然后我试着从这
int13h02h
替换为int13h42h
。它在QEMU中正常工作,但是,我用Bochs和我的笔记本电脑运行它时遇到问题
我使用ddif=main.bin of=/dev/sdb bs=512
将引导加载程序写入USB闪存驱动器。笔记本电脑加载Intel UNDI并显示以下错误:无可引导设备-插入引导盘并按任意键
所以我试着用Bochs调试它,注意到Bochs将这个二进制文件识别为可引导文件。但是,在执行int13h
后,没有加载任何内容
然后我试着从这个闪存驱动器加载我的旧电脑,它工作了!它加载程序并正确执行。QEMU给了我同样的结果
以下是引导加载程序代码:
org 0x7c00
bits 16
boot:
cli
; Overlap CS and DS
mov ax, cs
mov ds, ax
mov es, ax
; Setup 4K stack before this bootloader
mov ax, 0x07c0
mov ss, ax
mov sp, 4096
; Load next sectors
mov si, DAP
mov ah, 42h
; DL didn't changed
int 13h
; Start
jmp bootend
; Disk address packet
DAP:
db 10h, 0
dw %1 ; Number of sectors to be loaded
dd bootend
dq 1
; Fill the rest of bootsector with zeroes and end it
times 510 - ($ - boot) db 0
dw 0xAA55
bootend:
中银高铁:
megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xfffe0000
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
floppya: 1_44=main.bin, status=inserted
boot: a
panic: action=ask
log: bochsout.txt
mouse: enabled=0
keyboard: type=mf, serial_delay=200, paste_delay=100000
display_library: x, options="gui_debug"
LBA磁盘访问可用性
并非所有BIOS都支持扩展磁盘读写功能(尽管在现代硬件上,它们几乎都支持)。并非所有BIOS都支持通过扩展磁盘读取软盘。博克斯也是如此。您可以通过测试驱动器上是否有扩展磁盘功能。这将执行扩展磁盘安装检查
如果您想使用扩展磁盘读取和LBA在BOCHS上测试代码,您必须创建硬盘映像并修改BOCHS以从它而不是从软盘引导。BOCHS支持的最小硬盘映像大小为CHS=1/16/63,即512*16*63=516096字节或1008个扇区,每个扇区512字节
您可以将您的bochsrc.txt
修改为:
megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xfffe0000
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
boot: c
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="disk.img", mode=flat, cylinders=0, heads=0, spt=0, model="Generic 1234", biosdetect=auto, translation=auto
panic: action=ask
log: bochsout.txt
mouse: enabled=0
keyboard: type=mf, serial_delay=200, paste_delay=100000
display_library: x, options="gui_debug"
我使用一个名为disk.img
的磁盘映像。您可以创建它,并使用以下命令将生成的扇区放入其中:
nasm -f bin main.asm -o main.bin
创建一个516096字节的映像:
dd if=/dev/zero of=disk.img count=1008 bs=512
将引导扇区放入disk.img
的开头,但不截断文件:
dd if=main.bin of=disk.img conv=notrunc
我有更多关于使用DD创建磁盘映像的信息
一般守则意见 虽然磁盘映像是BOCHS问题的一部分,但您确实存在一些编码问题。当控制权从BIOS转移到引导加载程序时,您不能假设CS的值将被设置为您认为的值。有关更多信息,请参阅我的。如果希望DS和ES为零(这是使用
org 0x7c00
所需的),则应将代码的开头修改为:
org 0x7c00
bits 16
boot:
cli
xor ax, ax ; Explicitly set DS and ES to 0
mov ds, ax
mov es, ax
为了测试您的代码,我在bootend
之后添加了以下内容:
bootend:
; Print MDP to upper left of screen in white on light magenta
mov ax, 0xb800
mov es, ax
mov word [es:0x0000], 0x57<<8 | 'M'
mov word [es:0x0002], 0x57<<8 | 'D'
mov word [es:0x0004], 0x57<<8 | 'P'
; Infinite loop so we don't have the CPU wander memory
cli
endloop:
hlt
jmp endloop
NASM仅直接支持这一点:
dw 1 ; Number of sectors to be loaded
真正的硬件/USB/笔记本电脑问题 如果您试图使用USB在真正的硬件上引导,那么您可能会遇到另一个问题,即使您在BOCHS中通过上述更改使其正常工作。如果BIOS设置为进行USB FDD仿真(而不是USB HDD或其他),则可能需要在引导加载程序的开头添加一个。您可以创建一个如下所示的假文件:
org 0x7c00
bits 16
boot:
jmp main
TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB.
; Dos 4.0 EBPB 1.44MB floppy
OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses
bytesPerSector: dw 512
sectPerCluster: db 1
reservedSectors: dw 1
numFAT: db 2
numRootDirEntries: dw 224
numSectors: dw 2880
mediaType: db 0xf0
numFATsectors: dw 9
sectorsPerTrack: dw 18
numHeads: dw 2
numHiddenSectors: dd 0
numSectorsHuge: dd 0
driveNum: db 0
reserved: db 0
signature: db 0x29
volumeID: dd 0x2d7e5a1a
volumeLabel: db "NO NAME "
fileSysType: db "FAT12 "
main:
cli
xor ax, ax ; Explicitly set DS and ES to 0
mov ds, ax
mov es, ax
[rest of your code here]
如果要修改代码使其布局高于Unix/Linux文件
命令,则该命令可能能够在磁盘映像中转储它认为构成MBR的BPB数据。运行命令file disk.img
,您可能会得到以下输出:
disk.img:DOS/MBR引导扇区,代码偏移量0x3c+2,OEM-ID“mkfs.fat”,根条目224,扇区2880(感谢您提供完整的答案!但是,我没有成功地遵循它。当我将BPB添加到引导扇区的开头时,QEMU没有将此二进制文件识别为可引导。我创建了硬盘映像,但Bochs为ata0从属文件写入了
未知类型“none”
。也许我应该为ata0尝试另一种类型?P.S.Sor由于注释不完整,我在编写itBuild时意外按下了Enter键:nasm-f bin-I./lib/“main.asm-o main.bin
dd if=/dev/zero of=main.img count=1008 bs=512dd if=main.bin of=main.img conv=notrunc
Run:qemu-system-i386-s-m 32-drive format=raw,file=main.bin
(也尝试了file=main.img
)当我删除BPB时,QEMU运行正常。另外,我刚刚从bochsrc中删除了ata0从机,现在Bochs运行,但似乎int 13h 42h
即使在硬盘驱动器上也不工作,所以我将检查Bochs是否支持扩展磁盘读取。让我们来看看。
org 0x7c00
bits 16
boot:
jmp main
TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB.
; Dos 4.0 EBPB 1.44MB floppy
OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses
bytesPerSector: dw 512
sectPerCluster: db 1
reservedSectors: dw 1
numFAT: db 2
numRootDirEntries: dw 224
numSectors: dw 2880
mediaType: db 0xf0
numFATsectors: dw 9
sectorsPerTrack: dw 18
numHeads: dw 2
numHiddenSectors: dd 0
numSectorsHuge: dd 0
driveNum: db 0
reserved: db 0
signature: db 0x29
volumeID: dd 0x2d7e5a1a
volumeLabel: db "NO NAME "
fileSysType: db "FAT12 "
main:
cli
xor ax, ax ; Explicitly set DS and ES to 0
mov ds, ax
mov es, ax
[rest of your code here]
org 0x7c00
bits 16
section .text
boot:
jmp main
TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB.
; Dos 4.0 EBPB 1.44MB floppy
OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses
bytesPerSector: dw 512
sectPerCluster: db 1
reservedSectors: dw 1
numFAT: db 2
numRootDirEntries: dw 224
numSectors: dw 2880
mediaType: db 0xf0
numFATsectors: dw 9
sectorsPerTrack: dw 18
numHeads: dw 2
numHiddenSectors: dd 0
numSectorsHuge: dd 0
driveNum: db 0
reserved: db 0
signature: db 0x29
volumeID: dd 0x2d7e5a1a
volumeLabel: db "NO NAME "
fileSysType: db "FAT12 "
main:
cli
cld ; String instructions forward movement
xor ax, ax
mov ds, ax
mov es, ax
; Setup 4K stack before this bootloader
mov ss, ax
mov sp, 0x7c00
; Display a banner to know our bootloader is executing
mov si, msg_booting
call print_string
; Check that Int 13h Extensions are available
; http://www.ctyme.com/intr/rb-0706.htm
mov ah, 0x41 ; Int 13h/AH=41h: Check if extensions present
mov bx, 0x55aa
int 0x13
jc ext_drv_none ; CF set - no extensions available for drive
cmp bx, 0xaa55 ; Is BX 0xaa55?
jnz ext_none ; If not, int 13h extensions not supported
; by BIOS at all.
; Int 13h extensions supported by BIOS and drive at this point
; Load next sectors
mov si, DAP
mov ah, 42h
; DL didn't changed
int 13h
; Start
jmp bootend
; Error: BIOS doesn't support Int 13h extensions
ext_none:
mov si, err_no_extensions
call print_string
jmp error_end
; Error: BIOS supports Int 13h extensions but not for drive in DL
ext_drv_none:
mov si, err_no_drv_ext_support
call print_string
; Print the boot drive number in hex
xor dh, dh ; Zero extended drive number to all of DX
push word 0x00 ; Attribute and page number to write to
push dx ; The value to write as hex
call print_hex_word
error_end:
cli
.loop:
hlt
jmp .loop
; Print 16 bit value passed on stack as first parameter
; in hexadecimal. Use page number and foreground color
; passed in second parameter. This routine will work on 8086+
; processors. This code takes advantage of packed BCD to
; determine the ASCII values to print. This code could have
; used compare and branch to do the same or a translation table.
print_hex_word:
push bp
mov bp, sp ; BP=SP, on 8086 can't use sp in memory operand
push dx ; Save all registers we clobber
push cx
push bx
push ax
mov cx, 0x0404 ; CH = number of nibbles to process = 4 (4*4=16 bits)
; CL = Number of bits to rotate each iteration = 4 (a nibble)
mov dx, [bp+4] ; DX = word parameter on stack at [bp+4] to print
mov bx, [bp+6] ; BX = page / foreground attr is at [bp+6]
.loop:
rol dx, cl ; Roll 4 bits left. Lower nibble is value to print
mov ax, 0x0e0f ; AH=0E (BIOS tty print),AL=mask to get lower nibble
and al, dl ; AL=copy of lower nibble
add al, 0x90 ; Work as if we are packed BCD
daa ; Decimal adjust after add.
; If nibble in AL was between 0 and 9, then CF=0 and
; AL=0x90 to 0x99
; If nibble in AL was between A and F, then CF=1 and
; AL=0x00 to 0x05
adc al, 0x40 ; AL=0xD0 to 0xD9
; or AL=0x41 to 0x46
daa ; AL=0x30 to 0x39 (ASCII '0' to '9')
; or AL=0x41 to 0x46 (ASCII 'A' to 'F')
int 0x10 ; Print ASCII character in AL
dec ch
jnz .loop ; Go back if more nibbles to process
pop ax ; Restore registers
pop bx
pop cx
pop dx
pop bp
ret
; Print string pointed to by DS:SI using
; BIOS TTY output via int 10h/AH=0eh
print_string:
push ax
push si
mov ah, 0Eh ; int 10h 'print char' function
.repeat:
lodsb ; Get character from string
test al, al
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat
.done:
pop si
pop ax
ret
; Disk address packet
DAP:
db 10h, 0
dw 1 ; Number of sectors to be loaded
dd bootend
dq 1
msg_booting: db "Booting... ", 0x00
err_no_extensions: db "Int 13h extensions not supported by BIOS", 0x00
err_no_drv_ext_support: db "Int 13h Extensions not supported on drive 0x", 0x00
; Fill the rest of bootsector with zeroes and end it
times 510 - ($ - boot) db 0
dw 0xAA55
bootend:
mov ax, 0xb800
mov es, ax
mov word [es:0x0000], 0x57<<8 | 'M'
mov word [es:0x0002], 0x57<<8 | 'D'
mov word [es:0x0004], 0x57<<8 | 'P'
cli
hlt