        TITLE   'RxDOS Boot Sector Program'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Boot Sector Program                                    ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm

RxDOSBOOT SEGMENT PUBLIC 'CODE'
        assume cs:RxDOSBOOT, ds:RxDOSBOOT, es:RxDOSBOOT, ss:RxDOSBOOT

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Stack Arguments
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                               even
_rootDirectory                  dd ?
_sizeRootDirectory              dw ?
_readDrive                      dw ?
_readTrack                      dw ?
_readSector                     dw ?
_readHead                       dw ?
_diskParameterTable             db 12 dup(?)

_stackReserved                  equ ($ - _diskParameterTable) + 20h

ROMBIOS_DISKTABLE               equ ( 1Eh * 4 )

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; buffers start elsewhere
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                                org 500h
RXDOS_READBUFFER:

                                org 700h
RXDOS_DOSLOADBUFFER:

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; assume starts at 0000:7C00
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                                org 7C00h
RxDOS_START:                    jmp RxDOS_LOAD

; this information is standard for every boot sector

__bsOemName                     db 'RxDOS6.0'           ; 'RxDOS' if formatted by us
__bsBytesPerSector              dw ?                    ; 512 is default
__bsSectorsPerCluster           db ?
__bsResSectors                  dw ?
__bsNumCopiesFAT                db ?
__bsMaxAllocRootDir             dw ?
__bsMaxSectors                  dw ?                    ; if zero, see huge sectors
__bsMediaDescriptor             db ?
__bsSectorsPerFat               dw ?
__bsSectorsPerTrack             dw ?
__bsHeads                       dw ?
__bsHiddenSectors               dd ?
__bsHugeSectors                 dd ?

__bsDriveNumber                 db 0
                                db 0
__bsBootSignature               db 29h                  ; 29h if extended boot sector
__bsVolumeId                    dd 0                    ; unique disk ID
__bsVolumeLabel                 db sizeVolumeLabel dup(' '); not same as DOS Volume Id
__bsFileSystemType              db 'FAT12   '

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; the RxDOS boot process begins here
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_LOAD:
        cli                                             ; no interrupts
        cld                                             ; all that we need to init

        xor ax, ax
        mov ds, ax                                      ; allow debugging
        mov es, ax                                      ; allow debugging
        mov ss, ax                                      ; allow debugging
        mov sp, 7C00h - _stackReserved
        mov bp, sp
        mov byte ptr [ _readDrive ][ bp ], dl

        mov bx, offset ROMBIOS_DISKTABLE                ; int 1E
        lds si, es:[ bx ]                               ; 0000:0078
        lea di, offset [ _diskParameterTable ][ bp ]
        mov word ptr es:[ _pointer ][ bx ], di
        mov word ptr es:[ _segment ][ bx ], ss
        mov cx, sizeDISKPARAM
        rep movsb
        sti

        xor ax, ax
        mov ds, ax
        mov byte ptr [ _diskParameterTable. _dptHeadSettleTime ][ bp ], 15
        mov cx, word ptr [ __bsSectorsPerTrack ]
        mov byte ptr [ _diskParameterTable. _dptSectorsPerTrack ][ bp ], cl

        int 13h                                         ; reset disk drive (ax = 0)
        jc RxDOSLOAD_Error                              ; if error -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; if no huge sectors, fix up huge sectors
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov ax, word ptr [ __bsMaxSectors ]
        or ax, ax                                       ; not a huge address disk ?
        jz RxDOSLOAD_08                                 ; yes -->

        mov word ptr [ __bsHugeSectors ], ax

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; compute logical sector address of Root Directory
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOSLOAD_08:
        mov bp, sp                                      ; restore stack frame.
        xor ax, ax
        mov al, byte ptr [ __bsNumCopiesFAT ]
        mul word ptr [ __bsSectorsPerFat ]
        add ax, word ptr [ __bsHiddenSectors. _low ]
        adc dx, word ptr [ __bsHiddenSectors. _high ]

        add ax, word ptr [ __bsResSectors ]
        adc dx, 0000

        mov word ptr [ _rootDirectory. _low  ][ bp ], ax
        mov word ptr [ _rootDirectory. _high ][ bp ], dx

    ; read first sector of Root Directory

        mov bx, offset RXDOS_READBUFFER
        call RxDOSPerformRead
        jc RxDOSLOAD_Error                              ; if error -->

        mov di, offset RXDOS_READBUFFER
        mov si, offset RxDOS_RXDOSBIOCOM
        mov cx, sizeFILENAME
        rep cmpsb                                       ; compare first name
        jnz RxDOSLOAD_Error                             ; if not a system disk -->

        mov di, offset (RXDOS_READBUFFER. sizeDIRENTRY)
        mov cx, sizeFILENAME
        rep cmpsb                                       ; compare second name
        jz RxDOSLOAD_LoadDOS                            ; if equal -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; can't load
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOSLOAD_Error:
        mov si, offset RxDOS_DISKERROR
        call RxDOSLOAD_DisplayMsg

        xor ax, ax
        int 16h                                         ; wait on any key
        int 19h                                         ; not expected to return
        jmp RxDOSLOAD_Error

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; load DOS
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOSLOAD_LoadDOS:
        mov ax, word ptr [ __bsMaxAllocRootDir ]
        add ax, (sizeSector / sizeDIRENTRY) - 1
        mov cl, 4
        shr ax, cl                                      ; sectors used by directory
        mov word ptr [ _sizeRootDirectory ][ bp ], ax   ; save size
        
        mov ax, word ptr [ RXDOS_READBUFFER. deStartCluster ]
        dec ax
        dec ax                                          ; subtract 2

        xor ch, ch
        mov cl, [ __bsSectorsPerCluster ]
        mul cx

        add ax, word ptr [ _rootDirectory. _low  ][ bp ]
        adc dx, word ptr [ _rootDirectory. _high ][ bp ]
        add ax, word ptr [ _sizeRootDirectory    ][ bp ]
        adc dx, 0000

        mov bx, offset RXDOS_DOSLOADBUFFER              ; where to load
        mov cx, 3                                       ; read three sectors

RxDOSLOAD_LoadDOS_08:
        call RxDOSPerformRead
        jc RxDOSLOAD_Error                              ; if error -->

        add bx, word ptr [ __bsBytesPerSector ]
        add ax, 0001
        adc dx, 0000
        loop RxDOSLOAD_LoadDOS_08

        mov ch, byte ptr [ __bsMediaDescriptor ]
        mov dl, byte ptr [ _readDrive ][ bp ]
        mov bx, word ptr [ _rootDirectory. _low  ][ bp ]
        mov ax, word ptr [ _rootDirectory. _high ][ bp ]

        lea si, offset [ _diskParameterTable ][ bp ]
        JMP_FAR 70h, 0000h                              ; RXDOS_DOSLOADBUFFER

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Display Message, wait for ANY key
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOSLOAD_DisplayMsg:
        lodsb                                           ; get character (ds:si)
        or al, al                                       ; null terminator ?
        jz RxDOSLOAD_Return                             ; done -->

        push si
        mov ah, 0Eh
        mov bx, 0007h
        int 10h
        pop si
        jmp RxDOSLOAD_DisplayMsg

RxDOSLOAD_Return:
        ret

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; perform disk read
; ---------------------------------------------------------------
;  dx:ax logical sector to read
;  es:bx read buffer address
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOSPerformRead:
        push bp
        push dx
        push ax
        push cx
        div word ptr [ __bsSectorsPerTrack ]
        inc dl
        mov byte ptr [ _readSector ][ bp ], dl

        xor dx, dx
        div word ptr [ __bsHeads ]
      ; mov word ptr [ _readHead ][ bp ], ax            ; don't need to save heads
      ; mov byte ptr [ _readTrack ][ bp ], dl           ; dont need to save track
        mov dh, dl                                      ; track

        clc
        mov cl, 6
        shl ah, cl                                      ; move read head up
        or ah, byte ptr [ _readSector ][ bp ]           ; unused portion of sector
        mov cx, ax
        xchg ch, cl

        mov ax, 0201h                                   ; read one sector.
        mov dl, byte ptr [ _readDrive ][ bp ]
        int 13h
        jnc RxDOSPerformRead_08
        cmp ax, 11h                                     ; ECC corrected data ?
        jz RxDOSPerformRead_08                          ; return no carry -->
        stc

RxDOSPerformRead_08:
        pop cx
        pop ax
        pop dx
        pop bp
        ret

RxDOS_RXDOSBIOCOM:   db 'RXDOSBIOSYS'
RxDOS_RXDOSCOM:      db 'RXDOS   SYS'

RxDOS_DISKERROR:     db 'Not an RxDOS system disk or disk error', 0Dh, 0Ah
                     db 'Press any key to continue...', 0Dh, 0Ah, 00h

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; partition table
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                     org RxDOS_START+200h-2
RxDOS_BootSignature: db 055h, 0AAh 

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Write Stub                                                   ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  The stub loads at the normal 100h load address and writes    ;
        ;  the boot sector to drive A:                                  ;
        ;...............................................................;

                org 100h

RxDOS_WRITESTUB:
        cli
        cld
        push cs
        pop ss
        mov sp, offset RxDOS_WRITESTUB_STACK
        sti

        mov dx, cs
        mov ds, dx

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  see if drive specified
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        Entry
        def  _drive, 0000                               ; A:
        def  _WriteOnce, FALSE
        def  _SilentMode, FALSE
        def  _isRemovable, TRUE

        mov si, offset 80h
        mov cl, byte ptr es:[ si ]
        or cl, cl                                       ; arguments passed in command line ?
        jz RxDOS_WRITESTUB_36                           ; no, default to A: -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  switch processing
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_06:
        inc si
        mov al, byte ptr es:[ si ]                      ; scan command line
        cmp al, ControlM                                ; command line end ?
        jz RxDOS_WRITESTUB_36                           ; yes -->

        cmp al, ' '                                     ; space ?
        jz RxDOS_WRITESTUB_06                           ; skip any leading spaces -->
        cmp al, '-'                                     ; switch character ?
        jz RxDOS_WRITESTUB_10                           ; yes -->
        cmp al, '/'                                     ; switch character ?
        jnz RxDOS_WRITESTUB_22                          ; no -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  see if -1 (write once )
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_10:
        inc si
        mov al, byte ptr es:[ si ]                      ; get switch character
        cmp al, '1'                                     ; write once ?
        jnz RxDOS_WRITESTUB_12                          ; no -->
        storarg _WriteOnce, TRUE                        ; set write once mode
        jmp RxDOS_WRITESTUB_06

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  see if -s (silent mode)
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_12:
        cmp al, 's'                                     ; silent mode ?
        jz RxDOS_WRITESTUB_14                           ; yes -->
        cmp al, 'S'                                     ; silent mode ?
        jnz RxDOS_WRITESTUB_16                          ; no -->

RxDOS_WRITESTUB_14:
        storarg _SilentMode, TRUE                       ; set silent mode
        storarg _WriteOnce, TRUE                        ; silent makes -> write once mode
        jmp RxDOS_WRITESTUB_06

RxDOS_WRITESTUB_16:
        cmp al, ControlM                                ; command line end ?
        jnz RxDOS_WRITESTUB_06                          ; not yet -->
        jmp short RxDOS_WRITESTUB_36

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  drive letter processing
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_22:
        mov bl, al                                      ; get character
        sub bl, '0'                                     ; allow 0 as A:
        jc RxDOS_WRITESTUB_36                           ; 
        cmp al, '9' + 1                                 ; allow number for drive
        jc RxDOS_WRITESTUB_32                           ; 

        mov bl, al
        sub bl, 'A'                                     ; A - Z 
        jc RxDOS_WRITESTUB_36                           ; 
        cmp al, 'Z' + 1                                 ; 
        jc RxDOS_WRITESTUB_32                           ; 

        mov bl, al
        sub bl, 'a'                                     ; a - z 
        jc RxDOS_WRITESTUB_36                           ; 
        cmp al, 'z' + 1                                 ; 
        jc RxDOS_WRITESTUB_32                           ; 
        jmp RxDOS_WRITESTUB_InvalidDrive                ; cannot set invalid drive -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  get drive code, test if removable     
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_32:
        mov byte ptr [ _drive ][ bp ], bl               ; set drive if other than A:
        
RxDOS_WRITESTUB_36:
        mov bl, byte ptr [ _drive ][ bp ]
        inc bl
        Int21 IoControl, 08h                            ; is drive removable ?
        ifc RxDOS_WRITESTUB_InvalidDrive                ; invalid drive -->

        not ax                                          ; 0000 if removable,
        and ax, 1                                       ; ... convert to true or false
        mov word ptr [ _isRemovable ][ bp ], ax         ; 

        mov bl, byte ptr [ _drive ][ bp ]
        inc bl
        Int21 IoControl, 09h                            ; is drive remote ?
        jc RxDOS_WRITESTUB_40                           ; ignore possible unsupported error -->

        test dx, 1000h                                  ; remote flag set ?
        ifnz RxDOS_WRITESTUB_InvalidDrive               ; cannot set invalid drive -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  Write message
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_40:
        mov dl, byte ptr [ _drive ][ bp ]
        add dl, 'A'
        mov byte ptr RxDOS_PressKeyWhenReady_Drive, dl

        cmp word ptr [ _SilentMode ][ bp ], 0           ; silent mode ?
        jnz RxDOS_WRITESTUB_46                          ; ok to write -->

        mov si, offset RxDOS_PressKeyWhenReady
        call RxDOSLOAD_DisplayMsg

RxDOS_WRITESTUB_42:
        xor ax, ax
        int 16h                                         ; wait for keyboard command
        cmp al, ControlM
        jz RxDOS_WRITESTUB_46
        cmp al, ' '
        jz RxDOS_WRITESTUB_46
        cmp al, 'n'
        ifz RxDOS_WRITESTUB_80                          ; if no -->
        cmp al, 'N'
        ifz RxDOS_WRITESTUB_80                          ; if no -->
        cmp al, 'C'-40h
        ifz RxDOS_WRITESTUB_80                          ; if no -->
        jmp RxDOS_WRITESTUB_42

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if floppy drive, 
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_46:
        push cs
        pop es                                          ; restore es:

RxDOS_WRITESTUB_48:
        mov dl, byte ptr [ _drive ][ bp ]
        call _ReadBootSector                            ; read current information
        jc RxDOS_WRITESTUB_68                           ; if error -->

        cld
        mov si, offset [ _rwBUFFER. _bsBytesPerSector ]
        mov di, offset [ __bsBytesPerSector ]
        mov cx, ( __bsDriveNumber - __bsBytesPerSector )
        rep movsb                                       ; copy these parameters

        mov si, offset [ RxDOS_OEMNAME ]
        mov di, offset [ __bsOemName ]
        mov cx, 8
        rep movsb                                       ; copy product name

        push es
        xor ax, ax
        mov es, ax
        mov ax, word ptr es:[ 46Ch ]
        mov dx, word ptr es:[ 46Eh ]
        pop es

        mov word ptr [ __bsVolumeId. _High ], dx
        mov word ptr [ __bsVolumeId. _Low  ], ax

        xor dx, dx
        mov dl, byte ptr [ _drive ][ bp ]
        call _WriteBootSector                           ; write boot sector
        jnc RxDOS_WRITESTUB_72                          ; if everything is ok -->

RxDOS_WRITESTUB_68:
        mov si, offset RxDOS_diskA_NotReadyOrError
        call RxDOSLOAD_DisplayMsg
        jmp short RxDOS_WRITESTUB_76

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; success. try again ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_72:
        mov si, offset RxDOS_diskA_WrittenSuccesfully
        call RxDOSLOAD_DisplayMsg
        cmp word ptr [ _WriteOnce ][ bp ], TRUE
        jz RxDOS_WRITESTUB_80

        mov si, offset RxDOS_diskA_WriteAnother
        call RxDOSLOAD_DisplayMsg

RxDOS_WRITESTUB_76:
        xor ax, ax
        int 16h                                         ; wait for keyboard command
        cmp al, 'n'
        jz RxDOS_WRITESTUB_80                           ; if no -->
        cmp al, 'N'
        jz RxDOS_WRITESTUB_80                           ; if no -->
        cmp al, 'C'-40h
        jz RxDOS_WRITESTUB_80                           ; if cancel -->
        jmp RxDOS_WRITESTUB_40                          ; else if retry -->

RxDOS_WRITESTUB_80:
        Int21 TerminateProcess, 00

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  messages
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

RxDOS_WRITESTUB_InvalidDrive:
        mov si, offset RxDOS_InvalidDrive
        call RxDOSLOAD_DisplayMsg
        Int21 TerminateProcess, 02
        jmp RxDOS_WRITESTUB_InvalidDrive

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Read Boot Sector for ANY drive                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;    dx     drive ( 0 = A:, 1 = B:, 2 = C:, ... )               ;
        ;                                                               ;
        ;                                                               ;
        ;                                                               ;
        ;...............................................................;

_ReadBootSector:

        Entry
        def  _drive, dx                                 ; 0 = A:, 1 = B:, 2 = C:, ...
        def  _retries, 3                                ; max retries
        ddef _drivePB                                   ; drive parameter block
        ddef _strategy
        ddef _interrupt

        push ds
        mov dl, byte ptr [ _drive ][ bp ]
        inc dl                                          ; 1 = A:, ...
        Int21 GetDriveParameterBlock                    ; get pointer to drive data
        stordarg _drivePB, ds, bx                       ; drive parameter bloc

        pop ds
        cmp al, -1                                      ; invalid drive or error ?
        jnz _ReadBootSector_08                          ; no, ok -->
        stc
        Return

_ReadBootSector_08:
        mov bx, offset _ReqBlock
        mov byte ptr [ rwrLength   ][ bx ], sizeREADReqHeader
        mov byte ptr [ rwrFunction ][ bx ], DEVICEREAD

        mov al, byte ptr [ _drive ][ bp ]
        mov byte ptr [ rwrUnit ][ bx ], al

        getdarg es, si, _drivePB                        ; drive parameter bloc
        mov al, byte ptr es:[ _dpbMediaDescriptor ][ si ]
        mov byte ptr [ rwrMediaID ][ bx ], al

        mov word ptr [ rwrBytesReq ][ bx ], 1           ; one sector
        mov word ptr [ rwrStartSec ][ bx ], 0000        ; address
        mov word ptr [ rwrHugeStartSec. _high ][ bx ], 0000
        mov word ptr [ rwrHugeStartSec. _low  ][ bx ], 0000

        mov word ptr [ rwrBuffer. _pointer   ][ bx ], offset _rwBUFFER
        mov word ptr [ rwrBuffer. _segment   ][ bx ], cs
        mov word ptr [ rwrVolumeID. _pointer ][ bx ], offset _rwVOLBUFFER
        mov word ptr [ rwrVolumeID. _segment ][ bx ], cs

        les bx, dword ptr es:[ _dpbptrDeviceDriver ][ si ]
        mov ax, word ptr es:[ devStrategy  ][ bx ]
        stordarg _strategy, es, ax

        mov ax, word ptr es:[ devInterrupt ][ bx ]
        stordarg _interrupt, es, ax

_ReadBootSector_18:
        push ds
        pop es
        mov bx, offset _ReqBlock
        mov word ptr [ rwrStatus   ][ bx ], 0000
        call dword ptr [ _strategy ][ bp ]              ; strategy
        call dword ptr [ _interrupt ][ bp ]             ; interrupt

      ; dec word ptr [ _retries ][ bp ]                 ; retries
      ; jnz _ReadBootSector_18

        clc
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Write Boot Sector for ANY drive                              ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;    dx     drive ( 0 = A:, 1 = B:, 2 = C:, ... )               ;
        ;                                                               ;
        ;...............................................................;

_WriteBootSector:

        Entry
        def  _drive, dx                                 ; 0 = A:, 1 = B:, 2 = C:, ...
        def  _retries, 3                                ; max retries
        ddef _drivePB                                   ; drive parameter block
        ddef _strategy
        ddef _interrupt

        push ds
        mov dl, byte ptr [ _drive ][ bp ]
        inc dl                                          ; 1 = A:, ...
        Int21 GetDriveParameterBlock                    ; get pointer to drive data
        stordarg _drivePB, ds, bx                       ; drive parameter bloc

        pop ds
        cmp al, -1                                      ; invalid drive or error ?
        jnz _WriteBootSector_08                         ; no, ok -->
        stc
        Return

_WriteBootSector_08:
        mov bx, offset _ReqBlock
        mov byte ptr [ rwrLength   ][ bx ], sizeREADReqHeader
        mov byte ptr [ rwrFunction ][ bx ], DEVICEWRITE
        mov word ptr [ rwrStatus   ][ bx ], 0000

        mov al, byte ptr [ _drive ][ bp ]
        mov byte ptr [ rwrUnit ][ bx ], al

        getdarg es, si, _drivePB                        ; drive parameter bloc
        mov al, byte ptr es:[ _dpbMediaDescriptor ][ si ]
        mov byte ptr [ rwrMediaID ][ bx ], al

        mov word ptr [ rwrBytesReq ][ bx ], 1           ; one sector
        mov word ptr [ rwrStartSec ][ bx ], 0000        ; address
        mov word ptr [ rwrHugeStartSec. _high ][ bx ], 0000
        mov word ptr [ rwrHugeStartSec. _low  ][ bx ], 0000

        mov word ptr [ rwrBuffer. _pointer   ][ bx ], offset RxDOS_START
        mov word ptr [ rwrBuffer. _segment   ][ bx ], cs
        mov word ptr [ rwrVolumeID. _pointer ][ bx ], offset _rwVOLBUFFER
        mov word ptr [ rwrVolumeID. _segment ][ bx ], cs

        les bx, dword ptr es:[ _dpbptrDeviceDriver ][ si ]
        mov ax, word ptr es:[ devStrategy  ][ bx ]
        stordarg _strategy, es, ax

        mov ax, word ptr es:[ devInterrupt ][ bx ]
        stordarg _interrupt, es, ax

_WriteBootSector_18:
        push ds
        pop es
        mov bx, offset _ReqBlock
        call dword ptr [ _strategy ][ bp ]              ; strategy
        call dword ptr [ _interrupt ][ bp ]             ; interrupt

      ; dec word ptr [ _retries ][ bp ]                 ; retries
      ; jnz _WriteBootSector_18

        clc
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Messages                                                     ;
        ;...............................................................;

RxDOS_OEMNAME:
        db 'RxDOS6.0'

RxDOS_Welcome:
        db 0Dh, 0Ah
        db 0Dh, 0Ah, 'RxDOS Write Boot Sector Utility. '
        db 0Dh, 0Ah, 'Usage: rxd_boot [drive]'
        db 0Dh, 0Ah, 0

RxDOS_PressKeyWhenReady:
        db 0Dh, 0Ah, 0Dh, 0Ah, 'Press Space to write boot sector on disk '

RxDOS_PressKeyWhenReady_Drive:
        db 'A. ', 0

RxDOS_diskA_WriteAnother:
        db 0Dh, 0Ah, 'Disk updated. Would you like to write another? ', 0

RxDOS_diskA_WrittenSuccesfully:
        db 0Dh, 0Ah, 'Disk updated. ', 0

RxDOS_diskA_NotReadyOrError:
        db 0Dh, 0Ah, 'Disk error or drive not ready. Try again? ', 0

RxDOS_InvalidDrive:
        db 0Dh, 0Ah, 'Drive is invalid. Cannot write boot sector. ', 0

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  stack for stub
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                      even
                        dw 400h dup(0)
RxDOS_WRITESTUB_STACK:  dw 0

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  Drive Default Data
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
DriveDefaultData:

    ; 360k drive

        dw sizeSector                           ; __bsBytesPerSector
        db 2                                    ; __bsSectorsPerCluster
        dw 1                                    ; __bsResSectors
        db 2                                    ; __bsNumCopiesFAT
        dw 112                                  ; __bsMaxAllocRootDir
        dw 720                                  ; __bsMaxSectors
        db 0FDh                                 ; __bsMediaDescriptor
        dw 2                                    ; __bsSectorsPerFat
        dw 9                                    ; __bsSectorsPerTrack
        dw 2                                    ; __bsHeads
        dd 0                                    ; __bsHiddenSectors
        dd 0                                    ; __bsHugeSectors

    ; 1.2M drive

        dw sizeSector                           ; __bsBytesPerSector
        db 1                                    ; __bsSectorsPerCluster
        dw 1                                    ; __bsResSectors
        db 2                                    ; __bsNumCopiesFAT
        dw 224                                  ; __bsMaxAllocRootDir
        dw 2400                                 ; __bsMaxSectors
        db 0F9h                                 ; __bsMediaDescriptor
        dw 7                                    ; __bsSectorsPerFat
        dw 15                                   ; __bsSectorsPerTrack
        dw 2                                    ; __bsHeads
        dd 0                                    ; __bsHiddenSectors
        dd 0                                    ; __bsHugeSectors

    ; 720k drive

        dw sizeSector                           ; __bsBytesPerSector
        db 2                                    ; __bsSectorsPerCluster
        dw 1                                    ; __bsResSectors
        db 2                                    ; __bsNumCopiesFAT
        dw 112                                  ; __bsMaxAllocRootDir
        dw 1440                                 ; __bsMaxSectors
        db 0F9h                                 ; __bsMediaDescriptor
        dw 3                                    ; __bsSectorsPerFat
        dw 9                                    ; __bsSectorsPerTrack
        dw 2                                    ; __bsHeads
        dd 0                                    ; __bsHiddenSectors
        dd 0                                    ; __bsHugeSectors

    ; 1.44M drive

        dw sizeSector                           ; __bsBytesPerSector
        db 1                                    ; __bsSectorsPerCluster
        dw 1                                    ; __bsResSectors
        db 2                                    ; __bsNumCopiesFAT
        dw 224                                  ; __bsMaxAllocRootDir
        dw 2880                                 ; __bsMaxSectors
        db 0F0h                                 ; __bsMediaDescriptor
        dw 9                                    ; __bsSectorsPerFat
        dw 18                                   ; __bsSectorsPerTrack
        dw 2                                    ; __bsHeads
        dd 0                                    ; __bsHiddenSectors
        dd 0                                    ; __bsHugeSectors

        dw -1

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  working sector buffer
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

                      even
_ReqBlock:              db sizeREADReqHeader dup(0)

_rwBUFFER:              db sizeSector dup(0)
_rwVOLBUFFER:           db sizeSector dup(0)

RxDOSBOOT               ENDS
                        END  RxDOS_WRITESTUB
