Как исправить ошибку «Тип носителя не найден» при попытке загрузить сектор с int 13h ah = 02h? - PullRequest
1 голос
/ 02 мая 2019

У меня есть некоторый код для загрузки второго сектора с дискеты в реальном режиме, но int 0x13 завершается с ошибкой «тип носителя не найден».Почему это так?

Я пытался изменить цилиндры, головки и сектора с 0, 0 и 2 на 1, 1 и 1 соответственно, но безрезультатно (я не знаю, использует ли адресация CHS 0или 1 для начала).Я также много раз переделывал этот код, чтобы лучше организовать его по функциям, но безрезультатно.Это терпит неудачу, но не печатает мою строку ошибки, которая озадачивает меня.Кажется, что всегда происходит сбой с одной и той же ошибкой.

Вот код:

bits 16
org 0x7c00

start:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00
    mov si, msg

    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

    hlt

; routine to reset disk state
reset_disk:
    xor ah, ah          ; int 0x13 ah = 0x00
    xor dl, dl          ; drive 0
    int 0x13
    jc .error           ; error if carry flag is set
    ret
.error:
    mov si, err_reset
    call puts
    hlt

; 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, 0x01        ; cylinder 0
    mov cl, 0x02        ; sector 2
    xor dh, dh          ; head 0
    xor dl, dl          ; drive 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
    hlt

; 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
msg: db "Test", 0
times 510-($-$$) db 0
dw 0xaa55

Я ожидаю, что на выходе будет сообщение об успехе, но для EAX также будет ноль (указываяуспех).

1 Ответ

2 голосов
/ 02 мая 2019

Существует ряд потенциальных проблем:

  • Вы жестко закодировали номер диска в 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

Если все работает правильно, вывод должен выглядеть примерно так:

enter image description here

...