reorganization
[eightysix] / kern / src / boot.asm
diff --git a/kern/src/boot.asm b/kern/src/boot.asm
new file mode 100644 (file)
index 0000000..96506de
--- /dev/null
@@ -0,0 +1,257 @@
+; first stage boot loader
+       cpu 8086
+       bits 16
+       section .bootsect
+
+extern _stage2_start_seg
+extern _stage2_size
+
+boot_driveno   equ 7b00h
+num_read_tries equ 7b06h       ; 2 bytes
+sect_pending   equ 7b08h       ; 2 bytes
+sect_per_track equ 7b0ah       ; 2 bytes
+cur_head       equ 7b0ch       ; 2 bytes - current head
+start_sect     equ 7b0eh       ; 2 bytes - start sector in track
+destptr                equ 7b10h       ; 2 bytes - destination pointer
+num_heads      equ 7b12h       ; 2 bytes - number of heads
+cur_cyl                equ 7b14h       ; 2 bytes - current cylinder
+
+%macro floppy_motor_off 0
+       pushf
+       and dl, 80h
+       jnz %%end       ; skip if high bit is set (i.e. it's not a floppy)
+       mov dx, 3f2h
+       in al, dx
+       and al, 0fh
+       out dx, al
+%%end: popf
+%endmacro
+
+; 5.25" 360K floppy
+BPB_DISK_SECTORS       equ 720
+BPB_TRACK_SECTORS      equ 9
+BPB_MEDIA_TYPE         equ 0fdh
+; 3.5" 1.44M floppy
+;BPB_DISK_SECTORS      equ 2880
+;BPB_TRACK_SECTORS     equ 18
+;BPB_MEDIA_TYPE                equ 0f0h
+
+bios_param_block:
+       jmp start       ; 2 bytes
+       nop             ; 1 byte
+       ; start of BPB at offset 3
+       db "86BOOT00"   ; 03h: OEM ident, 8 bytes
+       dw 512          ; 0bh: bytes per sector
+       db 1            ; 0dh: sectors per cluster
+       dw 1            ; 0eh: reserved sectors (including boot record)
+       db 2            ; 10h: number of FATs
+       dw 224          ; 11h: number of dir entries
+       dw BPB_DISK_SECTORS     ; 13h: number of sectors in volume
+       db BPB_MEDIA_TYPE       ; 15h: media descriptor type (f0 = 3.5" HD floppy)
+       dw 9            ; 16h: number of sectors per FAT
+       dw BPB_TRACK_SECTORS    ; 18h: number of sectors per track
+       dw 2            ; 1ah: number of heads
+       dd 0            ; 1ch: number of hidden sectors
+       dd 0            ; 20h: high bits of sector count
+       db 0            ; 24h: drive number
+       db 0            ; 25h: winnt flags
+       db 28h          ; 26h: signature(?)
+       dd 0            ; 27h: volume serial number
+       db "80 SIX BOOT"; 2bh: volume label, 11 bytes
+       db "FAT12   "   ; 36h: filesystem id, 8 bytes
+
+start:
+       cld
+       xor ax, ax
+       mov ds, ax
+       mov es, ax
+       jmp 00:.setcs
+.setcs:
+       ; put the stack high
+       mov ax, 0x7f00
+       mov ss, ax
+       xor sp, sp
+       mov [boot_driveno], dl
+
+       ; query sectors per track
+       mov ah, 8       ; get drive parameters call, dl already has the drive
+       xor di, di
+       int 13h
+       jc .queryfail
+       and cx, 3fh
+       mov [sect_per_track], cx
+       mov cl, 8
+       shr dx, cl
+       inc dx
+       mov [num_heads], dx
+       jmp .querydone
+.queryfail:
+       ; in case of failure, try 18 sectors per track, 2 heads
+       mov word [sect_per_track], 18
+       mov word [num_heads], 2
+.querydone:
+
+       ; load the rest of the code high
+       mov ax, _stage2_size
+       add ax, 511
+       mov cl, 9
+       shr ax, cl
+       inc ax
+       mov [sect_pending], ax
+       mov ax, _stage2_start_seg
+       mov es, ax      ; destination segment
+       mov word [destptr], 0
+       mov word [start_sect], 1        ; start from sector 1 to skip boot sector
+       mov word [cur_cyl], 0
+       mov word [cur_head], 0
+
+.rdloop:
+       mov cx, [start_sect]
+       mov ax, [sect_pending]
+       sub ax, cx              ; num_sect = pending - start_sect
+       cmp ax, [sect_per_track]
+       jbe .noadj
+       mov ax, [sect_per_track]        ; read max sect_per_track at a time
+       sub ax, cx
+.noadj: test ax, ax
+       jz .done
+       push ax         ; save how many sectors we're reading
+
+       push ax
+       push bx
+       push cx
+       push dx
+       push si
+       call print_hex_word
+       mov ax, str_rdtrack2
+       call printstr
+       mov ax, [cur_cyl]
+       call print_hex_byte
+       mov ax, str_rdtrack3
+       call printstr
+       mov ax, [cur_head]
+       call print_hex_byte
+       mov ax, str_rdtrack3
+       call printstr
+       mov ax, [start_sect]
+       call print_hex_byte
+       mov ax, str_newline
+       call printstr
+       pop si
+       pop dx
+       pop cx
+       pop bx
+       pop ax
+
+       mov ch, [cur_cyl]
+       mov dh, [cur_head]
+       mov bx, [destptr]
+
+       inc cl                  ; sector numbers start from 1
+       mov ah, 2               ; read sectors is call 2
+       mov dl, [boot_driveno]
+       int 13h
+       jc .fail
+       ; track read sucessfully
+       mov word [start_sect], 0        ; all subsequent tracks are whole
+       mov ax, [cur_head]
+       inc ax
+       cmp ax, [num_heads]
+       jnz .skip_cyl_adv
+       xor ax, ax
+       inc byte [cur_cyl]
+.skip_cyl_adv:
+       mov [cur_head], ax
+
+       pop ax                  ; num_sect
+       sub [sect_pending], ax
+       push cx
+       mov cl, 9
+       shl ax, cl              ; convert to bytes
+       pop cx
+       add [destptr], ax
+       jnz .rdloop
+
+       ; loaded sucessfully, load segment registers and jump
+.done: mov ax, _stage2_start_seg
+       mov ds, ax
+       mov es, ax
+       push ax
+       xor ax, ax
+       push ax
+       retf
+
+
+.fail: add sp, 2       ; clear num_sect off the stack
+       dec word [num_read_tries]
+       jz .abort
+
+       ; reset controller and retry
+       xor ax, ax
+       mov dl, [boot_driveno]
+       int 13h
+       jmp .rdloop
+
+       ; failed to load second sector
+.abort:        xor ax, ax
+       mov es, ax
+       floppy_motor_off        ; turn off floppy motor (if dl is < 80h)
+       mov ax, str_load_fail
+       call printstr
+.hang: hlt
+       jmp .hang
+
+       ; expects string ptr in ax
+printstr:
+       mov si, ax
+.loop: mov al, [si]
+       inc si
+       test al, al
+       jz .done
+       mov ah, 0eh
+       mov bx, 7
+       int 10h
+       jmp .loop
+.done: ret
+
+print_hex_word:
+       mov cx, 4       ; 4 digits to print
+       jmp print_n_hex_digits
+
+print_hex_byte:
+       mov cx, 2       ; 2 digits to print
+       mov ah, al      ; move them in place
+
+print_n_hex_digits:
+       rol ax, 1
+       rol ax, 1
+       rol ax, 1
+       rol ax, 1
+       mov dx, ax      ; save ax, print_hex_digit destroys it
+       call print_hex_digit
+       mov ax, dx
+       dec cx
+       jnz print_n_hex_digits
+       ret
+
+print_hex_digit:
+       mov bl, al
+       and bx, 0fh
+       mov al, [bx + .hexdig_tab]
+       mov ah, 0eh
+       mov bx, 7
+       int 10h
+       ret
+
+.hexdig_tab:
+       db "0123456789abcdef"
+
+str_rdtrack2   db " from ",0
+str_rdtrack3   db "/",0
+str_load_fail  db "Failed to load 2nd stage!",0
+str_newline    db 13,10,0
+
+       times 510-($-$$) db 0
+bootsig dw 0xaa55
+
+; vi:set ts=8 sts=8 sw=8 ft=nasm: