;*************************************************************************
;Name: R.P.I.T. Somasiri
;E-mail: ishanthilina@gmail.com
;-------------------------------------------------------------------------
;the ultimate boot-strap loader
;to load a file from a DOS FAT32 Disk as the OS
;*************************************************************************

ORG 0x7c00
jmp START
nop
 bs_OEM db "MSDOS5.0"

    A_BF_BPB_BytesPerSector       DW    200h
    A_BF_BPB_SectorsPerCluster    DB    8h
    A_BF_BPB_ReservedSectors      DW    01f0h
    A_BF_BPB_NumberOfFATs         DB    02
    A_BF_BPB_RootEntries          DW    0
    A_BF_BPB_TotalSectors         DW    0
    A_BF_BPB_MediaDescriptor      DB    0f8h
    A_BF_BPB_SectorsPerFAT        DW    0
    A_BF_BPB_SectorsPerTrack      DW    03fh
    A_BF_BPB_Heads                DW    0ffh
    A_BF_BPB_HiddenSectors        DW    080h
    A_BF_BPB_HiddenSectorsHigh    DW    0h
    A_BF_BPB_BigTotalSectors      DW    3f00h
    A_BF_BPB_BigTotalSectorsHigh  DW    03ch
    A_BF_BPB_BigSectorsPerFat     DW    0f08h
    A_BF_BPB_BigSectorsPerFatHi   DW    0h
    A_BF_BPB_ExtFlags             DW    0
    A_BF_BPB_FS_Version           DW    0
    A_BF_BPB_RootDirStrtClus      DW    2
    A_BF_BPB_RootDirStrtClusHi    DW    0
    A_BF_BPB_FSInfoSec            DW    1h
    A_BF_BPB_BkUpBootSec          DW    6h
    A_BF_BPB_Reserved             DW    6 DUP (?)

BS_physical db 80h
db 00
BS_bootrecord db 29h
volumeid dd 0AE6DA6B2h
volumelabel db "No Name    "
filesystem db "FAT32   "

     
     START:
     ; code located at 0000:7C00, adjust segment registers
          cli
          mov     ax, 0x07C0
          mov     ds, ax
          mov     es, ax
          mov     fs, ax
          mov     gs, ax
     ; create stack
          mov     ax, 0x0000
          mov     ss, ax
          mov     sp, 0xFFFF
          sti



	  

      ; size of a cluster in sectors is stored in cx 
          mov    cx,  WORD[A_BF_BPB_SectorsPerCluster]


     ; compute location of the begining of the Data area and store in ax
          mov     al, BYTE [A_BF_BPB_NumberOfFATs]                ; Total number of FATs
          mul     WORD[A_BF_BPB_BigSectorsPerFat]                ; Number of sectors for a FAT
          add     ax, WORD [A_BF_BPB_ReservedSectors]          ; Find the start of the Data area
          mov     WORD [datasector], ax               ; Store the begining of the Data area



     ; read 1st data cluster into memory (7C00:0200)
          mov     ax, WORD[A_BF_BPB_RootDirStrtClus]
          call ClusterLBA
          mov     bx, 0x0200                          ; copy 1st data cluter above bootcode
          call    ReadSectors

   
     ; Point Index register to 1st File Entry
          mov     di, 0x0200 + 0x20                         

     
     

          mov     si, msgCRLF
          call    DisplayMessage
          
      ;Point to the offset where the file location information contains
      
          mov     dx, WORD [di + 0x001A]
          mov     WORD [cluster], dx                  




	   
          
	;Set up the segments where the kernel needs to be loaded
	
            mov ax, 0100h       ; set ES:BX = 0100:0000
            mov es, ax          
            mov bx, 0           
	   
	;Read the cluster which contains the kernel
            mov cx, 0x0008	
            mov ax, WORD[cluster]
            call ClusterLBA
            call ReadSectors
            
            
            


          mov     si, msgCRLF
          call    DisplayMessage
	
	;Jump to the location where the kernel was loded
	
          push    WORD 0x0100
          push    WORD 0x0000
          retf




	;An error has occured if this part is executed
          mov     si, msgFailure
          call    DisplayMessage
          mov     ah, 0x00
          int     0x16                                ; await keypress
          int     0x19                                ; warm boot computer







     ;*************************************************************************
     ; PROCEDURE ReadSectors
     ; reads ?cx? sectors from disk starting at ?ax? into
     ;memory location ?es:bx?
     ;*************************************************************************
     ReadSectors:
     .MAIN:
          mov     di, 0x0005                          ; five retries for error
     .SECTORLOOP:
          push    ax
          push    bx
          push    cx
          call    LBACHS
          mov     ah, 0x02                            ; BIOS read sector
          mov     al, 0x01                            ; read one sector
          mov     ch, BYTE [absoluteTrack]            ; track
          mov     cl, BYTE [absoluteSector]           ; sector
          mov     dh, BYTE [absoluteHead]             ; head
          mov     dl, BYTE [BS_physical]              ; drive
          int     0x13                                ; invoke BIOS
          jnc     .SUCCESS                            ; test for read error
          xor     ax, ax                              ; BIOS reset disk
          int     0x13                                ; invoke BIOS
          dec     di                                  ; decrement error counter
          pop     cx
          pop     bx
          pop     ax
          jnz     .SECTORLOOP                         ; attempt to read again
          int     0x18
     .SUCCESS:
          mov     si, msgProgress
          call    DisplayMessage
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [A_BF_BPB_BytesPerSector]           ; queue next buffer
          inc     ax                                  ; queue next sector
          loop    .MAIN                               ; read next sector
          ret

     
     ;*************************************************************************
     ; PROCEDURE DisplayMessage
     ; display ASCIIZ string at ds:si via BIOS
     ;*************************************************************************
     DisplayMessage:
          lodsb                                       ; load next character
          or      al, al                              ; test for NUL character
          jz      .DONE
          mov     ah, 0x0E                            ; BIOS teletype
          mov     bh, 0x00                            ; display page 0
          mov     bl, 0x07                            ; text attribute
          int     0x10                                ; invoke BIOS
          jmp     DisplayMessage
     .DONE:
          ret
     
     ;*************************************************************************



     ;*************************************************************************
     ; PROCEDURE ClusterLBA
     ; convert FAT cluster into LBA addressing scheme
     ; FileStartSector = ((X - 2) * A_BF_BPB_SectorsPerCluster(0x08))
     ;*************************************************************************
     ClusterLBA:
          sub     ax, 0x0002                          ; zero base cluster number
          xor     cx, cx
          mov     cl, BYTE [A_BF_BPB_SectorsPerCluster]        ; convert byte to word
          mul     cx
          add     ax, WORD [datasector]               ; base data sector
          ret


     ;*************************************************************************
     ; PROCEDURE LBACHS
     ; convert ?ax? 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)
     ;*************************************************************************
     LBACHS:
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [A_BF_BPB_SectorsPerTrack]              ; calculate
          inc     dl                                  ; adjust for sector 0
          mov     BYTE [absoluteSector], dl
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [A_BF_BPB_Heads]                     ; calculate
          mov     BYTE [absoluteHead], dl
          mov     BYTE [absoluteTrack], al
          ret
      ;************************************************************************

     absoluteSector db 0x00
     absoluteHead   db 0x00
     absoluteTrack  db 0x00

     cluster     dw 0x0000
     datasector  dw 0x0000

;*******************************************************************************
;messages that needs to be shown

     msgProgress db ".", 0x00
     msgFailure  db 0x0D, 0x0A, "Kernel loading failed...", 0x0D, 0x0A, 0x00
     msgCRLF     db 0x0D, 0x0A, 0x00
     
          TIMES 510-($-$$) DB 0
          DW 0xAA55
     ;*************************************************************************
