Q
Q
Qreen2021-06-23 14:25:22
assembler
Qreen, 2021-06-23 14:25:22

Nasm - why isn't more than one disk sector loaded?

I started learning the assembly language, and tried to write the simplest loader and kernel for it. The kernel was written in c and nasm, and the bootloader in pure nasm. My kernel code turned out to be more than 512 bytes, respectively, occupied more than 1 sector.
After testing, this code did not work, and just hung when the kernel loaded. At the same time, the kernel was fully working, tested on grub, as well as a version cut down to 508 bytes on its bootloader. The problem, as I understood it, was precisely in the line mov al, 02, but I could not do anything about it. The bootloader works fine when loading 1 sector

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


PS Please do not beat, I partially copied the code from Internet resources, because I don't know assembler very well

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2021-06-25
@Qreen

The bootloader works fine when loading 1 sector

So I assembled your bootloader, wrote it into the boot sector, finished it off with two garbage sectors and loaded qemu from such a disk. It looks like everything is working:
$ 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

In another terminal, see this answer to the question "how to see 16-bit code running in qemu in gdb":
$ wget https://gist.githubusercontent.com/MatanShahar/1441433e19637cf1bb46b1aa38a90815/raw/2687fb5daf60cf6aa8435efc8450d89f1ccf2205/target.xml

Further in the same terminal:
$ 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

-- here I stopped right in front of the reading team. Farther:
(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

the bytes read at the address where the end of the second sector should have ended up coincide with the random data that I wrote to the end of the disk image.
Well, everything is nice on the screen, the inscription "Loading kernel ...." is displayed, the inscription "Kernel.bin not found!" not output.
But in general, if you start to find fault, then dl is not initialized in the read_sector procedure, so it is not known from which device an attempt to read is made in your non-working case. You can add mov dl, 80hto select the first railway, for definiteness.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question