Page 1 of 1

FAT16 Example

Posted: Fri Jun 28, 2013 12:57 pm
by computertrick
Hi I have finally read a file with FAT16 in my OS here is the code just in case its useful for anybody

Code: Select all

%define ROOT_DIRECTORY_POS 0x7e00

org 0 ; we start everything at zero
	jmp short start
	nop     
MANU_DESC 			db 'mkdosfs '
BLOCK_SIZE	 		dw 512
BLOCKS_PER_ALLOCATION_UNIT 	db 128
RESERVED_BLOCKS			dw 1
TOTAL_FATS			db 1
TOTAL_ROOT_ENTRIES		dw 512
TOTAL_BLOCKS			dw 0xffff
MEDIA_DESCRIPTOR		db 0xf8
BLOCKS_PER_FAT			dw 0x01
BLOCKS_PER_TRACK		dw 18
TOTAL_HEADS			dw 0x02
HIDDEN_BLOCKS			dd 0x00
TOTAL_BLOCKS_2			dd 0x00
DRIVE_NUMBER			dw 0x00
EXTENDED_BOOT_SIGNATURE		db 0x29
VOLUME_SERIAL_NUMBER		dd 0x9d86f18c
VOLUME_LABEL			db 'SEAGULL    '
FILE_SYSTEM_IDENTIFIER		db 'FAT16   '

; Calculated in memory
ROOT_DIRECTORY		dw 0x00

DAPACK:
	db 0x10
	db 0
.len:	dw 1
.loc:	dd ROOT_DIRECTORY_POS
.sec:	dd 0
	dd 0
	
start:
	cli
	mov ax, 0x7c0
	mov ds, ax
	mov es, ax
	mov sp, 0x1000
	mov bp, 0
	mov ss, bp
	sti


	mov byte [DRIVE], dl

; Root Directory Logical Sector =  (TOTAL_FATS * BLOCKS_PER_FAT) + (RESERVED_BLOCKS)

	mov ax, [TOTAL_FATS]
	mul word [BLOCKS_PER_FAT]
	add ax, [RESERVED_BLOCKS]
	mov word [ROOT_DIRECTORY], ax


; Load root directory


	mov word [DAPACK.sec], ax

	mov si, DAPACK		; address of "disk address packet"
	mov ah, 0x42		; AL is unused
	mov dl, [DRIVE]		; drive number 0 (OR the drive # with 0x80)
	int 0x13
	jc err


FIND_KERNEL:

	cli			; Turn interrupts off when editing segment registers
	mov ax, 0x7e0
	mov es, ax
	sti

	mov bx, 0

; Calculate root directory data start - (ROOT_DIRECTORY + (TOTAL_ROOT_ENTRIES/16))
	mov ax, [ROOT_DIRECTORY]
	mov dx, 16
	div dl				; (TOTAL_ROOT_ENTRIES/16), AL = AX / DL
	add bx, ax
	mov ax, 1
	
.find:
	mov cx, 0
	mov si, KERNEL
.repeat:
	cmp cx, 11
	je .load_clusters
	lodsb
	cmp al, [es:bx]
	jne .next
	inc cx
	inc bx
	jmp .repeat
.next:
	mov ax, 32
	sub ax, cx
	add bx, ax
	jmp .find

.load_clusters:
	mov ax, 15	; 15 bytes away from start of cluster number
	add bx, ax	; Seek to cluster number
	mov ax, [es:bx]	; Grab cluster number
	
; Time to calculate the LBA of the kernel

; LBA = (cluster-2)*BLOCKS_PER_ALLOCATION_UNIT+(TOTAL_ROOT_ENTRIES/16)+(HIDDEN_BLOCKS+RESERVED_BLOCKS+TOTAL_FATS*BLOCKS_PER_FAT)


	mov bx, 2		
	sub ax, bx				; Subtract 2 from cluster number
	
	mov dl, [BLOCKS_PER_ALLOCATION_UNIT]
	mul dl					; AX = AL * BLOCKS_PER_ALLOCATION_UNIT

	push ax					; Push AX on to the stack
	mov dx, 0	
	mov ax, [TOTAL_ROOT_ENTRIES]
	mov bx, 16
	div bx					; DX:AX = TOTAL_ROOT_ENTRIES / 16
	mov bx, ax
	pop ax					; Pop AX off the stack
	add ax, bx				; Add the result on to AX

	mov bx, [HIDDEN_BLOCKS]			; NOTE: Hidden blocks is 32 bit. 16 bit will be fine.
	mov dx, [RESERVED_BLOCKS]
	add bx, dx				; BX = HIDDEN_BLOCKS + RESERVED_BLOCKS
	xor dx, dx
	mov dl, [TOTAL_FATS]			
	add bx, dx				; BX += TOTAL_FATS
	push ax					; Push AX on to the stack
	mov ax, bx
	mov dx, [BLOCKS_PER_FAT]
	mul dx					; DX:AX = AX * BLOCKS_PER_FAT
	mov bx, ax
	pop ax					; Pop AX off the stack
	add ax, bx				; AX += BX

LOAD_KERNEL:
						; Time to load the kernel!
	mov word [DAPACK.sec], ax
	mov si, DAPACK		; address of "disk address packet"
	mov ah, 0x42		; AL is unused
	mov dl, [DRIVE]		; drive number 0 (OR the drive # with 0x80)
	int 0x13
	jc err
	
	jmp 0x000:0x7e00				

err:
	mov si, ERROR
	call print
	


print:
	pusha
	mov ah, 0eh
.repeat:
	lodsb
	cmp al, 0
	je .done
	int 10h
	jmp .repeat
.done:
	popa
	ret


KERNEL db "KERNEL  BIN", 0
ERROR db "Failed to load sector", 10, 13, 0
DRIVE db 0

times 510-($-$$) db 0 ; fill in the remaining space with zero
dw 0xaa55 ; legacy boot signature
Its not yet complete the code above will only load one sector from the selected file. I'm planning to implement FAT16 more soon.

Hope it helps some one who is trying to load a file with FAT16.