#include "x16.h"
#include "mem.h"

#define RELOC 0x7c00

TEXT _magic(SB), $0
       BYTE $0xEB; BYTE $0x58;         /* jmp .+ 0x58  (_start0x5A) */
       BYTE $0x90                      /* nop */
TEXT _version(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _sectsize(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _clustsize(SB), $0
       BYTE $0x00
TEXT _nresrv(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _nfats(SB), $0
       BYTE $0x00
TEXT _rootsize(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _volsize(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _mediadesc(SB), $0
       BYTE $0x00
TEXT _fatsize(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _trksize(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _nheads(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _nhiddenlo(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _nhiddenhi(SB), $0
       BYTE $0x00; BYTE $0x00;
TEXT _bigvolsize(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
/* FAT32 structure, starting @0x24 */
TEXT _fatsz32lo(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _fatsz32hi(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _extflags(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _fsver(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _rootclust(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _fsinfo(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _bkboot(SB), $0
       BYTE $0x00; BYTE $0x00
TEXT _reserved0(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _driveno(SB), $0
       BYTE $0x00
TEXT _reserved1(SB), $0
       BYTE $0x00
TEXT _bootsig(SB), $0
       BYTE $0x00
TEXT _volid(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
TEXT _label(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
       BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _type(SB), $0
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
       BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00

_start0x5A:
       CLI
       CLR(rAX)
       MTSR(rAX, rSS)                  /* 0000 -> rSS */
       MTSR(rAX, rDS)                  /* 0000 -> rDS, source segment */
       MTSR(rAX, rES)

       LWI(0x100, rCX)
       LWI(RELOC, rSI)
       MW(rSI, rSP)
       LWI(_magic(SB), rDI)
       CLD
       REP; MOVSL                      /* MOV DS:[(E)SI] -> ES:[(E)DI] */

       MW(rSP, rBP)

       PUSHR(rCX)
       PUSHI(start16(SB))
       BYTE $0xCB                      /* FAR RET */

TEXT start16(SB), $0
       STI

       LWI(hello(SB), rSI)
       CALL16(print16(SB))

       STB(rDL, _driveno(SB))

       CLR(rDX)
       LW(_fatsize(SB), rAX)
       CLR(rCX)
       LB(_nfats(SB), rCL)
       MUL(rCX)
       OR(rAX, rAX)
       JNE _fatszok    /* zero? it's FAT32 */

       LW(_fatsz32hi(SB), rBX)
       IMUL(rCX, rBX)
       LW(_fatsz32lo(SB), rAX)
       MUL(rCX)
       ADD(rBX, rDX)

_fatszok:
       LW(_nhiddenlo(SB), rCX)
       ADD(rCX, rAX)
       LW(_nhiddenhi(SB), rCX)
       ADC(rCX, rDX)

       CLR(rBX)
       LW(_nresrv(SB), rCX)
       ADD(rCX, rAX)
       ADC(rDX, rBX)

       SW(rAX, _volid(SB))     /* save for later use */
       SW(rBX, _volid+2(SB))

       PUSHR(rBP)
       LW(_sectsize(SB), rCX)
       SUB(rCX, rSP)
       MW(rSP, rBP)
       MW(rSP, rSI)

_nextsect:
       CALL16(readsect16(SB))
       LW(_sectsize(SB), rCX)
       SHRI(5, rCX)

_nextdir:
       PUSHR(rCX)
       PUSHR(rSI)                      /* save for later if it matches */
       LWI(bootname(SB), rDI)
       LW(bootnamelen(SB), rCX)
       CLD
       REP
       CMPSB
       POPR(rSI)
       POPR(rCX)
       JEQ _found
       ADDI(0x20, rSI)
       LOOP _nextdir
       ADDI(1, rAX)
       ADC(rCX, rBX)
       JMP _nextsect

_found:
       CLR(rBX)
       LW(_rootsize(SB), rAX)          /* calculate and save Xrootsz */
       LWI(0x20, rCX)
       MUL(rCX)
       LW(_sectsize(SB), rCX)
       DEC(rCX)
       ADD(rCX, rAX)
       ADC(rBX, rDX)
       INC(rCX)
       DIV(rCX)
       PUSHR(rAX)                      /* Xrootsz */

       CLR(rCX)
       LXW(0x1a, xSI, rAX)             /* start cluster low */
       LXW(0x14, xSI, rBX)             /* start cluster high */
       SUBI(2, rAX)                    /* cluster -= 2 */
       SBB(rCX, rBX)

       LB(_clustsize(SB), rCL)         /* convert to sectors (AX:DX) */
       IMUL(rCX, rBX)
       MUL(rCX)
       ADD(rBX, rDX)

       LW(_volid(SB), rCX)             /* Xrootlo */
       ADD(rCX, rAX)
       LW(_volid+2(SB), rCX)           /* Xroothi */
       ADC(rCX, rDX)

       CLR(rBX)
       POPR(rCX)                       /* Xrootsz */
       ADD(rCX, rAX)
       ADC(rBX, rDX)

       PUSHR(rAX)                      /* calculate how many sectors to read (CX) */
       PUSHR(rDX)
       LXW(0x1c, xSI, rAX)
       LXW(0x1e, xSI, rDX)
       LW(_sectsize(SB), rCX)
       DEC(rCX)
       ADD(rCX, rAX)
       ADC(rBX, rDX)
       INC(rCX)
       DIV(rCX)
       MW(rAX, rCX)
       POPR(rBX)
       POPR(rAX)

       LWI(RELOC, rSI)
       PUSHR(rSI)      /* entry */

_loadnext:
       CALL16(readsect16(SB))

       LW(_sectsize(SB), rDX)
       ADD(rDX, rSI)

       CLR(rDX)
       ADDI(1, rAX)
       ADC(rDX, rBX)

       LOOP _loadnext

       LWI(ok(SB), rSI)
       CALL16(print16(SB))

       LB(_driveno(SB), rDL)
       CLI
       RET

TEXT print16(SB), $0
       PUSHA
       CLR(rBX)
_printnext:
       LODSB
       ORB(rAL, rAL)
       JEQ _printret
       LBI(0x0E, rAH)
       BIOSCALL(0x10)
       JMP _printnext
_printret:
       POPA
       RET

/*
* in:
*      AX:BX lba32,
*      0000:SI buffer
*/
TEXT readsect16(SB), $0
_retry:
       PUSHA
       CLR(rDX)

       PUSHR(rDX)              /* qword lba */
       PUSHR(rDX)
       PUSHR(rBX)
       PUSHR(rAX)

       PUSHR(rDX)              /* dword buffer */
       PUSHR(rSI)

       INC(rDX)
       PUSHR(rDX)              /* word # of sectors */

       PUSHI(0x0010)           /* byte reserved, byte packet size */

       MW(rSP, rSI)
       LB(_driveno(SB), rDL)
       LWI(0x4200, rAX)
       BIOSCALL(0x13)
       JCC _readok
       LWI((0x0E00|'!'), rAX)
       BIOSCALL(0x10)
       ADDI(0x10, rSP)
       POPA
       JMP _retry
_readok:
       LWI((0x0E00|'.'), rAX)
       BIOSCALL(0x10)
       ADDI(0x10, rSP)
       POPA
       RET

TEXT bootnamelen(SB), $0
       WORD $8
TEXT bootname(SB), $0
       BYTE $'9'; BYTE $'B'; BYTE $'O'; BYTE $'O';
       BYTE $'T'; BYTE $'F'; BYTE $'A'; BYTE $'T';
       BYTE $0

TEXT hello(SB), $0
       BYTE $'p'; BYTE $'b'; BYTE $'s'; BYTE $0
TEXT ok(SB), $0
       BYTE $'o'; BYTE $'k'; BYTE $'\r'; BYTE $'\n';
       BYTE $0