Задать вопрос
@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. Прошу не бить, код я частично скопировал с интернет-ресурсов, т.к. ассемблер я знаю не очень хорошо
  • Вопрос задан
  • 113 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 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 для выбора первого ЖД, для определённости.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы