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
Hope it helps some one who is trying to load a file with FAT16.