int 13h 42h ничего не загружает в Bochs

Я изменил свой загрузчик с CHS на LBA, поэтому я заменил int 13h 02h на int 13h 42h. Он корректно работает в QEMU, однако у меня проблемы с его запуском с Bochs и моим ноутбуком.

Записал загрузчик на флешку с dd if=main.bin of=/dev/sdb bs=512. Ноутбук загружает Intel UNDI и выдает следующую ошибку: No bootable device - insert boot disk and press any key.

Поэтому я попытался отладить его с помощью Bochs и заметил, что Bochs распознает этот двоичный файл как загрузочный. Однако после выполнения int 13h ничего не было загружено.

Затем я попытался загрузить свой старый компьютер с этой флешки, и он работает! Он загружает программу и правильно ее выполняет. 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:

bochsrc:

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"

person trexxet    schedule 04.05.2017    source источник


Ответы (1)


Доступность LBA Disk Access

Не все BIOS поддерживают расширенные функции чтения и записи на диск (хотя на современном оборудовании они, скорее всего, будут). Не все BIOS поддерживают расширенное чтение дискет через Int 13h / AH = 42h . Это верно и для BOCHS. Вы можете проверить, доступны ли расширенные дисковые функции на диске через Int 13 / AH = 41h / BX = 55AAh. Это расширенная проверка установки диска.

Если вы хотите протестировать свой код на BOCHS с использованием расширенного чтения с диска и LBA, вам придется создать образ жесткого диска и изменить 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 для создания образов дисков в этом ответе на Stackoverflow.


Общие замечания по Кодексу

Хотя образ диска является частью проблемы с BOCHS, у вас есть некоторые проблемы с кодированием. Вы не можете предположить, что значение CS будет установлено таким, как вы думаете, когда управление передается из BIOS в ваш загрузчик. Дополнительные сведения см. В моих общих советах по загрузчику. Если вы хотите, чтобы 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. Обычно эта строка представляет собой проблему с символом % перед 1:

dw %1 ; Number of sectors to be loaded

NASM поддерживает это только напрямую:

dw 1  ; Number of sectors to be loaded

Реальные проблемы с оборудованием / USB / ноутбуком

Если вы пытаетесь использовать USB для загрузки на реальном оборудовании, вы можете столкнуться с другой проблемой, даже если вы заставите его работать в BOCHS с указанными выше изменениями. Если ваш BIOS настроен на эмуляцию USB FDD (а не USB HDD или что-то еще), вам может потребоваться добавить Блок параметров загрузки (BPB) в начало загрузчика. Вы можете создать фальшивый вот так:

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 file, команда может иметь возможность выгружать данные BPB, которые, по ее мнению, составляют ваш MBR в образе диска. Запустите команду file disk.img, и вы можете получить следующий результат:

disk.img: загрузочный сектор DOS / MBR, смещение кода 0x3c + 2, OEM-ID "mkfs.fat", корневые записи 224, секторы 2880 (объемы ‹= 32 МБ), секторы / FAT 9, секторы / дорожка 18, последовательный число 0x2d7e5a1a, без метки, FAT (12 бит)


Полный пример с проверками расширения Int 13h

Следующий код проверяет, доступны ли расширения Int 13h в BIOS, а также определяет, поддерживает ли диск в DL расширения Int 13h. В случае сбоя код выведет соответствующую ошибку. Функция print_string используется для вывода строк на консоль с помощью вывода TTY BIOS, а функция print_hex_word предназначена для отображения номера загрузочного диска в шестнадцатеричном формате.

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

Используя информацию для создания образа жесткого диска выше, когда я запускаю его в BOCHS, я получаю следующий результат:

введите описание изображения здесь

Если я загружаю этот же образ как дискету (диск A :) в BOCHS, теперь сообщение об ошибке сообщает мне, что расширения Int 13h недоступны для диска 0x0000:

введите описание изображения здесь

Если вы обнаружите, что вам нужно прочитать устройство, которое не поддерживает расширения Int 13h, вам придется вернуться к стандартным дисковым подфункциям Int 13h для чтение (AH = 02) / писать (AH = 03).

person Michael Petch    schedule 04.05.2017
comment
Спасибо за исчерпывающий ответ! Однако добиться успеха у меня не получилось. Когда я добавил BPB в начало загрузочного сектора, QEMU не распознает этот двоичный файл как загрузочный. Я создал образ жесткого диска, как и вы, но Bochs пишет unknown type 'none' для ata0-slave. Может стоит попробовать другой тип для ata0? P.S. Извините за неполный комментарий, я случайно нажал Enter во время его написания - person trexxet; 05.05.2017
comment
Сборка: nasm -f bin -i "../lib/" main.asm -o main.bin dd if=/dev/zero of=main.img count=1008 bs=512 dd if=main.bin of=main.img conv=notrunc Запуск: qemu-system-i386 -s -m 32 -drive format=raw,file=main.bin (Также пробовал file=main.img) Когда я удаляю BPB, QEMU работает правильно. Также я только что удалил ata0-slave из bochsrc, и теперь Bochs работает, но кажется, что int 13h 42h не работает даже с жестким диском, поэтому я проверю, поддерживает ли Bochs расширенное чтение с диска. - person trexxet; 05.05.2017
comment
Позвольте нам продолжить это обсуждение в чате. - person trexxet; 05.05.2017