Skip to content

Commit

Permalink
More reliably load the extra sectors of code in the bootloader
Browse files Browse the repository at this point in the history
I found out that you're supposed to call the reset BIOS call and retry
several times because real floppy drives act like that. Sure enough when
I checked the BIOS manual it says you should retry!

I thought about using the "actual number of sectors read" return value
to request fewer sectors the next try but there are a few reasons why
not:
  1. I saw online that some BIOS impls don't return a valid value unless
     the status flag is set
  2. It's complicated to calculate the address to write to and
     technically I would have to calculate the track number as well if
     the number of sectors to read is more than 63 (but that's more than
     the size of the Code Segment anyway) and some BIOS support
     multi-track reads from one call so I don't have to calculate that.

So I don't really understand when and how you're supposed to use that
value. I would think you shouldn't trust any data read if you got an
error status.
  • Loading branch information
fsmv committed Sep 7, 2024
1 parent 12c9317 commit 1a266b4
Showing 1 changed file with 39 additions and 7 deletions.
46 changes: 39 additions & 7 deletions bootloader/bootsect.asm
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,27 @@ mov ax, 0x0305
;mov bx, 0x0107 ; 500 ms delay before repeat ; 16 characters per second
mov bx, 0x0100 ; 500 ms delay before repeat ; 30 characters per second
int 0x16
; fallthrough

load_extra_sectors:
; int 0x13 shouldn't be called with 0 for the amount to read.
; Can't use preprocessor for this unfortunately because it's a label
mov al, NUM_EXTRA_SECTORS ; number of sectors to read
test al, al
je start_

; Load the code from the extra sectors
; Try to do the full read every time to take advantage of possible BIOS support
; for multi-track reads if NUM_EXTRA_SECTORS > 63
mov ah, 0x02
mov al, NUM_EXTRA_SECTORS
mov bx, SECTOR_SIZE ; es:bx is address to write to. es = cs, so write directly after the boot sector
mov cx, 0x0002 ; Cylinder 0; Sector 2 (1 is the boot sector)
mov dl, [BOOT_DISK]
xor dh, dh ; Head 0
mov dl, [BOOT_DISK] ; Drive number
xor dh, dh ; Head number
mov cx, 0x0002 ; Read from Cylinder (track) 0; Sector 2 (1 is the boot sector)
int 0x13

; Check for errors
cmp ax, NUM_EXTRA_SECTORS
je start_
jnc start_ ; if there was no error, jump to the loaded user code
; Otherwise handle errors

push ax ; push the error code

Expand All @@ -99,6 +107,27 @@ int 0x10
pop cx ; pop the error code
call print_hex ; print the error code

mov ax, 0x1301 ; Write String, move cursor mode in al
mov bp, retry_msg ; String pointer in es:bp (es is at code start from bootsect-header.asm)
mov cx, retry_msg_len ; String length
mov dx, 0x0100 ; second line; left edge
mov bx, 0x004F ; bh = 0 (page number); bl = color (white on red)
int 0x10

mov cl, [READ_RETRIES]
call print_hex

cmp byte [READ_RETRIES], 0
je .no_more_tries

; Reset the disk and retry
dec byte [READ_RETRIES]
xor ax, ax
mov dl, [BOOT_DISK] ; Drive number
int 0x13
jmp load_extra_sectors

.no_more_tries:
jmp $ ; stop forever

; Prints the ascii hex character which represents the integer value of al
Expand Down Expand Up @@ -176,7 +205,10 @@ print_hex_byte:

error_msg: db `Error reading additional sectors from disk: `
error_msg_len: equ $-error_msg
retry_msg: db `Retry attempts remaining: `
retry_msg_len: equ $-retry_msg

BOOT_DISK: db 0x00 ; value is filled first thing
READ_RETRIES: db 5

%include "bootloader/bootsect-footer.asm"

0 comments on commit 1a266b4

Please sign in to comment.