I have a custom MBR that I compile with NASM to a binary and I can boot it just fine in qemu and bochs.
I am trying to boot this MBR in DosBox using boot mbr.bin
. This works fine as long as the MBR is tiny and does not call int 13h
to read sectors from the disk.
If I try to read the next sector, it fails, resulting in a disk read error of some sort. I imagine this has to do with the value of dl
not being set to the "boot drive". I've tried manually setting dl
to 0 and to 80h, but neither work.
Does anyone know what the value of dl
should be to make int 13h
work in DosBox using the boot
command? Or if there is perhaps some other way to obtain that value dynamically?
Edit; here is the initial code:
CPU 386
BITS 16
org 7C00h
; Calculate the full size of the code from start of segment $$ to the end label at the bottom (end - $$)
%define SECTORS_TO_LOAD ((end - $$) / 512) + ((end - $$) % 512 > 0) - 1
main:
jmp 0x0000:setcs
; Some error messages
disk_err db "Error reading disk", 0
sector_err db "Error reading sector", 0
setcs:
; Base setup
cld
xor ax, ax ; Set ES=DS=0 - this can be changed later for rep operations
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
; Clear the screen
mov ah, 0x07 ; Function 0x07: scroll window
mov al, 0x00 ; Clear entire window
mov bh, 0x07 ; White on black
mov cx, 0x00 ; Specifies top left of screen as (0,0)
mov dh, 0x18 ; 18h = 24 rows of chars
mov dl, 0x4f ; 4fh = 79 cols of chars
int 0x10 ; Video interrupt
; Move cursor to position 0,0
mov ah, 0x02 ; Function 0x02: set cursor position
mov dh, 0x00 ; Row 0
mov dl, 0x00 ; Col 0
mov bh, 0x00 ; Page 0
int 0x10 ; Video interrupt
; Load the calculated numbers of sector from the disk
; For this function call, dl should be set to the disk number to read from. The BIOS sets dl to
; the disk number of the MBR and dl was not changed, so we don't have to set it.
;mov dl, 0x80
mov ax, SECTORS_TO_LOAD ; Number of sectors to read
mov bx, next_sector ; The memory address to read to
xor ch, ch ; Cylinder 0
mov cl, 0x02 ; Start at sector 2 (sector 1 is the first part of the MBR)
xor dh, dh ; Head 0
mov ah, 0x02 ; Read mode
int 0x13 ; Read interrupt
jc .disk_error ; Check carry bit for error
cmp al, SECTORS_TO_LOAD ; The interrupt sets 'al' to the number of sectors actually read
jne .sectors_error
; After a succesful load, the layout in memory will be the same as the layout in our ASM files,
; so we can jump to a defined label without worrying about offsets and exact addresses.
jmp after_load
.disk_error:
push disk_err ; Print a disk error message
call print
cli ; Halt all interrupts and operations
hlt
.sectors_error:
push sector_err ; Same as above, different message
call print
cli
hlt
; The print function prints a string onto the screen in text mode
print:
push bp ; Basic stack setup
mov bp, sp
pusha ; Push everything - this function doesn't
; return anything
mov si, [bp+4] ; Grab the pointer to the data
mov bh, 0 ; Page 0
mov bl, 0 ; Foreground color, irrelevant - in text mode
mov ah, 0x0E ; Function 0x0E: print character in TTY
.char:
mov al, [si] ; Get current char from pointer position
inc si ; Keep incrementing si until a null char
or al, 0
je .return
int 0x10 ; Video interrupt
jmp .char
.return:
popa ; Restore registers
mov sp, bp ; Restore stack
pop bp
ret 2 ; Remove param from stack on return
times 510-($-$$) db 0
; MBR signature
db 55h, 0AAh
next_sector:
After that, under next_sector, it has some incbins and some other code, including the label after_load
.
The error I get is the first one; "Error reading disk", which displays fine. So it seems that es, ds, etc. are set up right.
Note the commented out mov dl, 0x80
- that was one of my attempts to get this working.
Getting error "BIOS:Disk 0 is not active" in asm program
DOSBox uses the image size to determine the disk geometry.
Pad the bin file to 1440*1024 bytes.