1

I'm currently working on developing a simple operating system using a custom bootloader and kernel. However, when I boot my system, it only displays a cursor on the screen and doesn't show any further output. I'm looking for some guidance on how to troubleshoot this issue.

Here are some details about my setup:

I have a custom bootloader written in assembly (bootloader.asm) that loads the kernel into memory.
My kernel is written in assembly (kernel.asm) and contains basic initialization code.
I'm using NASM to assemble the code and LD to link the object files together.
I'm testing the OS on physical hardware.

I verified that the bootloader is loading the kernel into memory correctly by inspecting the memory contents at the designated location.
I added debug output statements in the bootloader and kernel code to check if they are executing as expected. However, I'm not seeing any output on the screen beyond the cursor.
I suspect there might be an issue with my code or configuration that prevents the operating system from properly initializing and displaying output on the screen.

Could someone guide me on how to further troubleshoot this issue and get my operating system to display the expected output?

Any insights, suggestions, or debugging techniques would be greatly appreciated.

Bootloader:

[BITS 16]
[ORG 0x7C00]

section bootloader

jmp main

main:
    ; Set up segment registers
    mov ax, 0x07C0
    mov ds, ax
    mov es, ax

    ; Load the kernel into memory
    mov bx, 0x8000      ; Destination memory address
    mov ah, 0x02        ; Read sector function
    mov al, 1           ; Number of sectors to read
    mov dl, 0x80        ; Boot drive number
    mov ch, 0           ; Cylinder number
    mov dh, 0           ; Head number
    mov cl, 2           ; Sector number
    int 0x13            ; Disk interrupt

    ; Jump to the loaded kernel
    jmp 0x8000:0000

times 510 - ($ - $$) db 0
dw 0xAA55 ; Boot signature

Kernel (I also decided to have a UI in the kernel):

[BITS 16]
[ORG 0x8000]

section kernel

start:
    mov ax, 0x07C0  ; Set up segment registers
    mov ds, ax
    mov es, ax

    ; Clear the screen
    mov ah, 0x00    ; Video BIOS - Set video mode
    mov al, 0x03    ; Mode 3 (Text mode: 80x25, 16 colors)
    int 0x10        ; Video interrupt

    ; Print the menu options
    mov si, menu
    call printString

    ; Wait for user input
    call readChar

    ; Process user input
    cmp al, '1'
    je option1
    cmp al, '2'
    je option2
    jmp invalidOption

option1:
    mov si, msgOption1
    call printString
    jmp end

option2:
    mov si, msgOption2
    call printString
    jmp end

invalidOption:
    mov si, msgInvalid
    call printString

end:
    ; Halt the system
    cli
    hlt

printString:
    lodsb           ; Load the next character from string
    test al, al     ; Check if end of string
    jz done         ; If yes, return
    mov ah, 0x0E    ; Video BIOS - Teletype output
    mov bh, 0x00    ; Video page
    int 0x10        ; Video interrupt
    jmp printString ; Print next character

done:
    ret

readChar:
    mov ah, 0x00    ; BIOS - Wait for key press
    int 0x16        ; Keyboard interrupt
    ret

menu db 'Welcome to aiOS!', 0x0D, 0x0A, 'Select an option:', 0x0D, 0x0A, '1. Option 1', 0x0D, 0x0A, '2. Option 2', 0x0D, 0x0A, 0x00
msgOption1 db 'You selected Option 1.', 0x0D, 0x0A, 0x00
msgOption2 db 'You selected Option 2.', 0x0D, 0x0A, 0x00
msgInvalid db 'Invalid option.', 0x0D, 0x0A, 0x00

times 510 - ($ - $$) db 0
dw 0xAA55 ; Boot signature

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Your segment:offset addressing is inconsistent in a number of places. I could go through them all in an answer, but maybe you want to inspect them yourself first and save some trouble. – Nate Eldredge Jul 14 '23 at 15:59
  • Basically, each time you use an address, check which segment and offset are being used, and whether they result in the linear address that you are expecting. – Nate Eldredge Jul 14 '23 at 16:00
  • I have addressed the error, but it still shows a cursor. – LevathonDeveloper Jul 14 '23 at 16:08
  • Regarding debugging techniques: test your code on an emulator with a good debugger. Bochs is a good one (qemu is more popular overall but its debugger is awkward to use with real-mode code). Then you can single-step your boot code and see what is actually happening line by line, instead of having to infer from the program's behavior. – Nate Eldredge Jul 14 '23 at 16:16
  • If you still have problems, another thing to check would be your assembly/link process: post the exact commands you are using as well as any linker scripts. Modern linkers are usually designed for linking 32-bit or 64-bit code and there can be issues when trying to use them for 16-bit code. – Nate Eldredge Jul 14 '23 at 16:17

1 Answers1

3

You have several mixups related to segment:offset addressing. If you'd like a review, see What are the segment and offset in real mode memory addressing?.

  • Your int 0x13 reads into es:bx, which here is 0x07c0:0x8000. That translates to linear address 0xfc00 which is not what you want.

  • Similarly, [ORG 0x7c00] and [ORG 0x8000] tell the assembler to assume the code will be loaded at that offset. So for instance, it is going to assume the address of menu is something like 0x8055. That means that mov si, menu is mov si, 0x8055 and your printString is going to read from address 0x07c0:0x8055 (because ds = 0x07c0) which is again wrong.

Probably the simplest and least confusing fix is to load ds and es with zero instead of 0x07c0. Then you'll be reading the "kernel" sector into 0x0000:0x8000, you'll access menu at 0x0000:0x8055, and everything will be consistent with the ORG directives that you currently have.

As a separate issue, in jmp 0x8000:0000, you have the segment and offset reversed. Even though 8086 is little-endian and the offset is placed before the segment in memory, in the assembly language source you still use seg:ofs order. So make it jmp 0x0000:0x8000.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82