; METAKERNEL Copyright 2004-2005 Christopher Evans
; Website: http://nxdos.sourceforge.net/
; Eric Auer (c) www.freedos.org
;
;       This program is copyrighted, but may be freely distributed          ;
;       under the terms of the Free Software Foundation's GNU General       ;
;       Public License v2 (or later.)  See the file COPYING for the         ;
;       legalities.  If you did not receive a copy of COPYING, you          ;
;       may request one from the Free Software Foundation, Inc.,            ;
;       59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           ;
;       ABSOLUTELY NO WARRANTY -- use it at your own risk!                  ;
;

;.model tiny, basic
.286c
.287
;.486p
;.487

boot segment byte public
     assume  cs:boot, ds:boot

     org 0

start:

include \nxdos\src\boot\metakern.equ

BOOTVER EQU 0505h
BOOTEXP EQU 0 ; 1 2 or 3
;
BSSLIB2 EQU 0
BASE    EQU 7C00h
$KERNEL EQU 0060h
_KERNEL EQU 0100h
DPTADDR EQU (1eh * 4)  ; 1eh = 00011110 16+14  30
LOADSEG EQU $KERNEL
FATBUF  EQU 2000h      ; offset of temporary buffer for FAT

bss_stack macro
       cli
       cld           
       xor  ax, ax    
       ; push cs
       ; pop  ax
       mov  ds,ax
       mov  es,ax
       mov  ss,ax
       ; mov  sp, BASE 
       ; lea  bp, BASE       
       mov  bp, BASE
       mov  sp, BASE - 10h          ; Grows down from bootstart BP = BPB
       ; mov  sp, bp
       sti
       endm

bss_data macro
  ; name and extension must be padded
  ; with spaces (11 bytes total)
 ; ProgramName     db      'NXDOS   BIN ',0
  IF (BOOTEXP)
 KernelFile      db 'NXBIO   SYS',0
 replacemsg      db 'Replace.',0
 filefoundmsg    db 'Loading... ',0ffh,0
 fileloaded      db 'Loaded!',0ffh,0
 invalidsysmsg   db 'Invalid.',0ffh,0
 bad_kernelmsg   db 'Corrupt.',0ffh,0
 LBAMSG          db 'LBA ',0
 IF (BOOTEXP EQ 2)
  include \nxdos\src\kernel\fat12lf.inc
  ; include \nxdos\src\kernel\fat12lf2.inc
  ; include \nxdos\src\kernel\fat12l-2.inc
  ; include \nxdos\src\kernel\fat12fl.inc
 ENDIF
 IF (BOOTEXP EQ 3)
  EXTRA     db 0
 ENDIF
ELSE
 IF (CHECKIT)
  KernelFile      db      'CHLDR   SYS'
 ELSE
  KernelFile      db      'NXBIO   SYS'
 ENDIF
ENDIF
   endm

metakern proc far

Entry:

; Some BIOS don't pass drive number in DL, so don't use it if drive is known
; (fats*spf) + 1 + 0
; 2*9=18+1= 19 = 13H 
; 00010011
; (32*224-1)+512/512 = 14.99
; Translate to BIOS 
; ABS = sector(track offset) +
;       head * SPT (cylinder offset) +
;       track * SPT * heads (platter offset)

IF (MBR)
       d_0000_0600_e equ 0600h
       d_0000_068b_e equ 68bh
       d_0000_7dfe_e equ 7dfeh

       cli
       xor  ax, ax
       mov  ss, ax
       mov  sp, BASE
       mov  si, sp
       push ax
       pop  es
       push ax
       pop  ds
       sti
       ;
       cld
       mov  di, d_0000_0600_e
       mov  cx, 100h
       repne movsw
       ; jmp  far ptr l_1000_061D
       db   0eah
       dw   61dh, 0
; scan partitions
       mov  si, 07beh
       mov  bl, 4
l_0122:
       cmp  byte ptr [si], 80h
       je   l_0135
       cmp  byte ptr [si], 0
       jne  l_0148
       add  si, 10h
       dec  bl
       jnz  l_0122
       int  18h
l_0135:
       mov  dx, [si]
       mov  cx, [si+2]
       mov  bp, si
l_013c:
       add  si, 10h
       dec  bl
       jz   l_015D
       cmp  byte ptr [si], 0
       je   l_013c
l_0148:
       mov  si, d_0000_068b_e
l_014b:
       lodsb
       cmp  al, 0
       je   l_015b
       push si
       mov  bx, 7
       mov  ah, 0eh
       int  10h
       pop  si
       jmp  short l_014b
l_015b:
       jmp  short l_015b
l_015d:
       mov  di, 5
l_0160:
       mov  bx, BASE
       mov  ax, 201h
       push di
       int  13h
       pop  di
       jnc  l_0178
       xor  ax, ax
       int  13h
       dec  di
       jnz  l_0160
       mov  si, 6a3h
       jmp  short l_014b
l_0178:
       mov  si, 6c2h
       mov  di, d_0000_7dfe_e
       cmp  word ptr [di], 0aa55h
       jne  l_014b
       mov  si, bp
       ; jmp  far ptr l_0000:7c00
       db   0eah
       dw   BASE, 0
       db   'Invalid partition table',0
       db   'Error loading operating system',0
       db   'Missing operating system',0
ELSE ; MBR
       jmp  short abbootcode
       db   90h

include \nxdos\src\boot\metakern.bpb

abbootcode:
    IF (BOOTABLE)
       IF (EXTRAS)
       bss_stack

   IF (HELLO)
       lea  si, BASE+Helloworld
bootloop:
       cld
       mov  al, byte ptr [si]
       mov  ah, 0eh
       int  10h
       inc  si
       or   al, al
       jnz  bootloop
       call reboot    ; int  19h
Helloworld  db 'Hello World!',0dh,0ah,0
   ENDIF
   IF (MINI)
      ; File: BOOT.ASM 1.44MB Mini OS command interpreter experiment
      cld
      lea  si, BASE+cmdtitle
      call tty
bootloop:
      mov  ah, 0eh
      mov  al, '>'
      int  10h
      lea  di, BASE+cmdline
      xor  cx, cx
dataentry:
      call getkey
      ; xor ax, ax
      ; int 16h
      mov al, byte ptr [di]
      inc cx
      cmp al, 0dh ; CR
      jne dataentry
      cmp cx, 127
      jb  dataentry
      call newline
      ; mov  ah, 0eh
      ; mov  al, 0dh
      ; int  10h
      ; mov  ah, 0eh
      ; mov  al, 0ah
      ; int  10h
      ; process
      lea  si, BASE+_EXIT
      lea  di, BASE+cmdline
      push cx
      dec  cx
      mov  dl, 0
_exitcmp:
      dec  cx
      mov  al, byte ptr [si]
      mov  bl, byte ptr [di]
      cmp  al, bl
      je   _exiteq
      inc  dl
_exiteq:
      inc  si
      inc  di
      cmp  cx, 0
      jne  _exitcmp
      pop  cx
      or   dl, dl
      jnz  _echocmpl
boots:
      call reboot  ; int  19h
_echocmpl:
      lea  si, BASE+_ECHO
      lea  di, BASE+cmdline
      push cx
      dec  cx
      mov  dl, 0
_echocmp:
      dec  cx
      mov  al, byte ptr [si]
      mov  bl, byte ptr [di]
      cmp  al, bl
      je   _echoeq
      inc  dl
_echoeq:
      inc  si
      inc  di
      cmp  cx, 0
      jne  _echocmp
      pop  cx
      or   dl, dl
      jnz  bad
      cld
      lea  si, BASE+cmdline
      add  si, 5
      call tty
      jmp  nc
bad:
      cld
      lea  si, BASE+badcmd
      call tty
nc:                           
      jmp  bootloop
      call reboot    ; int  19h
cmdline_size    EQU 10 ; 127
cmdline         db cmdline_size dup(0),0 
_EXIT           db 'EXIT ',0
_ECHO           db 'ECHO ',0
; MINI Command BOOT-OS
CMDTITLE        db '(c) 1998 Chris Evans',0ffh,0 
BADCMD          db 'Bad command or filename',0ffh,0
   ENDIF
   IF (CREOS)
   ; File: BOOTCREO.ASM Displays message then waits for special key input
   ; Copyright 2004-2005 Christopher Evans
   ; This is just a message for those that boot up the laptop with out my
   ; express permission.
pw:
                cld
                lea  si, BASE+Message
                call tty

                call getkey
                ; xor  ax, ax
                ; int  16h
                cmp  al, 'X'
                jne  invalidpw

                call reboot ; int  19h

invalidpw:      mov  al, 7
                call _tty
                jmp short pw       
Message         db 0ffh,0ffh,'C.R.E.O.S. - ACCESS DENIED.',0ffh,0ffh
                db 'Please press any key to reboot and push the power button.',0ffh
                db 'This is just a message for those that boot up with out my',0ffh
                db 'express permission.',0ffh,0ffh
                db '1-(916)-401-7677',0ffh,0ffh
                db 'éÄ·Ä· ? ',0
   ENDIF ; CREOS
   IF (UMBBSS)
    mov  bp, 48     ; write 48 tracks (loop count)
    mov  ax, 0a000h ; starting segment address
    mov  cx, 101h   ; track (cyl) 1, sector 1
capuma1:
    push ax
    mov  es, ax ;ES -> segment address to read
    push es         ; this and the 'pop ax' below
    pop  ax         ; are redundant?
;    call wout
    mov  bx, 0      ; BX -> offset address to read
    mov  dx, 0      ; head 0, drive 0
    mov  ax, 310h   ; write 10h sectors (=2000h bytes)
;    call dsk_do_rw
;    call wout
    lahf
;    call wout
    pop  ax
    add  ax, 200h ;advance 200h paras
    inc  ch ;next track (cyl)
    dec  bp ;decr loop counter
    jnz  capuma1
    ret

;Is it important that you record the contents of 0xa0000 to 0xfffff
;at boot time? If not it would be a whole lot easier to write a
;small prog in (e.g.) C to dump the said contents to a file. Off
;the top of my head (hence untried/untested) and with zero error
;checking (for brevity):
;
;#define BLOCKSIZ 0x4000
;int main(void) {
;unsigned long seg;
;int fh = creat("somefile", S_IREAD | S_IWRITE);
;    for (seg = 0xa000L; seg < 0x10000L; seg += BLOCKSIZ) {
;        char far *p = MK_FP((unsigned)seg, 0);
;        write(fh, p, BLOCKSIZ);
;        }
;    close(fh);
;return 0; }

   ENDIF
IF (BOOTEXP)
   IF (BOOTEXP EQ 1)
; File: BOOT.ASM 1.44MB Floppy disk boot loader program
;
; File: bootf.asm
; Description: Based on DOS-C boot Copyright (c) 1997; Svante Frey
                mov     [BASE+bPhysicaldrvno], dl     ; rely on BIOS drive number in DL
                ; call    resetdrive


                ; the first sector of cluster 2 (data region) is computed as
                ; follows:
                ; RootDirSectors = ((BPB_RootEntries*32)+(BPB_Bytespersec-1))/BPB_Bytespersec;
                mov    ax, BASE+wRootentries
                mov    bx, 32
                xor    dx, dx
                mul    bx
                mov    bx, BASE+wSectsize
                dec    bx
                add    ax, bx
                xor    dx, dx
                mov    bx, BASE+wSectsize
                div    bx
                push   ax  ; rootdiresctors = 14

                ; 1stdatasector = BPB_reserved+(BPB_numFats*FATSz)+RootDirSect;
                xor    dx, dx
                mov    ax, BASE+wSectsperfat
                xor    bx, bx
                mov    bl, BASE+bFats
                mul    bx
                mov    bx, BASE+wReservedsects
                add    ax, bx
                push   ax  ; root dir location 

                pop     ax         ; mov     ax, 19     ; root dir location
                pop     cx         ; mov     cx, 14     ; root directory sectors
                mov     bx, offset BASE+READBUF
                call    readdisk
                jc      booterror

                mov     bx, word ptr [BASE+wRootentries]  ; 224   ; root entries
                mov     si, offset BASE+READBUF
findfile:
                cmp  byte ptr [si], 0  ; null entry?
                je   filenotfound
                mov  cx, 0bh
                push si
                mov  di, offset BASE+KernelFile
                repe cmpsb   ; repeat if ZF = 1 CX > 0
                pop  si
                je   filefound
                dec  bx
                jz   filenotfound
                add  si, 32      ; next entry
                jmp  findfile
filenotfound:
                jmp  short fileloaderror
filefound:
                mov  al, byte ptr [SI+0bh]  ; move attribute byte to bl
                and  al, 0018h              ; notvalidfilemask
                ja   filenotfound
                mov  ax, word ptr [SI+1aH]  ; first cluster
                cmp  ax, 2                  ; start cluster
                jb   short fileloaderror
                mov  word ptr [BASE+lHiddensects], ax
                ; save first cluster for using by kernel
load_fat:
                mov  ax, 1        ; location
                mov  cx, word ptr [BASE+wSectsperfat]  ; 9        ; sectors
                mov  bx, offset [BASE+READBUF+FATBUF]
                call readdisk
                jc   short fatloaderror
load_runtime:
                mov  si, offset BASE+filefoundmsg
                call tty

                mov  bx, LOADSEG
                mov  es, bx
                xor  bx, bx
                mov  ax, word ptr [BASE+lHiddensects]
                call loadimage
                jc   short fileloaderror

launch_runtime:
                mov  si, offset base+fileloaded
                call tty

                mov  dl, byte ptr [BASE+bPhysicaldrvno]
                push LOADSEG
                push 0000h
                sti
                retf
fatloaderror:
                mov  al, 7
                call _tty
booterror:
                mov  al, 7
                call _tty
fileloaderror:
                mov  si, offset BASE+replacemsg
                call tty
                xor  ax, ax
                int  16h
                int  19h

readdisk proc near
; AX = location sector
; CX = sector count
; ES:BX = Buffer
         mov  di, 3
retryread:
         push cx
         push ax
         ; Physical address calculation
         mov  cl, 18                    ; sectors per track
         div  cl
         mov  cl, ah    ; sector zero based
         inc  cl
         xor  ah, ah
         mov  dl, 2   ; heads
         div  dl
         ;  al=cyl, ah=head, cl=sector
         mov  dh, ah
         mov  dl, byte ptr [BASE+bPhysicaldrvno]
         mov  ch, al
         mov  ax, 0201h
         int  13h
         pop  ax
         pop  cx
         jc   readloop 
         inc  ax
         dec  cx
         jz   readexit
         add  bx, 512
         mov  di, 4
retrypf: jmp  retryread
readloop:
         dec  di
         jnz  retrypf  
         stc
readexit:
         mov  al, '.'
         mov  ah, 0eh
         int  10h
         ret
readdisk endp
   ENDIF
   IF (BOOTEXP EQ 2)
Entry:          jmp     short real_start
		nop
real_start:

                mov     [BASE+bPhysicaldrvno], dl     ; rely on BIOS drive number in DL
                ; call    resetdrive

                mov     ax, 19     ; root dir location
                mov     cx, 14     ; root directory sectors
                mov     bx, offset BASE+READBUF
                mov     si, bx
                call    readdisk
on_error:       jc      booterror

                mov     bx, 224   ; root entries
findfile:
                cmp  byte ptr [si], 0  ; null entry?
                je   filenotfound
                mov  cx, 0bh
                push si
                mov  di, offset BASE+KernelFile
                repe cmpsb   ; repeat if ZF = 1 CX > 0
                pop  si
                je   filefound
                dec  bx
                jz   filenotfound
                add  si, 32      ; next entry
                jmp  findfile
filenotfound:
                ; replace msg
                jmp  on_Error
filefound:
                mov  al, byte ptr [SI+0bh]  ; move attribute byte to bl
                and  al, 0018h              ; notvalidfilemask
                ja   filenotfound
                mov  ax, word ptr [SI+1aH]  ; first cluster
                cmp  ax, 2                  ; start cluster
                jb   on_error
                mov  word ptr [BASE+lHiddensects], ax
                ; save first cluster for using by kernel
load_fat:
                mov  ax, 1        ; location
                mov  cx, 9        ; sectors
                mov  bx, offset [BASE+READBUF+2000h]
                call readdisk
                jc   on_error
load_runtime:
                mov  ax, word ptr [BASE+lHiddensects]
                mov  bx, 0060h
                mov  es, bx
                xor  bx, bx
                call loadimage
                jc   on_error
launch_runtime:
                mov  dl, byte ptr [BASE+bPhysicaldrvno]
                mov  ax, 417
                push 0060h
                push 0000h
                retf
booterror:
                int  16h
                int  19h
readdisk proc near
         mov  di, 4
retryread:
         push cx
         push ax
         ; Physical address calculation
         mov  cl, 18                    ; sectors per track
         div  cl
         mov  cl, ah    ; sector zero based
         inc  cl
         xor  ah, ah
         mov  dl, 2   ; heads
         div  dl
         ;  al=cyl, ah=head, cl=sector
         mov  dh, ah
         mov  dl, byte ptr [BASE+bPhysicaldrvno]
         mov  ch, al
         mov  ax, 0201h
         int  13h
         pop  ax
         pop  cx
         jc   readloop 
         inc  ax
         dec  cx
         jz   readexit
         add  bx, 512
         mov  di, 4
retrypf: jmp  retryread
readloop:
         dec  di
         jnz  retrypf  
         stc
readexit:
         mov  al, '.'
         mov  ah, 0eh
         int  10h
         ret
readdisk endp
   ENDIF
   IF (BOOTEXP EQ 3)
LBA_PACKET      EQU EXTRA+50
LBA_SIZE        EQU EXTRA+50 ;  dw 10h
LBA_SECNUM      EQU EXTRA+52 ; dw 0
LBA_OFF         EQU EXTRA+54 ; dw 0
LBA_SEG         EQU EXTRA+56 ; dw 0
LBA_SECTOR_0    EQU EXTRA+58 ; dw 0
LBA_SECTOR_16   EQU EXTRA+60 ; dw 0
LBA_SECTOR_32   EQU EXTRA+62 ; dw 0
LBA_SECTOR_48   EQU EXTRA+64 ; dw 0

; Some BIOS don't pass drive number in DL, so don't use it if [drive] is known
                cmp     byte ptr [BASE+bPhysicalDrvno], 0ffh ; impossible number written by SYS
		jne     dont_use_dl     ; was SYS drive: other than A or B?
                mov     byte ptr [BASE+bPhysicalDrvno], dl     ; yes, rely on BIOS drive number in DL
dont_use_dl:				; no,  rely on [drive] written by SYS
                mov     ax, 10h
                mov     BASE+LBA_SIZE, ax
                mov     ax, 1
                mov     BASE+LBA_SECNUM, ax
; -----------------
                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+EXTRA+10], si
                mov     word ptr [BASE+EXTRA+10+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+EXTRA+20], si
                mov     word ptr [BASE+EXTRA+20+2], di

                ; Calculate how many sectors the root directory occupies.
                mov     bx, word ptr [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+EXTRA+40], ax  ; AX = sectors per root directory

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

                mov     word ptr [BASE+EXTRA+30], si
                mov     word ptr [BASE+EXTRA+30+2], di
; -----------------

;       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+BASE+EXTRA+20]
                mov     dx, word ptr [BASE+BASE+EXTRA+20+2]
                mov     di, word ptr [BASE+EXTRA+40]
                mov     bx, LOADSEG
                mov     es, bx
                xor     bx, bx
                call    readDisk
                jc      jmp_boot_error

                mov     di, LOADSEG
                mov     es, di
                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

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


