;----------------------------------;
;     Floppy Boot Record     ;
; Â Written by Christian Henrichsen ;
; Â Â Â Â Â Â 30.09.2024 Â Â Â Â Â Â ;
; Â Â Â Â Â Copyright (C) Â Â Â Â Â ;
;    Christian Henrichsen    ;
; Â Â Â Â Â Â Â 2024 Â Â Â Â Â Â Â ;
; Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ;
;   Copyright Notice Must be   ;
; Included with All Copies of This ;
;        Program       ;
;----------------------------------;
org 7c00h        ; Program origin of 7c00h
bits 16 Â Â Â Â Â Â Â Â ; 16-bit programing
cpu 8086 Â Â Â Â Â Â Â Â ; And assembling for the iAPX 8086 processor
jmp short start
nop
;------------------------------
; BIOS PARAMETER BLOCK
BPB:
OEMLabel     db "MSWIN4.1"  ; Disk label
bps   dw 512    ; Bytes per sector
spc db 1 Â Â Â Â ; Sectors per cluster
rs    dw 1     ; Reserved sectors for boot record
nFAT Â Â Â Â db 2 Â Â Â Â ; Number of copies of the FAT
MRDIR Â Â Â dw 224 Â Â Â ; Number of entries in root dir
          ; (224 * 32 = 7168 = 14 sectors to read)
tSect    dw 2880   ; Number of logical sectors
mdesc    db 0F0h   ; Medium descriptor byte
spfat    dw 9     ; Sectors per FAT
sptrk    dw 18    ; Sectors per track (36/cylinder)
nhead      dw 2     ; Number of sides/heads
hsect    dd 0     ; Number of hidden sectors
tsectl    dd 0     ; Number of LBA sectors
drvno      dw 0     ; Drive No: 0
ebsig    db 41    ; Drive signature: 41 for floppy
vsnum    dd 00000000h   ; Volume ID: any number
vlabl    db "MIKEOS   "; Volume Label: any 11 chars
fstyp    db "FAT12  "  ; File system type: don't change!
;bps  dw 512       ; Bytes Per Sector
;spc  db 2        ; Sectors Per Cluster
;rs  dw 0        ; Reserved Sectors
;nFAT db 2 Â Â Â Â Â Â Â ; Number of FAT's
;MRDIR dw 224 Â Â Â Â Â Â ; Max Root Directory Entries
;tSect dw 2880 Â Â Â Â Â ; Total Sectors
;mdesc db 0f0h      ; Media Descriptor Byte
;spfat dw 9 Â Â Â Â Â Â Â ; Sectors Per FAT
;sptrk dw 18 Â Â Â Â Â Â ; Sectors Per Track
;nhead dw 2 Â Â Â Â Â Â Â ; Number of heads
;hsect dd 0 Â Â Â Â Â Â Â ; Hidden Sectors
;tsect dd 0 Â Â Â Â Â Â Â ; Total Sectors
;drvno db 0 Â Â Â Â Â Â Â ; Drive Number
;flags db 0 Â Â Â Â Â Â Â ; Flags
;ebsig db 29h       ; Extended Boot Signature
;vsnum dd 12341234h    ; Volume Serial Number
;vlabl db 'NO NAME Â Â ' Â ; Volume Label
;fstyp db 'FAT12 Â ' Â Â ; Filesystem Type
FILES_AREA equ 33
ROOT_DIR equ 19
ROOT_SIZE equ 14
LOAD_OFFSET equ 0000h
LOAD_SEGMENT equ 2000h
;-----------------
; Boot Loader
start:
cli           ; Clear the interrupt flag, only non-maskable interrupts will be enabled
xor ax, ax        ; Zero out accumulator
mov ss, ax        ; Set the stack segment register
mov sp, 7c00h      ; and the Stack Pointer
push ax         ; Pushing AX
push ax         ; Pushing AX again
pop es          ; And popping it into ES
pop ds          ; and DS and setting them both to zero
sti           ; Set the interrupts flag back on, now every single interrupt can interrupt my work
jmp 0000:enforce_csip  ; Preforming a far jump to enforce CS:IP
enforce_csip: Â Â Â Â Â ; Now that CS:IP is enforced
read_rootdir:
  ;mov byte [drvno], dl ; Sve drive number
  mov ax, ROOT_DIR   ; AX = the lba of the root directory
  call convert_LBA   ; Convert it to its appropriate CHS parameters for int 13h
  mov al, ROOT_SIZE   ; How many sectors? 14, read 14 sectors
  mov bx, buffer
  call read_sect    ; Let's read those sector's
  mov cx, 224
