From f46871502cc1dafb9e4b4fa9646f46a199472a85 Mon Sep 17 00:00:00 2001 From: Nero <41307858+nero@users.noreply.github.com> Date: Mon, 6 Apr 2020 19:20:15 +0000 Subject: [PATCH] Pave way for supporting FAT16 and FAT12 --- Makefile | 31 ++- boot/fat.asm | 498 ++++++++++++++++++++++++------------------------- boot/fat32.asm | 281 ---------------------------- 3 files changed, 273 insertions(+), 537 deletions(-) delete mode 100644 boot/fat32.asm diff --git a/Makefile b/Makefile index 2f20979..d564f76 100644 --- a/Makefile +++ b/Makefile @@ -48,20 +48,41 @@ vga11.com: cp437.bin %.bs: boot/%.asm $(NASM) $(NASM_ARGS) -o $@ $< +# Special case: variations of FAT vbr +fat1.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT12 -DCHS -o $@ $< + +fat4.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT16 -DCHS -o $@ $< + +fat6.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT16 -DCHS -DLARGE -o $@ $< + +fatb.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT32 -DCHS -DLARGE -o $@ $< + +fatc.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT32 -DLBA -DLARGE -o $@ $< + +fate.bs: boot/fat.asm + $(NASM) $(NASM_ARGS) -DFAT16 -DLBA -DLARGE -o $@ $< + # BIOS option roms %.rom: rom/%.asm utils/fix-rom $(NASM) $(NASM_ARGS) -o $@ $< && utils/fix-rom $@ -fdimage.img: fat.bs $(DISTFILES) - mformat -C -i $@ -f $(FLOPPY) -B fat.bs :: - mcopy -i $@ $(DISTFILES) :: +fdimage.img: fat1.bs $(DISTFILES) + mformat -C -i $@ -f $(FLOPPY) -B fat1.bs :: + mmd -i $@ ::rdos + mcopy -i $@ $(DISTFILES) ::rdos + mattrib -i $@ +s ::rdos ::rdos/kernel.bs hdimage.img: mbr.bs fdimage.img cat mbr.bs fdimage.img >$@ -part.img: fat32.bs $(DISTFILES) +part.img: fatc.bs $(DISTFILES) dd if=/dev/zero bs=1024 count=33k of=$@ - mformat -i $@ -F -B fat32.bs :: + mformat -i $@ -F -B fatc.bs :: mmd -i $@ ::rdos mcopy -i $@ $(DISTFILES) ::rdos mattrib -i $@ +s ::rdos ::rdos/kernel.bs diff --git a/boot/fat.asm b/boot/fat.asm index 0416842..bef11cb 100644 --- a/boot/fat.asm +++ b/boot/fat.asm @@ -1,293 +1,289 @@ - ; 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 + ; Bootsector for FAT32 filesystems + ; Takes defines: + ; FAT12 FAT has 1.5 bytes per entry + ; FAT16 FAT has WORD per entry + ; FAT32 FAT has DWORD per entry + ; CHS uses int13h/AH=02h + ; LARGE requires 32 bit sector numbers + ; LBA uses int13h/AH=42h + cpu 8086 - jmp near init + org 0x0800 + jmp short init + nop - ; current cluster number -cclus: dw 0 - ; sector number in cluster -csec: dw 0 + %include "inc/bpb.asm" - times (0x0B - ($-$$)) db 0 - ; BIOS PARAMETER BLOCK -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 +bpb: equ 0x080B - ; mformat keeps writing until here - ; if we place init earlier, code gets overwritten - ; this also marks the end for the BPB - times (62 - ($-$$)) nop + ; Area for BPB + times ( 0x5A - ($-$$) ) db 0 init: xor ax, ax + mov ss, ax + mov sp, 0x7C00 + + ; save potential partition table entry + push ds + push si + mov ds, ax mov es, ax - mov ss, ax - mov sp, 0x0600 - ; Relocate and jump - mov di, sp mov si, 0x7C00 + mov di, 0x0800 mov cx, 0x0100 rep movsw - jmp 0:main + jmp 0x0:main - ; 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 + %include "inc/booterr.asm" - ; Read sector into ES:BX - ; Sector number has been previously set with seek -read: push ax + ; offsets relative to FS +readd: ; add offset of cluster data area to DX: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] - - int 0x13 - int 3 - - pop dx - pop cx - pop ax - ret - - ; 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 - - ; Get root directory length in sectors - ; OUT cx sectors -dirlen: push ax - mov ax, [cs:fdc.rde] + mov di, [bp+bpb_rde] mov cl, 4 - shr ax, cl ; 32 bytes per entry - mov cx, ax - pop ax - ret - - ; Get first sector of data area - ; OUT ax sector number -clusec: push cx - call dirsec - call dirlen - add ax, cx + shr di, cl ; 32 bytes per entry + add ax, di + adc dx, 0 pop cx -ret: ret - - ; 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 - - ; 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 - - ; 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: +readr: ; add offset to rootdir to DX:AX (FAT12/FAT16 only) 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 + xor ch, ch + mov cl, byte [bp+bpb_fn] +fatlp: add ax, [bp+bpb7_lsf] + adc dx, [bp+bpb7_lsf+2] + loop fatlp pop cx - je .found - add si, 0x20 - loop .loop - stc -.found: pop si - pop cx - ret -.name: db "HELLO " -.ext: db "COM" +readf: ; add offset to FAT table to DX:AX + add ax, word [bp+bpb_rsc] + adc dx, 0 +readp: ; read sector DX:AX from partition + add ax, word [bp+bpb_po] + adc dx, word [bp+bpb_po+2] + jnc ($+5) + call errcll -fopen: + %ifdef LBA +read_: ; read sector DX:AX from disk + ; this uses the EBIOS extensions + ; qword sector number DX:AX + push cs + push cs + push dx push ax + + ; dword target buffer: BX:0 + push bx + push cs + + ; word sector number + push cx + + ; size & passing + mov di, 0x10 + push di + + mov si, sp + mov ah, 0x42 + mov dl, [bp+bpb7_dn] + stc + int 0x13 + jnc ($+5) + call errcll + + add sp, di + + ret + %endif + + %ifdef CHS +read_: ; read sector DX:AX from disk + ; uses basic CHS disk IO + ; this cant reliable read over track boundaries + ; so we read each single sector in loop over CX +chslp: push ax push cx push dx push bx - push ds - push es - cmp word [cclus], 0 - jne .err - xor ax, ax - mov ds, ax - mov es, ax - call dirsec - call dirlen -.loop: xor dx, dx - mov bx, buf - call seek - call read - call scadir - jnc .found - inc ax - loop .loop -.err: stc - jmp .ret -.found: mov [cclus], bx - mov word [csec], 0 -.ret: pop es - pop ds + + ; calculate CHS data + div word [bp+bpb_spt] ; ax:temp = (lba / spt) + inc dx ; dx:sector = (lba % spt) + 1 + mov cl, dl ; sector number + xor dx, dx + div word [bp+bpb_nos] ; ax:cylinder = (tmp / heads) + ; dx:head = (tmp % heads) + mov ch, al ; cylinder number + mov dh, dl ; head number + mov dl, [bp+bpb7_dn] ; drive number + + ; set up read buffer + mov es, bx + xor bx, bx + + ; call bios + mov ax, 0x0201 + int 0x13 + jnc ($+5) + call errcll + pop bx pop dx pop cx pop ax - ret -fread: push ax - push cx - push dx - ; abort if there is no file opened - cmp word [cs:cclus], 0 - je .err - ; get start sector for data area - call clusec - push ax - ; get current cluster number - mov ax, [cs:cclus] - ; clusters are 2-indexed - sub ax, 2 - ; multiply that with sectors per cluster - mov cl, [cs:fdc.sc] - xor ch, ch - mul word cx - ; add current cluster offset, cluster start and current sector - pop cx - add cx, [cs:csec] - add ax, cx + ; increment sector num + write offset + add ax, 1 adc dx, 0 - ; dx:ax now point to the sector that should be read next - call seek - call read - jc .err - inc word [cs:csec] - jmp .ret -.err: ; in case of error, trash current state - call fclose - stc -.ret: pop dx - pop cx + add bx, 0x20 + ; loop on CX + loop chslp + ret + %endif + +next: ; Advances DX:AX to next FAT entry + push ax + push bx + ; shift 2 left for dword-sized FAT entries + ; shift 9 right for sector size + mov cl, 7 +shftl: clc + rcr dx, 1 + rcr ax, 1 + loop shftl + + mov bx, 0xA0 + %ifdef FAT12 + ; FAT item might span over two sectors + mov cx, 2 + %else + mov cx, 1 + %endif + call readf + + pop bx + + ; get lower part of cluster number + pop si + %ifdef FAT16 + ; double + sal si, 1 + %endif + %ifdef FAT32 + ; multiply with 4 + sal si, 1 + sal si, 1 + %endif + ; make sure its within sector range + and si, 0x1FF + add si, buf + %ifdef FAT16 + ; load word from FAT + lodsw + xor dx, dx + %endif + %ifdef FAT32 + ; load dword from FAT + lodsw + mov dx, [si] + %endif + ret + + ; reads current cluster into [dest] +readc: ; load cluster number + push ax + push dx + + ; subtract the two dummy entries from FAT start + sub ax, 2 + sbb dx, 0 + + ; convert cluster number to sector number + ; this is some cheapo multiplication with 2^n + mov cl, [bp+bpb_sc] +l02: shr cl, 1 + jz l02e + clc + rcl ax, 1 + rcl dx, 1 + jmp l02 +l02e: + ; dx:ax is now sector num in data area + mov cx, [bp+bpb_sc] + xor ch, ch + + call readd + + xchg di, cx + mov cl, 5 + sal di, cl + add bx, di + + pop dx pop ax + ret - ; Reset open file info -fclose: mov [cclus], bx - mov word [csec], 0 + ; Load root directory +loadr: mov ax, 2 + xor dx, dx + jmp load + + ; Load file identified by fsattr + ; Directory data is expected at 0x07C00 +loadf: mov si, (0x7C00-0x20) +sloop: add si, 0x20 + ; check if entry is valid + mov al, [si] + ; unallocated direntry + test al, al + jnz ($+5) + call errcll + ; deleted files + cmp al, 0xE2 + je sloop + ; check attr + mov al, [si+11] + and al, 0x5C + cmp al, ah + jne sloop + mov ax, [si+0x1A] + mov dx, [si+0x14] + + ; Load cluster chain DX:AX to 0x07C00 +load: mov bx, 0x07C0 +lloop: call readc + call next + cmp word dx, 0x0FFF + jne lloop ret -main: mov [seek.dl], dl ; save drive number +main: ; Set up BP to point to BPB + ; Relative addressing saves one instruction byte per access + mov bp, bpb + ; Save DL contents + mov [bp+bpb7_dn], dl - call fopen - mov bx, 0x1100 - call fread + ; load root directory + call loadr + ; search for first system directory + mov ah, 0x14 + call loadf + ; search for first system file + mov ah, 0x04 + call loadf - mov ax, 0x0100 - mov ds, ax - mov es, ax - call 0x100:0x100 + ; restore drive number + mov dl, [bp+bpb7_dn] -.hlt: hlt - jmp .hlt + ; restore potential partition table + pop si + pop ds + + jmp 0x7C00 ; Padding and signature times (0x1FE - ($-$$)) db 0 dw 0xAA55 +buf: diff --git a/boot/fat32.asm b/boot/fat32.asm deleted file mode 100644 index 8531cf1..0000000 --- a/boot/fat32.asm +++ /dev/null @@ -1,281 +0,0 @@ - ; Bootsector for FAT32 filesystems - org 0x0800 - cpu 8086 - jmp short init - nop - - %include "inc/bpb.asm" - -bpb: equ 0x080B - - ; Area for BPB - times ( 0x5A - ($-$$) ) db 0 - -init: xor ax, ax - mov ss, ax - mov sp, 0x7C00 - - ; save potential partition table entry - push ds - push si - - mov ds, ax - mov es, ax - - mov si, 0x7C00 - mov di, 0x0800 - mov cx, 0x0100 - rep movsw - jmp 0x0:main - - %include "inc/booterr.asm" - - ; offsets relative to FS -readd: ; add offset of cluster data area to DX:AX - push cx - mov di, [bp+bpb_rde] - mov cl, 4 - shr di, cl ; 32 bytes per entry - add ax, di - adc dx, 0 - pop cx -readr: ; add offset to rootdir to DX:AX (FAT12/FAT16 only) - push cx - xor ch, ch - mov cl, byte [bp+bpb_fn] -fatlp: add ax, [bp+bpb7_lsf] - adc dx, [bp+bpb7_lsf+2] - loop fatlp - pop cx -readf: ; add offset to FAT table to DX:AX - add ax, word [bp+bpb_rsc] - adc dx, 0 -readp: ; read sector DX:AX from partition - add ax, word [bp+bpb_po] - adc dx, word [bp+bpb_po+2] - jc dskerr - - ; This jump is overwritten with NOP's if LBA support -dskjmp: jmp rchs - -rebios: ; read sector DX:AX from disk - ; this uses the EBIOS extensions - ; qword sector number DX:AX - push cs - push cs - push dx - push ax - - ; dword target buffer: BX:0 - push bx - push cs - - ; word sector number - push cx - - ; size & passing - mov di, 0x10 - push di - - mov si, sp - mov ah, 0x42 - mov dl, [bp+bpb7_dn] - stc - int 0x13 - jc dskerr - - add sp, di - - ret - -rchs: ; read sector DX:AX from disk - ; uses basic CHS disk IO - ; this cant reliable read over track boundaries - ; so we read each single sector in loop over CX -chslp: push ax - push cx - push dx - push bx - - ; calculate CHS data - div word [bp+bpb_spt] ; ax:temp = (lba / spt) - inc dx ; dx:sector = (lba % spt) + 1 - mov cl, dl ; sector number - xor dx, dx - div word [bp+bpb_nos] ; ax:cylinder = (tmp / heads) - ; dx:head = (tmp % heads) - mov ch, al ; cylinder number - mov dh, dl ; head number - mov dl, [bp+bpb7_dn] ; drive number - - ; set up read buffer - mov es, bx - xor bx, bx - - ; call bios - mov ax, 0x0201 - int 0x13 - jc dskerr - - pop bx - pop dx - pop cx - pop ax - - ; increment sector num + write offset - add ax, 1 - adc dx, 0 - add bx, 0x20 - ; loop on CX - loop chslp - ret - - ; error handling for disk errors -dskerr: call errcll - -next: ; Advances DX:AX to next FAT entry - push ax - push bx - - ; shift 2 left for dword-sized FAT entries - ; shift 9 right for sector size - mov cl, 7 -shftl: clc - rcr dx, 1 - rcr ax, 1 - loop shftl - - mov bx, 0xA0 - mov cx, 1 - call readf - - pop bx - - ; get lower part of cluster number - pop si - ; multiply with 4 - sal si, 1 - sal si, 1 - ; make sure its within sector range - and si, 0x1FF - add si, buf - ; load dword from FAT - lodsw - mov dx, [si] - - ret - - ; reads current cluster into [dest] -readc: ; load cluster number - push ax - push dx - - ; subtract the two dummy entries from FAT start - sub ax, 2 - sbb dx, 0 - - ; convert cluster number to sector number - ; this is some cheapo multiplication with 2^n - mov cl, [bp+bpb_sc] -l02: shr cl, 1 - jz l02e - clc - rcl ax, 1 - rcl dx, 1 - jmp l02 -l02e: - ; dx:ax is now sector num in data area - mov cx, [bp+bpb_sc] - xor ch, ch - - call readd - - xchg di, cx - mov cl, 5 - sal di, cl - add bx, di - - pop dx - pop ax - - ret - - ; Load root directory -loadr: mov ax, 2 - xor dx, dx - jmp load - - ; Load file identified by fsattr - ; Directory data is expected at 0x07C00 -loadf: mov si, (0x7C00-0x20) -sloop: add si, 0x20 - ; check if entry is valid - mov al, [si] - ; unallocated direntry - test al, al - jz fserr - ; deleted files - cmp al, 0xE2 - je sloop - ; check attr - mov al, [si+11] - and al, 0x5C - cmp al, ah - jne sloop - mov ax, [si+0x1A] - mov dx, [si+0x14] - - ; Load cluster chain DX:AX to 0x07C00 -load: mov bx, 0x07C0 -lloop: call readc - call next - cmp word dx, 0x0FFF - jne lloop - ret - -main: ; Set up BP to point to BPB - ; Relative addressing saves one instruction byte per access - mov bp, bpb - ; Save DL contents - mov [bp+bpb7_dn], dl - - ; EBIOS is ignored for floppies (dl < 80h) - test dl, 0x80 - jz noebio - - ; check for EBIOS support - mov bx, 0x55AA - mov ah, 0x41 - ; set carry to assume failure if int didnt do anything - stc - int 0x13 - jc noebio - - ; disable CHS routine, fall into LBA routine instead - mov word [dskjmp], 0x9090 - -noebio: ; load root directory - call loadr - ; search for first system directory - mov ah, 0x14 - call loadf - ; search for first system file - mov ah, 0x04 - call loadf - - ; restore drive number - mov dl, [bp+bpb7_dn] - - ; restore potential partition table - pop si - pop ds - - jmp 0x7C00 - - ; error handling for file not found -fserr: call errcll - - ; Padding and signature - times (0x1FE - ($-$$)) db 0 - dw 0xAA55 -buf: