Существует ряд потенциальных проблем:
- Вы жестко закодировали номер диска в 0 (с помощью
xor dl, dl
). Это означает, что ваш код не будет работать, если вы запустите QEMU таким образом, чтобы не использовать дисковод гибких дисков A (FDA). Если вы загрузитесь как жесткий диск, он потерпит неудачу. BIOS помещает номер диска, загруженный с DL , перед передачей управления вашему загрузчику. Просто используйте это значение вместо. Это легко достигается в вашем коде, удалив оба вхождения xor dl, dl
- Вы копируете CS в регистры другого сегмента. На некоторых аппаратных средствах и эмуляторах CS не может быть 0 (на некоторых это может быть 0x07c0). Не полагайтесь на CS как конкретное значение. Поскольку вы используете исходную точку (
org 0x7c00
), вам нужно поставить 0 в регистры сегментов (особенно DS ).
- В Цилиндре, Голове, Секторной адресации (CHS) цилиндры основаны на 0, головки - на 0, и только номера секторов - на 1. Второй сектор на диске - это CHS = (0,0,2). Ваш код, как показано, читается как CHS = (1,0,2), что неверно.
Инструкция HLT
ожидает только следующего прерывания. Когда происходит прерывание (т.е. таймер), процессор продолжит выполнение кода после HLT
. Вы захотите отключить внешние прерывания с помощью CLI
перед выполнением HLT
. Вы также должны поместить HLT
в цикл, поскольку на реальном оборудовании возможны немаскируемые прерывания (NMI). Чтобы правильно использовать HLT
, вы можете сделать:
cli
.hltloop:
hlt
jmp .hltloop
В качестве альтернативы для загрузчика достаточно простого бесконечного цикла: jmp $
.
С такими изменениями в вашем коде и простым вторым этапом для целей тестирования мы можем создать код, который читает второй этап в память 0x9c00: 0x0000, а затем FAR JMP и выполняет код. В этом примере MDP
будет отображаться непосредственно на дисплее с белым на пурпурных атрибутах.
boot.asm
bits 16
org 0x7c00
start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
mov ah, 0x00
mov al, 0x03
int 0x10
call reset_disk
mov si, suc_reset
call puts
call load_stage2
mov si, suc_load
call puts
; As a test if stage2 is loaded jump to code contained in stage2
jmp 0x9c00:0x0000
; jmp halt
; routine to reset disk state
reset_disk:
xor ah, ah ; int 0x13 ah = 0x00
int 0x13
jc .error ; error if carry flag is set
ret
.error:
mov si, err_reset
call puts
jmp halt
; routine to load stage 2
load_stage2:
mov ah, 0x02 ; int 0x13 ah = 0x02 (read sectors)
mov al, 0x01 ; number of sectors to read
mov ch, 0x00 ; cylinder 0
mov cl, 0x02 ; sector 2
xor dh, dh ; head 0
mov bx, 0x9c00 ; address 9c00
mov es, bx
xor bx, bx ; 0x9c00:0x0000
int 0x13
or ah, ah
jnz .error
ret
.error:
mov si, err_load
call puts
halt:
cli
.hltloop:
hlt
jmp .hltloop
; routine to print a string
puts:
mov ah, 0x0e ; int 0x10 ah = 0x0e (putchar)
.loop:
lodsb ; load string byte from si
or al, al ; check if al is zero
jz .end ; if zero jump to end (null terminator)
int 0x10 ; print character
jmp .loop ; loop
.end:
ret
err_reset: db "Failed to reset disk", 0x0a, 0x0d, 0
err_load: db "Failed to load stage 2", 0x0a, 0x0d, 0
suc_reset: db "Successfully reset disk 0...", 0x0a, 0x0d, 0
suc_load: db "Successfully loaded stage 2...", 0x0a, 0x0d, 0
times 510-($-$$) db 0
dw 0xaa55
stage2.asm
org 0x0000
bits 16
stage2:
; Display MDP with white on magenta on 4th line of text display
mov ax, 0xb800
mov es, ax
mov word [es:480], 0x57<<8 | 'M'
mov word [es:482], 0x57<<8 | 'D'
mov word [es:484], 0x57<<8 | 'P'
jmp $
Я обычно использую DD для создания образов дисков, но так как вы используете CAT, вы можете собрать и собрать образ диска с помощью:
nasm -f bin boot.asm -o boot.bin
nasm -f bin stage2.asm -o stage2.bin
cat boot.bin stage2.bin >disk.img
Вы можете запустить QEMU и загрузиться с дискеты (FDA) или жесткого диска (HDA). Он должен работать, используя:
qemu-system-i386 -fda disk.img
или
qemu-system-i386 -hda disk.img
Если все работает правильно, вывод должен выглядеть примерно так: