1

I've been following a guide for creating an OS, just as an exercise, and it's been going fine until I reached the section where I attempt to read more data than just the boot sector from the disk. When I boot up the OS I see no output, just the blinking infinite loop cursor (AND NO ERROR MESSAGES), when it should display "Booting" followed by two Hex numbers. I'm using QEmu, and running this command:

qemu-system-x86_64 -drive format=raw,file=D:\booter.bin

Here is my code:

mov ah , 0x0e 

[ org 0x7c00 ]
    mov     si, WELCOME_STRING
    call    print_string
    mov     [ BOOT_DRIVE ], dl
    mov     bp , 0x8000
    mov     sp , bp
    mov     bx , 0x9000
    mov     dh , 5
    mov     dl , [ BOOT_DRIVE ]
    call    disk_load
    mov     dx , [0x9000]
    call    print_hex
    mov     dx , [0x9000 + 512]
    call    print_hex


print_string:
    pusha
    xor     bx,bx
    call    Next
    popa
    ret

Next:
    mov     al, byte [si + bx]
    int     0x10

    inc     bx
    or      al,al
    jnz     Next
    ret

 %include "D:\KOS\disk-load.asm"
 %include "D:\KOS\print-hex.asm"

WELCOME_STRING:
    db "Booting",0
HEX_OUT : db '0x0000' , 0
BOOT_DRIVE : db 0


jmp $ 


times 510 -( $ - $$ ) db 0 
dw 0xaa55

times 256 dw 0xdada
times 2000 dw 0xface

And here is disk-load.asm:

disk_load :
    push dx 
    mov ah , 0x02
    mov al , 0x03
    mov ch , 0x00
    mov dh , 0x00
    mov cl , 0x02

    mov bx, 0x00
    mov es, bx
    mov bx, 0x7c00 + 512
    int 0x13
    jc disk_error
    cmp dh , al
    jne disk_error
    pop dx
    ret

   ; int 0x13
   ; jc disk_error
   ; pop dx
   ; cmp dh , al
   ; jne disk_error
   ; ret

disk_error :
    mov si , DISK_ERROR_MSG
    call print_string

; Variables
DISK_ERROR_MSG db 'Disk read error!' , 0

And lastly, print-hex.asm, however, even when the calls to print_hex are removed, the problem persists, so the issue probably isn't here:

print_hex:
   pusha
   mov si, HEX_OUT + 2

next_character:
  mov bx, dx
  and bx, 0xf000
  shr bx, 4
  add bh, 0x30
  cmp bh, 0x39
  jg add_7

add_character_hex:
  mov al, bh
  mov [si], bh
  inc si
  shl dx, 4
  or dx, dx
  jnz next_character
  mov si, HEX_OUT
  call print_string
  popa
  ret

add_7:
  add bh, 0x7
  jmp add_character_hex

I have combed through multiple answers which seem to have the same problem, but unfortunately, none have worked, so I'm making another question with my own code. Why is the disk not loading properly, and how do I fix this?

Thanks in advance

NB I am on windows, so some functionality of QEmu is removed for me

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Arcayn
  • 87
  • 7
  • 1
    Your code is a mess! You never initialize the segment registers, change `sp` without changing `ss` (to a location that will intersect the loaded code!), `mov bx, 0x9000` (and similar) is later overwritten and it's unclear what should be there, not all your routines paths *return*, the spin loop is after the strings and routines. Start slowly in Assembly if you can't debug it easily. – Margaret Bloom Jan 21 '17 at 09:07
  • 1
    Beyond what Margaret has mentioned I have some general bootloader tips in this [SO answer](http://stackoverflow.com/a/32705076/3857942). Your stack is at 0x8000 and grows down. Your disk read will clobber the stack as it is reading the disk (the first sector of the read will load from 0x7e00 to 0x8000). You'll want to set the stack beyond the memory you are reading sectors into so that you don't clobber it. – Michael Petch Jan 21 '17 at 09:32
  • As well in disk load you do this comparison `cmp dh , al` . Problem is that `al` is the number of sectors actually read (for some BIOSes). But the number of sectors requested was also originally passed in `al`. Seems to me you were looking to save the original value of `al` and compare the number read with it. What you did was compare `al` with `dh` (which is the head number) which makes no sense. – Michael Petch Jan 21 '17 at 09:47
  • @MichaelPetch push/pop `dx` should actually read push/pop `dh`, and `dh` is _usually_ used to specify the number of sectors to be read before it has a head number assigned to it – Arcayn Jan 21 '17 at 10:52
  • The number of sectors to read is actually in _AL_ (only the upper 2 bits belong to the cylinder number). See Ralph Brown's Interrupt List http://www.ctyme.com/intr/rb-0607.htm . In your code you set _AL_ to 3 before the int 0x13 call. That reads 3 sectors. When the interrupt call is finished the original value in _AL_ is clobbered as it now contains the return value of the interrupt call. – Michael Petch Jan 21 '17 at 11:03
  • @MichaelPetch AL is clobbered, and now contains the actual number of sectors read, DH usually contains the number of sectors I want to read, specified in the main file, and is written into AL before 0x13 (DH is used as a "parameter") , DH is popped back after 0x13, and now contains the number of sectors I wanted to read, and AL contains the number of sectors that have actually been read – Arcayn Jan 21 '17 at 11:05
  • 1
    You shouldn't be changing your code like this. I see that your edit actually moved that `POP`. It was in the wrong place before. I'll revert your question back to the original state because now these comments are meaningless. In fact `push dh` and `pop dh` aren't even valid. You can't push and pop 1 byte at a time like that. And you modified the code so it no longer moved 3 into AL directly. – Michael Petch Jan 21 '17 at 11:09

0 Answers0