Int 13h BIOS routines not working on real hardware

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
threedot14
Posts: 4
Joined: Mon Jan 25, 2016 10:24 am

Int 13h BIOS routines not working on real hardware

Post by threedot14 »

I've been trying to develop a basic OS that includes a primitive bootloader. The full project is on Github (https://github.com/threedot14/AndromedOS) and I've gotten to the point of reading keyboard input using QEMU. However, once I run it on real hardware it fails on the first stage of the bootloader. Specifically, any call to Int 13h fails.

Code: Select all

;
; boot1.nasm
;  Stage 1 of boot process. Loads stage 2 into 0x600.
;

ORG 0x7C00
BITS 16

; This stage tries not to use the stack

jmp 0:start

; Data

error db "Bootloader Stage 1 failed. Error Letter: "
errorletter db 0
error2 db ". Error Code: 0x"
errorcode dw 0
error3 db ".",0

drive db 0

diskpacket:
    db 0x10, 0 ; Header
    dw 0x10 ; 16 sectors
    dw 0x600
    dw 0x0
    dq 0

; Text
;  Starts at 0x7D00 to make debugging more convenient
times 256 - ($-$$) db 0

start:
    ; Store any registers we want to keep
    mov byte [drive], dl

    ; If drive is 0, set to 0x80
    cmp byte [drive], 0
    jne .regc
    mov byte [drive], 0x80
.regc:

    ; Reset segment registers
    xor ax, ax
    mov ds, ax
    mov ss, ax
    mov es, ax
    jmp load_stage2

fail:
    ; Setup error code (stored in ah)
    ; Error letter (stored in al). followed by hexified error code will print
    mov [errorletter], al

    mov al, ah
    and ax, 0x0FF0
    shr al, 4

    add ah, 48
    add al, 48

    cmp al, 58
    jl .check1
    add al, 7
.check1:
    cmp ah, 58
    jl .check2
    add ah, 7
.check2:

    mov [errorcode], ax
.fail_init:
    ; Start printing
    mov bl, 4Fh ; White on Red
    mov cx, 1
    xor dh, dh
    xor dl, dl
    xor si, si
    xor bh, bh
.fail_loop:
    ; Set cursor position (starts 0,0)
    mov ah, 02h
    int 10h

    ; Write charater
    mov ah, 09h
    mov al, [error+si]
    int 10h

    inc si
    inc dl
    cmp byte [error+si], 0
    jne .fail_loop
hang:
    cli
    hlt
    jmp hang

load_stage2:
    ; Copy the first 5 sectors of the disk (boot1+boot2) to 0x600

    ; Check INT13 extensions
    mov ah, 41h
    mov dl, [drive]
    mov bx, 0x55AA
    int 13h
    mov ah, [drive]
    mov al, 'D' ;Error Letter D
    jnc .lba

    ; Reset Disk
    xor ax, ax
    mov dl, 0x80
    int 13h
    inc dl
    mov ah, 0x80
    mov al, 'E' ;Error Letter E
    cmp cl, 0
    je fail

.chs:
    ; CHS
    mov ah, 02h
    mov al, 15
    mov ch, 0
    mov cl, 1
    mov dh, 0
    mov dl, 0x80
    mov bx, 0x600
    int 13h
    mov al, 'C' ;Error Letter C
    jc fail
    jmp check_stage2

.lba:
    ; LBA
    mov ah, 42h
    mov dl, [drive]
    mov si, diskpacket
    int 13h
    mov al, 'A' ;Error Letter A
    jc fail

check_stage2:
    ; If the disk was read correctly then memory 0x7d00-0x7e00 (text from
    ; boot1) should be the same as 0x700-0x800. (0x7c00-0xd00 contains writable
    ; variables)
    mov si, 0x700
    mov ax, 0x0142 ;Error letter B, code 0x01
.check_loop:
    mov ebx, [si+0x7600]
    cmp ebx, [si]
    jne fail

    add si, 4
    cmp si, 0x800
    jne .check_loop

enter_stage2:
    jmp 0:0x800

times 510 - ($-$$) db 0
dw 0xAA55
The build process/run process:

Code: Select all

$ nasm -f bin -o boot1.img boot1.nasm
$ cat boot1.img boot2.img > boot.img
$ python AppendZeroUntilFileIs8192Bytes.py
$ qemu-system-i386 -drive file=andromedos.img,media=disk,format=raw
$ sudo dd if=boot.img of=/dev/sdb
Running with QEMU works without problems. When loaded onto a USB drive and booted on my old Asus Aspire 5735Z (BIOS: https://i.imgur.com/z4W1wSF.jpg) the carry flag is always set after Int 13h. All Int 10h work fine. Whenever I use one of the read functions it returns AH=0x01 (Bad command). I've tried CHS and LBA addressing (both work emulated) and looping each function until it works (computer hangs). I've tried looping through every drive number and hardcoding various drive numbers (0x00,0x01,0x02,0x80,0x81,0x82) to no avail. I don't think this has to do with using a USB stick because my computer consistently detects the drive as bootable and loads the above bootsector into memory. Running as an emulated USB mass storage device (qemu-system-i386 -usb file:boot.img) also works. Grub/Linux is installed on the computer's main HDD and loads without issue.
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Int 13h BIOS routines not working

Post by Octocontrabass »

One of the very first things you do is try to store the drive number, but without DS properly set, you don't know where it's actually being stored.
threedot14
Posts: 4
Joined: Mon Jan 25, 2016 10:24 am

Re: Int 13h BIOS routines not working

Post by threedot14 »

Octocontrabass wrote:One of the very first things you do is try to store the drive number, but without DS properly set, you don't know where it's actually being stored.
I do store the drive number at the beginning but am hardcoding it now because I suspect it's not being passed correctly. According to /grub-core/boot/i386/pc/boot.S of grub some BIOSes don't pass it correctly and I assume if my bootloader isn't being chainloaded the boot drive will always be 0x80.

I do set ds to 0 at the beginning. Is this not enough?
threedot14
Posts: 4
Joined: Mon Jan 25, 2016 10:24 am

Re: Int 13h BIOS routines not working on real hardware

Post by threedot14 »

Attached compiled image
Attachments
image.zip
(2.95 KiB) Downloaded 125 times
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Int 13h BIOS routines not working

Post by Octocontrabass »

threedot14 wrote:I assume if my bootloader isn't being chainloaded the boot drive will always be 0x80.
Nope. The BIOS provides emulation for USB drives, but that emulation can be either like a hard disk or like a floppy disk. With hard disk emulation, the USB drive will usually appear as device 0x80 and be accessible using int 0x13 extensions. With floppy disk emulation, the USB drive will usually appear as device 0x00 and be accessible only using C/H/S addressing.

Note that you must include a valid partition table with one active partition if you want hard disk emulation, and you must include a valid BPB if you want floppy disk emulation. This doesn't guarantee all BIOSes will choose the mode you want, but most will examine the contents of your boot sector and use that to determine which mode is appropriate. If you don't have either of those, you'll get inconsistent and occasionally broken behavior across different BIOSes.
threedot14 wrote:I do set ds to 0 at the beginning. Is this not enough?
It would be, if it were really at the beginning. You store DL to memory (using an unknown value in DS) before you set DS to 0. This is not the only bug in your code, just the first one I saw. Here's another big one:

Code: Select all

    mov ss, ax
You're setting SS without setting SP in the next instruction, so your stack is broken. Additionally, you're doing this with interrupts still enabled, so your broken stack is now in use by the BIOS. You then go on to use INT instructions which - you guessed it - use that broken stack. It's amazing that the computer doesn't crash and reboot immediately!
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Int 13h BIOS routines not working

Post by onlyonemac »

Octocontrabass wrote:You're setting SS without setting SP in the next instruction, so your stack is broken. Additionally, you're doing this with interrupts still enabled, so your broken stack is now in use by the BIOS. You then go on to use INT instructions which - you guessed it - use that broken stack. It's amazing that the computer doesn't crash and reboot immediately!
Actually it's not *that* amazing that his computer doesn't crash immediately; chances are his SP is defaulting to zero.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: Int 13h BIOS routines not working

Post by JAAman »

onlyonemac wrote:
Octocontrabass wrote:You're setting SS without setting SP in the next instruction, so your stack is broken. Additionally, you're doing this with interrupts still enabled, so your broken stack is now in use by the BIOS. You then go on to use INT instructions which - you guessed it - use that broken stack. It's amazing that the computer doesn't crash and reboot immediately!
Actually it's not *that* amazing that his computer doesn't crash immediately; chances are his SP is defaulting to zero.
no, SP doesn't "default" to anything, it simply contains whatever value was in it before (almost certainly not 0)
threedot14
Posts: 4
Joined: Mon Jan 25, 2016 10:24 am

Re: Int 13h BIOS routines not working on real hardware

Post by threedot14 »

Octocontrabass wrote:

Code: Select all

    mov ss, ax
You're setting SS without setting SP in the next instruction, so your stack is broken. Additionally, you're doing this with interrupts still enabled, so your broken stack is now in use by the BIOS. You then go on to use INT instructions which - you guessed it - use that broken stack. It's amazing that the computer doesn't crash and reboot immediately!
Thanks for the help! It turns out invalid stack pointers and bad segment registers were the problem. The drive number is 0x80, although I'm no longer hardcoding it. I'm able to load stage 2 using CHS without a valid MBR or BPB (I double checked to make sure there wasn't one left over from the last format) which saves me some trouble. I've rebooted a good number of times to make sure the behavior is consistent.
onlyonemac wrote:
Octocontrabass wrote:You're setting SS without setting SP in the next instruction, so your stack is broken. Additionally, you're doing this with interrupts still enabled, so your broken stack is now in use by the BIOS. You then go on to use INT instructions which - you guessed it - use that broken stack. It's amazing that the computer doesn't crash and reboot immediately!
Actually it's not *that* amazing that his computer doesn't crash immediately; chances are his SP is defaulting to zero.
For the record SP=0x6F08,BP=0x0 on QEMU (SeaBios) and SP=0x03E2,BP=0x0 on Hardware after booting. I guess it was just bad luck it didn't crash.
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: Int 13h BIOS routines not working on real hardware

Post by Octocontrabass »

threedot14 wrote:I'm able to load stage 2 using CHS without a valid MBR or BPB (I double checked to make sure there wasn't one left over from the last format) which saves me some trouble.
Keep in mind that you lose some compatibility by not including a partition table or BPB.
Post Reply