I'm very proud to announce the stage 1 bootloader for UselessOS, a (prospected) Useless OS for x86 processors that will be able to do pretty much nothing.
As you will see, it is comprised of very many lines of overly-commented NASM code.
Its functionality is pretty basic: it checks whether it is running from a floppy disk or a hard disk drive, and in the first case it uses CHS addressing to load 1 to 17 sectors of data, ensuring retro-compatibility with unextended INT 0x13.
In the second case, for now, it doesn't really do anything, as I've not implemented extended INT 0x13 loading yet.
Anyway, I'm posting it because I'd like you to completely destroy it. I know this is very basic stuff, I also know my code is not particularly good, and I'd really like to improve it.
Here is the code:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Stage 1 bootloader for UselessOS ;
; -------------------------------- ;
; Determines if it was loaded from ;
; a floppy disk or an hard disk ;
; drive, and then loads stage 2 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
; Assembler directives ;
;;;;;;;;;;;;;;;;;;;;;;;;
; tells the assembler that the program will be loaded at 0x7C00
; this is done by the BIOS
org 0x7C00
; we are targeting (x86) 16-bit real mode
bits 16
;;;;;;;;;;;;;;;;;
; Jump to start ;
;;;;;;;;;;;;;;;;;
jmp start
;;;;;;;;
; Data ;
;;;;;;;;
; fdd geometry & options
fddsamt db 8 ; how many sectors to load
fddretr db 5 ; max retries for fdd operations
fddcretr db 0 ; current retries left
; misc strings
welcome1 db "Welcome to the UselessOS Stage 1 bootloader.", 13, 10, 0
disktype db "Drive type: ", 0
diskfdd db "FDD", 13, 10, 0
diskhdd db "HDD", 13, 10, 0
loaded db "Data loaded!", 13, 10, 0
; errors
fdderes db "FDD reset failed.", 13, 10, 0
fddeload db "FDD read failed.", 13, 10, 0
; storage
disknum db 0
;;;;;;;;;;;
; Program ;
;;;;;;;;;;;
start:
xor ax, ax ; set up segment registers to segment 0 since
mov ds, ax ; our addresses are already relative to 0x7C00
mov es, ax
mov [disknum], dl ; save disk number to memory
mov ah, 0x01 ; set cursor shape
mov cx, 0x0100 ; hide cursor by setting ch = 1 and cl = 0x00
int 0x10 ; video interrupt
mov ah, 0x08 ; read page number into bh
int 0x10
mov si, welcome1 ; print welcome
call printstr
mov si, disktype ; print first part of disk type
call printstr
mov dl, [disknum] ; restore disk number - should not be
; strictly necessary but you never know
and dl, 0x80 ; sets zf if disk is floppy
jz fddload
hddload:
mov si, diskhdd ; print disk type
call printstr
jmp halt ; not implemented!
fddload:
mov si, diskfdd ; print disk type
call printstr
fddload_onto_reset:
mov ah, [fddretr] ; load max retries in memory
mov [fddcretr], ah
fddload_reset:
mov si, fdderes ; load error message pointer
dec byte [fddcretr] ; decrement the retries counter
jz fddload_err ; if it is 0, we stop trying
mov ah, 0x00 ; otherwise, reset function (int 0x13)
int 0x13
jc fddload_reset ; if jc (error), we try again
fddload_onto_load:
mov ah, [fddretr] ; reset retries counter
mov [fddcretr], ah
mov ax, 0x1000 ; need to stay within real mode limits
mov es, ax
fddload_load: ; loads 512*fddsamt bytes from sector 2 on.
mov si, fddeload
dec byte [fddcretr]
jz fddload_err
mov dh, 0 ; head 0
mov ch, 0 ; cyl/track 0
mov cl, 2 ; start sector
mov bx, 0 ; memory location
mov al, [fddsamt] ; how many sectors to read
mov ah, 0x02 ; read function (int 0x13)
int 0x13
jc fddload_load ; if jc (error), we try again
cmp al, [fddsamt] ; also if al is not 1, we have a problem
jnz fddload_load
fddload_done:
mov si, loaded ; we have successfully loaded the data
call printstr
jmp halt ; this will be jmp 0x1000:0x0000
fddload_err:
call printstr ; print
jmp halt ; and die
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; printstr routine, prints the string pointed by si using int 0x10 ;
; sets the direction flag to 0 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printstr:
cld ; clear df flag - lodsb increments si
printstr_loop:
lodsb ; load next character into al, increment si
or al, al ; sets zf if al is 0x00
jz printstr_end
mov ah, 0x0E ; teletype output (int 0x10)
int 0x10 ; print character
jmp printstr_loop
printstr_end:
ret ; return to caller address
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; halt routine - infinite loop ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
halt:
cli
jmp halt
;;;;;;;;;;;
; Padding ;
;;;;;;;;;;;
; $ is the address of the current line, $$ is the base address for
; this program.
; the expression is expanded to 510 - ($ - 0x7C00), or
; 510 + 0x7C00 - $, which is, in other words, the number of bytes
; before the address 510 + 0x7C00 (= 0x7DFD), where the 0xAA55
; signature shall be put.
times 510 - ($ - $$) db 0x00
;;;;;;;;;;;;;;;;;;
; BIOS signature ;
;;;;;;;;;;;;;;;;;;
dw 0xAA55