;       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 around 3 kb.
;
;       Call with:      AX = first cluster in chain

                ; Load the complete FAT into memory. The FAT can't be larger
                ; than 128 kb, so it should fit in the temporary buffer.

                mov     bx, LOADSEG
                mov     es, bx
                xor     bx, bx

                mov     di, [BASE+wSectsperfat]
                mov     ax, word ptr [BASE+BASE+EXTRA+10]
                mov     dx, word ptr [BASE+BASE+EXTRA+10+2]
                call    readDisk
                pop     ax                      ; restore first cluster number
jmp_boot_error: jc      boot_error

                ; 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

                ; 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
                mov     es, bx
                xor     bx, bx ; set ES:BX to load address 60:0

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

cluster_next:   lodsw                           ; AX = next cluster to read
                or      ax, ax                  ; if EOF...
                je      boot_success            ; ...boot was successful

                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, word ptr [BASE+BASE+EXTRA+30]
                adc     dx, word ptr [BASE+BASE+EXTRA+30+2]      ; DX:AX = first sector to read
                call    readDisk
                jnc     cluster_next


boot_error:
		xor	ah,ah
                int     16h                    ; wait for a key
                int     19h                    ; reboot the machine

boot_success:   
                mov     bl, byte ptr [BASE+bPhysicalDrvno]
                xor     ax, ax
                push    LOADSEG
                push    ax
                retf

readDisk proc near
; DX:AX = 32bit DOS sector number
;    DI = number of sectors
; ES:BX = destination buffer
;    ES = must be 64k aligned (1000h, 2000h etc)
         push si
         mov  BASE+LBA_SECTOR_0, ax
         mov  BASE+LBA_SECTOR_16, dx
         mov  BASE+LBA_SEG, es
         mov  BASE+LBA_OFF, bx
read_next:
         ; LBA READ
         ; Check for LBA support
         mov  ah, 41h
         mov  bx, 55aah
         mov  dl, BASE+bphysicaldrvno
         test dl, dl
         jz   normal_BIOS
         int  13h
         jc   normal_BIOS
         shr  cx, 1
         sbb  bx, 0aa55h - 1
         jne  normal_BIOS
         lea  si, BASE+LBA_SIZE  ; LBA_PACKET disk block
         mov  BASE+LBA_SECTOR_32, bx
         mov  BASE+LBA_SECTOR_48, bx
         mov  ah, 42h
         jmp  short int13_read
normal_BIOS:
         mov  cx, BASE+LBA_SECTOR_0
         mov  dx, BASE+LBA_SECTOR_16
         ; translate sector number to BIOS parameters
         ; abs = sector                           offset into track
         ;       + head * sectpertrack            offset into cylinder
         ;       + track * SectPerTrack * nHeads  offset into platter
         mov  ax, word ptr BASE+wSectspertrack
         mul  byte ptr BASE+wHeads
         xchg ax, cx
         ; cx    = nHeads*SPT <= 255*63
         ; dx:ax = abs
         div  cx
         ; ax    = track, dx = sector + head * SPT
         xchg ax, dx
         ; dx    = track, ax = sector + head * SPT
         div  byte ptr BASE+wSectspertrack
         ; dx = track, al = head, ah = sector
         mov  cx, dx
         ; cx = track, al = head, ah = sector
         ; We now have to place the parameters into the registers
         ; ch = cylinder number low 8 bits
         ; cl = 7-6: cylinder high two bits
         ;      5-0: sector
         mov  dh, al  ; head
         xchg ch, cl
         ror  cl, 1
         ror  cl, 1
         mov  ax, word ptr BASE+wSectsperTrack
         sub  al, ah
         inc  ah
         or   cl, ah
         push cs
         pop  es
         mov  bx, word ptr BASE+LBA_OFF
         mov  ax, 0201h
int13_read:
         mov  dl, BASE+bPhysicalDrvno
         int  13h
read_finished:
         jnc  read_ok
         xor  ah, ah
         int  13h
next_chained:
         jmp  short read_next
read_ok:
         mov  ax, word ptr BASE+wSectsize
         div  byte ptr [BASE+LBA_SIZE]  ; lucky 16!
         add  word ptr BASE+LBA_SEG, ax
         add  byte ptr BASE+LBA_SECTOR_0, 1
         adc  byte ptr BASE+LBA_SECTOR_16, 0
         ; dx:ax = next sector to read
         dec  di
         jnz  next_chained
         mov  es, word ptr BASE+LBA_SEG
         ; clear carry, ADC does it for us.
         pop  si
         ret
readDisk endp
   ENDIF
bss_data
READBUF:
ENDIF ; BOOTEXP

       ELSE ; EXTRAS
       IF (FIXEDDISK)

; ==========
; FIXED DISK 
; ==========

HARDDISK:

data_0001e      equ     2000h                   ;*
data_0002e	equ	63A0h			;*
data_0005e	equ	0A066h			;*
data_0008e	equ	2000h			;*
data_0011e	equ	7C5Ah			;*

drive equ bp+24h


       ;         db      0FAh,0FCh, 31h,0C0h, 8Eh,0D8h
       ;         db      0BDh, 00h, 7Ch,0B8h,0E0h, 1Fh
       ;         db       8Eh,0C0h, 89h,0EEh, 89h,0EFh
       ;         db      0B9h, 00h, 01h,0F3h,0A5h, 0EAh
       ;         db       5Eh, 7Ch,0E0h, 1Fh, 00h, 00h
         cli
         cld
         xor  ax, ax
         mov  dx, ax
         mov  bp, BASE
         mov  si, bp
         mov  di, bp
         mov  ax, 1fe0h
         mov  es, ax
         mov  cx, 0100h
         repz movsw
         ; jmp  word  1fe0:cont
         db   0eah, 5eh, 7ch, 0e0h, 01fh
;         db   0, 0
;         db       60h, 00h, 8Eh,0D8h, 8Eh,0D0h
;         db       8Dh, 66h,0A0h,0FBh, 80h, 7Eh
;         db       24h,0FFh, 75h, 03h, 88h
;        db       56h, 24h
loadseg_off dw 0
loadseg_seg dw $KERNEL
cont:
         mov  ds, ax
         mov  ss, ax
         lea  sp, [bp-60h]
         sti
         cmp  byte ptr [drive], 0ffh 
         jne  dont_use_dl    
         mov  byte ptr [drive], dl
dont_use_dl:
; GETDRIVEPARAMS

loc_0004:
LBA_PACKET     EQU bp-40h
LBA_SIZE       EQU [LBA_PACKET]
LBA_SECNUM     EQU [LBA_PACKET+2]
LBA_OFF        EQU LBA_PACKET+4
LBA_SEG        EQU LBA_PACKET+6
LBA_SECTOR_0   EQU [LBA_PACKET+8]
LBA_SECTOR_16  EQU [LBA_PACKET+10]
LBA_SECTOR_32  EQU [LBA_PACKET+12]
LBA_SECTOR_48  EQU [LBA_PACKET+14]
PARAMS         EQU LBA_PACKET+10h
RootDirSecs    EQU PARAMS+0         ; # of sectors root dir uses
fat_start      EQU PARAMS+2         ; first FAT sector
root_dir_start EQU PARAMS+6         ; first root directory sector
data_start     EQU PARAMS+0ah       ; first data sector

         mov  word ptr LBA_SIZE,   10h
         mov  word ptr LBA_SECNUM, 1 

            ;    mov     word ptr [bp-40h],10h
            ;    mov     word ptr [bp-3Eh],1
		mov	[bp-3Ah],ds
		mov	word ptr [bp-3Ch],63A0h
		mov	si,[bp+1Ch]
		mov	di,[bp+1Eh]
		add	si,[bp+0Eh]
		adc	di,0
		mov	[bp-2Eh],si
		mov	[bp-2Ch],di
		mov	al,[bp+10h]
		cbw				; Convrt byte to word
		mul	word ptr [bp+16h]	; ax = data * ax
		add	si,ax
		adc	di,dx
		mov	[bp-2Ah],si
		mov	[bp-28h],di
		mov	bx,[bp+0Bh]
		mov	cl,5
		shr	bx,cl			; Shift w/zeros fill
		mov	ax,[bp+11h]
		xor	dx,dx			; Zero register
		div	bx			; ax,dx rem=dx:ax/reg
		push	ax
		add	si,ax
		adc	di,0
		mov	[bp-26h],si
		mov	[bp-24h],di
		mov	ax,[bp-2Ah]
		mov	dx,[bp-28h]
		pop	di
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
		call	sub_0002
		les	di,dword ptr [bp+5Ah]	; Load 32 bit ptr
loc_0005:
		mov	cx,0Bh
                mov     si, offset 7c00h + KernelFile
		push	di
		repe	cmpsb			; Rep zf=1+cx >0 Cmp [si] to es:[di]
		pop	di
		mov	ax,es:[di+1Ah]
		jz	loc_0006		; Jump if zero
		add	di,20h
		cmp	byte ptr es:[di],0
		jne	loc_0005		; Jump if not equal
		jc	loc_0012		; Jump if carry Set
loc_0006:
		push	ax
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
		mov	di,[bp+16h]
		mov	ax,[bp-2Eh]
		mov	dx,[bp-2Ch]
		call	sub_0002
		pop	ax
		push	ds
		pop	es
		mov	ds,[bp+5Ch]
		mov	di,data_0001e
loc_0007:
		stosw				; Store ax to es:[di]
		mov	si,ax
		mov	dx,[bp+5Ch]
		add	si,si
		jnc	loc_0008		; Jump if carry=0
		add	dh,10h
loc_0008:
		mov	ds,dx
		lodsw				; String [si] to ax
		cmp	ax,0FFF8h
		jb	loc_0007		; Jump if below
		xor	ax,ax			; Zero register
		stosw				; Store ax to es:[di]
		push	cs
		pop	ds
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
		mov	si,data_0008e
loc_0009:
		lodsw				; String [si] to ax
		or	ax,ax			; Zero ?
		jnz	loc_0010		; Jump if not zero
		mov	bl,dl
		jmp	dword ptr [bp+5Ah]	;*
loc_0010:
		dec	ax
		dec	ax
		mov	di,[bp+0Dh]
		and	di,0FFh
		mul	di			; dx:ax = reg * ax
		add	ax,[bp-26h]
		adc	dx,[bp-24h]
		call	sub_0002
		jmp	short loc_0009

;==========================================================================
;			       SUBROUTINE
;==========================================================================

sub_0001	proc	near
loc_0011:
		pop	si
		lodsb				; String [si] to al
		push	si
		mov	ah,0Eh
		int	10h			; Video display   ah=functn 0Eh
						;  write char al, teletype mode
		cmp	al,2Eh			; '.'
		jne	loc_0011		; Jump if not equal
		retn
sub_0001	endp

loc_0012:
		call	sub_0001
		inc	bp
;*		jc	loc_0017		;*Jump if carry Set
		db	 72h, 72h
		outsw				; Out [si] to port dx
		jc	loc_0014		; Jump if carry Set
		db	 2Eh, 30h,0E4h,0CDh, 13h,0CDh
		db	 16h,0CDh, 19h

;==========================================================================
;			       SUBROUTINE
;==========================================================================

sub_0002	proc	near
		push	si
		mov	[bp-38h],ax
		mov	[bp-36h],dx
		mov	[bp-1862h],es
		mov	[bp-1864h],bx
		call	sub_0001
loc_0013:
		db	 2Eh,0B4h, 41h,0BBh,0AAh, 55h
loc_0014:
		mov	dl,[bp+24h]
		test	dl,dl
		jz	loc_0015		; Jump if zero
		int	13h			; Disk  dl=drive ?  ah=func 00h
						;  reset disk, al=return status
		jc	loc_0015		; Jump if carry Set
		shr	cx,1			; Shift w/zeros fill
		sbb	bx,0AA54h
		jnz	loc_0015		; Jump if not zero
		lea	si,[bp-40h]		; Load effective addr
		mov	[bp-34h],bx
		mov	[bp-32h],bx
		mov	ah,42h			; 'B'
		jmp	short loc_0016
loc_0015:
		mov	cx,[bp-38h]
		mov	dx,[bp-36h]
		mov	al,[bp+18h]
		mul	byte ptr [bp+1Ah]	; ax = data * al
		xchg	ax,cx
		div	cx			; ax,dx rem=dx:ax/reg
		xchg	ax,dx
		div	byte ptr [bp+18h]	; al,ah rem = ax/data
		mov	cx,dx
		mov	dh,al
		xchg	ch,cl
		ror	cl,1			; Rotate
		ror	cl,1			; Rotate
		or	cl,ah
		inc	cx
		les	bx,dword ptr [bp-3Ch]	; Load 32 bit ptr
		mov	ax,201h
loc_0016:
		mov	dl,[bp+24h]
		int	13h			; Disk  dl=drive ?  ah=func 02h
						;  read sectors to memory es:bx
						;   al=#,ch=cyl,cl=sectr,dh=head
		jc	loc_0012		; Jump if carry Set
		mov	ax,[bp+0Bh]
		push	di
		mov	si,data_0002e
		les	di,dword ptr [bp-1864h]	; Load 32 bit ptr
		mov	cx,ax
		rep	movsb			; Rep when cx >0 Mov [si] to es:[di]
		pop	di
		mov	cl,4
		shr	ax,cl			; Shift w/zeros fill
		add	[bp-1862h],ax
		add	word ptr [bp-38h],1
		adc	word ptr [bp-36h],0
		dec	di
		jnz	loc_0013		; Jump if not zero
		les	bx,dword ptr [bp-1864h]	; Load 32 bit ptr
		pop	si
		retn
