Search code examples
assemblykernelsystemx86-16bootloader

Why doesn't my bootloader load my kernel


I wrote a bootloader and a kernel and want my bootloader to load my kernel

[org 0x7c00]

    jmp     start

    ;%include "console.inc"

start:
    xor     ax, ax
    mov     ds, ax

    ;call    init_console
    ;call    clrscr

    ;mov     si, head
    ;mov     ah, 0x0f
    ;call    str_out

    ;mov     si, prompt
    ;mov     ah, 0x0f
    ;call    str_out

wait_in:
    in      al, 0x60

    cmp     al, 0
    jg      end_wait_in

    jmp     wait_in

end_wait_in:
    mov     ax, 0
    int     0x13

    jc      end_wait_in

read:
    mov     ax, 0x8000
    mov     es, ax
    mov     bx, 0

    mov     ah, 2
    mov     al, 1
    mov     ch, 0
    mov     cl, 2
    mov     dh, 0
    int     0x13

    jc      read

    jmp     0x8000:0x0000

head:        db          'XordaOS Bootloader v0.0.1', 0xa, 0xa, 0x0
prompt:      db          'Press any key to boot', 0x0

times 510 - ($ - $$) db 0
db 0x55
db 0xaa

This was my bootloader and now my kernel

    jmp     start

    %include "console.inc"

start:
    xor     ax, ax
    mov     ds, ax

    call    init_console
    call    clrscr

    mov     si, msg
    mov     ah, 0x0f
    call    str_out

    cli
    jmp     $

msg:        db          'Hello World', 0x0

This is console.inc (commented in loader.asm with all console code)

init_console:
    mov     ax, 0xb800
    mov     es, ax
    xor     bx, bx
    xor     dx, dx

    ret

str_out:
    lodsb
    cmp     al, 0x0
    je      str_out_end

    cmp     al, 0xa
    je      new_line

    mov     [es:bx], ax
    add     bx, 2

    jmp     str_out

new_line:
    add     dx, 160
    mov     cx, dx
    sub     dx, bx
    add     bx, dx
    mov     dx, cx

    jmp     str_out

str_out_end:

    ret

clrscr:
    mov     cx, 2000
    xor     bx, bx

    mov     al, ' '
    mov     ah, 0x00        

start_clr:
    mov     [es:bx], ax
    add     bx, 2

    loop    start_clr

    xor     bx, bx

    ret

then I entered following commands:

#!/bin/bash

nasm -fbin -o loader.bin loader.asm
nasm -fbin -o kernel.bin kernel.asm

dd if=/dev/zero of=XordaOS.img bs=1024 count=1440
dd if=loader.bin of=XordaOS.img bs=512 seek=0 conv=notrunc
dd if=kernel.bin of=XordaOS.img bs=512 seek=1 conv=notrunc

And then I started it in QEMU Launcher (GUI)

Everything is working until the code area where I load the kernel. After end_wait_in I called my clear screen function clrscr and the screen is cleared but after that my kernel doesn't do anything

I think something is wrong. Can anyone help me?


Solution

  • Given your original question, the disk read you are doing won't work on a number of emulators if the read is of a sector that doesn't have at least a sector worth of data in it (in this case a sector is 512 bytes). Emulator disk reads will usually return some type of error if there is an attempt to read an incomplete sector from a disk image.

    To get around this I often just create a 1.44MB disk image with something like:

    dd if=/dev/zero of=XordaOS.img bs=1024 count=1440
    

    This creates a zero filled file of 1024*1440 bytes, the size of a 1.44MB floppy. Many emulators will automatically determine the disk type from such a file size which is a bonus. You then need to add each part of the bootloader and kernel into the image without truncating it after each write (using DD's conv=notrunc option. You can do that with:

    dd if=loader.bin of=XordaOS.img bs=512 seek=0 conv=notrunc 
    dd if=kernel.bin of=XordaOS.img bs=512 seek=1 conv=notrunc
    

    When doing a disk read with Int 13h/ah=2h DL is the drive number. In your code you hard code it to 0 by placing 0 in DL. You should consider using the value passed to the bootloader by the BIOS in DL. You can save that value and restore it when needed for disk operations. As it is your code will only work on drive 0 (usually floppy disk A:).

    When you finally get the kernel loaded at 0x8000:0x0000 and you FAR JMP to it you need to ensure that DS is properly set. In this case you need to have 0x8000 in DS.

    I have a number of bootloader tips some of which you may wish to consider.

    To debug real mode bootloaders and other 16-bit real mode code I recommend using BOCHS which has proper real mode debugging support. You can use QEMU with remote debugging but it has limitations and pitfalls. You can get some ideas on debugging 16-bit code in QEMU in my other Stackoverflow Answer.