0

I'm trying to make a custom OS just for fun but have encountered an issue where my print_str code doesn't work after loading in the kernel from the bootloader. There are no compiler warnings and I can print char's. Instead of printing what I want it shows around two or three random characters.

Bootloader:

[ORG 0x7c00]
bits 16
boot_stuff:
mov [BOOT_DRIVE], dl ; store boot drive for later use because the BIOS stores the boot drive in dl
mov bp, 0x8000 ; set stack 
mov sp, bp ; out of the way at 0x8000
mov bx, 0x9000 ; Load 5 sectors to 0x0000(ES):0x9000(BX)
mov dh, 1 ; from the boot disk.
mov dl, [BOOT_DRIVE]
call disk_load
mov si, msg
call print_str
jmp 0x0000:0x9000
hang:
jmp hang
define_stuff:
print_str:
lodsb
mov ah, 0x0E
cmp al, 0
je done
int 0x10
jmp print_str
done:
ret
disk_load:
; load DH sectors to ES:BX from drive DL
push dx ; Store DX on stack so later we can recall how many sectors were requested to be read even if it is altered
mov ah, 0x02 ; BIOS read sector function
mov al, dh ; Read DH sectors
mov ch, 0x00 ; Select cylinder 0
mov dh, 0x00 ; Select head 0
mov cl, 0x02 ; Start reading from second sector (i.e. after the boot sector)
int 0x13 ; BIOS Interrupt
jc disk_error ; jump if carry flag set
pop dx ; Restore DX
cmp dh, al ; if AL (sectors read) != DH (sectors expected)
jne disk_error
ret
disk_error:
mov si, disk_error_msg
call print_str
jmp $
data_stuff:
BOOT_DRIVE db 0
msg db 'Booted', 0
nmsg db 'yonked', 0
disk_error_msg db 'DISK ERROR', 0
times 510-($-$$) db 0
dw 0xaa55

Kernel:

bits 16
entry:
mov ah, 0x0700
int 0x10
mov si, msg
call print_str
hang:
jmp hang
print_str:
lodsb
mov ah, 0x0E
cmp al, 0
je done
int 0x10
jmp print_str
done:
ret
data:
msg db 'Booted', 0
bad_coder
  • 11,289
  • 20
  • 44
  • 72
D_Man
  • 11
  • 2
    `LODSB`/`LODSW`/`LODSD` load the BYTE/WORD/DWORD from the address (E)DS:(E)SI. Have you set the segment register (E)DS to a valid value? Pay attention: the values of the (segment) registers (except CS) are undefined after booting. – zx485 Sep 06 '21 at 00:54
  • i set SI to msg and even if i set DS to 0x0000 which should be the same as ES which is the segment the kernel is in it doesnt work – D_Man Sep 06 '21 at 01:06
  • nvm i figured it out – D_Man Sep 06 '21 at 01:08
  • 1
    @zx485: Even CS isn't guaranteed, it could be either 0 or 7C0. [Michael Petch's tips](https://stackoverflow.com/questions/32701854/boot-loader-doesnt-jump-to-kernel-code). Also, segment registers don't have wider versions, it's always DS, no x86 has an EDS. https://www.felixcloutier.com/x86/lods:lodsb:lodsw:lodsd:lodsq. In modes other than real, it's a *selector* for a GDT / LDT entry so it still doesn't need to be wider. – Peter Cordes Sep 06 '21 at 01:17
  • @PeterCordes: Of course, you're right. Thanks for correcting these minor mistakes. I forgot that the entry address of BIOS could be either 0000:7C00 or 07C0:0000. So even CS has to be initialized. – zx485 Sep 06 '21 at 01:28
  • You should initialise `es` and `ss` to zero too. And `ss` should be set in the very instruction before the one that sets `sp`. – ecm Sep 06 '21 at 05:00
  • 1
    Should also make sure the direction flag is clear (with a `cld` instruction) before expecting `lodsb` to work in the "towards higher addresses" direction. – Brendan Sep 12 '21 at 03:28

1 Answers1

0

All i needed to do was [org 0x9000] as i had loaded the kernel to ES:0x9000

D_Man
  • 11
  • 3
    You got lucky that your BIOS happens to set DS=0 for you to match your `org`, that's not guaranteed. (Or ES=DS if they're both non-zero, and you're just overwriting memory at 0x9000 plus some unknown multiple of 16.) As well as writing to `DS:BOOT_DRIVE`, wherever that happens to be. – Peter Cordes Sep 06 '21 at 01:19