check_root_dir:
  mov di, buffer
  mov si, filename
  push cx
  mov cx, 11
  rep cmpsb
  je found_file
  pop cx
  add di, 32
  loop check_root_dir
no_kernel:
  mov si, non_sys_disk
  jmp print_string
 Â
found_file:
  pop cx
  mov ax, 1
  call convert_LBA
  mov al, 9
  mov bx, buffer
  call read_sect
 Â
  mov si, di
  mov al, [si+0bh]
  test al, 0d8h      ; Bit-mask for bits 11011000
  ;jnz no_kernel     ; The kernel is either invalid or not here
  xor ax, ax
  mov dx, ax
  mov word ax, [si+1ah] ; AX = First cluster of kernel
  push ax
  mov bx, LOAD_SEGMENT
  mov es, bx
  mov bx, LOAD_OFFSET
read_cluster:
  sub ax, 2       ; Cluster number - 2
  mul byte [spc]     ; Times Sectors Per Cluster
  add ax, FILES_AREA   ; AX now equals the actual LBA sector to read
  call convert_LBA    ; Convert to CHS
  mov al, [spc]     ; Sectors to read
  call read_sect     ; Read setctor's
  pop ax         ; AX = Cluster number for next entry in FAT
  push bx        ; Save BX since it has the load pointer
  mov bx, buffer     ; BX = FAT buffer
  call get_fat      ; Get FAT12 field
  cmp ax, 0ff8h     ; Is it ff8 or greater?
  jae short jump_to_kernel ; Yes, it's the end of our kernel. Let's jump to it
  pop bx         ; Nope keep reading
  add bx, 512      ; Add 512 since we are to not overwrite what we have read
  jmp short read_cluster
jump_to_kernel:
  pop bx
  jmp LOAD_SEGMENT:LOAD_OFFSET
;-----------------
; Loader Subroutines
get_fat:
  push bx
  push cx
  mov cx, ax
  shl ax, 1
  add ax, cx
  test ax, 1
  pushf
  shr ax, 1
  add bx, ax
  mov ax, [bx]
  popf
  jnz .getfat1
  and ax, 0fffh
  jmp .getfat2
.getfat1:
  mov cl, 4
  shr ax, cl
.getfat2:
  pop cx
  pop bx
  ret
print_string:
  mov ah, 0eh
.print_loop:
  lodsb
  cmp al, 0
  je .done
  int 10h
  jmp short .print_loop
.done:
reboot:
  xor ax, ax
  int 16h
  mov word [ds:472h], 1234h ; To simulate a ctrl+alt+del
  jmp 0ffffh:0000h   ; Reset the system
read_sect: Â Â Â Â Â Â Â ; IN: call to convert_LBA, DL = Drive to read, BX = Buffer address, ES = Segment
  mov ah, 02h
  int 13h
  ret
convert_LBA: Â Â Â Â Â ; Converts LBA to CHS tuple ready for int 13h call
  push bx
  push ax
  mov bx, ax      ; Save logical sector
  mov dx, 0      ; First the sector
  div word [sptrk]
  add dl, 01h     ; Physical sectors start at 1
  mov cl, dl      ; Sectors belong in CL for int 13h
  mov ax, bx
  mov dx, 0      ; Now calculate the head
  div word [sptrk]
  mov dx, 0
  div word [nhead]
  mov dh, dl      ; Head/side
  mov ch, al      ; Track
  pop ax
  pop bx
  ret
non_sys_disk db 'Non system disk or disk error!', 0
filename db 'AC-DOS Â SYS'
  times 510-($-$$) db 0  ; Pad remainder of boot sector with zeros
  dw 0AA55h    ; Boot signature (DO NOT CHANGE!)
buffer: