; loader.asm
;
; originally written on Fri  05-27-1994  by Ed Beroset
;
; rewritten on Sun  11-25-2001  by Ed Beroset
;

CalcClust2 PROTO   C cResSectors:WORD, cFATsecs:WORD, cFATs:BYTE
LsectToGeom PROTO  C lHiddenSecs:DWORD,    \
                      lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD
FindFile PROTO C dirbuffer:WORD, limit:WORD, filespec:WORD
public BootFileName

PartEntry STRUC
        Bootable        db ?    ;80h = bootable, 00h = nonbootable
        BeginHead       db ?    ;beginning head
        BeginSector     db ?    ;beginning sector
        BeginCylinder   db ?    ;beginning cylinder
        FileSystem      db ?    ;name of file system
        EndHead         db ?    ;ending head
        EndSector       db ?    ;ending sector
        EndCylinder     db ?    ;ending cylinder
        StartSector     dd ?    ;starting sector (relative to beg. of disk)
        PartSectors     dd ?    ;number of sectors in partition
PartEntry ENDS

BootSector STRUC
        bsJump          db 0EBh, 03eh, 090h ;(bsExtra - bsJump), 090h
          ; E9 XX XX or EB xx 90
        OemName       db 8 dup (?)    ; OEM name and version
        ; start of BIOS parameter block
        BytesPerSec   dw ?      ; bytes per sector
        SecPerClust   db ?      ; sectors per cluster
        ResSectors    dw ?      ; number of reserved sectors
        FATs          db ?      ; number of FATs
        RootDirEnts   dw ?      ; number of root directory entries
        Sectors       dw ?      ; total number of sectors (see HugeSectors)
        Media         db ?      ; media descriptor byte (0f0h for floppies)
        FATsecs       dw ?      ; number of sectors per FAT
        SecPerTrack   dw ?      ; sectors per track
        Heads         dw ?      ; number of heads
        HiddenSecs    dd ?      ; number of hidden sectors
        HugeSectors   dd ?      ; number of sectors if Sectors equals 0
        ; end of BIOS parameter block
        DriveNumber   db ?      ;
        Reserved1     db ?      ;
        BootSignature db ?      ;
        VolumeID      dd ?      ;
        VolumeLabel   db 11 dup (?)
        FileSysType   db 8 dup (?)
        bsExtra       dw ?
BootSector ENDS

DirEntry STRUC
        FileName        db '????????'   ;name
        Extension       db '???'        ;extension
        Attributes      db ?            ;attributes
        Reserved        db 10 dup (?)   ;reserved
        Time            dw ?            ;time stamp
        Date            dw ?            ;date stamp
        StartCluster    dw ?            ;starting cluster
        FileSize        dd ?            ;file size
DirEntry ENDS

CR      EQU     0DH
LF      EQU     0AH

yonder segment para use16 at 2000h
  org 0h
  destination proc far
  destination endp
yonder ends

myfilename = offset BootFileName

code segment para public use16 '_CODE'
        .386
        assume cs:code, ds:code, es:code, ss:code
        org 7c00h
main PROC
MBR:
Boot bootsector < ,'BEROSET ',512,1,1,2,224,2880,0f0h,9,18,2,\
          0,0,0,0,29h,02a04063ch,'BEROSET 001',\
          'FAT12   ',07df1h>
over:
        mov     ax,cs               ;
        cli
        mov     ss,ax                   ; point ss:sp to CS:7c00h
        mov     sp,7c00h                ; which sets up a stack in first 64K
        sti
        mov     ds,ax
        mov     es,ax
;****************************************************************************
;
; CalcClustOff - calculates the starting logical sector number of
;               cluster 0, which isn't really a cluster, but the
;               number returned is useful for calculations converting
;               cluster number to logical sector
;
; INPUT:     ResSectors, FATsecs, FATs
; OUTPUT:    dx:ax contains the starting logical sector number
; DESTROYED: none
;
;****************************************************************************
CalcClustOff PROC
        xor     dh,dh
        mov     ax,[Boot.FatSecs]
        mov     dl,[Boot.FATs]
        mul     dx
        add     ax,[Boot.ResSectors]
        adc     dx,0
        ; now dx:ax = FATs * FATsecs + ResSectors
        mov     word ptr [ClustOffs],ax
        mov     word ptr [ClustOffs+2],dx
        mov     dx,20h                  ; bytes per dir entry
        mov     ax,[Boot.RootDirEnts]
        mul     dx                      ; multiply 'em out
        div     word ptr [Boot.BytesPerSec]  ; and divide by bytes/sec
        add     word ptr [ClustOffs],ax
        adc     word ptr [ClustOffs+2],dx ; create the aggregate
        mov     al,[Boot.SecPerClust] ;
        xor     ah,ah                   ;
        shl     ax,1                    ; AX = SecPerClust * 2
        sub     word ptr [ClustOffs],ax  ;
        sbb     word ptr [ClustOffs+2],0 ; propagate carry flag
;        mov     ax,word ptr [ClustOffs]   ;
;        mov     dx,word ptr [ClustOffs+2] ;
;        ret
CalcClustOff ENDP

;        mov     WORD ptr [ClustOffs],ax
;        mov     WORD ptr [ClustOffs+2],dx
        mov     bx,offset Boot
        invoke CalcClust2 ,                                 \
                WORD ptr (BootSector PTR [bx]).ResSectors,    \
                WORD ptr (BootSector PTR [bx]).FATsecs,       \
                BYTE ptr (BootSector PTR [bx]).FATs
        ; now dx:ax contains the logical sector for cluster 2
        invoke  LsectToGeom ,                                \
                WORD ptr (BootSector PTR [bx]).HiddenSecs  ,  \
                WORD ptr ((BootSector PTR [bx]).HiddenSecs+2),\
                (BootSector PTR [bx]).Heads,                  \
                (BootSector PTR [bx]).SecPerTrack

        mov     dl,(BootSector PTR [bx]).DriveNumber
        mov     bx,offset buff
retry1:
        mov     al,(BootSector PTR [MBR]).SecPerClust
        mov     ah,2h                   ; get ready to read
        int     13h
        jc      retry1
        ; now find our desired filename within buffer (which has the root dir)

        invoke  FindFile, \
                bx, 200h * 40h, 07d80h
        xor     dh,dh
        mov     dl,(BootSector PTR [MBR]).SecPerClust
        mov     si,ax
        mov     ax,(DirEntry PTR [si]).StartCluster
        mul     dx
        add     ax,WORD ptr [ClustOffs]
        adc     dx,WORD ptr [ClustOffs+2]
        ; now dx:ax contains logical sector number for start of file

        invoke LsectToGeom, \
                WORD ptr (BootSector PTR [MBR]).HiddenSecs  ,  \
                WORD ptr ((BootSector PTR [MBR]).HiddenSecs)+2,\
                (BootSector PTR [MBR]).Heads,                  \
                (BootSector PTR [MBR]).SecPerTrack
retry2:
        mov     si,offset Boot
        mov     dl,(BootSector PTR [si]).DriveNumber
        mov     ah,2h
        ; read in a cluster's worth of data
        mov     al,(BootSector PTR [si]).SecPerClust
        ; point to our magic location
        mov     bx,seg destination
        mov     es,bx
        mov     bx,offset destination
        int     13h
        jc      retry2
@@exit:
        jmp     destination
main   ENDP

;****************************************************************************
;
; LsectToGeom - converts from logical sector number to the physical
;               geometry (head, cylinder, track) in the form required
;               by the BIOS (Int 13h) disk read and write calls.
;
; INPUT:     dx:ax=lsect, HiddenSecs, Heads, SecPerTrack
; OUTPUT:    cx, dx are set with cylinder/track, and head respectively
; DESTROYED: none
;****************************************************************************
LsectToGeom PROC C USES ax,              ;save registers we'll use
        lHiddenSecs:DWORD,    \
                      lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD
        stc                             ;add one additional
        adc     ax, WORD ptr [lHiddenSecs]   ;add starting sector
        adc     dx, WORD ptr [lHiddenSecs+2] ;
        div     [lSecPerTrack]          ;
        mov     cl,dl                   ;store sector in cl
        xor     dx,dx                   ;
        div     [lHeads]                ;
        mov     dh,dl                   ;store head in dh
        mov     ch,al                   ;store low 8 bits of cylinder in ch
        shr     ax,1                    ;
        shr     ax,1                    ;
        and     al,0c0h                 ;pass through two hi bits only
        or      cl,ah                   ;mov bits into location
        ret                             ;
LsectToGeom ENDP

;****************************************************************************
;
; CalcClust2  - calculates the starting logical sector number of
;               cluster 2, (the beginning of data space for
;               partitions).
;
; INPUT:     ResSectors, FATsecs, FATs
; OUTPUT:    dx:ax contains the starting logical sector number
; DESTROYED: none
;
;****************************************************************************
CalcClust2 PROC    C cResSectors:WORD, cFATsecs:WORD, cFATs:BYTE
        xor     dx,dx                   ;
        mov     ax,[cFATsecs]           ;
        mul     [cFATs]                 ;
        add     ax,[cResSectors]        ;
        adc     dx,0                    ;
        ret
CalcClust2 ENDP

;****************************************************************************
;
; FindFile -    given a memory buffer containing the directory data
;               and a static file name for which to search, this routine
;               finds the file and returns a pointer to its directory
;               entry in ds:si
;
; INPUT:        dirbuffer, filespec
; OUTPUT:       ax    contains pointer to directory entry (or NULL)
; DESTROYED:    none
;****************************************************************************

FindFile PROC C USES    cx dx di si es,
          dirbuffer:WORD, limit:WORD, filespec:WORD
        mov     cx,ds                   ;
        mov     es,cx                   ; es and ds point to same segment
        cld                             ; always count forward
        mov     ax,[dirbuffer]          ; load 'em up
        add     [limit],ax
        mov     dx,[filespec]           ;
keepsearching:
        mov     cx,11                   ; size of dos filename (8.3)
        mov     si,dx                   ;
        mov     di,ax                   ;
        repe    cmpsb                   ; compare 'em
        jz      foundit                 ;
        add     ax,20h                  ; size of directory entry
        cmp     ax,[limit]
        jb      keepsearching
        xor     ax,ax

foundit:
        ret
FindFile ENDP


BootFileName  db  "BEROSET SYS"         ;the boot loader for this OS
; MBR           db  0200h DUP (?)
buff          db  0200h * 40h DUP (?)
ClustOffs     dd  ?
        org 7dfeh
        dw      0AA55h          ; signature byte
code ends

        END main
