org 0

include "fat12_16.inc"

jmp short start
nop

BPB fat12_16_bpb

;----------------------------
align 4
start:
	cli
	
	cld
	
	xor di,di
	mov bx,0x1000
	mov ax,0x2000
	mov ds,di
	mov sp,di
	mov bp,di

	mov si,0x7c00
	mov cx,128
	
	mov ss,bx
	mov es,bx
	
	rep movsd
	
	jmp 0x1000:go_on
;----------------------------
align 4
go_on:
	push cs
	mov es,ax
	pop ds
	
	sti
	
	mov byte[dap.size],0x10
	mov word[dap.segment],ax
	
	mov [bp+BPB.BS_DrvNum],dl
;----------------------------
;	FAT start lba= BPB_ResvdSecCnt + BPB_HiddSec
	movzx eax,word[bp+BPB.BPB_ResvdSecCnt]
	mov cx,word[bp+BPB.BPB_FATSz16]
	add eax,dword[bp+BPB.BPB_HiddSec]

	push eax
;----------------------------
;	load the FAT
	call load_lba
;----------------------------
load_root_dir:
;----------------------------
;	RootDirSectors= ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec
	xor ecx,ecx
	mov bx,word[bp+BPB.BPB_RootEntCnt]
	mov cx,511
	shl bx,5
	add cx,bx
	shr cx,9
;----------------------------
;	StartSector= BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16) + BPB_HiddSec
	movzx eax,word[bp+BPB.BPB_FATSz16]
	shl ax,1
	
	pop ebx
	
	add eax,ebx
	mov dx,0x50
	mov ebx,eax
	add ebx,ecx
	
	push ebx
;----------------------------
;	destination of rootdir
	mov word[dap.segment],dx
	mov es,dx
;----------------------------
;	load the rootdir
	call load_lba
;----------------------------
load_loader:
;----------------------------
	mov dx,word[bp+BPB.BPB_RootEntCnt]
	xor di,di
;----------------------------
;	search the rootdir for the loader
align 4
.loop@search_entry:
;----------------------------
;	compare the loader name with the actual entry name
	push di

	mov si,osloader_img
	mov cx,11

	rep cmpsb

	pop di

	je .loop@found_entry

	dec dx
	jnz .loop@next
;----------------------------
.err_loader:
	mov si,msg_err_loader
	call print

	jmp reboot
;----------------------------
; check next entry
align 4
.loop@next:
	add di,fat_dir_ent.size_t

	jmp .loop@search_entry
;----------------------------
;	right entry, so save the cluster
.loop@found_entry:
	pop ecx
	
	mov bx,word[es:di+fat_dir_ent.cluster]
;----------------------------
;	test if this was the last cluster
align 4
.loop@cluster:
	cmp bx,0fff8h
	jae .end
;----------------------------
;	look if the cluster is above 64KiB
	mov si,bx
	mov dx,0x2000
	shl si,1

	jnc .loop@cluster@doit

	mov dx,0x3000
;----------------------------
;	calc the lba of the actual cluster and get the new cluster
.loop@cluster@doit:
	mov fs,dx

	movzx eax,bx
	movzx bx,byte[bp+BPB.BPB_SecPerClus]
	sub ax,2
	mul bx
	shl edx,16
	mov bx,[fs:si]
	or eax,edx

	add eax,ecx
;----------------------------
;	load the cluster and calculate the new segment address of the next cluster
.loop@cluster@load:
	push bx
	push ecx

	movzx cx,byte[bp+BPB.BPB_SecPerClus]
	call load_lba

	pop ecx
	pop bx

	movzx ax,byte[bp+BPB.BPB_SecPerClus]
	shl ax,5
	add word[dap.segment],ax

	jmp .loop@cluster
;----------------------------
align 4
.end:
	mov dl,[bp+BPB.BS_DrvNum]

	jmp 0x50:0x0
;----------------------------

;----------------------------
align 4
print:
	mov ah,0eh

align 4
.loop:
	lodsb
	
	test al,al
	jz .end
	
	int 10h
	
	jmp .loop
align 4
.end:
	ret
;----------------------------
;	Input:
;	EAX - LBA
;	CX - # of lbas 2 load
align 4
load_lba:
	mov [dap.lba],eax			;save lba to load
	mov [dap.blocks],cx			;save # of blocks 2 load

	mov si,dap
	mov ah,42h
	mov dl,[bp+BPB.BS_DrvNum]
	int 13h

	jc .end_err

.end:
	ret

.end_err:
	mov si,msg_err_read
	call print
;----------------------------

;----------------------------
reboot:
	mov si,msg_reboot
	call print

	xor ax,ax
	int 16h
	int 19h
;----------------------------

align 4
;----------------------------
;	consts
osloader_img	db 'OSLOADER   '

;	msgs
msg_err_read	db 'Error reading disk',13,10,0
msg_err_loader	db 'OS-Loader not found',13,10,0
msg_reboot		db 'Press any key to reboot',0

times 510-($-$$) db 0
dw 0aa55h
;----------------------------
;	bss
dap:
	.size		rb 1
	.reserved	rb 1
	.blocks		rw 1
	.offset		rw 1
	.segment	rw 1
	.lba		rd 2