From 9288ad46a4554e9bb4137ad7bc0e2b87b4cebbbc Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Mon, 2 Mar 2020 19:44:37 +0000 Subject: [PATCH] fat: rework bootloader --- fat.asm | 441 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 221 insertions(+), 220 deletions(-) diff --git a/fat.asm b/fat.asm index 71a2ab4..771856a 100644 --- a/fat.asm +++ b/fat.asm @@ -1,241 +1,242 @@ -; Memory layout: -%define segment 0x00100 + ; Bootsector for FAT12 filesystems + ; Memory layout: + ; 0000-03FF IVT + ; 0400-0500 Bios data area + ; 0501-0600 Stack for us + ; 0600-0800 This code + org 0x0600 + ; 0800-0A00 Buffer for disk +buf: equ 0x0800 -%define self (0x7C00-(segment<<4)) ; 1 sector -%define fattab (self+0x200) ; variable size -%define rootdir 0x00100 ; variable size -%define prog 0x0F000 ; 4K at the end for OS + jmp near init -org self + ; current cluster number +cclus: dw 0 + ; sector number in cluster +csec: dw 0 -jmp short init + times (0x0B - ($-$$)) db 0 +fdc: ; sector size +.ss: dw 0x200 + ; sectors per cluster +.sc: db 2 + ; reserved sector count +.rsc: dw 1 +.fn: ; number of file allocation tables + db 2 +.rde: ; number of root directory entries + dw 0x70 +.ts: ; total number of sectors + dw 720 +.mid: db 0xFD +.sf: dw 2 +.spt: dw 9 +.nos: dw 2 +.po: dd 0 +.lrgts: ; large sector count - relevant if .ts is 0 + dd 0 -cluster_offset: - dw 0 + ; mformat keeps writing until here + ; if we place init earlier, code gets overwritten + times (62 - ($-$$)) nop -times (0x0B - ($-$$)) db 0 +init: xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov sp, 0x0600 -fdc: -.ss: - dw 0x200 ; sector size -.sc: - db 2 ; sectors per cluster -.rsc: - dw 1 ; reserved sector count -.fn: - db 2 ; number of file allocation tables -.rde: - dw 0x70 ; number of root directory entries -.ts: - dw 720 ; total number of sectors -.mi: ; medium identifier - db 0xFD ; 5.25-inch Double sided, 40 tracks per side, 9 sectors per track (360 KB) -.sf: ; sectors per fat - dw 2 -.spt: - dw 9 ; sectors per track -.nos: - dw 2 ; number of sides (heads) -.po: - dd 0 ; partition offset (in LBA blocks) -.lrgts: - dd 0 -.drv: - db 0 ; drive number - db 0 - db 0x29 ; efdc signature -.vid: - dd 0 ; volume id -.vlabel: - db "2B" - times (54 - ($-$$)) db " " -.fstype: - db "FAT12" - times (62 - ($-$$)) db " " + ; Relocate and jump + mov di, sp + mov si, 0x7C00 + mov cx, 0x0100 + rep movsw + jmp 0:main -; mformat keeps writing until here -; if we place init earlier, code gets overwritten -times (62 - ($-$$)) nop + ; Set adress for sector read/write + ; Number is relative to current partition + ; IN dx:ax sector number +seek: push ax + push dx + push ds + push cs + pop ds + ; add partition offset (required for HDD) + add ax, [fdc.po] + adc dx, [fdc.po+2] + ; ax:temp = (lba / spt) + ; dx:sector = (lba % spt) + 1 + div word [fdc.spt] + inc dx + ; Sector number (bits 0-5) into CL + ; This is blindly assumed to never exeed 63 + mov byte [.cl], dl + ; ax:cylinder = (tmp / heads) + ; dx:head = (tmp % heads) + xor dx, dx + div word [fdc.nos] + ; Cylinder number bit 0-7 into CH + mov byte [.ch], al + ; Head number into DL + mov byte [.dh], dl + ; Bits 8-9 of cylinder number into bits 6-7 of CL + and ah, 0x03 + ror ah, 1 + ror ah, 1 + or byte [.cl], ah + pop ds + pop dx + pop ax + ret +.cl: db 0 +.ch: db 0 +.dl: db 0 +.dh: db 0 -init: - cli - jmp segment:main + ; Read sector into ES:BX + ; Sector number has been previously set with seek +read: push ax + push cx + push dx + ; ah = int13 subfunction 2 + ; al = read 1 sector + mov ax, 0x0201 + ; load seek data into registers + mov cx, word [cs:seek.cl] + mov dx, word [cs:seek.dl] -main: - ; Stack grows down from 64k - mov ax, cs - mov ss, ax - mov sp, prog - mov ds, ax - mov es, ax + int 0x13 - mov [fdc.drv], dl ; save drive number in fd - sti + pop dx + pop cx + pop ax + ret - ; load fat table into memory - mov ax, [fdc.rsc] - mov cx, [fdc.sf] - xor dx, dx - mov bx, fattab - call load_sectors + ; Get start sector of root dirrectory + ; OUT ax sector number +dirsec: ; Multiply sectors per fat with number of fats + mov ax, [cs:fdc.sf] + mul byte [cs:fdc.fn] + ; Add number of reserved sectors + add ax, [cs:fdc.rsc] + ret - ; calculate length of rootdir - mov ax, [fdc.rde] - mov cl, 4 - shr ax, cl ; 32 bytes per entry - mov cx, ax + ; Get root directory length in sectors + ; OUT cx sectors +dirlen: push ax + mov ax, [cs:fdc.rde] + mov cl, 4 + shr ax, cl ; 32 bytes per entry + mov cx, ax + pop ax + ret - ; load root dir - xor dx, dx - mov ax, [fdc.sf] - mul byte [fdc.fn] - add ax, [fdc.rsc] - mov bx, rootdir - call load_sectors + ; Get first sector of data area + ; OUT ax sector number +clusec: push cx + call dirsec + call dirlen + add ax, cx + pop cx +ret: ret - ; remember where we left off - ; clusters start after rootdir - mov [cluster_offset], ax + ; Get total number of sectors + ; OUT: dx:ax number of sectors +secnum: xor dx, dx + mov ax, [cs:fdc.ts] + test ax, ax + jnz ret + mov ax, [cs:fdc.lrgts] + mov dx, [cs:fdc.lrgts+2] + ret - ; Load kernel - mov bx, prog - mov ax, kernel_name - call load_file - mov bp, 0x3332 - jc error + ; Get number of clusters + ; OUT: ax number of clusters + ; Cant overflow for FAT16 :P +clunum: push cx + push dx + call clusec + mov cx, ax + call secnum + sub ax, cx + sbb dx, 0 + mov cl, byte [cs:fdc.sc] + xor ch, ch + div cx + pop dx + pop cx + ret - mov dl, [fdc.drv] + ; Scan current buffer for matching file + ; IN ds = cs + ; es = cs + ; OUT bx start cluster if file found + ; trashed if no match + ; carry is set if no file was found +scadir: + push cx + push si + mov si, buf + mov cx, 0x10 +.loop: push cx + push si + mov bx, [si+0x1A] + mov di, .name + mov cx, 11 + repe cmpsb + pop si + pop cx + je .found + add si, 0x20 + loop .loop + stc +.found: pop si + pop cx + ret +.name: db "HELLO " +.ext: db "COM" - ; jump into kernel - jmp segment:prog +open: + push ax + push cx + push dx + push bx + push ds + push es + xor ax, ax + mov ds, ax + mov es, ax + mov [csec], ax + call dirsec + call dirlen +.loop: xor dx, dx + mov bx, buf + call seek + call read + call scadir + jnc .found + inc ax + loop .loop + stc +.found: + mov [cclus], bx + pop es + pop ds + pop bx + pop dx + pop cx + pop ax + ret -; Load a file into memory -; IN AX pointer to 8.3 filename -; ES:BX pointer to target area -; OUT CF flag set if error -; DI file size in bytes (<64K) -load_file: - mov si, rootdir - mov cx, [fdc.rde] -.search: - push cx - push si - mov di, ax - mov cx, 11 - repe cmpsb - pop si - pop cx - je .read - add si, 0x20 - loop .search - xor di, di - stc - ret -.read: - mov ax, [si+0x1A] - mov di, [si+0x1C] - jmp read_clusters +main: mov [seek.dl], dl ; save drive number -; Read the file given by cluster number -; into the target program area -; in ax cluster number -read_clusters: - ; read cluster into area for target file - push ax - sub ax, 2 - mul BYTE [fdc.sc] - add ax, [cluster_offset] - xor dx, dx - mov cx, [fdc.sc] - xor ch, ch - call load_sectors - pop ax + int 3 + call open + int 3 - ; calculate index in FAT - mov si, ax - shr si, 1 - add si, ax - add si, fattab +.hlt: hlt + jmp .hlt - ; load entry from FAT, truncate to 12 bit - mov dx, [si] - test ax, 1 - jz .noshift - mov cl, 4 - shr dx, 4 -.noshift: - mov ax, dx - - and ax, 0x0FFF - cmp ax, 0x0FF8 - jc read_clusters - - ret - -; Read sectors from disk -; Does not return on error -; ax and bx will be incremented, cx decremented -; in dx:ax sector number -; es:bx buffer -; cx number of sectors to read -; out dx:ax next sector to read -; es:bx next free buffer -; cx zero -load_sectors: - ; fail instantly if reading sectors > 16 bit - test dx, dx - mov bp, 0x3330 - jnz error - -.loop: - push ax - push cx - push dx - - ; add partition offset (required for HDD) - add ax, [fdc.po] - adc dx, [fdc.po+2] - - ; calculate CHS data - div word [cs:fdc.spt] ; ax:temp = (lba / spt) - inc dx ; dx:sector = (lba % spt) + 1 - mov cl, dl ; sector number - xor dx, dx - div word [cs:fdc.nos] ; ax:cylinder = (tmp / heads) - ; dx:head = (tmp % heads) - mov ch, al ; cylinder number - mov dh, dl ; head number - mov dl, [cs:fdc.drv] ; driver number - mov ax, 0x0201 ; ah=0x02 al=0x01 - int 0x13 - mov bp, 0x3331 - jc error - - pop dx - pop cx - pop ax - - ; count up for next sector - add bx, 0x0200 - inc ax - - loop .loop - ret - -error: - mov ax, bp - mov ah, 0x0e - mov bx, 7 - int 0x10 - mov al, 0x21 - int 0x10 - xor ax, ax - int 0x16 - int 0x19 - -kernel_name: - db "BDOS BIN" - -times (0x1FE - ($-$$)) db 0 - -dw 0xAA55 + ; Padding and signature + times (0x1FE - ($-$$)) db 0 + dw 0xAA55