
hddstart:  
     cld
     cli
     xor  ax, ax
     mov  ss, ax         
     mov  ds, ax
     mov  es, ax
     mov  bp, BASE
     mov  sp, [bp - 20h]
     sti

     jmp  short bss1
     FATSTART dd 0
bss1:
     mov  byte ptr [bp+24h], dl ; save drive

; Calculate FAT Start
     mov  si, word ptr [nHidden]
     mov  di, word ptr [nHidden+2]
     add  si, word ptr [bsResSectors]
     adc  di, 0
     mov  word ptr [bp+FATSTART], si
     mov  word ptr [bp+FATSTART+2], di
; Calculate 
     mov  al, 20h                 ; 32 bytes in each directory entry
     mul  word ptr [bp+11h]       ; number of entries in root directory
     div  word ptr [bp+0Bh]       ; sector size
     mov  cx, ax                  ; number of sectors in root directory
     ;
     mov  al, [bp+10h]            ; Number of FATs
     cbw
     mul  word ptr [bp+16h]       ; Size of the FAT
     add  ax, [bp+0Eh]            ; Reserved Sectors
     adc  dx, 0
     add  ax, [bp+1Ch]            ; Hidden sectors
     adc  dx, [bp+1Eh]

     push cx
     mov  bx, 0500h               ; Lets read root dir to that address
     mov  cx, 1
     call BSSREAD             ; Reading 1 sector to make DOS happy
     pop  cx
     mov  bx, 8000h               ; Here we have enought space for large
                                  ; root directory (more than 944 entr.)
     call BSSREAD             ; Reading CX sectors to address BX
     jb   @@print_error           ; starting with sector DX:AX
     add  ax, cx
     adc  dx, 0
     push dx      ; Now DX:AX is the first sector of the first cluster
     push ax

     ; Look for our kernel file ...
     lea  di, [bp+(KERNELFILE)]
@@next_name:
     mov  si, bx
     cmp  Byte Ptr [di], 0
     je   @@print_error
     mov  cx, [bp+11h]    ; number of entries in root directory
@@next_entr:
        push si
        push di
        push cx
        mov  cx, 0Bh
        repz cmpsb
        pop  cx
        pop  di
        pop  si
        jz   @@found
        add  si, 20h
        loop @@next_entr
     add  di, 0Bh
     jmp  @@next_name
@@found:
     push ax
     push dx
     mov  di, [si+1Ah]    ; first cluster in file
     lea  ax, [di-2]
     jc   @@print_error
     mov  dl, [bp+0Dh]    ; cluster size
     mov  dh, 0
     mul  dx
     pop  cx
     pop  bx
     add  ax, bx
     adc  dx, cx

     mov  bx, 0070h
     mov  es, bx
     xor  bx, bx
     ; mov  bx, 0700h
     mov  cx, 4
     call BSSREAD
     jb   @@print_error
     cmp  word ptr es:[bx], 5A4Dh    ; "MZ"
     je   @@win95
     cmp  byte ptr es:[bx], 0e9h
     jne  @@print_error
     pop  bx      ;ax
     pop  ax      ;dx
     mov  ch, [bp+15h]    ; Media descriptor byte
     mov  dl, [bp+24h]    ; Hard drive number
@@dos:
;    jmp  0070:0000
     DB   0EAh
     DW   0000, 0070h
@@win95:
     mov  bx, 0078h       ; IO.SYS expects to see all this garbage.
     lds  si, [bx]        ; Plus it's cluster number in DI and
     push ds              ; it's relative sector in [bp-02]:[bp-04].
     push si
     push ss
     push bx
     lea  si, [bp+(NULL00)]
;    jmp  0070:0200
     DB   0EAh
     DW   0100h, 0070h

@@print_error:
     lea     si, [bp+(ERRMSG)]
     mov     ah, 0Eh
     mov     bx, 0007h
@@prstrl:
     lodsb
     or      al, al
     jz      @@keybexit
     int     10h
     jmp     @@prstrl
@@keybexit:
     xor     ax, ax
     int     16h
     int     19h

; ===========================================================================
BSSREAD proc near
; ES:BX   = Destination
; DX:AX   = Relative sector on disk
; CX      = Number of sectors to read
; Out: CF = set if error
; ===========================================================================

        push    ax
        push    bx
        push    cx
        push    dx
@@next_sect:

BSSREAD1:
;       call    READ_SECT
		push	si
		push	di
		push	bx
		push	cx
		push	dx
		push	ax

		mov	cx, 3
		push	cx
@@next_try:
		mov	ah, 08		; Get disk parameters
		mov	dl, [bp+24h]	; Hard disk number
		int	13h
		jb	@@reset

		mov	ah, 0
		mov	al, dh
		inc	ax		; Number of heads / cylinder
		and	cx, 3Fh
		mov	di, cx		; Number of sectors / head
		mul	cx
		mov	si, ax		; Number of sectors / cylinder

		pop	cx
		pop	ax		; Rel sect low
		pop	dx		; Rel sect high
		push	dx
		push	ax
		push	cx

		div	si	; Now ax=cylinder, dx=sector on cylinder
		mov	cx, ax
		shr	cx, 1
		shr	cx, 1
		and	cl, 0C0h
		mov	ch, al
		mov	ax, dx
		xor	dx, dx
		div	di	; Now ax=head, dx=sector on head
		mov	dh, al
		inc	dl
		and	dl, 3Fh
		or	cl, dl
		mov	dl, [bp+24h]	; Hard disk number
		mov	ax, 0201h	; Read (AH=02) 1 Sector (AL=01)
		int	13h
		jnb	@@end
@@reset:
		pop	cx
		dec	cx
		push	cx

                jb      @@end

		mov	ax, 0
		int	13h
		jmp	@@next_try
@@end:
		pop	cx
		pop	ax
		pop	dx
		pop	cx
		pop	bx
		pop	di
		pop	si
        jb      @@end1
        add     ax, 1
        adc     dx, 0
        add     bx, [bp+0Bh]    ; Sector size
        loop    @@next_sect
@@end1:
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
BSSREAD endp 



; === BSSLIB.TXT

; ===========================================================================
convert proc near
; This routine converts a sector address (an LBA) to a CHS address.
; The LBA is in DX:AX.
; ===========================================================================
        cmp  dx,  word ptr bootstart+wSectspertrack  ; LBA > SPT
        jnb  _c_sc                                   ; yes
        div  word ptr bootstart+wSectspertrack
        inc  dl                                      ; add 1 to sector number
        mov  bootstart+sectornum, dl
        xor  dx, dx
        div  word ptr bootstart+wHeads
        mov  bootstart+bCurrenthead, dl
        mov  bootstart+cylinder, ax
_c_cc:  clc
        ret      ; c3
_c_sc:  stc
        ret
convert endp

; ===========================================================================
calc_b  proc near
; ===========================================================================
        ; if rootcluster # < 2 or >= EOC then not FAT32  EOC = 0ffffff8h
        ; wRootSects = (wRootEntries * 32) / wSectSize
        mov  ax, bootstart+wRootentries
        mov  bx, 32
        xor  dx, dx
        mul  bx
        mov  bx, bootstart+wSectsize
        xor  dx, dx
        div  bx
        mov  bootstart+wRootSects, ax
        ; wFirstData = wResSects + (wFatSects * bFatCnt) + wRootSects
        mov  ax, bootstart+wSectsperfat
        xor  bx, bx
        mov  bl, bootstart+bFats
        xor  dx, dx
        mul  bx                                      ; AX = total FAT sectors
        mov  bx, wReservedsects
        xor  dx, dx
        add  ax, bx
        mov  bx, wRootSects
        add  ax, bx
        mov  wFirstdata, ax
        ; lAbsSector = wFirstData + ((lAnyClusterNo - 2) * bClustects)
        ret
calc_b  endp

; ===========================================================================
rdisks  proc near
; ===========================================================================
        mov ah, 02
        mov dx, ds:[7c4dh] ; cylinder #
        mov cl, 6
        shl dh, cl
        or  dh, ds:[7c4fh] ; Sector
        mov cx, dx
        xchg ch, cl
        ; convert to BIOS requirements
        ; CX=ccccccccCCssssss
        ; CH=c's cylinder number (low 8bits)
        ; CL=s's sector (high 6bits)
        ; CC's highorder 6 and 7 bits HD only
        mov dl, ds:[7c24h] ; drive 
        mov dh, ds:[7c25h] ; head
        int 13h
        ret
rdisks  endp

; ===========================================================================
calclog proc near 
; ===========================================================================
        cmp dx, ds:[7c18h]                             ; >= DX goto errorexit
        jnb cls1
        div word ptr ds:[7c18h]                        ; ds:ax / 7c18h = ax
        inc dl                                         ; reminder+1
        mov ds:[7c4fh], dl                             ; sector
        xor dx, dx
        div word ptr ds:[7c1ah]                 ; 0:ax / 7c1ah = ax  cylinder
        mov ds:[7c25h], dl                             ; head
        mov ds:[7c4dh], ax                             ; cylinder
        clc
        jmp short cls2
cls1:   stc
cls2:   ret
calclog endp

; DEBUG print hex digit routines
PrintLowNibble:         ; Prints low nibble of AL, AX is destroyed
	and  AL, 0Fh	; ignore upper nibble
	cmp  AL, 09h	; if greater than 9, then don't base on '0', base on 'A'
	jbe .printme
	add  AL, 7		; convert to character A-F
	.printme:
	add  AL, '0'	; convert to character 0-9
      mov  AH,  0Eh     ; show character
      int    10h        ; via "TTY" mode
      retn
PrintAL:                ; Prints AL, AX is preserved
	push AX		; store value so we can process a nibble at a time
	shr  AL, 4		; move upper nibble into lower nibble
      call PrintLowNibble
	pop  AX		; restore for other nibble
	push AX		; but save so we can restore original AX
      call PrintLowNibble
	pop  AX		; restore for other nibble
      retn
PrintNumber:            ; Prints (in Hex) value in AX, AX is preserved
      xchg AH, AL ; high byte 1st
      call PrintAL
      xchg AH, AL  ; now low byte
      call PrintAL
	retn

; shows text after the call to this function.

show:           pop     si
                lodsb                           ; get character
                push    si                      ; stack up potential return address
                mov     ah,0Eh                 ; show character
                int     10h                    ; via "TTY" mode
                cmp     al,'.'                  ; end of string?
                jne     show                    ; until done
                ret

;       readDisk:       Reads a number of sectors into memory.
;
;       Call with:      DX:AX = 32-bit DOS sector number
;                       DI = number of sectors to read
;                       ES:BX = destination buffer
;
;       Returns:        CF set on error
;                       ES:BX points one byte after the last byte read.

readDisk:       push    si

		mov     LBA_SECTOR_0,ax
		mov     LBA_SECTOR_16,dx
                mov     word ptr [READADDR_SEG], es
                mov     word ptr [READADDR_OFF], bx

                mov  al, '.'
                mov  ah, 0eh
                int  10h

read_next:

;******************** LBA_READ *******************************

						; check for LBA support
										
  		mov 	ah,041h		;
        	mov 	bx,055aah	;
                mov     dl, [BASE+bPhysicaldrvno]
		test	dl,dl			; don't use LBA addressing on A:
		jz	read_normal_BIOS	; might be a (buggy)
						; CDROM-BOOT floppy emulation

                int     13h
                jc	read_normal_BIOS

                shr     cx,1			; CX must have 1 bit set

                sbb	bx,0aa55h - 1		; tests for carry (from shr) too!
                jne	read_normal_BIOS
                
  				
						; OK, drive seems to support LBA addressing

                lea     si,  word ptr [LBA_PACKET]
                            
						; setup LBA disk block                            	
                mov     word ptr [LBA_SECTOR_32],bx  ; bx is 0 if extended 13h mode supported
                mov     word ptr [LBA_SECTOR_48],bx
	
		mov	ah,042h
                jmp short    do_int13_read

							
read_next_platform:
                jmp read_next
read_normal_BIOS:      

;******************** END OF LBA_READ ************************
                mov     cx, word ptr [LBA_SECTOR_0]
                mov     dx, word ptr [LBA_SECTOR_16]


                ;
                ; translate sector number to BIOS parameters
                ;

                ;
                ; abs = sector                          offset in track
                ;     + head * sectPerTrack             offset in cylinder
                ;     + track * sectPerTrack * nHeads   offset in platter
                ;
                mov     ax, word ptr [BASE+wSectspertrack]
                mul     byte ptr [BASE+wHeads]
                xchg    ax, cx
                ; cx = nHeads * sectPerTrack <= 255*63
                ; dx:ax = abs
                div     cx
                ; ax = track, dx = sector + head * sectPertrack
                xchg    ax, dx
                ; dx = track, ax = sector + head * sectPertrack
                div     word ptr [BASE+wSectspertrack]
                ; dx =  track, al = head, ah = sector
                mov     cx, dx
                ; cx =  track, al = head, ah = sector

                ; the following manipulations are necessary in order to
                ; properly place parameters into registers.
                ; ch = cylinder number low 8 bits
                ; cl = 7-6: cylinder high two bits
                ;      5-0: sector
                mov     dh, al                  ; save head into dh for bios
                xchg    ch, cl                  ; set cyl no low 8 bits
                ror     cl, 1                   ; move track high bits into
                ror     cl, 1                   ; bits 7-6 (assumes top = 0)
                or      cl, ah                  ; merge sector into cylinder
                inc     cx                      ; make sector 1-based (1-63)

                mov     bx, BASE
                mov     es, bx
                mov     bx, offset LBA_OFF
                mov     ax, 0201h
