@Qreen
Разъяренный питонист

Nasm — почему не загружается более одного сектора диска?

Я начал изучение языка assembly, и пытался написать простейший загрузчик и ядро к нему. Ядро было написано на си и nasm, а загрузчик на чистом nasm. Мой код ядра получился больше, чем 512 байт, соответственно, занимал более 1 сектора.
После тестирования этот код не работал, и просто зависал, после загрузки ядра. При этом ядро было полностью рабочим, тестировал на grub, а так же урезанную до 508 байт версию на своем загрузчике. Проблема, как я понял, была именно в строке mov al, 02, но ничего поделать с этим я не смог. Загрузчик нормально работает при загрузке 1 сектора
bits 16]
[org 0x7c00]

                   ; Use the boot drive number passed to us by BIOS in register DL
start:
    xor ax,ax      ; We want a segment of 0 for DS for this question
    mov ds,ax      ;     Set AX to appropriate segment value for your situation
    mov es,ax      ; In this case we'll default to ES=DS
    mov bx,0x8000  ; Stack segment can be any usable memory

    mov ss,bx      ; This places it with the top of the stack @ 0x80000.
    mov sp,ax      ; Set SP=0 so the bottom of stack will be @ 0x8FFFF

    cld            ; Set the direction flag to be positive direction

    mov si, wolf_wel_msg
    call wolf_print

    mov si, wolf_kernel_load
    call wolf_print

    pushf
    stc

    mov ah,00
    int 13h

    read_sector:
        mov ax, 0x0
        mov es, ax      ; ES = 0
        mov bx, 0x1000  ; BX = 0x1000. ES:BX=0x0:0x1000
                        ; ES:BX = starting address to read sector(s) into
        mov ah, 02      ; Int 13h/AH=2 = Read Sectors From Drive
        mov al, 02      ; Sectors to read = 2
        mov ch, 00      ; CH=Cylinder. Second sector of disk
                        ; is at Cylinder 0 not 1
        mov cl, 02      ; Sector to read =2
        mov dh, 00      ; Head to read = 0
                        ; DL hasn't been destroyed by our bootloader code and still
                        ;     contains boot drive # passed to our bootloader by the BIOS
        int 13h
  

    jc wolf_error
    popf
    jmp 0x0:0x1000
    cli
    hlt

    wolf_error:
        mov si, wolf_error_msg
        call wolf_print
        mov si, wolf_error_msg1
        call wolf_print
        mov ah,00
        int 16h
        xor ax,ax
        int 19h

    wolf_print:
        lodsb
        or al,al
        jz exit
        mov ah,0x0e
        int 10h
        jmp wolf_print
        exit:
        ret

; Moved the data before the boot signature but after the code
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
wolf_error_msg1 db 'Press any key to restart..',0
times 510-($-$$) db 0
dw 0xAA55


P.S. Прошу не бить, код я частично скопировал с интернет-ресурсов, т.к. ассемблер я знаю не очень хорошо
  • Вопрос задан
  • 103 просмотра
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
Загрузчик нормально работает при загрузке 1 сектора

Вот я собрал твой загрузчик, записал его в бут-сектор, добил двумя секторами мусора и загрузил с такого диска qemu. Выглядит так, будто бы всё работает:
$ nasm test.s -o test
$ head -c 2b /dev/urandom >> test
$ hexdump -Cv test | tail -n2
000005f0  49 93 ad 56 25 97 25 82  61 1d d9 a1 66 2a cb 19  |I..V%.%.a...f*..|
00000600
$ qemu-system-i386 -hda test -gdb tcp::1235 -S

В другом терминале, см этот ответ на вопрос "как в gdb посмотреть 16-битный код выполняющийся в qemu":
$ wget https://gist.githubusercontent.com/MatanShahar/1441433e19637cf1bb46b1aa38a90815/raw/2687fb5daf60cf6aa8435efc8450d89f1ccf2205/target.xml


Далее в том же терминале:
$ gdb
(gdb) set tdesc filename target.xml
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default i8086 settings.

(gdb) target remote :1235
(gdb) set disassembly-flavor intel
(gdb) b *0x7c32
Breakpoint 2 at 0x7c32
(gdb) c
Continuing.

Breakpoint 2, 0x00007c32 in ?? ()
(gdb) x/2i $pc
=> 0x7c32:      int    0x13
   0x7c34:      jb     0x7c3e

-- тут я остановился прямо перед командой чтения. Дальше:
(gdb) tb *0x7c34
Temporary breakpoint 3 at 0x7c34
(gdb) c
Continuing.

Temporary breakpoint 3, 0x00007c34 in ?? ()
(gdb) x/16x 0x13f0
0x13f0: 0x49    0x93    0xad    0x56    0x25    0x97    0x25    0x82
0x13f8: 0x61    0x1d    0xd9    0xa1    0x66    0x2a    0xcb    0x19

прочитанные байты по адресу куда должен был попасть конец второго сектора совпадают со случайными данными которые я записал в конец образа диска.

Ну и на экране всё мило, надпись "Loading kernel...." выводится, надпись "Kernel.bin not found!" не выводится.

Но вообще, если начать придираться, то в процедуре read_sector не инициализирован dl, так что неизвестно, с какого именно устройства происходит попытка чтения в твоём неработающем случае. Можно добавить mov dl, 80h для выбора первого ЖД, для определённости.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы