; ****************************************************************************
;
; TRFDBOOT.ASM
;
; Turkish Rational's
; (MS-DOS 6.2 Clone) Disk Operation System v1.0 Project
; TR-DOS Executer (MS-DOS Filesystem) Presentation 2000 Floppy Disk Boot Code
;
; Copyright (C) 1998  Erdogan TAN  [ Last Modification: 18/04/2000 ]
;
; ****************************************************************************

trmagicword     equ    01A1h
notvalidfmask   equ    0018h

destination     equ    7E00h
bootstack       equ    7BFAh

sizeBPB         equ    0019h
sizeofdirentry  equ    0020h

RxDOSBOOT       SEGMENT PUBLIC 'CODE'
                assume cs:RxDOSBOOT, ds:RxDOSBOOT, es:RxDOSBOOT, ss:RxDOSBOOT

                org 100h

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Write Stub                                                   ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  The stub loads at the normal 100h load address and writes    ;
        ;  the boot sector to drive A:                                  ;
        ;...............................................................;

RxDOS_WRITESTUB:

                cli
                cld
                push cs
                pop ss
                mov sp, 0FFFEh
                sti

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; see if drive specified
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                mov si, offset 80h                      ; PSP command tail
                mov cl, byte ptr [ si ]
                or cl, cl                               
                jz RxDOS_WRITESTUB_12                   ; jump if zero

RxDOS_WRITESTUB_06:
                inc si
                mov al, byte ptr [ si ]
                cmp al, ' '                             ; is it SPACE ?
                jnz RxDOS_WRITESTUB_08

                dec cl                                  
                jnz RxDOS_WRITESTUB_06                  
                jmp short RxDOS_WRITESTUB_12

RxDOS_PRINT     proc near

RxDOS_PRINT_LOOP:
                lodsb                           ; Load byte at DS:SI to AL
                and     AL,AL            
                jz      RxDOS_PRINT_OK       
		mov	AH,0Eh			
                mov     BX,07h             
		int	10h			; BIOS Service func ( ah ) = 0Eh
                                                ; Write char as TTY
						;AL-char BH-page BL-color
                jmp     RxDOS_PRINT_LOOP           

RxDOS_PRINT_OK:
                retn

RxDOS_PRINT     endp

RxDOS_WRITESTUB_08:
                cmp al, '0'                             ; 0 - 9
                jc RxDOS_WRITESTUB_12
                cmp al, '9' + 1                         ; allow number for drive
                jc RxDOS_WRITESTUB_09                    
                cmp al, 'A'
                jc RxDOS_WRITESTUB_12
                cmp al, 'Z' + 1                         ; A - Z
                jc RxDOS_WRITESTUB_10                    
                cmp al, 'a'                             ; a - z 
                jc RxDOS_WRITESTUB_12                  
                cmp al, 'z' + 1                           
                jnc RxDOS_WRITESTUB_12                 

                sub al, 'a'-'A'                         ; to upper case

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; get drive code
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_10:
                mov byte ptr RxDOS_DRIVE, al
                jmp RxDOS_WRITESTUB_20


RxDOS_WRITESTUB_09:
                add al, 'A'-'0'                         ; 0 based -> A based
                jmp RxDOS_WRITESTUB_10 

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Write message
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_12:
                mov si, offset RxDOS_Welcome
                call RxDOS_PRINT
                cmp cl,0
                ja RxDOS_WRITESTUB_60

RxDOS_WRITESTUB_13:
                mov si, offset RxDOS_PressKeyWhenReady
                call RxDOS_PRINT

RxDOS_WRITESTUB_14:
                xor ax, ax
                int 16h                                 ; wait for keyboard command
                push ax
                mov si, offset RxDOS_CRLF
                call RxDOS_PRINT
                pop ax
                cmp al, 'M'-40h                         ; Enter (OK) key
                jz RxDOS_WRITESTUB_20                   ; write
                cmp al, 'C'-40h
                jz RxDOS_WRITESTUB_60                   ; no write (exit)
                cmp al, 27
                jz RxDOS_WRITESTUB_60
                jmp RxDOS_WRITESTUB_13                  ; No write (exit)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; get drive parameters
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_20:
                mov ah, 08h
                mov dl, byte ptr RxDOS_DRIVE            ; drive
                sub dl, 'A'                             ; make it zero based 
                int 13h                                 ; return disk parameters

                push cs
                pop es                                  ; restore es:

                xor bh, bh
                mov ax, bx                              ; drive type
                dec ax                                  ; make it zero based
                mov cx, sizeBPB
                mul cx
                mov si, offset DriveDefaultData
                add si, ax
                mov di, offset bsBytesPerSec                            
                rep movsb                               ; copy correct BPB info
        
                xor ax, ax
                int 1Ah                                 ; get time of day

                mov word ptr [bsVolumeID], dx
                mov word ptr [bsVolumeID+2], cx         ; set unique volume ID

                mov ax, 0301h                           ; write to disk
                mov bx, offset start                    ; location of boot code

                mov ch, 00                              ; cylinder = 0
                mov cl, 01                              ; sector = 1

                mov dh, 00                              ; head = 0
                mov dl, byte ptr RxDOS_DRIVE            ; drive 
                sub dl,'A'                              ; make it zero based
                int 13h

                jnc RxDOS_WRITESTUB_36                  ; if everything is ok -->

RxDOS_WRITESTUB_30:
                mov si, offset RxDOS_disk_NotReadyOrError
                call RxDOS_PRINT
                jmp short RxDOS_WRITESTUB_40

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; success. try again ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_36:
                mov si, offset RxDOS_disk_WrittenSuccesfully
                call RxDOS_PRINT
                jmp RxDOS_WRITESTUB_60

RxDOS_WRITESTUB_40:
                xor ax, ax
                int 16h                                 ; wait for keyboard command
                push ax
                mov si, offset RxDOS_CRLF
                call RxDOS_PRINT
                pop ax
                cmp al, 'y'
                jz RxDOS_WRITESTUB_13                   ; retry
                cmp al, 'Y'
                jz RxDOS_WRITESTUB_13
                cmp al, 'n'
                jz RxDOS_WRITESTUB_60                   ; exit
                cmp al, 'N'
                jz RxDOS_WRITESTUB_60
                cmp al, 'C'-40h
                jz RxDOS_WRITESTUB_60                   
                cmp al, 27
                jz RxDOS_WRITESTUB_60
                jz RxDOS_WRITESTUB_30                   ; repeat the message

RxDOS_WRITESTUB_60:
                mov ax, 4c00h                           ; terminate
                int 21h

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  messages
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_Welcome:
                db 0Dh, 0Ah
                db 'TR-DOS Floppy Disk Boot Sector Rebuilder v1.0'
                db 0Dh, 0Ah
                db '(c) Erdogan TAN 1998'
                db 0dh,0Ah
                db 0Dh,0Ah
                db 'Usage: trfdboot [drive]'
RxDOS_CRLF:
                db 0Dh, 0Ah, 0

RxDOS_PressKeyWhenReady:
                db 0Dh, 0Ah
                db 'Press Enter to write boot sector on disk '

RxDOS_Drive:
                db 'A: ', 0

RxDOS_disk_WrittenSuccesfully:
                db 0Dh, 0Ah
                db 'Boot sector updated to TR-DOS X format...'
                db 0Dh, 0Ah
                db 0

RxDOS_disk_NotReadyOrError:
                db 0Dh, 0Ah
                db 'Disk error or drive not ready. Try again? (Y/N) '
                db 0


;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  Drive Default Data
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
DriveDefaultData:

    ; 360k drive   **needs updating**

                dw 512                                  ; BytesPerSector
                db 1                                    ; SectorsPerCluster
                dw 1                                    ; ResSectors
                db 2                                    ; NumCopiesFAT
                dw 00E0h                                ; MaxAllocRootDir
                dw 0960h                                ; MaxSectors
                db 0f9h                                 ; MediaDescriptor
                dw 7                                    ; SectorsPerFat
                dw 15                                   ; SectorsPerTrack
                dw 2                                    ; Heads
                dd 0                                    ; HiddenSectors
                dd 0                                    ; HugeSectors

    ; 1.2M drive

                dw 512                                  ; BytesPerSector
                db 1                                    ; SectorsPerCluster
                dw 1                                    ; ResSectors
                db 2                                    ; NumCopiesFAT
                dw 00E0h                                ; MaxAllocRootDir
                dw 0960h                                ; MaxSectors
                db 0f9h                                 ; MediaDescriptor
                dw 7                                    ; SectorsPerFat
                dw 15                                   ; SectorsPerTrack
                dw 2                                    ; Heads
                dd 0                                    ; HiddenSectors
                dd 0                                    ; HugeSectors
        
    ; 720k drive  **needs updating**

                dw 512                                  ; BytesPerSector
                db 1                                    ; SectorsPerCluster
                dw 1                                    ; ResSectors
                db 2                                    ; NumCopiesFAT
                dw 00E0h                                ; MaxAllocRootDir
                dw 0960h                                ; MaxSectors
                db 0f9h                                 ; MediaDescriptor
                dw 7                                    ; SectorsPerFat
                dw 15                                   ; SectorsPerTrack
                dw 2                                    ; Heads
                dd 0                                    ; HiddenSectors
                dd 0                                    ; HugeSectors

    ; 1.44M drive

                dw 512                                  ; BytesPerSector
                db 1                                    ; SectorsPerCluster
                dw 1                                    ; ResSectors
                db 2                                    ; NumCopiesFAT
                dw 224                                  ; MaxAllocRootDir
                dw 2880                                 ; MaxSectors
                db 0f0h                                 ; MediaDescriptor
                dw 9                                    ; SectorsPerFat
                dw 18                                   ; SectorsPerTrack
                dw 2                                    ; Heads
                dd 0                                    ; HiddenSectors
                dd 0                                    ; HugeSectors

                db  '(c) Erdogan TAN 1998'

                db  1 dup (?)                           ; trick for assembler
                                                        ; to keep 'start'
                                                        ; at 7C00h
                org 7C00h

;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;±
;±		PROCEDURE proc_start
;±
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

proc_start      proc    near

start:
                jmp     short loc_2
                nop

; BootSector Identification (Data) Block

bsOemName       db 'TR-DOS X'          
bsBytesPerSec   dw ?
bsSecPerClust   db ?
bsResSectors    dw ?
bsFATs          db ?
bsRootDirEnts   dw ?
bsSectors       dw ?
bsMedia         db ?
bsFATsecs       dw ?
bsSecPerTrack   dw ?
bsHeads         dw ?
bsHiddenSecs    label dword
bsHidden1       dw ?
bsHidden2       dw ?
bsHugeSectors   label dword
bsHugeSec1      dw ?
bsHugeSec2      dw ?
bsDriveNumber   db ?
bsReserved1     db ?
bsbootsignature db 29h                 
bsVolumeID      dd ?
bsVolumeLabel   db 11 dup(?)
bsFileSysType   db "FAT12   "          
bsReserved2     dw ?

loc_2:          
                xor     AX,AX            
                mov     DS,AX
                mov     ES,AX
                mov     SS,AX
                mov     SP,bootstack            ; 7BFAh

                mov     BP,7C00h                ; Bootsector location on memory
                mov     DL,byte ptr bsDriveNumber ; Fixed. 18/04/2000
                int     13h                     ; BIOS Service func ( ah ) = 0
                                                ; Reset disk system
                jc      short loc_ioerr         ; To print i/o error message
loc_3:                                          ; AX = 0 for AMIBIOS (no error)
                mov     AL,Byte Ptr bsFATs      ; BP+10h = Number of FATs
                mul     Word Ptr bsFATsecs      ; BP+16h = # of FAT sectors
                add     AX,Word Ptr bsHidden1   ; BP+1Ch = Hidden sectors LSW
                adc     DX,Word Ptr bsHidden2   ; BP+1Eh = Hidden sectors MSW
                add     AX,Word Ptr bsResSectors; BP+0Eh = Reserved sectors
                adc     DX,0                    ; ADD with carry
                push    AX                      ; LSW of root directory location
                push    DX                      ; MSW of root directory location
                mov     Word Ptr [BP-4],AX      ; LSW of Data Area = 7BFCh
                mov     Word Ptr [BP-2],DX      ; MSW of Data Area = 7BFEh
                mov     AX,sizeofdirentry       ; Size of a directory entry (32)
                mov     SI,Word Ptr bsRootDirEnts ; BP+11h = Root dir entries
		mul	SI			; DX_AX = AX * data
                mov     BX,Word Ptr bsBytesPerSec ; BP+0Bh = Bytes per sector
                add     AX,BX                   ; Round up
		dec	AX			
                div	BX			; AX=AX_DX/data DX=AX_DX%data
                add     Word Ptr [BP-4],AX      ; Location of the first data cluster
                adc     Word Ptr [BP-2],0       ; 
                pop     DX                      ; DX_AX = Location of root directory
		pop	AX			
loc_4:                                 
                mov     BX,destination          ; Destination offset = 7E00h
		mov	DI,BX			
                mov     CX,1                    ; Sector count for transfer
                call    proc_read  
loc_5:          
                jc      short loc_failed        ; Transaction failed message
loc_6:          
                cmp     Byte Ptr [DI],00h       ; Is it null entry?
                je      short loc_nofile        ; Jump if zero ( = )
                mov     CX,0Bh                  ; Size of file/directory name
                push    SI                      ; SI = number of the entries
                push    DI
                mov     SI,offset stdfilename   ; Offset of the std file name
                repe    cmpsb                   ; Repeat if ZF = 1, CX > 0
						; Cmp byte at DS:SI to ES:DI
                pop     DI
                pop	SI
                je      short loc_found         ; If the file name found
                dec     SI                      
                jz      short loc_nofile        ; Jump if no next entry
                add     DI,20h                  ; To next directory entry
                cmp     DI,BX                   ; Any more on current sector?
                jb      short loc_6             ; Jump if it is no last 
                jmp     short loc_4             ; Jump for next sector
loc_nofile:          
                mov     Byte Ptr notfoundmsg,20h
                mov     SI,offset stdfilename
                jmp     short loc_9
loc_boss:       
                mov     DI,trmagicword
                jmp     short loc_9
loc_ioerr:      
                mov     SI, offset IOerrormsg       
                jmp     short loc_9      
loc_failed:
                mov     SI,offset failmessage
loc_9:          
		lodsb				; Load byte at DS:SI to AL
                and     AL,AL            
                je      short loc_reboot        ; If AL = 00h then stop
		mov	AH,0Eh			
                mov     BX,07h             
		int	10h			; BIOS Service func ( ah ) = 0Eh
						; Write char as TTY
						;AL-char BH-page BL-color
                jmp     short loc_9           
loc_reboot:     
                mov     SI,offset rebootmsg
                cmp     DI,trmagicword          ; Replace/Reboot msg control 
                jne     loc_boss                ; Print Replace/Reboot message
                xor	AX,AX
		int	16h			; BIOS Service func ( ah ) = 0
						; Read next kbd char
						;AH-scan code AL-char code
		int	19h			; Reboot

infinite_loop:  jmp     short infinite_loop     ; Never come here !

loc_found:
                mov     AL,Byte Ptr [DI+0Bh]    ; Move attributes byte to BL
                and     AL,notvalidfmask        ; Is it a file, really?
                ja      short loc_nofile        ; Jump if above ( > )
                mov     AX,Word Ptr [DI+1Ah]    ; First cluster of the file
                cmp     AX,02h                  ; Start cluster
                jb      short loc_failed        ; If It is invalid ( < 2 )               mov     AX,DI

                mov     Word Ptr bsReserved2,AX ; Save the first cluster
                                                ; for using by presentator

                dec     AX                      ; First cluster is cluster 2
                dec     AX               
                mov     CL,Byte Ptr bsSecPerClust
                mul     CX                      ; DX_AX = AX * data
		add	AX,Word Ptr [BP-4]	
		adc	DX,Word Ptr [BP-2]	; ADD with carry

                mov     BX,destination
                push    BX
                call    proc_read               ; CX = sectors per cluster
                pop     BX
                jb      short loc_ioerr         ; If CF = 1 then I/O err msg
                jmp     BX                      ; Jump to 7E00h                dw      0000h,0070h             ;         seg : off

proc_start	endp

proc_read       proc    near
loop_loc_14:            
                push    CX
                push    AX                      ; PHYSICAL ADRESS CALCULATION
                push    DX                      ; DX_AX = Linear address
                div     Word Ptr bsSecPerTrack  ; BP+18h = Sectors per track
                mov     CX,DX                   ; Sector (zero based)
                inc     CL                      ; To make it 1 based
                xor     DX,DX
                div     Word Ptr bsHeads        ; Convert track to head/cylinder
                                                ; AX = cyl, DX = head, CX = sector
                mov     DH,DL
                mov     DL,Byte Ptr bsDriveNumber
		mov	CH,AL			
		ror	AH,1			; Rotate right
                ror     AH,1                   
		or	CL,AH			
                mov     AX,0201h
		int	13h			; BIOS Service func ( ah ) = 2
						; Read disk sectors
						;AL-sec num CH-track CL-sec
						; DH-head DL-drive ES:BX-buffer
						;CF-flag AH-stat AL-sec read
                pop	DX
		pop	AX			
                pop     CX
                jc      short loc_16
                add     AX,01h
                adc     DX,0h    
                jc      short loc_16
loc_15:                 
                add     BX,Word Ptr bsBytesPerSec
                loop    loop_loc_14             ; Loop if CX > 0
loc_16:         
                retn

proc_read       endp

                dw      0

IOerrormsg      db      'Disk I/O error...',0
failmessage     db      'Transaction failed...',0
rebootmsg       db      0Dh, 0Ah
                db      'Replace the disk, and press any key to reboot...'
                db      0Dh, 0Ah,0
                db      0
stdfilename     db      'PRESENTATOR'
notfoundmsg     db      0, 'not found...', 0

version         db      'TR-DOS Boot v1.0', 0
                db      0
                db      '¸ Erdo§an Tan [ 1998-2000 ]'
                db      0
bossmagic       db      01h
                db      0A1h
                db      1 dup(0)

                org     start+200h-2

bootsignature   db      55h, 0AAh

RxDOSBOOT       ends

                end     RxDOS_WRITESTUB