sub_0002	endp

		db	0, 0, 0
bss_data

;    db   00h, 00h, 55h,0AAh

       ELSE
; ===========
; FLOPPY DISK
; ===========

FLOPPYDISK:

FATBUF          equ     2000h
_filename       equ     7DF1h                   
data_4e         equ     0A066h                  
data_6e         equ     2000h                   
data_7e         equ     7C5Ah                   

		cli				; Disable interrupts
		cld				; Clear direction
		xor	ax,ax			; Zero register
		mov	ds,ax
                mov     bp,BASE
		mov	ax,1FE0h
		mov	es,ax
		mov	si,bp
		mov	di,bp
		mov	cx,100h
		rep	movsw			; Rep when cx >0 Mov [si] to es:[di]
;*		jmp	far ptr loc_2		;*
		db	0EAh, 5Eh, 7Ch,0E0h, 1Fh
		add	[bx+si],al
		pusha				; Save all regs
		add	[bp-7128h],cl
		ror	byte ptr ds:data_4e[di],1	; Rotate
		sti				; Enable interrupts
		cmp	byte ptr [bp+24h],0FFh
                jne     calculate_root          ; Jump if not equal
		mov	[bp+24h],dl
calculate_root:
		mov	word ptr [bp-40h],10h
		mov	word ptr [bp-3Eh],1
		mov	si,[bp+1Ch]
		mov	di,[bp+1Eh]
		add	si,[bp+0Eh]
		adc	di,0
		mov	[bp-2Eh],si
		mov	[bp-2Ch],di
		mov	al,[bp+10h]
		cbw				; Convrt byte to word
		mul	word ptr [bp+16h]	; ax = data * ax
		add	si,ax
		adc	di,dx
		mov	[bp-2Ah],si
		mov	[bp-28h],di
		mov	bx,[bp+0Bh]
		mov	cl,5
		shr	bx,cl			; Shift w/zeros fill
		mov	ax,[bp+11h]
		xor	dx,dx			; Zero register
		div	bx			; ax,dx rem=dx:ax/reg
		mov	[bp-30h],ax
		add	si,ax
		adc	di,0
		mov	[bp-26h],si
		mov	[bp-24h],di
		mov	ax,[bp-2Ah]
		mov	dx,[bp-28h]
		mov	di,[bp-30h]
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
                call    readdisk
		les	di,dword ptr [bp+5Ah]	; Load 32 bit ptr
findfile:
		mov	cx,0Bh
                mov     si, offset BASE+KernelFile
		push	di
		repe	cmpsb			; Rep zf=1+cx >0 Cmp [si] to es:[di]
		pop	di
		mov	ax,es:[di+1Ah]
                jz      loadFAT                   ; Jump if zero
		add	di,20h
		cmp	byte ptr es:[di],0
                jne     findfile                   ; Jump if not equal
                jc      boot_error                  ; Jump if carry Set
loadFAT:
		push	ax
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
		mov	di,[bp+16h]
		mov	ax,[bp-2Eh]
		mov	dx,[bp-2Ch]
                call    readdisk
		pop	ax
		push	ds
		pop	es
		mov	ds,[bp+5Ch]
                mov     di,FATBUF
load_file:
		stosw				; Store ax to es:[di]
		mov	si,ax
		add	si,si
		add	si,ax
		shr	si,1			; Shift w/zeros fill
		lodsw				; String [si] to ax
                jnc     fat_cluster_even                   ; Jump if carry=0
		mov	cl,4
		shr	ax,cl			; Shift w/zeros fill
fat_cluster_even:
		and	ah,0Fh
		cmp	ax,0FF8h
                jb      load_file                   ; Jump if below
		xor	ax,ax			; Zero register
		stosw				; Store ax to es:[di]
		push	cs
		pop	ds
		les	bx,dword ptr [bp+5Ah]	; Load 32 bit ptr
		mov	si,data_6e
loc_9:
		lodsw				; String [si] to ax
		or	ax,ax			; Zero ?
		jnz	loc_10			; Jump if not zero
		mov	bl,dl
;*		jmp	dword ptr [bp+5Ah]	;*1 entry
		db	0FFh, 6Eh, 5Ah
loc_10:
		dec	ax
		dec	ax
		mov	di,[bp+0Dh]
		and	di,0FFh
		mul	di			; dx:ax = reg * ax
		add	ax,[bp-26h]
		adc	dx,[bp-24h]
                call    readdisk
		jmp	short loc_9

;==========================================================================
;			       SUBROUTINE
;==========================================================================

show_text           proc    near
showtext1:
		pop	si
		lodsb				; String [si] to al
		push	si
		mov	ah,0Eh
		int	10h			; Video display   ah=functn 0Eh
						;  write char al, teletype mode
		cmp	al,2Eh			; '.'
                jne     showtext1                  ; Jump if not equal
		retn
show_text           endp

boot_error:
                call    show_text
		inc	bp
;*		jc	loc_20			;*Jump if carry Set
		db	 72h, 72h
		outsw				; Out [si] to port dx
		jc	loc_13			; Jump if carry Set
		and	[bx+si+69h],cl
;*		jz	loc_14			;*Jump if zero
		db	 74h, 20h
		popa				; Restore all regs
		and	[bp+di+65h],ch
;*		jns	loc_15			;*Jump if not sign
		db	 79h, 20h
		jz	loc_22			; Jump if zero
		and	[bp+si+65h],dh
		bound	bp,dword ptr [bx+6Fh]
		jz	loc_17			; Jump if zero
		xor	ah,ah			; Zero register
		int	13h			; Disk  dl=drive a  ah=func 00h
						;  reset disk, al=return status
		int	16h			; Keyboard i/o  ah=function 00h
						;  get keybd char in al, ah=scan
		int	19h			; Bootstrap loader

readdisk        proc    near
		push	si
		mov	[bp-38h],ax
loc_13:
		mov	[bp-36h],dx
		mov	[bp-3Ah],es
		mov	[bp-3Ch],bx
                call    show_text

;1341--BX55AA
;Category: disk I/O enhancements
;
;INT 13 - IBM/MS INT 13 Extensions - INSTALLATION CHECK
;
;        AH = 41h
;        BX = 55AAh
;        DL = drive (80h-FFh)
;Return: CF set on error (extensions not supported)
;            AH = 01h (invalid function)
;        CF clear if successful
;            BX = AA55h if installed
;            AH = major version of extensions
;                01h = 1.x
;                20h = 2.0 / EDD-1.0
;                21h = 2.1 / EDD-1.1
;                30h = EDD-3.0
;            AL = internal use
;            CX = API subset support bitmap (see #00271)
;            DH = extension version (v2.0+ ??? -- not present in 1.x)
;Note:   the Phoenix Enhanced Disk Drive Specification v1.0 uses version 2.0 of
;          the INT 13 Extensions API
;SeeAlso: AH=42h"INT 13 Ext",AH=48h"INT 13 Ext"
;
;Bitfields for IBM/MS INT 13 Extensions API support bitmap:
;Bit(s)  Description     (Table 00271)
; 0      extended disk access functions (AH=42h-44h,47h,48h) supported
; 1      removable drive controller functions (AH=45h,46h,48h,49h,INT 15/AH=52h)
;          supported
; 2      enhanced disk drive (EDD) functions (AH=48h,AH=4Eh) supported
;        extended drive parameter table is valid (see #00273,#00278)
; 3-15   reserved (0)

;         mov  ah, 41h
;         mov  bx, 55aah
;         mov  dl, [bp+24h]
;         test dl, dl
;         jz   no_diskext
;         int  13h
;         jb   no_diskext
;
;no_diskext:

;2e      CS:
;b441    mov  ah, 41h  ; IBM/MS INT 13 Extensions - INSTALLATION CHECK
;bbaa55  mov  bx, 55aah
;8a5624  mov  dl, [bp+24h]
;84d2    test dl, dl
;7419    jz   0126
;cd13    int  13h
;7215    jb   0126
;d1e9    shr  cx, 1
;81db5490 dbb  bx, 9054h

		db	 2Eh,0B4h, 41h,0BBh,0AAh, 55h
		db	 8Ah, 56h, 24h, 84h,0D2h, 74h
		db	 19h,0CDh, 13h, 72h, 15h,0D1h
		db	0E9h, 81h,0DBh
		db	54h
loc_17:
		stosb				; Store al to es:[di]
		jnz	loc_19			; Jump if not zero
		lea	si,[bp-40h]		; Load effective addr
		mov	[bp-34h],bx
		mov	[bp-32h],bx
		mov	ah,42h			; 'B'
		jmp	short loc_21
loc_19:
		mov	cx,[bp-38h]
		mov	dx,[bp-36h]
		mov	al,[bp+18h]
		mul	byte ptr [bp+1Ah]	; ax = data * al
		xchg	ax,cx
		div	cx			; ax,dx rem=dx:ax/reg
		xchg	ax,dx
		div	byte ptr [bp+18h]	; al,ah rem = ax/data
		mov	cx,dx
		mov	dh,al
		xchg	ch,cl
		ror	cl,1			; Rotate
		ror	cl,1			; Rotate
		or	cl,ah
		inc	cx
		les	bx,dword ptr [bp-3Ch]	; Load 32 bit ptr
		mov	ax,201h
loc_21:
		mov	dl,[bp+24h]
loc_22:
		int	13h			; Disk  dl=drive a  ah=func 02h
						;  read sectors to memory es:bx
              ;  db   0fh
              ;  xor  byte ptr [di-01], 8bh
              ;  inc  si
              ;  or   si, si
              ;  jbe  00cah
              ;  add  [bp-3ah], ax
              ;  add  word ptr [bp-38h],+01
              ;  adc  word ptr [bp-36h],+00
              ;  dec  di
              ;  jnz  00b0h
              ;  mov  es, [bp-3ah]
              ;  pop  si

		db	 0Fh, 82h, 75h,0FFh, 8Bh, 46h
		db	 0Bh,0F6h, 76h,0C0h, 01h, 46h
		db	0C6h, 83h, 46h,0C8h, 01h, 83h
		db	 56h,0CAh, 00h, 4Fh, 75h, 98h
                db       8Eh, 46h,0C6h, 5Eh

                ret      ; db 0c3h
readdisk        endp

bss_data
                db 0
       ENDIF ; FIXEDDISK
       ENDIF ; EXTRAS
    ELSE
; NON-BOOTABLE CODE HERE
;
; format boot code displays message that floppy isnt bootable
; based from Freedos Format 0.91k
boot_code       db 31h,0c0h             ; xor ax, ax
                db 0fah                 ; cli
                db 08eh, 0d0h           ; mov ss, ax
                db 0bch, 0, 7ch         ; mov sp,0x7c00  
                db 0fbh                 ; sti
                db 0eh, 1fh             ; push cs, pop ds 
                db 0ebh, 19h            ; jmp XSTRING
                db 5eh                  ; PRN: pop si  ; string offs  
                db 0fch                 ; cld 
                db 0ach                 ; XLOOP: lodsb
                db 08h, 0c0h            ; or al,al     ; EOF reached?
                db 74h, 09h             ; jz EOF
                db 0b4h, 0eh            ; mov ah,0x0e  ; tty function
                db 0bbh, 07h, 0         ; mov bx,7
                db 0cdh, 10h            ; int 0x10     ; VIDEO BIOS   
                db 0ebh, 0f2h           ; jmp short XLOOP
                db 031h, 0c0h           ; EOF: xor ax,ax ; getkey  
                db 0cdh, 16h            ; int 0x16     ; KEYB BIOS   
                db 0cdh, 19h            ; int 0x19     ; REBOOT  
                db 0f4h                 ; HANG: hlt    ; save energy
                db 0ebh, 0fdh           ; jmp short HANG  
                db 0e8h, 0e4h, 0ffh     ; XSTRING: call PRN
boot_message    db 'This is not a bootable disk. Please insert a bootable floppy and',0ah,0dh
                db 'press any key to try again...',0ah,0dh,0
    ENDIF ; BOOTABLE
IF (EXTRAS)

; BSSLIB.ASM

; ===========================================================================
_tty    proc near
; ===========================================================================
        push ax
        push cx
        push dx
        push bx
        mov  ah, 0eh
        mov  bl,7
        int  10h
        pop  bx
        pop  dx
        pop  cx
        pop  ax
        ret
_tty    endp

; ===========================================================================
tty     proc near
; ===========================================================================
        push ax
        cld
_tty1:  lodsb             ; write ascii-z string to display using bios
        test  al, al
        jz    short _ttyx
        cmp   al, 0ffh
        jne   short _tty2
        mov   ax, 0e0ah
        int   10h
        mov   al, 0dh
_tty2:
        call  _tty
        jmp   short _tty1
_ttyx:
        pop  ax
        ret
tty     endp

; ===========================================================================
newline proc near
; ===========================================================================
        push ax
        mov  al, 0ah
        call _tty
        mov  al, 0dh
        call _tty
        pop  ax
        ret
newline endp

; ===========================================================================
put_bin  proc near
; ===========================================================================
        push ax
        mov  cx, 16
_pb:    shl  ax, 1
        jnc  _pbzero
        push ax
        mov  al, '1'
        call _tty
        pop  ax
        jmp  _pbx
_pbzero:
        push ax
        mov  al, '0'
        call _tty
        pop ax
_pbx:
        loop _pb
        mov  al, 'b'
        call _tty
        pop  ax
        ret
put_bin  endp

; ===========================================================================
putnum proc near
; ===========================================================================
          push ax
          push bx
          push cx
          push dx
          xor  cx, cx
putnum1:
          xor  dx, dx
          mov  bx, 10
          div  bx
          mov  bx, ax
          mov  ax, dx
          add  al, 48
          push ax                            ; I'll have to use a lifo
          inc  cx
          mov  ax, bx    
          or   ax, ax
          mov  ax, bx
          jnz  putnum1
putnum2:  pop  ax
          call _tty
          dec  cx
          jnz  putnum2
          pop dx
          pop cx
          pop bx
          pop ax
          ret
putnum endp

; ===========================================================================
getkey  proc    near
; ===========================================================================
        xor  ax, ax
        int  16h     
        ret 
getkey  endp

reboot  proc near
        int  19h
        ret
reboot  endp

memavail proc near
        int     12h     
        ; shl     ax, 6   ; KB
        ret
memavail endp

; ===========================================================================
debug proc near
; ===========================================================================
        push ax
        push bx
        push cx
        push dx
        call putnum
        call newline
        mov  ax, bx
        call putnum
        call newline
        mov  ax, cx
        call putnum
        call newline
        mov  ax, dx
        call putnum
        call newline
        pop  dx
        pop  cx
        pop  bx
        pop  ax
        ret
debug endp

; ===========================================================================
resetdrive proc near
; dl = drive
; ===========================================================================
        mov  ah, 0
        int  13h
        ; jc retryreset
        ret
resetdrive endp

; ===========================================================================
readdrive proc near
; ES:BX = buffer
; al    = sector #
; ch    = cylinder
; cl    = sector
; dh    = head
; dl    = drive
; ===========================================================================
retryread:
          push    ax
          mov     al,2Eh  
          call    _tty   
          pop     ax
          mov     ah,2
          int     13h     
          jc      retryread
          ret
readdrive endp

IF (BSSLIB2)

; 9-25-2006

ClusterLBA proc near
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
; AX = Cluster
; BL = SPC
; DX = Datasector
; Output: AX = LBA 
;*************************************************************************
     push dx
     push cx
     push bx
     dec  ax
     dec  ax       ; sub  ax, 2
     xor  cx, cx
     mov  cl, bl   ; sectorspercluster
     mov  bx, dx   ; BX = Datasector
     mul  cx
     add  ax, bx   ; addin offset into data area
     pop  bx
     pop  cx
     pop  dx
     ret
ClusterLBA endp

LBACHS proc near
;*************************************************************************
; PROCEDURE LBACHS
; convert "ax=2; LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head   = (logical sector / sectors per track) MOD number of heads
; absolute track  = logical sector / (sectors per track * number of heads)
; BX = SPT
; CX = Heads
; AX = LBASECTOR
;*************************************************************************
     push ax
     push bx
     push cx
     push dx

     push ax
     push bx
     push cx
     xor  dx, dx
     div  bx
     inc  dl
     mov  byte ptr [BASE+sector], dl
     pop  bx  ; heads
     xor  dx, dx
     div  bx
     mov  byte ptr [BASE+Head], dl
     mov  byte ptr [BASE+Track], al
     pop  bx
     pop  bx

     push dx
     push cx
     push bx
     push ax

     ret
sector db ?
head   db ?
track  db ?
LBACHS endp

ReadSectors proc near
;*************************************************************************
; PROCEDURE ReadSectors
; reads "cx" sectors from disk starting at "ax" into memory location "es:bx"
;*************************************************************************

     mov     di, 3                           ; five retries for error
RSL:
     push    ax
     push    bx
     push    cx
     call    LBACHS
     mov     ah, 02                            ; BIOS read sector
     mov     al, 01                            ; read one sector
     mov     ch, byte ptr [BASE+Track]            ; track
     mov     cl, byte ptr [BASE+Sector]           ; sector
     mov     dh, byte ptr [BASE+Head]             ; head
     mov     dl, byte ptr [BASE+bPhysicaldrvno]              ; drive
     int     13h                                ; invoke BIOS
     jnc     RSX                                 ; test for read error
     xor     ax, ax                              ; BIOS reset disk
     int     13h                                ; invoke BIOS
     dec     di                                  ; decrement error counter
     pop     cx
     pop     bx
     pop     ax
     jnz     RSL                                 ; attempt to read again
RSX: ret
ReadSectors endp

LOADIMAGE proc near
LOAD_IMAGE:
     mov     ax, word ptr [BASE+cluster]                  ; cluster to read
     push    bx
     call    ClusterLBA                          ; convert cluster to LBA
     xor     cx, cx
     mov     cl, BYTE PTR [BASE+bSectsperclust]        ; sectors to read
     call    ReadSectors
     push    bx
; compute next cluster
     mov     ax, word ptr [BASE+cluster]                  ; identify current cluster
     mov     cx, ax                              ; copy current cluster
     mov     dx, ax                              ; copy current cluster
     shr     dx, 0001h                         ;divide by two
     add     cx, dx                              ; sum for (3/2)
     mov     bx, 0200h                         ; location of FAT in memory
     add     bx, cx                              ; index into FAT
     mov     dx, word ptr [bx]                       ; read two bytes from FAT
     test    ax, 0001h
     jnz     ODD_CLUSTER
EVEN_CLUSTER:
     and     dx, 0000111111111111b               ; take low twelve bits
    jmp     __DONE
ODD_CLUSTER:
     shr     dx, 0004h                          ; take high twelve bits
__DONE:
     mov     word ptr [BASE+cluster], dx                  ; store new cluster
     cmp     dx, 0FF0h                          ; test for end of file
     jb      LOAD_IMAGE
_SUCCESS:
     pop     cx
     pop     bx
     pop     ax
     add     bx, word ptr [BASE+wSectsize]           ; queue next buffer
     inc     ax                                  ; queue next sector
     loop    LOAD_IMAGE                               ; read next sector

     ret
LOADIMAGE endp
ENDIF ; BSSLIB2

ENDIF ; EXTRAS

ENDIF ; MBR

metakern endp

CodeSize        EQU $-start          ; org boot+200h-2
$padding        EQU (512-CodeSize-2)
IF ($padding) 
padding         db $padding dup(0)
ENDIF
bootsignature   db 55h,0aah

boot ends
     end     start

; ===========================================================================
; === END OF METAKERN.ASM ===================================================
; ===========================================================================