do_int13_read:                
                mov     dl, [BASE+bPhysicaldrvno]
                int     13h
                jnc     nobooterror

                call  boot_error              ; exit on error
nobooterror:
                mov     ax, word ptr [BASE+wSectSize]  

                push    di
                mov     si, offset BASE+READBUF              ; copy read in sector data to
                mov     bx, BASE
                mov     es, bx
                mov     di, offset [BASE+READADDR_OFF] ;user provided buffer

                mov     cx, ax
;                shr     cx, 1                   ; convert bytes to word count
;                rep     movsw
                rep     movsb
                pop     di

;               div     byte ptr [LBA_PACKET]        ; luckily 16 !!
                mov     cl, 4
                shr     ax, cl                  ; adjust segment pointer by increasing
                add     word ptr [READADDR_SEG], ax ; by paragraphs read in (per sector)

                add     word ptr [LBA_SECTOR_0],  1
                adc     word ptr [LBA_SECTOR_16], 0   ; DX:AX = next sector to read
                dec     di                      ; if there is anything left to read,
                jnz     read_next_platform      ; continue

                mov     bx, BASE
                mov     es, bx
                mov     bx, offset [BASE + READADDR_OFF]
                ; clear carry: unnecessary since adc clears it
                pop     si
                ret

;%ifdef ISFAT16
;                ; This is a FAT-16 disk. The maximal size of a 16-bit FAT
;                ; is 128 kb, so it may not fit within a single 64 kb segment.
;
;fat_16:         mov     dx, [LOADSEG]
;                add     si, si          ; multiply cluster number by two
;                jnc     first_half      ; if overflow...
;                add     dh, 10h        ; ...add 64 kb to segment value
;
;first_half:     mov     ds, dx          ; DS:SI = pointer to next cluster
;                lodsw                   ; AX = next cluster
;
;                cmp     ax, 0fff8h      ; >= FFF8 = 16-bit EOF
;                jb      next_clust      ; continue if not EOF
;%endif

read_Disk proc near
;      Reads a number of sectors into memory.
;       Call with:      DX:AX = 32-bit DOS sector number
;                       DI = number of sectors to read
;                       ES:BX = destination buffer
;
;       Returns:        CF set on error
;                       ES:BX points one byte after the last byte read.
readDisk:       push    si
            ;    mov     LBA_SECTOR_0,ax
            ;    mov     LBA_SECTOR_16,dx
            ;    mov     word ptr [READADDR_SEG], es
            ;    mov     word ptr [READADDR_OFF], bx
read_next:
; check for LBA support
        push ax
        push dx
        mov  ah, 0eh
        mov  al, '.'
        int  10h
        mov  ah, 41h
        mov  bx, 0055aah
        int  13h
        pop  dx
        pop  ax
        jc   NormalRead
LBARead:
        mov  dl, [BASE+bPhysicaldrvno]
        test dl,dl                   ; don't use LBA addressing on A:
        jz   NormalRead              ; might be a (buggy) CDROM-BOOT floppy emulation
        shr  cx, 1                   ; must have bit 1 set
        sbb  bx, 0aa55h - 1          ; test for carry from above
        jne  NormalRead
        ; OK, drive seems to support LBA addressing
        ; lea     si,  word ptr [LBA_PACKET]   ; setup LBA disk block                             
        ; mov     word ptr [LBA_SECTOR_32],bx  ; bx is 0 if extended 13h mode supported
        ; mov     word ptr [LBA_SECTOR_48],bx
        mov     ah,042h
        jmp  short do_int13
read_next_platform:
        jmp read_next
NormalRead:
        ;   mov     cx, word ptr [LBA_SECTOR_0]
        ;   mov     dx, word ptr [LBA_SECTOR_16]
        ; translate sector number to BIOS parameters
        ; abs = sector                          offset in track
        ;     + head * sectPerTrack             offset in cylinder
        ;     + track * sectPerTrack * nHeads   offset in platter
        ;
        mov     ax, word ptr [BASE+wSectspertrack]
        mul     byte ptr [BASE+wHeads]
        xchg    ax, cx
        ; cx = nHeads * sectPerTrack <= 255*63
        ; dx:ax = abs
        div     cx
        ; ax = track, dx = sector + head * sectPertrack
        xchg    ax, dx
        ; dx = track, ax = sector + head * sectPertrack
        div     word ptr [BASE+wSectspertrack]
        ; dx =  track, al = head, ah = sector
        mov     cx, dx
        ; cx =  track, al = head, ah = sector
        ; the following manipulations are necessary in order to
        ; properly place parameters into registers.
        ; ch = cylinder number low 8 bits
        ; cl = 7-6: cylinder high two bits
        ;      5-0: sector
        mov     dh, al                  ; save head into dh for bios
        xchg    ch, cl                  ; set cyl no low 8 bits
        ror     cl, 1                   ; move track high bits into
        ror     cl, 1                   ; bits 7-6 (assumes top = 0)
        or      cl, ah                  ; merge sector into cylinder
        inc     cx                      ; make sector 1-based (1-63)
        mov     bx, BASE
        mov     es, bx
        mov     bx, offset BASE+READBUF
        mov     ax, 0201h
do_int13:
        mov     dl, byte ptr [BASE+bPhysicaldrvno]
        int     13h
        jc      read_next                                                                            

 ;      mov     ax, word ptr [BASE+wSectSize]
 ;      push    di
 ;      mov     si, offset BASE+READBUF
 ;      ; copy read in sector data to
 ;      mov     bx, BASE
 ;      mov     es, bx
 ;      mov     di, offset [BASE+READADDR_OFF] ;user provided buffer
 ;      mov     cx, ax
 ;      ; shr     cx, 1                   ; convert bytes to word count
 ;      ; rep     movsw
 ;      rep     movsb
 ;      pop     di
 ;      ; div     byte ptr [LBA_PACKET]        ; luckily 16 !!
 ;      mov     cl, 4
 ;      shr     ax, cl                  ; adjust segment pointer by increasing
 ;      add     word ptr [READADDR_SEG], ax ; by paragraphs read in (per sector)
        ;   add     word ptr [LBA_SECTOR_0],  1
        ;   adc     word ptr [LBA_SECTOR_16], 0   ; DX:AX = next sector to read
        dec     di                      ; if there is anything left to read,
        jnz     read_next_platform      ; continue

        mov     bx, BASE
        mov     es, bx
        mov     bx, offset [BASE + READADDR_OFF]
        ; clear carry: unnecessary since adc clears it
        pop     si
                ret
read_disk endp


 mov  bx, BASE
 mov  es, bx
 mov  bx, offset base+readbuf

readdisk proc near
; AX    = sector
; ES:BX = Buffer
; CX    = number sectors
         mov  

         mov  cx, 4
retryread:
         dec  cx
         cmp  cx, 0
         je   readexit
         mov  ah, 2h
         mov  al, sectors
         mov  ch, base+cylinder
         mov  cl, base+phy_sec
         mov  dh, base+side
         mov  dl, base+bphysicaldrvno
         int  13h
         jc   retryread
readexit:
         ret
cylinder dw 0
side     dw 0
phy_sec  dw 0
readdisk endp



;       GETFATCHAIN:
;
;       Reads the FAT chain and stores it in a temporary buffer in the first
;       64 kb.  The FAT chain is stored an array of 16-bit cluster numbers,
;       ending with 0.
;
;       The file must fit in conventional memory, so it can't be larger than
;       640 kb. The sector size must be at least 512 bytes, so the FAT chain
;       can't be larger than 2.5 KB (655360 / 512 * 2 = 2560).
;
;       Call with:      AX = first cluster in chain

         ;       les     bx, [LOADSEG]     ; es:bx=60:0
                mov     bx, LOADSEG
                mov     es, bx
                xor     bx, bx
                mov     di, [BASE+wSectsPerFat]
                mov     ax, word ptr [BASE+fat_start]
                mov     dx, word ptr [BASE+fat_start+2]
                call    read_Disk
                pop     ax                      ; restore first cluster number

                ; Set ES:DI to the temporary storage for the FAT chain.
                push    ds
                pop     es
                mov     bx, LOADSEG
                mov     ds, bx
                mov     di, FATBUF

next_clust:     stosw                           ; store cluster number
                mov     si, ax                  ; SI = cluster number

; %ifdef ISFAT12
                ; This is a FAT-12 disk.

fat_12:         add     si, si          ; multiply cluster number by 3...
                add     si, ax
                shr     si, 1           ; ...and divide by 2
                lodsw

                ; If the cluster number was even, the cluster value is now in
                ; bits 0-11 of AX. If the cluster number was odd, the cluster
                ; value is in bits 4-15, and must be shifted right 4 bits. If
                ; the number was odd, CF was set in the last shift instruction.

                jnc     fat_even
		mov	cl, 4
		shr	ax, cl

fat_even:       and     ah, 0fh        ; mask off the highest 4 bits
                cmp     ax, 0ff8h      ; check for EOF
                jb      next_clust      ; continue if not EOF



finished:       ; Mark end of FAT chain with 0, so we have a single
                ; EOF marker for both FAT-12 and FAT-16 systems.

                xor     ax, ax
                stosw

                push    cs
                pop     ds

;       loadFile: Loads the file into memory, one cluster at a time.

                mov     bx, LOADSEG   ; set ES:BX to load address 60:0
                mov  es, bx
                xor  bx, bx

                mov     si, FATBUF      ; set DS:SI to the FAT chain

cluster_next:   lodsw                           ; AX = next cluster to read
                or      ax, ax                  ; EOF?
                jne     load_next               ; no, continue
                mov     bl,dl ; drive (left from readDisk)
                push    LOADSEG
                push    0000h
                retf
;                jmp     far [LOADSEG]     ; yes, pass control to kernel

load_next:      dec     ax                      ; cluster numbers start with 2
                dec     ax

                mov     di, word ptr [BASE+bSectsperclust]
                and     di, 0ffh                ; DI = sectors per cluster
                mul     di
                add     ax, [data_start]
                adc     dx, [data_start+2]      ; DX:AX = first sector to read
                call    read_Disk
                jmp     short cluster_next



;       FINDFILE: Searches for the file in the root directory.
;
;       Returns:
;                               AX = first cluster of file

                ; First, read the whole root directory
                ; into the temporary buffer.

                mov     ax, word ptr [BASE+root_dir_start]
                mov     dx, word ptr [BASE+root_dir_start+2]
                pop     di                      ; mov     di, word ptr [RootDirSecs]
                mov     bx, LOADSEG ; es:bx = 60:0
                mov     es, bx
                xor     bx, bx
                push    es
                push    bx
                call    read_Disk
                pop  bx
                pop  es
                xor     di, di


		; Search for KERNEL.SYS file name, and find start cluster.

next_entry:     mov     cx, 11
                mov     si, offset BASE+KernelFile
                push    di
                repe    cmpsb
                pop     di
                mov     ax, [es:di+1Ah]; get cluster number from directory entry
                je      ffDone

                add     di, 20h   ; go to next directory entry
                cmp     byte ptr [es:di], 0 ; if the first byte of the name is 0,
                jnz     next_entry	; there is no more files in the directory

                jnc     ffDone
                call    boot_error      ; fail if not found
ffDone:
                push    ax              ; store first cluster number

GETDRIVEPARAMS proc near
;       GETDRIVEPARMS:  Calculate start of some disk areas.
;
                mov     si, word ptr [BASE+lHiddensects]
                mov     di, word ptr [BASE+lHiddensects+2]
                add     si, word ptr [BASE+wReservedsects]
                adc     di, 0              ; DI:SI = first FAT sector

                mov     word ptr [BASE+fat_start], si
                mov     word ptr [BASE+fat_start+2], di

                mov     al, [BASE+bFATs]
                cbw
                mul     word ptr [BASE+wSectsPerFat]       ; DX:AX = total number of FAT sectors

                add     si, ax
                adc     di, dx                  ; DI:SI = first root directory sector
                mov     word ptr [BASE+root_dir_start], si
                mov     word ptr [BASE+root_dir_start+2], di

                ; Calculate how many sectors the root directory occupies.
                mov     bx, [BASE+wSectSize]
                mov     cl, 5                   ; divide BX by 32
                shr     bx, cl                  ; BX = directory entries per sector

                mov     ax, word ptr [BASE+wRootentries]
                xor     dx, dx
                div     bx

;                mov     word ptr [BASE+RootDirSecs], ax  ; AX = sectors per root directory
                push    ax

                add     si, ax
                adc     di, 0              ; DI:SI = first data sector

                mov     word ptr [BASE+data_start], si
                mov     word ptr [BASE+data_start+2], di
                ret
GETDRIVEPARAMS endp


LOADSEG EQU 0060h

bootcode:
                push cs
                pop  ds
                xor  ax, ax   
                cli              
                mov  ss, ax
                mov  sp, bootstart ; Grows down from bootstart
                lea  bp, BPB       ; BP = BPB
                sti

                mov     [bootstart+bPhysicaldrvno], dl    

           ;     32*rootentries/sectsize = rootdir size
           ;     rootdir size/fats*sectsperfat = logical address

                ; 0700:0000 FAT table
                mov  bx, 0700h
                mov  es, bx
                xor  bx, bx
readfat:
                mov  al, 2
                mov  cx, 0bh ; sector
                mov  dh, 0
                mov  dl, 0
                call readsector

                ; 0800:0000 root directory
                mov  bx, 0800h
                mov  es, bx
                xor  bx, bx
readroot:
                mov  al, 2
                mov  cx, 02h ; sector
                mov  dh, 1
                mov  dl, 0
                call readsector

                push ds
                push es
                pop  ds
                mov  si, bx
                call ListFiles
                pop  ds
                or   ax, ax
                jz   _files
                lea  si, bootstart+NOFILESMSG
                call tty
_files:        

                mov  bx, 0800h
                mov  es, bx
                xor  bx, bx
findname:
                lea  si, bootstart+KernelFile
                mov  di, bx
                mov  cx, 11
fncycle:
                mov  al, byte ptr [ds:si]
                mov  dl, byte ptr [es:di]
                cmp al, dl
                je  failed
                pusha
                repe cmpsb
                popa
                je found
                add di, 32
                dec dx
                jnz fncycle
failed:
                jmp ErrFind
found:
                ; store cluster into AX
                mov  ax, [es:di+1ah]
                push ax
                call putnum
                mov  al, 7
                call _tty
                pop  ax

                mov  si, ax  ; cluster no.
                mov  bx, 0800h
                mov  es, bx
                mov  bx, 0100h
readnextcluster:
                call readcluster
                cmp  si, 0ff8h
                jc   readnextcluster   ; not an EOF

                ; next cluster
              ;  pop  ax
              ;  mov  bx, 0700h
              ;  mov  es, bx
              ;  mov  cx, ax
              ;  mov  dx, ax
              ;  shr  dx, 1  ; div half
              ;  add  cx, dx
              ;  mov  bx, 0000h  ; location of FAT in mem
              ;  add  bx, cx
              ;  mov  dx, word ptr [es:bx] ; read two byes from fat
              ;  test ax, 1
              ;  jnz  oddcluster
evencluster:
              ;  and  dx, 0000111111111111b
              ;  jmp done
oddcluster:
              ;  shr  dx, 4

              ;  inc  di
              ;  push dx   ; store new cluster
              ;  cmp  dx, 0ff0h ; eof
              ;  jb   LoadFile

run:
             push 0060h       ; CS
             push 0100h       ; IP
             ; give program some knowledge
             mov  ch, [cs:bootstart+bMedia]
             mov  dl, [cs:bootstart+bPhysicaldrvno]
             sti
             retf

;; Load entire a program ;;

             ; es:bx 0060:0010h
loadprogram:
         ;    pop  si           ; si = cluster
         ;    call readcluster
         ;    push si
         ;    cmp  si, 0ff8h ; EOF?
         ;    jc   loadprogram
         ;    ; check for program type
         ;    cmp  word ptr [es:0100], 5A4Dh      ; EXE header
         ;    je   setupEXE
         ;    ; COM
         ; ;    call debug
         ;    ; dos progs want a PSP even if they dont use it
         ;    mov     ax, es
         ;    sub     ax, 10h    
         ;    mov     es, ax
         ;    mov     ds, ax
         ;    mov     ss, ax
         ;    xor     sp, sp
         ;    push    es
         ;    push    100h
         ;    jmp     run
setupEXE:;
;             add     ax, [es:08h]            ; ax = image base
;             mov     cx, [es:06h]            ; cx = reloc items
;             mov     bx, [es:18h]            ; bx = reloc table pointer
;             jcxz    RelocationDone
ReloCycle:
           ;  mov     di, [ds:bx]             ; di = item ofs
           ;  mov     dx, [ds:bx+2]           ; dx = item seg (rel)
;             add     dx, ax                  ; dx = item seg (abs)

           ;  push    ds
           ;  mov     ds, dx                 
           ;  add     [ds:di], ax             
           ;  pop     ds

           ;  add     bx, 4                   ; point to next entry
;             loop    ReloCycle
RelocationDone:
;             mov     bx, ax
;             add     bx, [es:0Eh]
             ; stack section in EXE
;             mov     ss, bx                 
;             mov     sp, [es:10h]           

;             add     ax, [es:16h]            ; cs
;             push    ax
;             push    [ds:14h]           ; ip

; ===========================================================================
readcluster proc near
; Reads a FAT12 Table
; Input:  ES:BX = Buffer
;            SI = Cluster
; Output:    SI = Next Cluster
;         ES:BX = Next address
; ===========================================================================
        ; sectorspercluster*cluster = sectorLBA
        ; readsector
        ; sectsize/4=paragraphs per sector*paragraphs read

        ; cluster * 3 / 2

        ; and ax, 0fffh ; mask cluster value

;        mov  bx, si
;        mov  ax, si
;        and  ax, 1
;        jc   _even
;        shr  bx, 4
;        jmp  _odd
;_even:   and  bx, 0fffh
;_odd:
;        call readsector
;        mov  ax, 3
;        mul  si
;        shr  ax, 1
;        xchg ax, si
;        ; si = next cluster
;        pusha
;        push ax
;        mov al, '*'
;        call _tty
;        pop ax
;        ret
readcluster endp

; ===========================================================================
readsector proc near
; Reads a sector using BIOS Int 13h fn 2 
; Input : ES:BX = Address
;         DH/DL = HEAD/DRIVE
;         CH/CL = TRACK/SECTOR
;            AL = Sector count
; Output:    CF = NZ on error
; ===========================================================================
         mov  di, 4
_read:
         push ax
         mov  al, '.'
         call _tty
         pop  ax
         ; LBA / SPT = ax
         ; LBA % SPT = dx  sector - 1

         ; ax = (LBA / SPT) / HPC = cylinder
         ; dx = (LBA / SPT) % HPC = head

         dec  di
         jz   _readx    
         mov  ah, 2   ; read
         int  13h
         jnc  _read
         xor     ah, ah       
         int     13h                     ; reset drive
         push ax
         mov al, '!'
         call _tty
         pop ax
         jc   _read
_readx:  ret
readsector endp

; ===========================================================================
ListFiles proc near
; DS:SI = Root Directory
; ===========================================================================
        mov  word ptr [bootstart+FILECOUNT], 0
readnextfile:
        mov  cx, 0bh  ; 11
nextchar:
        mov  al, byte ptr ds:[si]
        inc  si
        cmp  al, 0 
        jz   done 
        cmp  al, 0e5h
        jz   filedeleted
        mov  ah, 0eh
        int  10h
        loop nextchar
        mov  byte ptr [bootstart+FILEEXISTS], 1
        inc  word ptr [bootstart+FILECOUNT]
        mov  al, 0dh
        call _tty
        mov  al, 0ah
        call _tty
;..............File Deleted...........................
filedeleted:
        mov  cx, 15h
        rep  lodsb
        jmp  readnextfile
done:
        xor  ax, ax
        cmp  byte ptr [bootstart+FILEEXISTS], 1
        jz   nofiles
filereadok:
        mov  ax, word ptr [bootstart+FILECOUNT]
nofiles:
        ret
FILECOUNT  db ?
FILEEXISTS db 0
NOFILESMSG db 0ffh,'No files.',0ffh,0
ListFiles endp

include bootlib.asm

ErrFind:
        mov  al, 7
        call _tty
        mov  al, 7
        call _tty
ErrRead:
        mov  al, 7
        call _tty
        mov  al, 7
        call _tty
        mov  al, 7
        call _tty

; ===========================================================================
ClusterLBA proc near
; ===========================================================================
; absolutetrack = (LogicalSector/SectorsPerTrack/heads
; LBA = (cluster - 2) * SPC
;           sub  ax, 2
;           xor  cx, cx
;           mov  cl, byte ptr [bootstart+bSectsperclust]
;           mul  cx
;           ; add  ax, word ptr datasector
;           ret
ClusterLBA endp

; ===========================================================================
LBACHS proc near 
; ===========================================================================
; abs sector = (logical sector / spt)+1
; abs head   = (logical sector / spt) MOD heads
; abs track  = logical sector / (spt * heads)
;       xor  dx, dx
;       div  word ptr [bootstart+bSectsperclust]
;       inc  dl
;       mov  byte ptr bootstart+abs, dl
;       push dx
;       xor  dx, dx
;       div  word ptr [bootstart+wheads]
;       push dx
;       push ax
;       pop  cx   ; logical sector
;       pop  bx   ; logical head
;       pop  ax   ; logical track
;       mov  dl, al
;       mov  dh, bl
;       ret
LBACHS endp



