0

So, I am having issues with running the kernel code. I read the second sector, pad it with 512 bytes, then jump to the address where the kernel is to be. But, instead of printing, like it should, it just halts and does nothing.

Here is my code:

boot.s:

[org 0x7C00]
[bits 16]

jmp 0x0000:init

init:
    xor ax, ax
    mov ds, ax
    mov es, ax

; ===============================
;      SET BP AND STACK SIZE
; ===============================
cli

; =========================
;      SET STACK SIZE
; =========================
mov sp, 0x7C00
mov ss, ax

sti
; 
; Mimick old windows machine by requiring user to press
; a key to boot.
; 
call read

; 
; Load second sector from disk
; 
call load_disk


; jmp 0x0:0x1000

; call graphical

; 
; Boot kernel
; 
; call init_kernel

jmp 0x1000:0x0

; jmp $

%include "helper.s"
%include "disk_loader.s"
; %include "kernel.s"


; =========================
;       BOOT SECTOR
; =========================
times 510 - ($ - $$) db 0
dw 0xaa55

; times 512 db 0

helper.s just contains some functions to boot in graphics mode, clear the screen etc.

disk_loader.s:

[bits 16]

global load_disk

load_disk:

    mov ax, 0x1000
    mov es, ax
    xor bx, bx

    mov ah, 0x02
    mov al, 1
    mov ch, 0
    mov cl, 0x02
    mov dh, 0
    mov dl, 0x80
    int 0x13

    jc failure

    cmp ah, 0x0
    jne failure
    jmp succeed

    succeed:
        ret
    failure:
        ; jmp load_disk
        mov ah, 0x0e
        mov bx, reading_err
        call print

        ; Never-ending loop.
        jmp $

reading_err: db "Error reading from disk", 0x0

It works perfectly. I set the address to 0x1000, which is where the kernel should be. Here is my kernel.s code:

[bits 16]
[org 0x1000]

; ======================
;     16-BIT KERNEL
;     AUTHOR: Moca
;     DATE: 07/14/21
;      DO NOT COPY
; ======================

mov ah, 0x0e
mov bx, info
call print
int 0x10

jmp $

times 510 - ($ - $$) db 0

Additional, here is my helper.s file:

; 
; 
; Helper functions to use throughout all assembly files.
; Author: MocaCDeveloper
; DO NOT COPY WITHOUT PERMISSION.
; 
[bits 16]

; =====================================
;        FUNCTIONS TO USE
; =====================================
global print
global check_disk
global clear_screen
global read

print:
    mov al, [bx]
    add bx, 1
    int 0x10

    cmp al, 0
    je done
    jmp print

    done:
        ret

clear_screen:
    mov ah, 0x00
    mov al, 0x00
    int 0x10
    ret

set_official:
    mov ah, 0x00
    mov al, 0x03
    int 0x10
    ret

read:
    call clear_screen

    mov ah, 0x0e
    mov bx, TEXT
    call print
    int 0x10

    mov ah, 0x00
    int 0x16

    cmp al, 13
    je DO
    jmp read

    ret

DO:
    call set_official

    ret
graphical:
    mov ax, 0x13
    int 0x10

    ret

; ===============================
;       MESSAGES FOR INPUT
; ===============================
Welcome: 
    db 13, 10, "Welcome to AOS",13, 10,0x0
TEXT: 
    db "PRESS ENTER TO BOOT"
    db 13, 13, 13, 10
    db 13, '$'
    db 0x00

I align the kernel(in kernel.s) using org 0x1000. I have heard that it's the correct way, and I have also heard that it should be org 0x0.

Either way, after loading the second sector from the disk, and set the address to 0x1000, then jump to it, it simply halts and executes no further.

Here are the commands:

nasm -f bin -o boot.bin boot.s

nasm -f bin -o kernel.bin kernel.s

cat kernel.bin >> boot.bin - this is to insert the kernel after the bootloader.

qemu-system-i386 -L "C:\Program Files\qemu" boot.bin

For some reason qemu fails to run if I do not specify the path of qemu. That's not the problem, however. I am simply looking for an answer as to how to make sure the kernel is at the correct address, and how to correctly jump to it.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 2
    `jmp 0x1000:0x0` implies you should use `org 0` in your kernel.s source. Also, you're not setting `ds` anywhere. `ds` is still zero when you enter the kernel. Note that `org 0x1000` would fit `ds` equal to zero if you loaded the kernel to segment 100h (one zero less because paragraphs are 16 bytes). But you're using `es:bx` = 1000h:0 which would only be addressable with an offset of 10000h from segment base zero, beyond the first 64 KiB. And your source is incomplete, you aren't defining `info` and `print` anywhere in the kernel source. And your NASM commands have the input and output swapped. – ecm Jun 16 '21 at 08:16
  • 2
    Unrelated nitpick: You should set `ss` first and then in the very next instruction `sp`. There is special handling in the processor to insure that no interrupt occurs with one register initialised while the other one isn't yet. This only works if you set `ss` first. – ecm Jun 16 '21 at 08:21
  • Ok. So. I need to add `org 0` in kernel.s. Where would I set ds? (also I forgot to put in the code for the print function in the kernel.s file, apologies) – Aidan White Jun 16 '21 at 18:03
  • At the top of the file, to tell NASM where the *first* byte of that file will be loaded. That's the whole point of `org`, to set the origin. – Peter Cordes Jun 16 '21 at 18:09
  • Before you call `print` in the kernel you can add `push cs` then `pop ds`. This is valid in real/virtual 86 mode to set one segment register equal to another. As `cs` is set up to match the `org 0` it will be the correct value for `ds` too. – ecm Jun 16 '21 at 18:34
  • Ok. I added in `push cs` `pop ds` in kernel.s. I added in `[org 0]` in kernel.s as well, but still nothing is happening..I changed the address where I am jumping to 0x7E00 so i don't have to do a far jump. The jump instruction is `jmp 0x7E00:0` in boot.s. Any advice? – Aidan White Jun 16 '21 at 23:50
  • Please learn about segmentation. `jmp 0x7E00:0` jumps to linear address 7_E000h. `jmp` with two colon-separated numbers is always a far jump. If you want to have your kernel directly behind the loader, put `org 7E00h`, set `es:bx` = 0:7E00h and do `jmp 7E00h` (or equivalently `jmp 0:7E00h`). – ecm Jun 17 '21 at 09:20

0 Answers0