; loader.asm
;
; originally written on Fri  05-27-1994  by Ed Beroset
;
; rewritten on Sun  11-25-2001  by Ed Beroset
;

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, (extra - 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 (?)
        extra           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 public use16 at 2000h
  org 0h
  destination proc far
  destination endp
yonder ends


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
        call    CalcClust2 C,                                 \
                WORD ptr [(BootSector PTR bx).ResSectors],    \
                WORD ptr [(BootSector PTR bx).FATsecs],       \
                WORD ptr [(BootSector PTR bx).FATs]
        ; now dx:ax contains the logical sector for cluster 2
        call    LsectToGeom C,                                \
                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)

        call    FindFile C, \
                bx, 200h * 40h, offset BootFileName
        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

        call    LsectToGeom C, \
                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
ENDP    main

;****************************************************************************
;
; 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 lHiddenSecs:DWORD,    \
                      lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD
        USES    ax                      ;save registers we'll use
        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 dirbuffer:WORD, limit:WORD, filespec:WORD
        USES    cx, dx, di, si, es
        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
