;       Copyright (C) 2009  Guillaume DELESTIC
;       This file is part of DNA Workstation.
;
;   DNA Workstation is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   DNA Workstation is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with DNA Workstation.  If not, see <http://www.gnu.org/licenses/>.

;       Original code from www.brokenthorn.com

bits    16

%include "Floppy16.asm"                                 ; the erm.. floppy driver

%define ROOT_OFFSET 0x2e00
%define FAT_SEG 0x2c0
%define ROOT_SEG 0x2e0

;*******************************************
; LoadRoot ()
;       - Load Root Directory Table to 0x7e00
;*******************************************

LoadRoot:

        pushad                                                  ; store registers
        push    es

     ; compute size of root directory and store in "cx"

        xor     cx, cx                                          ; clear registers
        xor     dx, dx
        mov     ax, 32                                  ; 32 byte directory entry
        mul     WORD [bpbRootEntries]                           ; total size of directory
        div     WORD [bpbBytesPerSector]                        ; sectors used by directory
        xchg    ax, cx                                          ; move into AX

     ; compute location of root directory and store in "ax"

        mov     al, BYTE [bpbNumberOfFATs]                      ; number of FATs
        mul     WORD [bpbSectorsPerFAT]                         ; sectors used by FATs
        add     ax, WORD [bpbReservedSectors]
        mov     WORD [datasector], ax                           ; base of root directory
        add     WORD [datasector], cx

     ; read root directory into 0x7e00

        push    word ROOT_SEG
        pop             es
        mov     bx, 0                                                           ; copy root dir
        call    ReadSectors                                                     ; read in directory table
        pop             es
        popad                                                                           ; restore registers and return
        ret

;*******************************************
; LoadFAT ()
;       - Loads FAT table to 0x7c00
;
;       Parm/ ES:DI => Root Directory Table
;*******************************************

LoadFAT:

        pushad                                                  ; store registers
        push    es

     ; compute size of FAT and store in "cx"

        xor     ax, ax
        mov     al, BYTE [bpbNumberOfFATs]                      ; number of FATs
        mul     WORD [bpbSectorsPerFAT]                         ; sectors used by FATs
        mov     cx, ax

     ; compute location of FAT and store in "ax"

        mov     ax, WORD [bpbReservedSectors]

     ; read FAT into memory (Overwrite our bootloader at 0x7c00)

        push    word FAT_SEG
        pop             es
        xor             bx, bx
        call    ReadSectors
        pop             es
        popad                                                   ; restore registers and return
        ret

;*******************************************
; FindFile ()
;       - Search for filename in root table
;
; parm/ DS:SI => File name
; ret/ AX => File index number in directory table. -1 if error
;*******************************************

FindFile:

        push    cx                                              ; store registers
        push    dx
        push    bx
        mov     bx, si                                          ; copy filename for later

     ; browse root directory for binary image

        mov     cx, WORD [bpbRootEntries]                       ; load loop counter
        mov     di, ROOT_OFFSET                                         ; locate first root entry at 1 MB mark
        cld                                                     ; clear direction flag

.LOOP:
        push    cx
        mov     cx, 11                                  ; eleven character name. Image name is in SI
        mov     si, bx                                          ; image name is in BX
        push    di
     rep  cmpsb                                                 ; test for entry match
        pop     di
        je      .Found
        pop     cx
        add     di, 32                                  ; queue next directory entry
        loop    .LOOP

.NotFound:
        pop     bx                                              ; restore registers and return
        pop     dx
        pop     cx
        mov     ax, -1                                          ; set error code
        ret

.Found:
        pop     ax                                              ; return value into AX contains entry of file
        pop     bx                                              ; restore registers and return
        pop     dx
        pop     cx
        ret

;*******************************************
; LoadFile ()
;       - Load file
; parm/ ES:SI => File to load
; parm/ EBX:BP => Buffer to load file to
; ret/ AX => -1 on error, 0 on success
; ret/ CX => number of sectors read
;*******************************************

LoadFile:

        xor     ecx, ecx                ; size of file in sectors
        push    ecx

.FIND_FILE:

        push    bx                      ; BX=>BP points to buffer to write to; store it for later
        push    bp
        call    FindFile                ; find our file. ES:SI contains our filename
        cmp     ax, -1
        jne     .LOAD_IMAGE_PRE
        pop     bp
        pop     bx
        pop     ecx
        mov     ax, -1
        ret

.LOAD_IMAGE_PRE:

        sub     edi, ROOT_OFFSET
        sub     eax, ROOT_OFFSET

        ; get starting cluster

        push    word ROOT_SEG           ;root segment loc
        pop     es
        mov     dx, WORD [es:di + 0x001A]; DI points to file entry in root directory table. Refrence the table...
        mov     WORD [cluster], dx      ; file's first cluster
        pop     bx                      ; get location to write to so we dont screw up the stack
        pop     es
        push    bx                      ; store location for later again
        push    es
        call    LoadFAT

.LOAD_IMAGE:

        ; load the cluster

        mov     ax, WORD [cluster]      ; cluster to read
        pop     es                      ; bx:bp=es:bx
        pop     bx
        call    ClusterLBA
        xor     cx, cx
        mov     cl, BYTE [bpbSectorsPerCluster]
        call    ReadSectors
        pop     ecx
        inc     ecx                     ; add one more sector to counter
        push    ecx
        push    bx
        push    es
        mov     ax, FAT_SEG             ;start reading from fat
        mov     es, ax
        xor     bx, bx

        ; get next cluster

        mov     ax, WORD [cluster]      ; identify current cluster
        mov     cx, ax                  ; copy current cluster
        mov     dx, ax
        shr     dx, 0x0001              ; divide by two
        add     cx, dx                  ; sum for (3/2)

        mov     bx, 0                   ;location of fat in memory
        add     bx, cx
        mov     dx, WORD [es:bx]
        test    ax, 0x0001              ; test for odd or even cluster
        jnz     .ODD_CLUSTER

.EVEN_CLUSTER:

        and     dx, 0000111111111111b   ; take low 12 bits
        jmp     .DONE

.ODD_CLUSTER:

        shr     dx, 0x0004              ; take high 12 bits

.DONE:

        mov     WORD [cluster], dx
        cmp     dx, 0x0ff0              ; test for end of file marker
        jb      .LOAD_IMAGE

.SUCCESS:
        pop     es
        pop     bx
        pop     ecx
        xor     ax, ax
        ret
