diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/DEV/VDISK/VDISK.ASM | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0/src/DEV/VDISK/VDISK.ASM')
| -rw-r--r-- | v4.0/src/DEV/VDISK/VDISK.ASM | 2221 |
1 files changed, 2221 insertions, 0 deletions
diff --git a/v4.0/src/DEV/VDISK/VDISK.ASM b/v4.0/src/DEV/VDISK/VDISK.ASM new file mode 100644 index 0000000..5994111 --- /dev/null +++ b/v4.0/src/DEV/VDISK/VDISK.ASM | |||
| @@ -0,0 +1,2221 @@ | |||
| 1 | PAGE ,132 | ||
| 2 | TITLE VDISK - Virtual Disk Device Driver | ||
| 3 | |||
| 4 | ;VDISK simulates a disk drive, using Random Access Memory as the storage medium. | ||
| 5 | |||
| 6 | ;This program is meant to serve as an example of a device driver. It does not | ||
| 7 | ;reflect the current level of VDISK.SYS. | ||
| 8 | |||
| 9 | ;(C) Copyright 1988 Microsoft | ||
| 10 | ;Licensed Material - Program Property of Microsoft | ||
| 11 | |||
| 12 | ;Add the following statement to CONFIG.SYS | ||
| 13 | ; DEVICE=[d:][path]VDISK.SYS bbb sss ddd [/E:m] | ||
| 14 | |||
| 15 | ; where: bbb is the desired buffer size (in kilobytes) | ||
| 16 | ; minimum 1KB, maximum is size of available memory, | ||
| 17 | ; default is 64KB. | ||
| 18 | |||
| 19 | ; VDISK will leave at least 64KB of available memory, | ||
| 20 | ; although subsequent device drivers (other than VDISK) | ||
| 21 | ; other programs that make themselves resident, and | ||
| 22 | ; COMMAND.COM will result in less than 64KB as shown | ||
| 23 | ; by CHKDSK. | ||
| 24 | |||
| 25 | ; Must be large enough for 1 boot sector + FAT sectors | ||
| 26 | ; + 1 directory sector + at least 1 data cluster, | ||
| 27 | ; or the device driver won't be installed. | ||
| 28 | |||
| 29 | ; sss is the desired sector size (in bytes) | ||
| 30 | ; 128, 256, or 512, default is 128. | ||
| 31 | ; Will be adjusted if number of FAT entries > 0FE0H | ||
| 32 | |||
| 33 | ; ddd is the desired number of directory entries | ||
| 34 | ; Minimum 2, maximum 512, default 64. | ||
| 35 | ; Will be rounded upward to sector size boundary. | ||
| 36 | |||
| 37 | ; /E may only be used if extended memory above 1 megabyte | ||
| 38 | ; is to be used. INT 15H functions 87H and 88H are used | ||
| 39 | ; to read and write this extended memory. | ||
| 40 | ; The m parameter in the /E option specifies the maximum | ||
| 41 | ; number of sectors that the VDISK will transfer at a time. | ||
| 42 | ; Optional values are 1,2,3,4,5,6,7 or 8 sectors, the default | ||
| 43 | ; is 8 sectors. | ||
| 44 | |||
| 45 | ; Brackets indicate optional operands. | ||
| 46 | |||
| 47 | |||
| 48 | ; Samples: | ||
| 49 | ; DEVICE=\path\VDISK.SYS 160 512 64 | ||
| 50 | ; results in a 160KB VDISK, with 512 byte sectors, 64 directory entries | ||
| 51 | |||
| 52 | ; DEVICE=VDISK.SYS Buffersize 60 Sectorsize 128 Directory entries 32 | ||
| 53 | ; (since only numbers are interpreted, you may comment the line with | ||
| 54 | ; non-numeric characters) | ||
| 55 | |||
| 56 | SUBTTL Structure Definitions | ||
| 57 | PAGE | ||
| 58 | ;-----------------------------------------------------------------------; | ||
| 59 | ; Request Header (Common portion) ; | ||
| 60 | ;-----------------------------------------------------------------------; | ||
| 61 | RH EQU DS:[BX] ;addressability to Request Header structure | ||
| 62 | |||
| 63 | RHC STRUC ;fields common to all request types | ||
| 64 | DB ? ;length of Request Header (including data) | ||
| 65 | DB ? ;unit code (subunit) | ||
| 66 | RHC_CMD DB ? ;command code | ||
| 67 | RHC_STA DW ? ;status | ||
| 68 | DQ ? ;reserved for DOS | ||
| 69 | RHC ENDS ;end of common portion | ||
| 70 | |||
| 71 | CMD_INPUT EQU 4 ;RHC_CMD is INPUT request | ||
| 72 | |||
| 73 | ;status values for RHC_STA | ||
| 74 | |||
| 75 | STAT_DONE EQU 01H ;function complete status (high order byte) | ||
| 76 | STAT_CMDERR EQU 8003H ;invalid command code error | ||
| 77 | STAT_CRC EQU 8004H ;CRC error | ||
| 78 | STAT_SNF EQU 8008H ;sector not found error | ||
| 79 | STAT_BUSY EQU 0200H ;busy bit (9) for Removable Media call | ||
| 80 | ;-----------------------------------------------------------------------; | ||
| 81 | ; Request Header for INIT command ; | ||
| 82 | ;-----------------------------------------------------------------------; | ||
| 83 | RH0 STRUC | ||
| 84 | DB (TYPE RHC) DUP (?) ;common portion | ||
| 85 | RH0_NUN DB ? ;number of units | ||
| 86 | ;set to 1 if installation succeeds, | ||
| 87 | ;set to 0 to cause installation failure | ||
| 88 | RH0_ENDO DW ? ;offset of ending address | ||
| 89 | RH0_ENDS DW ? ;segment of ending address | ||
| 90 | RH0_BPBO DW ? ;offset of BPB array address | ||
| 91 | RH0_BPBS DW ? ;segment of BPB array address | ||
| 92 | RH0_DRIV DB ? ;drive code (DOS 3 only) | ||
| 93 | RH0 ENDS | ||
| 94 | |||
| 95 | RH0_BPBA EQU DWORD PTR RH0_BPBO ;offset/segment of BPB array address | ||
| 96 | ;Note: RH0_BPBA at entry to INIT points to all after DEVICE= on CONFIG.SYS stmt | ||
| 97 | |||
| 98 | ;-----------------------------------------------------------------------; | ||
| 99 | ; Request Header for MEDIA CHECK Command ; | ||
| 100 | ;-----------------------------------------------------------------------; | ||
| 101 | RH1 STRUC | ||
| 102 | DB (TYPE RHC) DUP (?) ;common portion | ||
| 103 | DB ? ;media descriptor | ||
| 104 | RH1_RET DB ? ;return information | ||
| 105 | RH1 ENDS | ||
| 106 | ;-----------------------------------------------------------------------; | ||
| 107 | ; Request Header for BUILD BPB Command ; | ||
| 108 | ;-----------------------------------------------------------------------; | ||
| 109 | RH2 STRUC | ||
| 110 | DB (TYPE RHC) DUP(?) ;common portion | ||
| 111 | DB ? ;media descriptor | ||
| 112 | DW ? ;offset of transfer address | ||
| 113 | DW ? ;segment of transfer address | ||
| 114 | RH2_BPBO DW ? ;offset of BPB table address | ||
| 115 | RH2_BPBS DW ? ;segment of BPB table address | ||
| 116 | RH2 ENDS | ||
| 117 | ;-----------------------------------------------------------------------; | ||
| 118 | ; Request Header for INPUT, OUTPUT, and OUTPUT with verify ; | ||
| 119 | ;-----------------------------------------------------------------------; | ||
| 120 | RH4 STRUC | ||
| 121 | DB (TYPE RHC) DUP (?) ;common portion | ||
| 122 | DB ? ;media descriptor | ||
| 123 | RH4_DTAO DW ? ;offset of transfer address | ||
| 124 | RH4_DTAS DW ? ;segment of transfer address | ||
| 125 | RH4_CNT DW ? ;sector count | ||
| 126 | RH4_SSN DW ? ;starting sector number | ||
| 127 | RH4 ENDS | ||
| 128 | |||
| 129 | RH4_DTAA EQU DWORD PTR RH4_DTAO ;offset/segment of transfer address | ||
| 130 | |||
| 131 | ;-----------------------------------------------------------------------; | ||
| 132 | ; Segment Descriptor (part of Global Descriptor Table) ; | ||
| 133 | ;-----------------------------------------------------------------------; | ||
| 134 | DESC STRUC ;data segment descriptor | ||
| 135 | DESC_LMT DW 0 ;segment limit (length) | ||
| 136 | DESC_BASEL DW 0 ;bits 15-0 of physical address | ||
| 137 | DESC_BASEH DB 0 ;bits 23-16 of physical address | ||
| 138 | DB 0 ;access rights byte | ||
| 139 | DW 0 ;reserved | ||
| 140 | DESC ENDS | ||
| 141 | |||
| 142 | SUBTTL Equates and Macro Definitions | ||
| 143 | PAGE | ||
| 144 | |||
| 145 | MEM_SIZE EQU 12H ;BIOS memory size determination INT | ||
| 146 | ;returns system size in KB in AX | ||
| 147 | |||
| 148 | EM_INT EQU 15H ;extended memory BIOS interrupt INT | ||
| 149 | EM_BLKMOVE EQU 87H ;block move function | ||
| 150 | EM_MEMSIZE EQU 88H ;memory size determination in KB | ||
| 151 | |||
| 152 | BOOT_INT EQU 19H ;bootstrap DOS | ||
| 153 | |||
| 154 | DOS EQU 21H ;DOS request INT | ||
| 155 | DOS_PCHR EQU 02H ;print character function | ||
| 156 | DOS_PSTR EQU 09H ;print string function | ||
| 157 | DOS_VERS EQU 30H ;get DOS version | ||
| 158 | |||
| 159 | TAB EQU 09H ;ASCII tab | ||
| 160 | LF EQU 0AH ;ASCII line feed | ||
| 161 | CR EQU 0DH ;ASCII carriage return | ||
| 162 | BEL EQU 07H ;ASCII bell | ||
| 163 | |||
| 164 | PARA_SIZE EQU 16 ;number of bytes in one 8088 paragraph | ||
| 165 | DIR_ENTRY_SIZE EQU 32 ;number of bytes per directory entry | ||
| 166 | MAX_FATE EQU 0FE0H ;largest number of FAT entries allowed | ||
| 167 | |||
| 168 | ;default values used if parameters are omitted | ||
| 169 | |||
| 170 | DFLT_BSIZE EQU 64 ;default VDISK buffer size (KB) | ||
| 171 | DFLT_SSZ EQU 128 ;default sector size | ||
| 172 | DFLT_DIRN EQU 64 ;default number of directory entries | ||
| 173 | DFLT_ESS EQU 8 ;default maximum sectors to transfer | ||
| 174 | |||
| 175 | MIN_DIRN EQU 2 ;minimum number of directory entries | ||
| 176 | MAX_DIRN EQU 512 ;maximum number of directory entries | ||
| 177 | |||
| 178 | STACK_SIZE EQU 512 ;length of stack during initialization | ||
| 179 | |||
| 180 | ;-----------------------------------------------------------------------; | ||
| 181 | ; MSG invokes the console message subroutine ; | ||
| 182 | ;-----------------------------------------------------------------------; | ||
| 183 | |||
| 184 | MSG MACRO TEXT | ||
| 185 | PUSH DX ;;save DX across call | ||
| 186 | MOV DX,OFFSET TEXT ;;point to message | ||
| 187 | CALL SHOW_MSG ;;issue message | ||
| 188 | POP DX | ||
| 189 | ENDM | ||
| 190 | |||
| 191 | |||
| 192 | SUBTTL Resident Data Area | ||
| 193 | PAGE | ||
| 194 | ;-----------------------------------------------------------------------; | ||
| 195 | ; Map INT 19H vector in low storage ; | ||
| 196 | ;-----------------------------------------------------------------------; | ||
| 197 | INT_VEC SEGMENT AT 00H | ||
| 198 | ORG 4*BOOT_INT | ||
| 199 | BOOT_VEC LABEL DWORD | ||
| 200 | BOOT_VECO DW ? ;offset | ||
| 201 | BOOT_VECS DW ? ;segment | ||
| 202 | INT_VEC ENDS | ||
| 203 | |||
| 204 | |||
| 205 | CSEG SEGMENT PARA PUBLIC 'CODE' | ||
| 206 | ASSUME CS:CSEG | ||
| 207 | ;-----------------------------------------------------------------------; | ||
| 208 | ; Resident data area. ; | ||
| 209 | ; ; | ||
| 210 | ; All variables and constants required after initialization ; | ||
| 211 | ; part one are defined here. ; | ||
| 212 | ;-----------------------------------------------------------------------; | ||
| 213 | |||
| 214 | START EQU $ ;begin resident VDISK data & code | ||
| 215 | |||
| 216 | ;DEVICE HEADER - must be at offset zero within device driver | ||
| 217 | DD -1 ;becomes pointer to next device header | ||
| 218 | DW 0800H ;attribute (IBM format block device) | ||
| 219 | ;supports OPEN/CLOSE/RM calls | ||
| 220 | DW OFFSET STRATEGY ;pointer to device "strategy" routine | ||
| 221 | DW OFFSET IRPT ;pointer to device "interrupt handler" | ||
| 222 | DB 1 ;number of block devices | ||
| 223 | DB 7 DUP (?) ;7 byte filler (remainder of 8-byte name) | ||
| 224 | ;END OF DEVICE HEADER | ||
| 225 | |||
| 226 | ;This volume label is placed into the directory of the new VDISK | ||
| 227 | ;This constant is also used to determine if a previous extended memory VDISK | ||
| 228 | ;has been installed. | ||
| 229 | |||
| 230 | VOL_LABEL DB 'VDISK ' ;00-10 volume name (shows program level) | ||
| 231 | DB 28H ;11-11 attribute (volume label) | ||
| 232 | DT 0 ;12-21 reserved | ||
| 233 | DW 6000H ;22-23 time=12:00 noon | ||
| 234 | DW 0986H ;24-25 date=12/06/84 | ||
| 235 | VOL_LABEL_LEN EQU $-VOL_LABEL ;length of volume label | ||
| 236 | |||
| 237 | ;The following field, in the first extended memory VDISK device driver, | ||
| 238 | ;is the 24-bit address of the first free byte of extended memory. | ||
| 239 | ;This address is not in the common offset/segment format. | ||
| 240 | ;The initial value, 10 0000H, is 1 megabyte. | ||
| 241 | |||
| 242 | AVAIL_LO DW 0 ;address of first free byte of | ||
| 243 | AVAIL_HI DB 10H ;extended memory | ||
| 244 | |||
| 245 | ;The INT 19H vector is "stolen" by the first VDISK installed in extended memory. | ||
| 246 | ;The original content of the interrupt vector is saved here. | ||
| 247 | |||
| 248 | INTV19 LABEL DWORD | ||
| 249 | INTV19O DW ? ;offset | ||
| 250 | INTV19S DW ? ;segment | ||
| 251 | |||
| 252 | |||
| 253 | PARAS_PER_SECTOR DW ? ;number of 16-byte paragraphs in one sector | ||
| 254 | |||
| 255 | START_BUFFER_PARA DW ? ;segment address of start of VDISK buffer | ||
| 256 | ;for extended memory, this segment address | ||
| 257 | ;is the end of the VDISK device driver. | ||
| 258 | |||
| 259 | EM_SW DB 0 ;non-zero if Extended Memory | ||
| 260 | |||
| 261 | EM_STAT DW 0 ;AX from last unsuccessful extended memory I/O | ||
| 262 | |||
| 263 | START_EM_LO DW ? ;24-bit address of start of VDISK buffer | ||
| 264 | START_EM_HI DB ? ;(extended memory only) | ||
| 265 | |||
| 266 | WPARA_SIZE DW PARA_SIZE ;number of bytes in one paragraph | ||
| 267 | |||
| 268 | MAX_CNT DW ? ;(0FFFFH/BPB_SSZ) truncated, the maximum | ||
| 269 | ;number of sectors that can be transferred | ||
| 270 | ;without worrying about 64KB wrap | ||
| 271 | |||
| 272 | SECT_LEFT DW ? ;sectors left to transfer | ||
| 273 | |||
| 274 | IO_SRCA LABEL DWORD ;offset/segment of source | ||
| 275 | IO_SRCO DW ? ;offset | ||
| 276 | IO_SRCS DW ? ;segment | ||
| 277 | |||
| 278 | IO_TGTA LABEL DWORD ;offset/segment of target | ||
| 279 | IO_TGTO DW ? ;offset | ||
| 280 | IO_TGTS DW ? ;segment | ||
| 281 | |||
| 282 | ;-----------------------------------------------------------------------; | ||
| 283 | ; BIOS Parameter Block (BPB) ; | ||
| 284 | ;-----------------------------------------------------------------------; | ||
| 285 | ;This is where the characteristics of the virtual disk are established. | ||
| 286 | ;A copy of this block is moved into the boot record of the virtual disk. | ||
| 287 | ;DEBUG can be used to read sector zero of the virtual disk to examine the | ||
| 288 | ;boot record copy of this block. | ||
| 289 | |||
| 290 | BPB LABEL BYTE ;BIOS Parameter Block (BPB) | ||
| 291 | BPB_SSZ DW 0 ;number of bytes per disk sector | ||
| 292 | BPB_AUSZ DB 1 ;sectors per allocation unit | ||
| 293 | BPB_RES DW 1 ;number of reserved sectors (for boot record) | ||
| 294 | BPB_FATN DB 1 ;number of File Allocation Table (FAT) copies | ||
| 295 | BPB_DIRN DW 0 ;number of root directory entries | ||
| 296 | BPB_SECN DW 1 ;total number of sectors | ||
| 297 | ;computed from buffer size and sector size | ||
| 298 | ;(this includes reserved, FAT, directory, | ||
| 299 | ;and data sectors) | ||
| 300 | BPB_MCB DB 0FEH ;media descriptor byte | ||
| 301 | BPB_FATSZ DW 1 ;number of sectors occupied by a single FAT | ||
| 302 | ;computed from BPBSSZ and BPBSECN | ||
| 303 | BPB_LEN EQU $-BPB ;length of BIOS parameter block | ||
| 304 | |||
| 305 | BPB_PTR DW BPB ;BIOS Parameter Block pointer array (1 entry) | ||
| 306 | ;-----------------------------------------------------------------------; | ||
| 307 | ; Request Header (RH) address, saved here by "strategy" routine ; | ||
| 308 | ;-----------------------------------------------------------------------; | ||
| 309 | RH_PTRA LABEL DWORD | ||
| 310 | RH_PTRO DW ? ;offset | ||
| 311 | RH_PTRS DW ? ;segment | ||
| 312 | ;-----------------------------------------------------------------------; | ||
| 313 | ; Global Descriptor Table (GDT), used for extended memory moves ; | ||
| 314 | ;-----------------------------------------------------------------------; | ||
| 315 | ;Access Rights Byte (93H) is | ||
| 316 | ; P=1 (segment is mapped into physical memory) | ||
| 317 | ; E=0 (data segment descriptor) | ||
| 318 | ; D=0 (grow up segment, offsets must be <= limit) | ||
| 319 | ; W=1 (data segment may be written into) | ||
| 320 | ; DPL=0 (privilege level 0) | ||
| 321 | |||
| 322 | GDT LABEL BYTE ;begin global descriptor table | ||
| 323 | DESC <> ;dummy descriptor | ||
| 324 | DESC <> ;descriptor for GDT itself | ||
| 325 | SRC DESC <,,,93H,> ;source descriptor | ||
| 326 | TGT DESC <,,,93H,> ;target descriptor | ||
| 327 | DESC <> ;BIOS CS descriptor | ||
| 328 | DESC <> ;stack segment descriptor | ||
| 329 | |||
| 330 | SUBTTL INT 19H (boot) interrupt handler | ||
| 331 | PAGE | ||
| 332 | ;-----------------------------------------------------------------------; | ||
| 333 | ; INT 19H Interrupt Handler routine ; | ||
| 334 | ;-----------------------------------------------------------------------; | ||
| 335 | ;The INT 19H vector is altered by VDISK initialization to point to this | ||
| 336 | ;routine within the first extended memory VDISK device driver. | ||
| 337 | |||
| 338 | ;The vector points to the device driver so that subsequent VDISKs installed | ||
| 339 | ;in extended memory can find the first one to determine what memory has | ||
| 340 | ;already been allocated to VDISKs. | ||
| 341 | |||
| 342 | ;This routine restores the original INT 19H vector's content, then jumps | ||
| 343 | ;to the original routine. | ||
| 344 | |||
| 345 | ;INT 19H, the "Boot" INT, is always altered when DOS is booted. | ||
| 346 | |||
| 347 | ;This routine is entered with interrupts disabled. | ||
| 348 | |||
| 349 | VDISK_INT19 PROC ;INT 19H received | ||
| 350 | PUSH DS ;save registers we're going to alter | ||
| 351 | PUSH AX | ||
| 352 | |||
| 353 | XOR AX,AX | ||
| 354 | MOV DS,AX ;set DS = 0 | ||
| 355 | ASSUME DS:INT_VEC | ||
| 356 | |||
| 357 | MOV AX,CS:INTV19O ;get offset of saved vector | ||
| 358 | MOV DS:BOOT_VECO,AX ;store offset in interrupt vector | ||
| 359 | |||
| 360 | MOV AX,CS:INTV19S ;get segment of saved vector | ||
| 361 | MOV DS:BOOT_VECS,AX ;store segment in interrupt vector | ||
| 362 | |||
| 363 | POP AX | ||
| 364 | POP DS | ||
| 365 | |||
| 366 | JMP CS:INTV19 ;go to original interrupt routine | ||
| 367 | |||
| 368 | VDISK_INT19 ENDP | ||
| 369 | |||
| 370 | ASSUME DS:NOTHING | ||
| 371 | |||
| 372 | SUBTTL Device Strategy & interrupt entry points | ||
| 373 | PAGE | ||
| 374 | ;-----------------------------------------------------------------------; | ||
| 375 | ; Device "strategy" entry point ; | ||
| 376 | ; ; | ||
| 377 | ; Retain the Request Header address for use by Interrupt routine ; | ||
| 378 | ;-----------------------------------------------------------------------; | ||
| 379 | STRATEGY PROC FAR | ||
| 380 | MOV CS:RH_PTRO,BX ;offset | ||
| 381 | MOV CS:RH_PTRS,ES ;segment | ||
| 382 | RET | ||
| 383 | STRATEGY ENDP | ||
| 384 | ;-----------------------------------------------------------------------; | ||
| 385 | ; Table of command processing routine entry points ; | ||
| 386 | ;-----------------------------------------------------------------------; | ||
| 387 | CMD_TABLE LABEL WORD | ||
| 388 | DW OFFSET INIT_P1 ; 0 - Initialization | ||
| 389 | DW OFFSET MEDIA_CHECK ; 1 - Media check | ||
| 390 | DW OFFSET BLD_BPB ; 2 - Build BPB | ||
| 391 | DW OFFSET INPUT_IOCTL ; 3 - IOCTL input | ||
| 392 | DW OFFSET INPUT ; 4 - Input | ||
| 393 | DW OFFSET INPUT_NOWAIT ; 5 - Non destructive input no wait | ||
| 394 | DW OFFSET INPUT_STATUS ; 6 - Input status | ||
| 395 | DW OFFSET INPUT_FLUSH ; 7 - Input flush | ||
| 396 | DW OFFSET OUTPUT ; 8 - Output | ||
| 397 | DW OFFSET OUTPUT_VERIFY ; 9 - Output with verify | ||
| 398 | DW OFFSET OUTPUT_STATUS ;10 - Output status | ||
| 399 | DW OFFSET OUTPUT_FLUSH ;11 - Output flush | ||
| 400 | DW OFFSET OUTPUT_IOCTL ;12 - IOCTL output | ||
| 401 | DW OFFSET DEVICE_OPEN ;13 - Device OPEN | ||
| 402 | DW OFFSET DEVICE_CLOSE ;14 - Device CLOSE | ||
| 403 | MAX_CMD EQU ($-CMD_TABLE)/2 ;highest valid command follows | ||
| 404 | DW OFFSET REMOVABLE_MEDIA ;15 - Removable media | ||
| 405 | |||
| 406 | ;-----------------------------------------------------------------------; | ||
| 407 | ; Device "interrupt" entry point ; | ||
| 408 | ;-----------------------------------------------------------------------; | ||
| 409 | IRPT PROC FAR ;device interrupt entry point | ||
| 410 | PUSH DS ;save all registers Revised | ||
| 411 | PUSH ES | ||
| 412 | PUSH AX | ||
| 413 | PUSH BX | ||
| 414 | PUSH CX | ||
| 415 | PUSH DX | ||
| 416 | PUSH DI | ||
| 417 | PUSH SI | ||
| 418 | ;BP isn't used, so it isn't saved | ||
| 419 | CLD ;all moves forward | ||
| 420 | |||
| 421 | LDS BX,CS:RH_PTRA ;get RH address passed to "strategy" into DS:BX | ||
| 422 | |||
| 423 | MOV AL,RH.RHC_CMD ;command code from Request Header | ||
| 424 | CBW ;zero AH (if AL > 7FH, next compare will | ||
| 425 | ;catch that error) | ||
| 426 | |||
| 427 | CMP AL,MAX_CMD ;if command code is too high | ||
| 428 | JA IRPT_CMD_HIGH ;jump to error routine | ||
| 429 | |||
| 430 | MOV DI,OFFSET IRPT_CMD_EXIT ;return addr from command processor | ||
| 431 | PUSH DI ;push return address onto stack | ||
| 432 | ;command routine issues "RET" | ||
| 433 | |||
| 434 | ADD AX,AX ;double command code for table offset | ||
| 435 | MOV DI,AX ;put into index register for JMP | ||
| 436 | |||
| 437 | XOR AX,AX ;initialize return to "no error" | ||
| 438 | |||
| 439 | ;At entry to command processing routine: | ||
| 440 | |||
| 441 | ; DS:BX = Request Header address | ||
| 442 | ; CS = VDISK code segment address | ||
| 443 | ; AX = 0 | ||
| 444 | |||
| 445 | ; top of stack is return address, IRPT_CMD_EXIT | ||
| 446 | |||
| 447 | JMP CS:CMD_TABLE[DI] ;call routine to handle the command | ||
| 448 | |||
| 449 | |||
| 450 | IRPT_CMD_ERROR: ;CALLed for unsupported character mode commands | ||
| 451 | |||
| 452 | INPUT_IOCTL: ;IOCTL input | ||
| 453 | INPUT_NOWAIT: ;Non-destructive input no wait | ||
| 454 | INPUT_STATUS: ;Input status | ||
| 455 | INPUT_FLUSH: ;Input flush | ||
| 456 | |||
| 457 | OUTPUT_IOCTL: ;IOCTL output | ||
| 458 | OUTPUT_STATUS: ;Output status | ||
| 459 | OUTPUT_FLUSH: ;Output flush | ||
| 460 | |||
| 461 | POP AX ;pop return address off stack | ||
| 462 | |||
| 463 | IRPT_CMD_HIGH: ;JMPed to if RHC_CMD > MAX_CMD | ||
| 464 | MOV AX,STAT_CMDERR ;"invalid command" and error | ||
| 465 | |||
| 466 | IRPT_CMD_EXIT: ;return from command routine | ||
| 467 | ;AX = value to OR into status word | ||
| 468 | LDS BX,CS:RH_PTRA ;restore DS:BX as Request Header pointer | ||
| 469 | OR AH,STAT_DONE ;add "done" bit to status word | ||
| 470 | MOV RH.RHC_STA,AX ;store status into request header | ||
| 471 | POP SI ;restore registers | ||
| 472 | POP DI | ||
| 473 | POP DX | ||
| 474 | POP CX | ||
| 475 | POP BX | ||
| 476 | POP AX | ||
| 477 | POP ES | ||
| 478 | POP DS | ||
| 479 | RET | ||
| 480 | IRPT ENDP | ||
| 481 | |||
| 482 | SUBTTL Command Processing routines | ||
| 483 | PAGE | ||
| 484 | ;-----------------------------------------------------------------------; | ||
| 485 | ; Command Code 1 - Media Check ; | ||
| 486 | ; At entry, DS:BX point to request header, AX = 0 ; | ||
| 487 | ;-----------------------------------------------------------------------; | ||
| 488 | MEDIA_CHECK PROC | ||
| 489 | MOV RH.RH1_RET,1 ;indicate media not changed | ||
| 490 | RET ;AX = zero, no error | ||
| 491 | MEDIA_CHECK ENDP | ||
| 492 | ;-----------------------------------------------------------------------; | ||
| 493 | ; Command Code 2 - Build BPB ; | ||
| 494 | ; At entry, DS:BX point to request header, AX = 0 ; | ||
| 495 | ;-----------------------------------------------------------------------; | ||
| 496 | BLD_BPB PROC | ||
| 497 | MOV RH.RH2_BPBO,OFFSET BPB ;return pointer to our BPB | ||
| 498 | MOV RH.RH2_BPBS,CS | ||
| 499 | RET ;AX = zero, no error | ||
| 500 | BLD_BPB ENDP | ||
| 501 | ;-----------------------------------------------------------------------; | ||
| 502 | ; Command Code 13 - Device Open ; | ||
| 503 | ; Command Code 14 - Device Close ; | ||
| 504 | ; Command Code 15 - Removable media ; | ||
| 505 | ; At entry, DS:BX point to request header, AX = 0 ; | ||
| 506 | ;-----------------------------------------------------------------------; | ||
| 507 | REMOVABLE_MEDIA PROC | ||
| 508 | MOV AX,STAT_BUSY ;set status bit 9 (busy) | ||
| 509 | ;indicating non-removable media | ||
| 510 | DEVICE_OPEN: ;NOP for device open | ||
| 511 | DEVICE_CLOSE: ;NOP for device close | ||
| 512 | RET | ||
| 513 | REMOVABLE_MEDIA ENDP ;fall thru to return | ||
| 514 | ;-----------------------------------------------------------------------; | ||
| 515 | ; Command Code 4 - Input ; | ||
| 516 | ; Command Code 8 - Output ; | ||
| 517 | ; Command Code 9 - Output with verify ; | ||
| 518 | ; At entry, DS:BX point to request header, AX = 0 ; | ||
| 519 | ;-----------------------------------------------------------------------; | ||
| 520 | INOUT PROC | ||
| 521 | INPUT: | ||
| 522 | OUTPUT: | ||
| 523 | OUTPUT_VERIFY: | ||
| 524 | |||
| 525 | ;Make sure I/O is entirely within the VDISK sector boundaries | ||
| 526 | |||
| 527 | MOV CX,CS:BPB_SECN ;get total sector count | ||
| 528 | MOV AX,RH.RH4_SSN ;starting sector number | ||
| 529 | CMP AX,CX ;can't exceed total count | ||
| 530 | JA INOUT_E1 ;jump if start > total | ||
| 531 | |||
| 532 | ADD AX,RH.RH4_CNT ;start + sector count | ||
| 533 | CMP AX,CX ;can't exceed total count | ||
| 534 | JNA INOUT_A ;jump if start + count <= total | ||
| 535 | |||
| 536 | INOUT_E1: ;I/O not within VDISK sector boundaries | ||
| 537 | MOV RH.RH4_CNT,0 ;set sectors transferred to zero | ||
| 538 | MOV AX,STAT_SNF ;indicate 'Sector not found' error | ||
| 539 | RET ;return with error status in AX | ||
| 540 | |||
| 541 | INOUT_A: ;I/O within VDISK bounds | ||
| 542 | MOV AX,RH.RH4_CNT ;get sector count | ||
| 543 | MOV CS:SECT_LEFT,AX ;save as sectors left to process | ||
| 544 | |||
| 545 | CMP CS:EM_SW,0 ;extended memory mode? | ||
| 546 | JNE INOUT_EM ;jump to extended memory I/O code | ||
| 547 | |||
| 548 | ;Compute offset and segment of VDISK buffer for starting segment in CX:SI | ||
| 549 | |||
| 550 | MOV AX,RH.RH4_SSN ;starting sector number | ||
| 551 | MUL CS:PARAS_PER_SECTOR ;* length of one sector in paragraphs | ||
| 552 | ADD AX,CS:START_BUFFER_PARA ;+ segment of VDISK buffer sector 0 | ||
| 553 | MOV CX,AX ;segment address to CX | ||
| 554 | XOR SI,SI ;offset is zero | ||
| 555 | |||
| 556 | ;Compute address of caller's Data Transfer Addr in DX:AX with smallest offset, | ||
| 557 | ;so that there is no possibility of overflowing a 64KB boundary moving MAX_CNT | ||
| 558 | ;sectors. | ||
| 559 | |||
| 560 | MOV AX,PARA_SIZE ;16 | ||
| 561 | MUL RH.RH4_DTAS ;* segment of caller's DTA in DX,AX | ||
| 562 | ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA | ||
| 563 | ADC DL,0 ;carry in from addition | ||
| 564 | DIV CS:WPARA_SIZE ;AX is segment of caller's DTA | ||
| 565 | ;DX is smallest offset possible | ||
| 566 | ;AX:DX = DTA address | ||
| 567 | |||
| 568 | ;AX:DX is caller's DTA segment:offset, CX:SI is VDISK buffer segment:offset | ||
| 569 | |||
| 570 | ;If this is an OUTPUT request, exchange the source and target addresses | ||
| 571 | |||
| 572 | CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation? | ||
| 573 | JE INOUT_B ;jump if INPUT operation | ||
| 574 | |||
| 575 | XCHG AX,CX ;swap source and target segment | ||
| 576 | XCHG DX,SI ;swap source and target offset | ||
| 577 | |||
| 578 | INOUT_B: ;CX:SI is source, AX:DX is target | ||
| 579 | MOV CS:IO_SRCS,CX ;save source segment | ||
| 580 | MOV CS:IO_SRCO,SI ;save source offset | ||
| 581 | MOV CS:IO_TGTS,AX ;save target segment | ||
| 582 | MOV CS:IO_TGTO,DX ;save target offset | ||
| 583 | |||
| 584 | JMP SHORT INOUT_E ;AX := SECT_LEFT, test for zero | ||
| 585 | INOUT_C: ;SECT_LEFT in AX, non-zero | ||
| 586 | |||
| 587 | ; Compute number of sectors to transfer in a single move, | ||
| 588 | ; AX = minimum of (SECT_LEFT, MAX_CNT) | ||
| 589 | |||
| 590 | ; MAX_CNT is the maximum number of sectors that can be moved without | ||
| 591 | ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated) | ||
| 592 | |||
| 593 | MOV CX,CS:MAX_CNT ;MAX sectors with one move | ||
| 594 | CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary | ||
| 595 | JBE INOUT_D ;then move SECT_LEFT sectors | ||
| 596 | |||
| 597 | MOV AX,CX ;else move MAX_CNT sectors | ||
| 598 | INOUT_D: | ||
| 599 | SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move | ||
| 600 | |||
| 601 | ;Move AX sectors from source to target | ||
| 602 | |||
| 603 | MUL CS:BPB_SSZ ;sectors * sector size = byte count | ||
| 604 | ;(cannot overflow into DX) | ||
| 605 | SHR AX,1 ;/2 = word count | ||
| 606 | MOV CX,AX ;word count to CX for REP MOVSW | ||
| 607 | |||
| 608 | LDS SI,CS:IO_SRCA ;source segment/offset to DS:SI | ||
| 609 | LES DI,CS:IO_TGTA ;target segment/offset to ES:DI | ||
| 610 | |||
| 611 | REP MOVSW ;move MOV_CNT sectors | ||
| 612 | |||
| 613 | ;Update source and target paragraph addresses | ||
| 614 | ;AX has number of words moved | ||
| 615 | |||
| 616 | SHR AX,1 ;words moved / 8 = paragraphs moved | ||
| 617 | SHR AX,1 | ||
| 618 | SHR AX,1 | ||
| 619 | |||
| 620 | ADD CS:IO_SRCS,AX ;add paragraphs moved to source segment | ||
| 621 | ADD CS:IO_TGTS,AX ;add paragraphs moved to target segment | ||
| 622 | |||
| 623 | ;Determine if more sectors need to be transferred | ||
| 624 | |||
| 625 | INOUT_E: ;do while SECT_LEFT <> zero | ||
| 626 | MOV AX,CS:SECT_LEFT ;get sectors left to transfer | ||
| 627 | OR AX,AX ;set flags | ||
| 628 | JNZ INOUT_C ;go back to transfer some sectors | ||
| 629 | RET ;AX = zero, all sectors transferred | ||
| 630 | |||
| 631 | SUBTTL Extended Memory I/O routine | ||
| 632 | PAGE | ||
| 633 | ;-----------------------------------------------------------------------; | ||
| 634 | ; Extended Memory I/O routine ; | ||
| 635 | ;-----------------------------------------------------------------------; | ||
| 636 | INOUT_EM: ;Extended memory I/O routine | ||
| 637 | ;change to larger stack | ||
| 638 | MOV SI,SS ;save old SS in SI | ||
| 639 | MOV DX,SP ;save old SP in DX | ||
| 640 | CLI ;disable interrupts | ||
| 641 | MOV AX,CS | ||
| 642 | MOV SS,AX ;set SS = CS | ||
| 643 | MOV SP,OFFSET EM_STACK ;point to new stack | ||
| 644 | STI ;enable interrupts | ||
| 645 | PUSH SI ;save old SS at top of new stack | ||
| 646 | PUSH DX ;save old SP on new stack | ||
| 647 | |||
| 648 | MOV SI,RH.RH4_DTAO ;caller's DTA offset | ||
| 649 | |||
| 650 | ;Compute 24-bit address of VDISK sector in CX (hi) and SI (low) | ||
| 651 | |||
| 652 | MOV AX,RH.RH4_SSN ;starting sector number | ||
| 653 | MUL CS:BPB_SSZ ;* sector size = offset within buffer | ||
| 654 | ADD AX,CS:START_EM_LO ;+ base address of this VDISK buffer | ||
| 655 | ADC DL,CS:START_EM_HI | ||
| 656 | MOV CX,DX ;save high byte | ||
| 657 | MOV SI,AX ;save low word | ||
| 658 | |||
| 659 | ;Compute 24-bit address of caller's DTA in DX (hi) and AX (low) | ||
| 660 | |||
| 661 | MOV AX,PARA_SIZE ;16 | ||
| 662 | MUL RH.RH4_DTAS ;* segment of caller's DTA | ||
| 663 | ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA | ||
| 664 | ADC DL,0 ;carry in from addition | ||
| 665 | |||
| 666 | ;Caller's DTA address is in CX,SI, VDISK buffer address is in DX,AX. | ||
| 667 | |||
| 668 | ;If this is an OUTPUT request, exchange the source and target addresses | ||
| 669 | |||
| 670 | CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation? | ||
| 671 | JE INOUT_EM_B ;jump if INPUT operation | ||
| 672 | |||
| 673 | XCHG DX,CX ;swap source and target high byte | ||
| 674 | XCHG AX,SI ;swap source and target low word | ||
| 675 | |||
| 676 | INOUT_EM_B: ;CX,SI is source, DX,AX is target | ||
| 677 | |||
| 678 | MOV SRC.DESC_BASEL,SI ;low 16 bits of source address | ||
| 679 | MOV SRC.DESC_BASEH,CL ;high 8 bits of source address | ||
| 680 | |||
| 681 | MOV TGT.DESC_BASEL,AX ;low 16 bits of target address | ||
| 682 | MOV TGT.DESC_BASEH,DL ;high 8 bits of target address | ||
| 683 | |||
| 684 | JMP SHORT INOUT_EM_E ;AX := SECT_LEFT, test for zero | ||
| 685 | INOUT_EM_C: ;SECT_LEFT in AX, non-zero | ||
| 686 | |||
| 687 | ; Compute number of sectors to transfer in a single move, | ||
| 688 | ; AX = minimum of (SECT_LEFT, MAX_CNT) | ||
| 689 | |||
| 690 | ; MAX_CNT is the maximum number of sectors that can be moved without | ||
| 691 | ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated) | ||
| 692 | |||
| 693 | MOV CX,CS:MAX_CNT ;MAX sectors with one move | ||
| 694 | CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary | ||
| 695 | JBE INOUT_EM_D ;then move SECT_LEFT sectors | ||
| 696 | |||
| 697 | MOV AX,CX ;else move MAX_CNT sectors | ||
| 698 | INOUT_EM_D: | ||
| 699 | SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move | ||
| 700 | |||
| 701 | ;Move AX sectors from source to target | ||
| 702 | |||
| 703 | MUL CS:BPB_SSZ ;sectors * sector size = byte count | ||
| 704 | ;(cannot overflow into DX) | ||
| 705 | MOV TGT.DESC_LMT,AX ;store segment limit (byte count) | ||
| 706 | MOV SRC.DESC_LMT,AX | ||
| 707 | |||
| 708 | PUSH AX ;preserve byte count on stack | ||
| 709 | |||
| 710 | SHR AX,1 ;/2 = word count | ||
| 711 | MOV CX,AX ;word count to CX | ||
| 712 | |||
| 713 | PUSH CS | ||
| 714 | POP ES ;set ES = CS | ||
| 715 | MOV SI,OFFSET GDT ;ES:SI point to GDT | ||
| 716 | |||
| 717 | MOV AH,EM_BLKMOVE ;function is block move | ||
| 718 | INT EM_INT ;move an even number of words | ||
| 719 | |||
| 720 | POP CX ;get byte count back from stack | ||
| 721 | |||
| 722 | OR AH,AH ;get error code | ||
| 723 | |||
| 724 | JNZ INOUT_EM_XE ;jump if I/O error encountered | ||
| 725 | |||
| 726 | ;Update source and target addresses | ||
| 727 | |||
| 728 | ADD SRC.DESC_BASEL,CX ;add bytes moved to source | ||
| 729 | ADC SRC.DESC_BASEH,0 ;pick up any carry | ||
| 730 | |||
| 731 | ADD TGT.DESC_BASEL,CX ;add bytes moved to target | ||
| 732 | ADC TGT.DESC_BASEH,0 ;pick up any carry | ||
| 733 | |||
| 734 | ;Determine if more sectors need to be transferred | ||
| 735 | |||
| 736 | INOUT_EM_E: ;do while SECT_LEFT <> zero | ||
| 737 | MOV AX,CS:SECT_LEFT ;get sectors left to transfer | ||
| 738 | OR AX,AX ;set flags | ||
| 739 | JNZ INOUT_EM_C ;go back to transfer some sectors | ||
| 740 | |||
| 741 | INOUT_EM_X2: ;revert to original stack | ||
| 742 | POP DI ;get old SP | ||
| 743 | POP SI ;get old SS | ||
| 744 | CLI ;disable interrupts | ||
| 745 | MOV SS,SI ;restore old SS | ||
| 746 | MOV SP,DI ;restore old SP | ||
| 747 | STI ;enable interrupts | ||
| 748 | RET ;return to IRPT_EXIT | ||
| 749 | |||
| 750 | INOUT_EM_XE: ;some error with INT 15H | ||
| 751 | MOV CS:EM_STAT,AX ;save error status for debugging | ||
| 752 | MOV RH.RH4_CNT,0 ;indicate no sectors transferred | ||
| 753 | MOV AX,STAT_CRC ;indicate CRC error | ||
| 754 | JMP INOUT_EM_X2 ;fix stack and exit | ||
| 755 | INOUT ENDP | ||
| 756 | |||
| 757 | DW 40 DUP (?) ;stack for extended memory I/O | ||
| 758 | EM_STACK LABEL WORD | ||
| 759 | |||
| 760 | SUBTTL Boot Record | ||
| 761 | PAGE | ||
| 762 | ;-----------------------------------------------------------------------; | ||
| 763 | ; Adjust the assembly-time instruction counter to a paragraph ; | ||
| 764 | ; boundary ; | ||
| 765 | ;-----------------------------------------------------------------------; | ||
| 766 | |||
| 767 | IF ($-START) MOD 16 | ||
| 768 | ORG ($-START) + 16 - (($-START) MOD 16) | ||
| 769 | ENDIF | ||
| 770 | |||
| 771 | VDISK EQU $ ;start of virtual disk buffer | ||
| 772 | VDISKP EQU ($-START) / PARA_SIZE ;length of program in paragraphs | ||
| 773 | ;-----------------------------------------------------------------------; | ||
| 774 | ; If this VDISK is in extended memory, this address is passed ; | ||
| 775 | ; back to DOS as the end address that is to remain resident. ; | ||
| 776 | ; ; | ||
| 777 | ; It this VDISK is not in extended memory, the VDISK buffer ; | ||
| 778 | ; begins at this address, and the address passed back to DOS ; | ||
| 779 | ; as the end address that is to remain resident is this address ; | ||
| 780 | ; plus the length of the VDISK buffer. ; | ||
| 781 | ;-----------------------------------------------------------------------; | ||
| 782 | |||
| 783 | BOOT_RECORD LABEL BYTE ;Format of Boot Record documented in | ||
| 784 | ;DOS Technical Reference Manual | ||
| 785 | DB 0,0,0 ;3-byte jump to boot code (not bootable) | ||
| 786 | DB 'VDISK ' ;8-byte vendor identification | ||
| 787 | BOOT_BPB LABEL BYTE ;boot record copy of BIOS parameter block | ||
| 788 | DW ? ;number of bytes per disk sector | ||
| 789 | DB ? ;sectors per allocation unit | ||
| 790 | DW ? ;number of reserved sectors (for boot record) | ||
| 791 | DB ? ;number of File Allocation Table (FAT) copies | ||
| 792 | DW ? ;number of root directory entries | ||
| 793 | DW ? ;total number of sectors | ||
| 794 | DB ? ;media descriptor byte | ||
| 795 | DW ? ;number of sectors occupied by a single FAT | ||
| 796 | ;end of boot record BIOS Parameter block | ||
| 797 | |||
| 798 | ;The following three words mean nothing to VDISK, they are placed here | ||
| 799 | ;to conform to the DOS standard for boot records. | ||
| 800 | DW 8 ;sectors per track | ||
| 801 | DW 1 ;number of heads | ||
| 802 | DW 0 ;number of hidden sectors | ||
| 803 | ;The following word is the 16-bit kilobyte address of the first byte in | ||
| 804 | ;extended memory that is not occupied by a VDISK buffer | ||
| 805 | ;It is placed into this location so that other users of extended memory | ||
| 806 | ;may find where all the VDISKs end. | ||
| 807 | |||
| 808 | ;This field may be accessed by moving the boot record of the First extended | ||
| 809 | ;memory VDISK from absolute location 10 0000H. Before assuming that the | ||
| 810 | ;value below is valid, the vendor ID (constant VDISK) should be verified | ||
| 811 | ;to make sure that SOME VDISK has been installed. | ||
| 812 | |||
| 813 | ;For example, if two VDISKs are installed, one 320KB and one 64KB, the | ||
| 814 | ;address calculations are as follows: | ||
| 815 | |||
| 816 | ;Extended memory start address = 100000H (1024KB) | ||
| 817 | ;Start addr of 1st VDISK buffer = 100000H (1024KB) | ||
| 818 | ;Length of 1st VDISK buffer = 050000H ( 320KB) | ||
| 819 | ;End addr of 1st VDISK buffer = 14FFFFH | ||
| 820 | ;Start addr of 2nd VDISK buffer = 150000H (1344KB) | ||
| 821 | ;Length of 2nd VDISK buffer = 010000H ( 64KB) | ||
| 822 | ;End addr of 2nd VDISK buffer = 15FFFFH | ||
| 823 | ;First byte after all VDISKs = 160000H (1408KB) | ||
| 824 | ;Divide by 1024 = 0580H (1408D) | ||
| 825 | |||
| 826 | ;Content of BOOT_EM = 0580H | ||
| 827 | |||
| 828 | BOOT_EM_OFF EQU $-BOOT_RECORD ;offset from 10 0000H of the following word | ||
| 829 | BOOT_EM DW 1024 ;KB addr of first free byte of extended memory | ||
| 830 | ;-----------------------------------------------------------------------; | ||
| 831 | ; Part 2 of Initialization (executed last) ; | ||
| 832 | ;-----------------------------------------------------------------------; | ||
| 833 | ;Initialization is divided into two parts. | ||
| 834 | |||
| 835 | ;INIT_P1 is overlaid by the virtual disk buffer | ||
| 836 | |||
| 837 | ;INIT_P1 is executed first, then jumps to INIT_P2. INIT_P2 returns to caller. | ||
| 838 | |||
| 839 | ;Exercise caution if extending the initialization part 2 code. | ||
| 840 | ;It overlays the area immediately following the boot sector. | ||
| 841 | ;If this section of code must be expanded, make sure it fits into the minimum | ||
| 842 | ;sector size of 128 bytes. | ||
| 843 | ;Label TEST_LENGTH must equate to a non-negative value (TEST_LENGTH >= 0). | ||
| 844 | ;If this code it must be extended beyond the 128 byte length of the boot sector, | ||
| 845 | ;move all of INIT_P2 before label VDISK. | ||
| 846 | |||
| 847 | ;Registers at entry to INIT_P2 (set up at end of INIT_P1): | ||
| 848 | ; BL = media control byte from BPB (for FAT) | ||
| 849 | ; CX = number of FAT copies | ||
| 850 | ; DX = number of bytes in one FAT - 3 | ||
| 851 | ; SI = OFFSET of Volume Label field | ||
| 852 | ; ES:DI = VDISK buffer address of first FAT sector | ||
| 853 | ; CS = DS = VDISK code segment | ||
| 854 | |||
| 855 | INIT_P2 PROC ;second part of initialization | ||
| 856 | ASSUME DS:CSEG ;DS set in INIT_P1 | ||
| 857 | |||
| 858 | ;Initialize File Allocation Table(s) (FATs) | ||
| 859 | |||
| 860 | INIT_P2_FAT: ;set up one FAT, sector number in AX | ||
| 861 | |||
| 862 | PUSH CX ;save loop counter on stack | ||
| 863 | MOV AL,BL ;media control byte | ||
| 864 | STOSB ;store media control byte, increment DI | ||
| 865 | MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH | ||
| 866 | STOSW | ||
| 867 | |||
| 868 | MOV CX,DX ;FAT size in bytes - 3 | ||
| 869 | XOR AX,AX ;value to store in remainder of FAT | ||
| 870 | REP STOSB ;clear remainder of FAT | ||
| 871 | |||
| 872 | POP CX ;get loop counter off stack | ||
| 873 | LOOP INIT_P2_FAT ;loop for all copies of the FAT | ||
| 874 | |||
| 875 | ;Put the volume label in the first directory entry | ||
| 876 | |||
| 877 | MOV CX,VOL_LABEL_LEN ;length of volume directory entry | ||
| 878 | REP MOVSB ;move volume id to directory | ||
| 879 | |||
| 880 | ;Zero the remainder of the directory | ||
| 881 | |||
| 882 | MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry | ||
| 883 | MUL BPB_DIRN ;* number entries = bytes of directory | ||
| 884 | SUB AX,VOL_LABEL_LEN ;less length of volume label | ||
| 885 | MOV CX,AX ;length of rest of directory | ||
| 886 | XOR AX,AX | ||
| 887 | REP STOSB ;clear directory to nulls | ||
| 888 | RET ;return with AX=0 | ||
| 889 | INIT_P2 ENDP | ||
| 890 | |||
| 891 | PATCH_AREA DB 5 DUP ('PATCH AREA ') | ||
| 892 | TEST_LENGTH EQU 128-($-VDISK) ;if negative, boot record has too much | ||
| 893 | ;data area, move some fields below VDISK | ||
| 894 | ;-----------------------------------------------------------------------; | ||
| 895 | ; All fields that must remain resident after device driver ; | ||
| 896 | ; initialization must be defined before this point. ; | ||
| 897 | ;-----------------------------------------------------------------------; | ||
| 898 | DB 'MS DOS Version 4.00 - Virtual Disk Device Driver' | ||
| 899 | DB '-------- Licensed Material ---------' | ||
| 900 | DB 'Program Property of Microsoft Corporation. ' | ||
| 901 | DB '(C)Copyright 1988 Microsoft' | ||
| 902 | DB 'Thank You For Your ' | ||
| 903 | DB ' Support ' | ||
| 904 | |||
| 905 | MAXSEC_TRF DW 0 ;maximum number of sectors to transfer when | ||
| 906 | ;in extended memory | ||
| 907 | |||
| 908 | BUFF_SIZE DW 0 ;desired VDISK buffer size in kilobytes | ||
| 909 | |||
| 910 | MIN_MEMORY_LEFT DW 64 ;minimum amount of system memory (kilobytes) | ||
| 911 | ;that must remain after VDISK is installed | ||
| 912 | |||
| 913 | FIRST_EM_SW DB ? ;0FFH if this is the first device driver | ||
| 914 | ;to be installed in extended memory | ||
| 915 | ;00H if another VDISK extended memory driver | ||
| 916 | ;has been installed | ||
| 917 | |||
| 918 | FIRST_VDISK DW ? ;segment address of 1st VDISK device driver | ||
| 919 | PARA_PER_KB DW 1024/PARA_SIZE ;paragraphs in one kilobyte | ||
| 920 | C1024 DW 1024 ;bytes in one kilobyte | ||
| 921 | DIRE_SIZE DW DIR_ENTRY_SIZE ;bytes in one directory entry | ||
| 922 | DIR_SECTORS DW ? ;number of sectors of directory | ||
| 923 | |||
| 924 | ERR_FLAG DB 0 ;error indicators to condition messages | ||
| 925 | ERR_BSIZE EQU 80H ;buffer size adjusted | ||
| 926 | ERR_SSZ EQU 40H ;sector size adjusted | ||
| 927 | ERR_DIRN EQU 20H ;number of directory entries adjusted | ||
| 928 | ERR_PASS EQU 10H ;some adjustment made that requires | ||
| 929 | ;recomputation of values previously computed | ||
| 930 | ERR_SSZB EQU ERR_SSZ+ERR_PASS ;sector size altered this pass | ||
| 931 | ERR_SYSSZ EQU 08H ;system storage too small for VDISK | ||
| 932 | ERR_SWTCH EQU 04H ;invalid switch character | ||
| 933 | ERR_EXTSW EQU 02H ;extender card switches don't match memory size | ||
| 934 | ERR_ESIZE EQU 01H ;Transfer size adjusted | ||
| 935 | |||
| 936 | ; additional errors added - kwc | ||
| 937 | |||
| 938 | major_version equ 4 ;Major DOS version | ||
| 939 | minor_version equ 00 ;Minor DOS Version | ||
| 940 | |||
| 941 | expected_version equ (MINOR_VERSION SHL 8)+MAJOR_VERSION | ||
| 942 | |||
| 943 | err_flag2 db 0 | ||
| 944 | err_baddos equ 01h ; Invalid DOS Version | ||
| 945 | |||
| 946 | SUBTTL Initialization, Part one | ||
| 947 | PAGE | ||
| 948 | ;-----------------------------------------------------------------------; | ||
| 949 | ; Command Code 0 - Initialization ; | ||
| 950 | ; At entry, DS:BX point to request header, AX = 0 ; | ||
| 951 | ;-----------------------------------------------------------------------; | ||
| 952 | ;Initialization is divided into two parts. | ||
| 953 | ;This part, executed first, is later overlaid by the VDISK buffer. | ||
| 954 | |||
| 955 | INIT_P1 PROC ;first part of initialization | ||
| 956 | MOV DX,SS ;save stack segment register | ||
| 957 | MOV CX,SP ;save stack pointer register | ||
| 958 | CLI ;inhibit interrupts while changing SS:SP | ||
| 959 | MOV AX,CS ;move CS to SS through AX | ||
| 960 | MOV SS,AX | ||
| 961 | MOV SP,OFFSET MSGEND ;end of VDISKMSG | ||
| 962 | ADD SP,STACK_SIZE ;+ length of our stack | ||
| 963 | STI ;allow interrupts | ||
| 964 | PUSH DX ;save old SS register on new stack | ||
| 965 | PUSH CX ;save old SP register on new stack | ||
| 966 | |||
| 967 | push bx ;secure registers before DOS int | ||
| 968 | push cx ;secure registers before DOS int | ||
| 969 | |||
| 970 | ; add version check - kwc | ||
| 971 | |||
| 972 | mov ah,030h | ||
| 973 | int 21h | ||
| 974 | pop cx ;restore pointer values | ||
| 975 | pop bx ;restore pointer values | ||
| 976 | cmp ax,expected_version | ||
| 977 | je okdos | ||
| 978 | |||
| 979 | or cs:err_flag2,err_baddos | ||
| 980 | |||
| 981 | okdos: | ||
| 982 | CALL GET_PARMS ;get parameters from CONFIG.SYS line | ||
| 983 | |||
| 984 | PUSH CS | ||
| 985 | POP DS ;set DS = CS | ||
| 986 | ASSUME DS:CSEG | ||
| 987 | |||
| 988 | CALL APPLY_DEFAULTS ;supply any values not specified | ||
| 989 | CALL DETERMINE_START ;compute start address of VDISK buffer | ||
| 990 | CALL VALIDATE ;validate parameters | ||
| 991 | CALL COPY_BPB ;Copy BIOS Parameter Block to boot record | ||
| 992 | |||
| 993 | CALL VERIFY_EXTENDER ;Verify that extender card switches are right | ||
| 994 | |||
| 995 | TEST ERR_FLAG,ERR_EXTSW ;are switches wrong? | ||
| 996 | JNZ INIT_P1_A ;if so, exit with messages | ||
| 997 | |||
| 998 | test CS:err_flag2,err_baddos | ||
| 999 | jnz init_p1_a | ||
| 1000 | |||
| 1001 | CMP EM_SW,0 ;extended memory requested? | ||
| 1002 | JE INIT_P1_A ;jump if not | ||
| 1003 | |||
| 1004 | TEST ERR_FLAG,ERR_SYSSZ ;is system too small for VDISK? | ||
| 1005 | JNZ INIT_P1_A ;if so, don't do extended memory init | ||
| 1006 | |||
| 1007 | CALL UPDATE_AVAIL ;update AVAIL_HI and AVAIL_LO to reflect | ||
| 1008 | ;addition of extended memory VDISK | ||
| 1009 | CALL FORMAT_VDISK ;construct a boot record, FATs and | ||
| 1010 | ;directory in storage immediately | ||
| 1011 | ;following this device driver | ||
| 1012 | CALL MOVE_VDISK ;move formatted boot record, FATs, | ||
| 1013 | ;and directory to extended memory | ||
| 1014 | CALL UPDATE_BOOT ;place the end address of ALL VDISKs | ||
| 1015 | ;in the boot record of the first VDISK | ||
| 1016 | CMP FIRST_EM_SW,0 ;is this the first extended memory VDISK? | ||
| 1017 | JE INIT_P1_A ;no, exit | ||
| 1018 | |||
| 1019 | CALL STEAL_INT19 ;point INT 19H to this VDISK | ||
| 1020 | INIT_P1_A: | ||
| 1021 | CALL FILL_RH ;fill in INIT request header | ||
| 1022 | CALL WRITE_MESSAGES ;display all messages | ||
| 1023 | POP CX ;get old SP from stack | ||
| 1024 | POP DX ;get old SS from stack | ||
| 1025 | CLI ;disable interrupts while changing SS:SP | ||
| 1026 | MOV SS,DX ;restore stack segment register | ||
| 1027 | MOV SP,CX ;restore stack pointer register | ||
| 1028 | STI ;enable interrupts | ||
| 1029 | ;-----------------------------------------------------------------------; | ||
| 1030 | ; INIT_P2 must be short enough to fit into the boot sector ; | ||
| 1031 | ; (minimum size of boot sector is 128 bytes), so we set up ; | ||
| 1032 | ; as many pointers as we can to help keep INIT_P2 short. ; | ||
| 1033 | ; ; | ||
| 1034 | ; ES:DI = storage address of first FAT sector ; | ||
| 1035 | ; BL = media control byte ; | ||
| 1036 | ; CX = number of FAT copies ; | ||
| 1037 | ; DX = number of bytes in one FAT, less 3 ; | ||
| 1038 | ; SI = offset of VOL label field ; | ||
| 1039 | ;-----------------------------------------------------------------------; | ||
| 1040 | MOV ES,START_BUFFER_PARA ;start paragraph of VDISK buffer | ||
| 1041 | |||
| 1042 | MOV AX,BPB_RES ;number of reserved sectors | ||
| 1043 | MUL BPB_SSZ ;* sector size | ||
| 1044 | MOV DI,AX ;ES:DI point to FAT start | ||
| 1045 | |||
| 1046 | MOV BL,BPB_MCB ;media control byte | ||
| 1047 | |||
| 1048 | MOV CL,BPB_FATN ;number of FAT copies | ||
| 1049 | XOR CH,CH | ||
| 1050 | |||
| 1051 | MOV AX,BPB_FATSZ ;FAT size in sectors | ||
| 1052 | MUL BPB_SSZ ;* sector size = total FAT bytes | ||
| 1053 | |||
| 1054 | SUB AX,3 ;-3 (FEFFFF stored by code) | ||
| 1055 | MOV DX,AX | ||
| 1056 | |||
| 1057 | MOV SI,OFFSET VOL_LABEL ;point to VOL label directory entry | ||
| 1058 | JMP INIT_P2 ;jump to second part of initialization | ||
| 1059 | ;this is redundant if the VDISK is in | ||
| 1060 | ;extended memory, but is executed anyway | ||
| 1061 | |||
| 1062 | SUBTTL GET_PARMS Parameter Line Scan | ||
| 1063 | PAGE | ||
| 1064 | ;-----------------------------------------------------------------------; | ||
| 1065 | ;GET_PARMS gets the parameters from the CONFIG.SYS statement ; | ||
| 1066 | ; ; | ||
| 1067 | ;Register usage: ; | ||
| 1068 | ; DS:SI indexes parameter string ; | ||
| 1069 | ; AL contains character from parameter string ; | ||
| 1070 | ; CX value from GET_NUMBER ; | ||
| 1071 | ;-----------------------------------------------------------------------; | ||
| 1072 | ASSUME DS:NOTHING ;DS:BX point to Request Header | ||
| 1073 | GET_PARMS PROC ;get parameters from CONFIG.SYS line | ||
| 1074 | PUSH DS ;save DS | ||
| 1075 | LDS SI,RH.RH0_BPBA ;DS:SI point to all after DEVICE= | ||
| 1076 | ;in CONFIG.SYS line | ||
| 1077 | XOR AL,AL ;not at end of line | ||
| 1078 | |||
| 1079 | ;Skip until first delimiter is found. There may be digits in the path string. | ||
| 1080 | |||
| 1081 | ;DS:SI points to \pathstring\VDISK.SYS nn nn nn | ||
| 1082 | ;The character following VDISK.SYS may have been changed to a null (00H). | ||
| 1083 | ;All letters have been changed to uppercase. | ||
| 1084 | |||
| 1085 | GET_PARMS_A: ;skip to DOS delimiter character | ||
| 1086 | CALL GET_PCHAR ;get parameter character into AL | ||
| 1087 | JZ GET_PARMS_X ;get out if end of line encountered | ||
| 1088 | OR AL,AL ;test for null | ||
| 1089 | JZ GET_PARMS_C ; | ||
| 1090 | CMP AL,' ' | ||
| 1091 | JE GET_PARMS_C ; | ||
| 1092 | CMP AL,',' | ||
| 1093 | JE GET_PARMS_C ; | ||
| 1094 | CMP AL,';' | ||
| 1095 | JE GET_PARMS_C ; | ||
| 1096 | CMP AL,'+' | ||
| 1097 | JE GET_PARMS_C ; | ||
| 1098 | CMP AL,'=' | ||
| 1099 | JE GET_PARMS_C ; | ||
| 1100 | CMP AL,TAB | ||
| 1101 | JNE GET_PARMS_A ;skip until delimiter or CR | ||
| 1102 | |||
| 1103 | |||
| 1104 | |||
| 1105 | GET_PARMS_C: | ||
| 1106 | PUSH SI ;save to rescan | ||
| 1107 | MOV CS:EM_SW,0 ;indicate no /E found | ||
| 1108 | JMP GET_SLASH ;see if current character is an slash | ||
| 1109 | |||
| 1110 | GET_PARMS_D: ;scan for / | ||
| 1111 | CALL GET_PCHAR | ||
| 1112 | JZ GET_PARMS_B ;exit if end of line | ||
| 1113 | |||
| 1114 | GET_SLASH: ;check for slash | ||
| 1115 | CMP AL,'/' ;found slash? | ||
| 1116 | JNE GET_PARMS_D ;no, continue scan | ||
| 1117 | |||
| 1118 | CALL GET_PCHAR ;get char following slash | ||
| 1119 | CMP AL,'E' ;don't have to test for lower case E, | ||
| 1120 | ;letters have been changed to upper case | ||
| 1121 | JNE GET_PARMS_E ;not 'E' | ||
| 1122 | MOV CS:EM_SW,AL ;indicate /E found | ||
| 1123 | |||
| 1124 | CALL GET_PCHAR ;get char following E | ||
| 1125 | CMP AL,':' ;is it a delimeter ? | ||
| 1126 | JNE GET_PARMS_D ;not a ':' | ||
| 1127 | |||
| 1128 | |||
| 1129 | CALL GET_MAXSIZE ;get maximum sector size | ||
| 1130 | |||
| 1131 | |||
| 1132 | JMP GET_PARMS_D ;continue forward scan | ||
| 1133 | |||
| 1134 | GET_PARMS_E: ;/ found, not 'E' | ||
| 1135 | OR CS:ERR_FLAG,ERR_SWTCH ;indicate invalid switch character | ||
| 1136 | JMP GET_PARMS_D ;continue scan | ||
| 1137 | |||
| 1138 | |||
| 1139 | |||
| 1140 | GET_PARMS_B: ;now pointing to first delimiter | ||
| 1141 | POP SI ;get pointer, used to rescan for /E | ||
| 1142 | XOR AL,AL ;not at EOL now | ||
| 1143 | CALL GET_PCHAR ;get first character | ||
| 1144 | CALL SKIP_TO_DIGIT ;skip to first digit | ||
| 1145 | JZ GET_PARMS_X ;found EOL, no digits remain | ||
| 1146 | |||
| 1147 | CALL GET_NUMBER ;extract digits, convert to binary | ||
| 1148 | MOV CS:BUFF_SIZE,CX ;store buffer size | ||
| 1149 | |||
| 1150 | CALL SKIP_TO_DIGIT ;skip to next digit | ||
| 1151 | JZ GET_PARMS_X ;found EOL, no digits remain | ||
| 1152 | |||
| 1153 | CALL GET_NUMBER ;extract digits, convert to binary | ||
| 1154 | MOV CS:BPB_SSZ,CX ;store sector size | ||
| 1155 | |||
| 1156 | CALL SKIP_TO_DIGIT ;skip to next digit | ||
| 1157 | JZ GET_PARMS_X ;found EOL, no digits remain | ||
| 1158 | |||
| 1159 | CALL GET_NUMBER ;extract digits, convert to binary | ||
| 1160 | MOV CS:BPB_DIRN,CX ;store number of directory entries | ||
| 1161 | |||
| 1162 | |||
| 1163 | |||
| 1164 | GET_PARMS_X: ;premature end of line | ||
| 1165 | POP DS ;restore DS | ||
| 1166 | RET | ||
| 1167 | |||
| 1168 | |||
| 1169 | |||
| 1170 | GET_MAXSIZE PROC ;get maximum sector size | ||
| 1171 | |||
| 1172 | CALL GET_PCHAR ;get next character | ||
| 1173 | CALL CHECK_NUM ;is it a number ? | ||
| 1174 | JZ GET_NEXTNUM ;yes, go get next number | ||
| 1175 | OR CS:ERR_FLAG,ERR_ESIZE ;indicate invalid sector size | ||
| 1176 | RET ; | ||
| 1177 | GET_NEXTNUM: ;get next number | ||
| 1178 | CALL GET_NUMBER ;extract digits and convert to binary | ||
| 1179 | MOV CS:MAXSEC_TRF,CX ;save maximum sector size to transfer | ||
| 1180 | RET | ||
| 1181 | GET_MAXSIZE ENDP | ||
| 1182 | |||
| 1183 | |||
| 1184 | |||
| 1185 | GET_PCHAR PROC ;internal proc to get next character into AL | ||
| 1186 | CMP AL,CR ;carriage return already encountered? | ||
| 1187 | JE GET_PCHAR_X ;don't read past end of line | ||
| 1188 | CMP AL,LF ;line feed already encountered? | ||
| 1189 | JE GET_PCHAR_X ;don't read past end of line | ||
| 1190 | LODSB ;get char from DS:SI, increment SI | ||
| 1191 | CMP AL,CR ;is the char a carriage return? | ||
| 1192 | JE GET_PCHAR_X ;yes, set Z flag at end of line | ||
| 1193 | CMP AL,LF ;no, is it a line feed? | ||
| 1194 | GET_PCHAR_X: ;attempted read past end of line | ||
| 1195 | RET | ||
| 1196 | GET_PCHAR ENDP ;returns char in AL | ||
| 1197 | |||
| 1198 | |||
| 1199 | CHECK_NUM PROC ;check AL for ASCII digit | ||
| 1200 | CMP AL,'0' ;< '0'? | ||
| 1201 | JB CHECK_NUM_X ;exit if it is | ||
| 1202 | |||
| 1203 | CMP AL,'9' ;> '9'? | ||
| 1204 | JA CHECK_NUM_X ;exit if it is | ||
| 1205 | |||
| 1206 | CMP AL,AL ;set Z flag to indicate numeric | ||
| 1207 | CHECK_NUM_X: | ||
| 1208 | RET ;Z set if numeric, NZ if not numeric | ||
| 1209 | CHECK_NUM ENDP | ||
| 1210 | |||
| 1211 | |||
| 1212 | SKIP_TO_DIGIT PROC ;skip to first numeric character | ||
| 1213 | CALL CHECK_NUM ;is current char a digit? | ||
| 1214 | JZ SKIP_TO_DIGIT_X ;if so, skip is complete | ||
| 1215 | |||
| 1216 | CALL GET_PCHAR ;get next character from line | ||
| 1217 | JNZ SKIP_TO_DIGIT ;loop until first digit or CR or LF | ||
| 1218 | RET ;character is CR or LF | ||
| 1219 | |||
| 1220 | SKIP_TO_DIGIT_X: | ||
| 1221 | CMP AL,0 ;digit found, force NZ | ||
| 1222 | RET | ||
| 1223 | SKIP_TO_DIGIT ENDP | ||
| 1224 | |||
| 1225 | C10 DW 10 | ||
| 1226 | GN_ERR DB ? ;zero if no overflow in accumulation | ||
| 1227 | |||
| 1228 | GET_NUMBER PROC ;convert string of digits to binary value | ||
| 1229 | XOR CX,CX ;accumulate number in CX | ||
| 1230 | MOV CS:GN_ERR,CL ;no overflow yet | ||
| 1231 | GET_NUMBER_A: ;accumulate next digit | ||
| 1232 | SUB AL,'0' ;convert ASCII to binary | ||
| 1233 | CBW ;clear AH | ||
| 1234 | XCHG AX,CX ;previous accumulation in AX, new digit in CL | ||
| 1235 | MUL CS:C10 ;DX:AX := AX*10 | ||
| 1236 | OR CS:GN_ERR,DL ;set GN_ERR <> 0 if overflow | ||
| 1237 | ADD AX,CX ;add new digit from | ||
| 1238 | XCHG AX,CX ;number now in CX | ||
| 1239 | DEC SI ;back up to prior entry | ||
| 1240 | MOV AL,' ' ;blank out prior entry | ||
| 1241 | MOV [SI],AL ; | ||
| 1242 | INC SI ;set to current entry | ||
| 1243 | CALL GET_PCHAR ;get next character | ||
| 1244 | CALL CHECK_NUM ;see if it was numeric | ||
| 1245 | JZ GET_NUMBER_A ;continue accumulating | ||
| 1246 | CMP CS:GN_ERR,0 ;did we overflow? | ||
| 1247 | JE GET_NUMBER_B ;if not, we're done | ||
| 1248 | XOR CX,CX ;return zero (always invalid) if overflow | ||
| 1249 | GET_NUMBER_B: | ||
| 1250 | RET ;number in CX, next char in AL | ||
| 1251 | GET_NUMBER ENDP | ||
| 1252 | |||
| 1253 | GET_PARMS ENDP | ||
| 1254 | |||
| 1255 | SUBTTL APPLY_DEFAULTS | ||
| 1256 | PAGE | ||
| 1257 | ;-----------------------------------------------------------------------; | ||
| 1258 | ; APPLY_DEFAULTS supplies any parameter values that the user ; | ||
| 1259 | ; failed to specify ; | ||
| 1260 | ;-----------------------------------------------------------------------; | ||
| 1261 | ASSUME DS:CSEG | ||
| 1262 | APPLY_DEFAULTS PROC | ||
| 1263 | XOR AX,AX | ||
| 1264 | CMP BUFF_SIZE,AX ;is buffer size zero? | ||
| 1265 | JNE APPLY_DEFAULTS_A ;no, user specified something | ||
| 1266 | |||
| 1267 | MOV BUFF_SIZE,DFLT_BSIZE ;supply default buffer size | ||
| 1268 | OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted | ||
| 1269 | |||
| 1270 | APPLY_DEFAULTS_A: | ||
| 1271 | CMP BPB_SSZ,AX ;is sector size zero? | ||
| 1272 | JNE APPLY_DEFAULTS_B ;no, user specified something | ||
| 1273 | |||
| 1274 | MOV BPB_SSZ,DFLT_SSZ ;supply default sector size | ||
| 1275 | OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted | ||
| 1276 | |||
| 1277 | APPLY_DEFAULTS_B: | ||
| 1278 | CMP BPB_DIRN,AX ;are directory entries zero? | ||
| 1279 | JNE APPLY_DEFAULTS_C ;no, user specified something | ||
| 1280 | |||
| 1281 | MOV BPB_DIRN,DFLT_DIRN ;supply default directory entries | ||
| 1282 | OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted | ||
| 1283 | |||
| 1284 | APPLY_DEFAULTS_C: ; | ||
| 1285 | CMP EM_SW,0 ;extended memory ? | ||
| 1286 | JE APPLY_DEFAULTS_D ;no, jump around | ||
| 1287 | CMP MAXSEC_TRF,AX ;is maximum sectors zero? | ||
| 1288 | JNE APPLY_DEFAULTS_D ;no, user specified something | ||
| 1289 | |||
| 1290 | MOV MAXSEC_TRF,DFLT_ESS ;supply default maximum number of | ||
| 1291 | ;sector to transfer | ||
| 1292 | OR ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted | ||
| 1293 | APPLY_DEFAULTS_D: | ||
| 1294 | RET | ||
| 1295 | APPLY_DEFAULTS ENDP | ||
| 1296 | |||
| 1297 | SUBTTL DETERMINE_START address of VDISK buffer | ||
| 1298 | PAGE | ||
| 1299 | ;-----------------------------------------------------------------------; | ||
| 1300 | ; DETERMINE_START figures out the starting address of the VDISK ; | ||
| 1301 | ; buffer ; | ||
| 1302 | ;-----------------------------------------------------------------------; | ||
| 1303 | ASSUME DS:CSEG | ||
| 1304 | DETERMINE_START PROC | ||
| 1305 | |||
| 1306 | ;If extended memory is NOT being used, the VDISK buffer immediately | ||
| 1307 | ;follows the resident code. | ||
| 1308 | |||
| 1309 | ;If extended memory IS being used, START_BUFFER_PARA becomes the | ||
| 1310 | ;end of device driver address passed back to DOS. | ||
| 1311 | |||
| 1312 | MOV AX,CS ;start para of VDISK code | ||
| 1313 | ADD AX,VDISKP ;+ length of resident code | ||
| 1314 | MOV START_BUFFER_PARA,AX ;save as buffer start para | ||
| 1315 | |||
| 1316 | CMP EM_SW,0 ;is extended memory requested? | ||
| 1317 | JE DETERMINE_START_X ;if not, we're done here | ||
| 1318 | |||
| 1319 | ;If this is the first extended memory VDISK device driver to be installed, | ||
| 1320 | ;the start address for I/O is 1 megabyte. | ||
| 1321 | |||
| 1322 | ;If one or more extended memory VDISK device drivers have been installed, | ||
| 1323 | ;the start address for I/O for THIS device driver is acquired from the | ||
| 1324 | ;fields AVAIL_LO and AVAIL_HI in the FIRST VDISK device driver. | ||
| 1325 | |||
| 1326 | ;The first extended memory VDISK device driver is located by INT 19H's vector. | ||
| 1327 | |||
| 1328 | MOV FIRST_EM_SW,0FFH ;indicate first VDISK device driver | ||
| 1329 | MOV FIRST_VDISK,CS ;segment addr of first VDISK | ||
| 1330 | |||
| 1331 | PUSH DS ;preserve DS | ||
| 1332 | XOR AX,AX | ||
| 1333 | MOV DS,AX ;set DS = 0 | ||
| 1334 | ASSUME DS:INT_VEC | ||
| 1335 | |||
| 1336 | MOV AX,DS:BOOT_VECS ;get segment addr of INT 19H routine | ||
| 1337 | MOV DS,AX ;to DS | ||
| 1338 | ASSUME DS:NOTHING | ||
| 1339 | |||
| 1340 | PUSH CS | ||
| 1341 | POP ES ;set ES = CS | ||
| 1342 | MOV SI,OFFSET VOL_LABEL ;DS:SI point to VOL label field | ||
| 1343 | ;in first VDISK (if present) | ||
| 1344 | MOV DI,SI ;ES:DI point to VOL label field of | ||
| 1345 | ;this VDISK | ||
| 1346 | |||
| 1347 | MOV CX,VOL_LABEL_LEN ;length of volume label | ||
| 1348 | REP CMPSB ;does INT 19H vector point to a VDISK | ||
| 1349 | ;device driver? | ||
| 1350 | JNE DETERMINE_START_A ;jump if this is the first VDISK | ||
| 1351 | |||
| 1352 | ;Another extended memory VDISK device driver has been installed. | ||
| 1353 | ;Its AVAIL_LO and AVAIL_HI are the first free byte of extended memory. | ||
| 1354 | |||
| 1355 | MOV CS:FIRST_EM_SW,0 ;indicate not first device driver | ||
| 1356 | MOV CS:FIRST_VDISK,DS ;save pointer to 1st device driver | ||
| 1357 | |||
| 1358 | ;Copy AVAIL_LO and AVAIL_HI from first VDISK to this VDISK | ||
| 1359 | |||
| 1360 | MOV SI,OFFSET AVAIL_LO ;DS:SI point to AVAIL_LO in first VDISK | ||
| 1361 | MOV DI,SI ;ES:DI point to AVAIL_LO in this VDISK | ||
| 1362 | MOVSW ;copy AVAIL_LO from first to this VDISK | ||
| 1363 | MOVSB ;copy AVAIL_HI | ||
| 1364 | |||
| 1365 | DETERMINE_START_A: ;copy AVAIL_LO and AVAIL_HI to START_EM | ||
| 1366 | POP DS ;set DS = CS | ||
| 1367 | |||
| 1368 | MOV SI,OFFSET AVAIL_LO ;source offset | ||
| 1369 | MOV DI,OFFSET START_EM_LO ;destination offset | ||
| 1370 | |||
| 1371 | MOVSW ;move AVAIL_LO to START_EM_LO | ||
| 1372 | MOVSB ;move AVAIL_HI to START_EM_HI | ||
| 1373 | DETERMINE_START_X: | ||
| 1374 | RET | ||
| 1375 | DETERMINE_START ENDP | ||
| 1376 | |||
| 1377 | SUBTTL VALIDATE parameters | ||
| 1378 | PAGE | ||
| 1379 | ;-----------------------------------------------------------------------; | ||
| 1380 | ; VALIDATE adjusts parameters as necessary ; | ||
| 1381 | ;-----------------------------------------------------------------------; | ||
| 1382 | VAL_SSZ_TBL LABEL WORD ;table of valid sector sizes | ||
| 1383 | VAL_SSZ_S DW 128 ;smallest valid sector size | ||
| 1384 | DW 256 | ||
| 1385 | VAL_SSZ_L DW 512 ;largest valid sector size | ||
| 1386 | VAL_SSZ_N EQU ($-VAL_SSZ_TBL)/2 ;number of table entries | ||
| 1387 | |||
| 1388 | ASSUME DS:CSEG | ||
| 1389 | VALIDATE PROC ;validate parameters | ||
| 1390 | MOV BPB_AUSZ,1 ;initial allocation unit is 1 sector | ||
| 1391 | |||
| 1392 | CALL VAL_BSIZE ;validate buffer size | ||
| 1393 | |||
| 1394 | CALL VAL_SSZ ;validate (adjust if necessary) BPB_SSZ | ||
| 1395 | |||
| 1396 | VALIDATE_A: | ||
| 1397 | AND ERR_FLAG,255-ERR_PASS ;indicate nothing changed this pass | ||
| 1398 | |||
| 1399 | MOV AX,BPB_SSZ ;sector size | ||
| 1400 | CWD ;clear DX for division | ||
| 1401 | DIV WPARA_SIZE ;sector size/para size | ||
| 1402 | MOV PARAS_PER_SECTOR,AX ;number of paragraphs/sector | ||
| 1403 | |||
| 1404 | MOV AX,BUFF_SIZE ;requested buffersize in KB | ||
| 1405 | MUL C1024 ;DX:AX = buffer size in bytes | ||
| 1406 | DIV BPB_SSZ ;/sector size = # sectors | ||
| 1407 | MOV BPB_SECN,AX ;store number of sectors | ||
| 1408 | |||
| 1409 | CALL VAL_DIRN ;validate number of directory entries | ||
| 1410 | |||
| 1411 | TEST ERR_FLAG,ERR_PASS ;may have reset sector size | ||
| 1412 | JNZ VALIDATE_A ;recompute directory & FAT sizes | ||
| 1413 | |||
| 1414 | CALL VAL_FAT ;compute FAT entries, validity test | ||
| 1415 | |||
| 1416 | TEST ERR_FLAG,ERR_PASS ;if cluster size altered this pass | ||
| 1417 | JNZ VALIDATE_A ;recompute directory & FAT sizes | ||
| 1418 | |||
| 1419 | ;Make certain buffer size is large enough to contain: | ||
| 1420 | ; boot sector(s) | ||
| 1421 | ; FAT sector(s) | ||
| 1422 | ; directory sector(s) | ||
| 1423 | ; at least 1 data cluster | ||
| 1424 | |||
| 1425 | MOV AL,BPB_FATN ;number of FAT copies | ||
| 1426 | CBW ;clear AH | ||
| 1427 | MUL BPB_FATSZ ;* sectors for 1 FAT = FAT sectors | ||
| 1428 | ADD AX,BPB_RES ;+ reserved sectors | ||
| 1429 | ADD AX,DIR_SECTORS ;+ directory sectors | ||
| 1430 | MOV CL,BPB_AUSZ ;get sectors/cluster | ||
| 1431 | XOR CH,CH ;CX = sectors in one cluster | ||
| 1432 | ADD AX,CX ;+ one data cluster | ||
| 1433 | CMP BPB_SECN,AX ;compare with sectors available | ||
| 1434 | JAE VALIDATE_X ;jump if enough sectors | ||
| 1435 | |||
| 1436 | CMP DIR_SECTORS,1 ;down to 1 directory sector? | ||
| 1437 | JBE VALIDATE_C ;can't let it go below 1 | ||
| 1438 | |||
| 1439 | MOV AX,BPB_SSZ ;sector size | ||
| 1440 | CWD ;clear DX for division | ||
| 1441 | DIV DIRE_SIZE ;sectorsize/dir entry size = entries/sector | ||
| 1442 | SUB BPB_DIRN,AX ;reduce directory entries by 1 sector | ||
| 1443 | |||
| 1444 | OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted | ||
| 1445 | JMP VALIDATE_A ;retry with new directory entries number | ||
| 1446 | |||
| 1447 | VALIDATE_C: ;not enough space for any VDISK | ||
| 1448 | OR ERR_FLAG,ERR_SYSSZ | ||
| 1449 | VALIDATE_X: | ||
| 1450 | RET | ||
| 1451 | |||
| 1452 | SUBTTL VAL_BSIZE Validate buffer size | ||
| 1453 | PAGE | ||
| 1454 | ;-----------------------------------------------------------------------; | ||
| 1455 | ; VAL_BSIZE adjusts the buffer size as necessary ; | ||
| 1456 | ;-----------------------------------------------------------------------; | ||
| 1457 | VAL_BSIZE PROC | ||
| 1458 | CALL GET_MSIZE ;determine memory available to VDISK | ||
| 1459 | ;returns available KB in AX | ||
| 1460 | OR AX,AX ;is any memory available at all? | ||
| 1461 | JNZ VAL_BSIZE_B ;yes, continue | ||
| 1462 | |||
| 1463 | OR ERR_FLAG,ERR_SYSSZ ;indicate system too small for VDISK | ||
| 1464 | MOV BUFF_SIZE,1 ;set up minimal values to continue init | ||
| 1465 | MOV AX,VAL_SSZ_S ;smallest possible sector size | ||
| 1466 | MOV BPB_SSZ,AX | ||
| 1467 | MOV BPB_DIRN,4 ;4 directory entries | ||
| 1468 | RET | ||
| 1469 | |||
| 1470 | VAL_BSIZE_B: ;some memory is available | ||
| 1471 | CMP AX,BUFF_SIZE ;is available memory >= requested? | ||
| 1472 | JAE VAL_BSIZE_C ;if so, we're done | ||
| 1473 | |||
| 1474 | MOV BUFF_SIZE,AX ;give all available memory | ||
| 1475 | OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted | ||
| 1476 | VAL_BSIZE_C: | ||
| 1477 | RET | ||
| 1478 | |||
| 1479 | |||
| 1480 | GET_MSIZE PROC ;determine memory available to VDISK | ||
| 1481 | ;returns KB available in AX | ||
| 1482 | CMP EM_SW,0 ;extended memory? | ||
| 1483 | JE GET_MSIZE_2 ;use non-extended memory routine | ||
| 1484 | |||
| 1485 | MOV AH,EM_MEMSIZE ;function code to AH | ||
| 1486 | INT EM_INT ;get extended memory size in AX | ||
| 1487 | JC GET_MSIZE_Z ;if error, no extended memory installed | ||
| 1488 | |||
| 1489 | MUL C1024 ;DX,AX = bytes of extended memory | ||
| 1490 | ADD DX,10H ;DX,AX = high addr of extended memory+1 | ||
| 1491 | SUB AX,AVAIL_LO ;- address of first available byte | ||
| 1492 | SBB DL,AVAIL_HI ;is number of free bytes | ||
| 1493 | DIV C1024 ;AX = number of whole free kilobytes | ||
| 1494 | RET | ||
| 1495 | |||
| 1496 | GET_MSIZE_2: ;non-extended memory size determination | ||
| 1497 | |||
| 1498 | ;Compute AX = total system size, - (VDISK end address + 64KB) | ||
| 1499 | |||
| 1500 | MOV AX,START_BUFFER_PARA ;paragraph end of VDISK code | ||
| 1501 | XOR DX,DX ;clear for division | ||
| 1502 | DIV PARA_PER_KB ;KB address of load point | ||
| 1503 | ADD DX,0FFFFH ;round upward to KB boundary | ||
| 1504 | ADC AX,MIN_MEMORY_LEFT ;pick up CY and the 64KB we should leave | ||
| 1505 | PUSH AX ;save across interrupt | ||
| 1506 | INT MEM_SIZE ;get total system size | ||
| 1507 | POP DX ;amount of total that we can't use | ||
| 1508 | SUB AX,DX ;available space to VDISK | ||
| 1509 | JNC GET_MSIZE_X ;exit if positive | ||
| 1510 | |||
| 1511 | GET_MSIZE_Z: | ||
| 1512 | XOR AX,AX ;indicate no memory available | ||
| 1513 | GET_MSIZE_X: ;exit from memory size determination | ||
| 1514 | RET | ||
| 1515 | GET_MSIZE ENDP | ||
| 1516 | |||
| 1517 | VAL_BSIZE ENDP | ||
| 1518 | |||
| 1519 | SUBTTL VAL_SSZ Validate Sector Size | ||
| 1520 | PAGE | ||
| 1521 | ;-----------------------------------------------------------------------; | ||
| 1522 | ; VAL_SSZ validates sector size, adjusting if necessary ; | ||
| 1523 | ;-----------------------------------------------------------------------; | ||
| 1524 | VAL_SSZ PROC ;validate sector size | ||
| 1525 | CMP CS:EM_SW,0 ;extended memory ? | ||
| 1526 | JE VAL_SSZ_ST ;no,go check sector size | ||
| 1527 | MOV BX,MAXSEC_TRF ;move number of sectors to transfer | ||
| 1528 | CMP BX,1 ;> or equal to 1 ? | ||
| 1529 | JB DFLT_TRF ;set default if it is | ||
| 1530 | CMP BX,8 ;> than 8 ? | ||
| 1531 | JA DFLT_TRF ;set default if it is | ||
| 1532 | JMP VAL_SSZ_ST ;continue processing | ||
| 1533 | |||
| 1534 | DFLT_TRF: ;set default | ||
| 1535 | MOV MAXSEC_TRF,DFLT_ESS ; | ||
| 1536 | MOV BX,MAXSEC_TRF ; | ||
| 1537 | OR CS:ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted | ||
| 1538 | |||
| 1539 | VAL_SSZ_ST: ;validate sector size | ||
| 1540 | MOV MAX_CNT,BX ;initialize maximum number of sectors | ||
| 1541 | ;to transfer for extended memory case | ||
| 1542 | MOV BX,BPB_SSZ ;requested sector size | ||
| 1543 | MOV CX,VAL_SSZ_N ;number of table entries | ||
| 1544 | MOV SI,OFFSET VAL_SSZ_TBL ;DS:SI point to table start | ||
| 1545 | VAL_SSZ_A: | ||
| 1546 | LODSW ;get table entry, step table pointer | ||
| 1547 | CMP AX,BX ;is value in table? | ||
| 1548 | JE VAL_SSZ_X ;exit if value found | ||
| 1549 | LOOP VAL_SSZ_A ;loop until table end | ||
| 1550 | |||
| 1551 | MOV BX,DFLT_SSZ ;get default sector size | ||
| 1552 | MOV BPB_SSZ,BX ;set sector size to default value | ||
| 1553 | OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted | ||
| 1554 | VAL_SSZ_X: | ||
| 1555 | |||
| 1556 | ;Compute the maximum number of sectors that can be moved in 64KB (less one) | ||
| 1557 | ;Restricting moves to this amount avoids 64KB boundary problems. | ||
| 1558 | |||
| 1559 | CMP CS:EM_SW,0 ;extended memory ? | ||
| 1560 | JNE SIZE_DONE ;yes, we are done | ||
| 1561 | XOR DX,DX | ||
| 1562 | MOV AX,0FFFFH ;64KB - 1 | ||
| 1563 | DIV BX ;/sector size | ||
| 1564 | MOV MAX_CNT,AX ;max sectors in one move | ||
| 1565 | SIZE_DONE: | ||
| 1566 | RET | ||
| 1567 | VAL_SSZ ENDP | ||
| 1568 | |||
| 1569 | SUBTTL VAL_DIRN Validate number of directory entries | ||
| 1570 | PAGE | ||
| 1571 | ;-----------------------------------------------------------------------; | ||
| 1572 | ; VAL_DIRN validates and adjusts the number of directory entries. ; | ||
| 1573 | ; ; | ||
| 1574 | ; Minimum is MIN_DIRN, maximum is MAX_DIRN. If outside these ; | ||
| 1575 | ; limits, DFLT_DIRN is used. ; | ||
| 1576 | ; ; | ||
| 1577 | ; The number of directory entries is rounded upward to fill ; | ||
| 1578 | ; a sector ; | ||
| 1579 | ;-----------------------------------------------------------------------; | ||
| 1580 | VAL_DIRN PROC | ||
| 1581 | MOV AX,BPB_DIRN ;requested directory entries | ||
| 1582 | CMP AX,MIN_DIRN ;if less than minimum | ||
| 1583 | JB VAL_DIRN_A ;use default instead | ||
| 1584 | |||
| 1585 | CMP AX,MAX_DIRN ;if <= maximum | ||
| 1586 | JBE VAL_DIRN_B ;accept value as provided | ||
| 1587 | |||
| 1588 | VAL_DIRN_A: | ||
| 1589 | MOV AX,DFLT_DIRN ;use default directory entries | ||
| 1590 | OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted | ||
| 1591 | VAL_DIRN_B: ;AX is number of directory entries | ||
| 1592 | MUL DIRE_SIZE ;* 32 = bytes of directory requested | ||
| 1593 | DIV BPB_SSZ ;/ sector size = # of directory sectors | ||
| 1594 | OR DX,DX ;test remainder for zero | ||
| 1595 | JZ VAL_DIRN_C ;jump if exact fit | ||
| 1596 | |||
| 1597 | INC AX ;increment directory sectors | ||
| 1598 | OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted | ||
| 1599 | VAL_DIRN_C: ;make sure enough sectors available | ||
| 1600 | MOV DX,BPB_SECN ;total sectors on media | ||
| 1601 | SUB DX,BPB_RES ;less reserved sectors | ||
| 1602 | SUB DX,2 ;less minimum FAT and 1 data sector | ||
| 1603 | CMP AX,DX ;if directory sectors <= available | ||
| 1604 | JLE VAL_DIRN_D ;use requested amount | ||
| 1605 | |||
| 1606 | MOV AX,1 ;use only one directory sector | ||
| 1607 | OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted | ||
| 1608 | VAL_DIRN_D: | ||
| 1609 | MOV DIR_SECTORS,AX ;save number of directory sectors | ||
| 1610 | MUL BPB_SSZ ;dir sectors * sector size = dir bytes | ||
| 1611 | DIV DIRE_SIZE ;dir bytes / entry size = entries | ||
| 1612 | MOV BPB_DIRN,AX ;store adjusted directory entries | ||
| 1613 | RET | ||
| 1614 | VAL_DIRN ENDP | ||
| 1615 | |||
| 1616 | SUBTTL VAL_FAT Validate File Allocation Table (FAT) | ||
| 1617 | PAGE | ||
| 1618 | ;-----------------------------------------------------------------------; | ||
| 1619 | ;VAL_FAT computes: ; | ||
| 1620 | ;BPB_FATSZ, the number of sectors required per FAT copy ; | ||
| 1621 | ; ; | ||
| 1622 | ;Each FAT entry is 12 bits long, for a maximum of 4095 FAT entries. ; | ||
| 1623 | ;(A few FAT entries are reserved, so the highest number of FAT entries ; | ||
| 1624 | ;we permit is 0FE0H.) With large buffer sizes and small sector sizes, ; | ||
| 1625 | ;we have more allocation units to describe than a 12-bit entry will ; | ||
| 1626 | ;describe. If the number of FAT entries is too large, the sector size ; | ||
| 1627 | ;is increased (up to a maximum of 512 bytes), and then the allocation ; | ||
| 1628 | ;unit (cluster) size is doubled, until we have few enough allocation ; | ||
| 1629 | ;units to be properly described in 12 bits. ; | ||
| 1630 | ; ; | ||
| 1631 | ;This computation is slightly conservative in that the FAT entries ; | ||
| 1632 | ;necessary to describe the FAT sectors are included in the computation. ; | ||
| 1633 | ;-----------------------------------------------------------------------; | ||
| 1634 | VAL_FAT PROC | ||
| 1635 | MOV AX,BPB_SECN ;total number of sectors | ||
| 1636 | SUB AX,BPB_RES ;don't count boot sector(s) | ||
| 1637 | SUB AX,DIR_SECTORS ;don't count directory sectors | ||
| 1638 | JG VAL_FAT_A ;jump if some remaining | ||
| 1639 | MOV BPB_SSZ,DFLT_SSZ ;force default sector size | ||
| 1640 | OR ERR_FLAG,ERR_SSZ+ERR_PASS ;indicate sector size adjusted | ||
| 1641 | JMP SHORT VAL_FAT_X ;recompute all values | ||
| 1642 | VAL_FAT_A: | ||
| 1643 | XOR DX,DX ;clear DX for division | ||
| 1644 | MOV CL,BPB_AUSZ ;CX = sectors/cluster | ||
| 1645 | XOR CH,CH | ||
| 1646 | DIV CX ;whole number of clusters in AX | ||
| 1647 | ADD DX,0FFFFH ;set carry if remainder | ||
| 1648 | ADC AX,0 ;increment AX if remainder | ||
| 1649 | CMP AX,MAX_FATE ;number of FAT entries too large? | ||
| 1650 | JBE VAL_FAT_C ;no, continue | ||
| 1651 | |||
| 1652 | MOV AX,BPB_SSZ ;pick up current sector size | ||
| 1653 | CMP AX,VAL_SSZ_L ;already at largest permitted? | ||
| 1654 | JE VAL_FAT_B ;yes, can't make it any larger | ||
| 1655 | |||
| 1656 | SHL BPB_SSZ,1 ;double sector size | ||
| 1657 | OR ERR_FLAG,ERR_SSZB ;indicate sector size adjusted | ||
| 1658 | JMP SHORT VAL_FAT_X ;recompute all sizes with new BPBSSZ | ||
| 1659 | |||
| 1660 | VAL_FAT_B: ;sector size is at maximum | ||
| 1661 | SHL BPB_AUSZ,1 ;double allocation unit size | ||
| 1662 | OR ERR_FLAG,ERR_PASS ;indicate another pass required | ||
| 1663 | JMP SHORT VAL_FAT_X ;recompute values | ||
| 1664 | |||
| 1665 | VAL_FAT_C: ;FAT size = 1.5 * number of clusters | ||
| 1666 | MOV CX,AX ;number of clusters | ||
| 1667 | SHL AX,1 ;* 2 | ||
| 1668 | ADD AX,CX ;* 3 | ||
| 1669 | SHR AX,1 ;* 1.5 | ||
| 1670 | ADC AX,3 ;add 3 bytes for first 2 FAT entries | ||
| 1671 | ;(media descriptor and FFFFH), and CY | ||
| 1672 | XOR DX,DX ;clear DX for division | ||
| 1673 | DIV BPB_SSZ ;FAT size/sector size | ||
| 1674 | ADD DX,0FFFFH ;set carry if remainder | ||
| 1675 | ADC AX,0 ;round upward | ||
| 1676 | MOV BPB_FATSZ,AX ;number of sectors for 1 FAT copy | ||
| 1677 | VAL_FAT_X: | ||
| 1678 | RET | ||
| 1679 | VAL_FAT ENDP | ||
| 1680 | |||
| 1681 | |||
| 1682 | VALIDATE ENDP | ||
| 1683 | |||
| 1684 | SUBTTL COPY_BPB Copy BPB to Boot Record | ||
| 1685 | PAGE | ||
| 1686 | ;-----------------------------------------------------------------------; | ||
| 1687 | ; COPY_BPB copies the BIOS Parameter Block (BPB) ; | ||
| 1688 | ; to the VDISK Boot Record ; | ||
| 1689 | ;-----------------------------------------------------------------------; | ||
| 1690 | ASSUME DS:CSEG | ||
| 1691 | COPY_BPB PROC ;Copy BBP to Boot Record | ||
| 1692 | PUSH DS | ||
| 1693 | POP ES ;set ES = DS | ||
| 1694 | |||
| 1695 | MOV CX,BPB_LEN ;length of BPB | ||
| 1696 | MOV SI,OFFSET BPB ;source offset | ||
| 1697 | MOV DI,OFFSET BOOT_BPB ;target offset | ||
| 1698 | REP MOVSB ;copy BPB to boot record | ||
| 1699 | RET | ||
| 1700 | COPY_BPB ENDP | ||
| 1701 | |||
| 1702 | SUBTTL VERIFY_EXTENDER | ||
| 1703 | PAGE | ||
| 1704 | ;-----------------------------------------------------------------------; | ||
| 1705 | ; VERIFY_EXTENDER makes sure that if an Expansion Unit is ; | ||
| 1706 | ; installed, the memory size switches on the Extender Card ; | ||
| 1707 | ; are correctly set. ; | ||
| 1708 | ;-----------------------------------------------------------------------; | ||
| 1709 | |||
| 1710 | |||
| 1711 | ASSUME DS:CSEG | ||
| 1712 | EXT_P210 EQU 0210H ;write to latch expansion bus data | ||
| 1713 | ;read to verify expansion bus data | ||
| 1714 | EXT_P213 EQU 0213H ;Expansion Unit status | ||
| 1715 | |||
| 1716 | VERIFY_EXTENDER PROC | ||
| 1717 | |||
| 1718 | NOP | ||
| 1719 | |||
| 1720 | MOV DX,EXT_P210 ;Expansion bus data port address | ||
| 1721 | |||
| 1722 | MOV AX,5555H ;set data pattern | ||
| 1723 | OUT DX,AL ;write 55H to control port | ||
| 1724 | PUSH DX | ||
| 1725 | POP DX | ||
| 1726 | |||
| 1727 | JMP SHORT $+2 ;Let the I/O circuits catch up | ||
| 1728 | IN AL,020h ;Clear the CMOS bus drivers! | ||
| 1729 | |||
| 1730 | IN AL,DX ;recover data | ||
| 1731 | CMP AH,AL ;did we recover the same data? | ||
| 1732 | JNE VERIFY_EXTENDER_X ;if not, no extender card | ||
| 1733 | |||
| 1734 | NOT AX ;set AX = 0AAAAH | ||
| 1735 | OUT DX,AL ;write 0AAH to control port | ||
| 1736 | PUSH DX ;load data line | ||
| 1737 | POP DX ;load data line | ||
| 1738 | |||
| 1739 | JMP SHORT $+2 ;Let the I/O circuits catch up | ||
| 1740 | IN AL,020h ;Clear the CMOS bus drivers! | ||
| 1741 | |||
| 1742 | IN AL,DX ;recover data | ||
| 1743 | CMP AH,AL ;did we recover the same data? | ||
| 1744 | JNE VERIFY_EXTENDER_X ;if not, no extender card | ||
| 1745 | |||
| 1746 | ;Expansion Unit is present. | ||
| 1747 | |||
| 1748 | ;Determine what the switch settings should be on the Extender Card | ||
| 1749 | |||
| 1750 | INT MEM_SIZE ;get system memory size in KB in AX | ||
| 1751 | ADD AX,63D ;memory size + 63K | ||
| 1752 | MOV CL,6 ;2^6 = 64 | ||
| 1753 | SHR AX,CL ;divide by 64 | ||
| 1754 | ;AX is highest segment address | ||
| 1755 | MOV AH,AL ;save number of segments | ||
| 1756 | |||
| 1757 | ;Read Expander card switch settings | ||
| 1758 | |||
| 1759 | MOV DX,EXT_P213 ;expansion unit status | ||
| 1760 | IN AL,DX ;read status | ||
| 1761 | ;bits 7-4 (hi nibble) are switches | ||
| 1762 | MOV CL,4 ;shift count | ||
| 1763 | SHR AL,CL ;shift switches to bits 3-0 of AL | ||
| 1764 | |||
| 1765 | CMP AH,AL ;do switches match memory size? | ||
| 1766 | JE VERIFY_EXTENDER_X ;yes, exit normally | ||
| 1767 | |||
| 1768 | OR ERR_FLAG,ERR_EXTSW ;indicate switch settings are wrong | ||
| 1769 | |||
| 1770 | VERIFY_EXTENDER_X: | ||
| 1771 | RET | ||
| 1772 | VERIFY_EXTENDER ENDP | ||
| 1773 | |||
| 1774 | SUBTTL UPDATE_AVAIL | ||
| 1775 | PAGE | ||
| 1776 | ;-----------------------------------------------------------------------; | ||
| 1777 | ; UPDATE_AVAIL updates the address of the first byte in extended ; | ||
| 1778 | ; memory not used by any VDISK buffer ; | ||
| 1779 | ;-----------------------------------------------------------------------; | ||
| 1780 | UPDATE_AVAIL PROC ;update AVAIL_LO and AVAIL_HI of first VDISK | ||
| 1781 | MOV AX,BUFF_SIZE ;number of KB of VDISK buffer | ||
| 1782 | MUL C1024 ;DX,AX = number of bytes of VDISK buffer | ||
| 1783 | |||
| 1784 | PUSH DS | ||
| 1785 | MOV DS,FIRST_VDISK ;set DS to first VDISK | ||
| 1786 | ADD DS:AVAIL_LO,AX ;update first available byte location | ||
| 1787 | ADC DS:AVAIL_HI,DL | ||
| 1788 | POP DS | ||
| 1789 | RET | ||
| 1790 | UPDATE_AVAIL ENDP | ||
| 1791 | |||
| 1792 | SUBTTL FORMAT_VDISK | ||
| 1793 | PAGE | ||
| 1794 | ;-----------------------------------------------------------------------; | ||
| 1795 | ; This Request Header is used by MOVE_VDISK to move the ; | ||
| 1796 | ; first few sectors of the virtual disk (boot, FAT, and ; | ||
| 1797 | ; Directory) into extended memory. ; | ||
| 1798 | ;-----------------------------------------------------------------------; | ||
| 1799 | |||
| 1800 | MOVE_RH DB MOVE_RH_L ;length of request header | ||
| 1801 | DB 0 ;sub unit | ||
| 1802 | DB 8 ;output operation | ||
| 1803 | DW 0 ;status | ||
| 1804 | DQ ? ;reserved for DOS | ||
| 1805 | DB ? ;media descriptor byte | ||
| 1806 | MOVE_RHO DW ? ;offset of data transfer address | ||
| 1807 | MOVE_RHS DW ? ;segment of data transfer address | ||
| 1808 | MOVE_RHCNT DW ? ;count of sectors to transfer | ||
| 1809 | DW 0 ;starting sector number | ||
| 1810 | MOVE_RH_L EQU $-MOVE_RH ;length of request header | ||
| 1811 | |||
| 1812 | ;-----------------------------------------------------------------------; | ||
| 1813 | ; FORMAT_VDISK formats the boot sector, FAT, and directory of an ; | ||
| 1814 | ; extended memory VDISK in storage immediately following ; | ||
| 1815 | ; VDISK code, in preparation for moving to extended memory. ; | ||
| 1816 | ;-----------------------------------------------------------------------; | ||
| 1817 | FORMAT_VDISK PROC ;format boot record, FATs and directory | ||
| 1818 | |||
| 1819 | MOV AX,CS ;compute 20-bit address | ||
| 1820 | MUL WPARA_SIZE ;16 * segment | ||
| 1821 | ADD AX,OFFSET MSGEND ;+ offset | ||
| 1822 | ADC DL,0 ;pick up carry | ||
| 1823 | ADD AX,STACK_SIZE ;plus stack size | ||
| 1824 | ADC DL,0 ;pick up carry | ||
| 1825 | |||
| 1826 | DIV WPARA_SIZE ;split into segment(AX)&offset(DX) | ||
| 1827 | MOV MOVE_RHS,AX ;save in Request Header for move | ||
| 1828 | MOV MOVE_RHO,DX | ||
| 1829 | |||
| 1830 | MOV DI,DX ;offset to DI | ||
| 1831 | MOV ES,AX ;segment to ES | ||
| 1832 | |||
| 1833 | ;copy the boot record | ||
| 1834 | |||
| 1835 | MOV SI,OFFSET BOOT_RECORD ;point to source field | ||
| 1836 | MOV AX,BPB_RES ;number of reserved sectors | ||
| 1837 | MUL BPB_SSZ ;* sector size = length of boot records | ||
| 1838 | MOV CX,AX ;length to CX for move | ||
| 1839 | REP MOVSB ;move boot record(s) | ||
| 1840 | |||
| 1841 | ;format the FAT(s) | ||
| 1842 | |||
| 1843 | MOV CL,BPB_FATN ;number of FATs | ||
| 1844 | XOR CH,CH | ||
| 1845 | FORMAT_VDISK_A: ;set up one FAT | ||
| 1846 | PUSH CX ;save loop counter on stack | ||
| 1847 | MOV AL,BPB_MCB ;media control byte | ||
| 1848 | STOSB ;store media control byte, increment DI | ||
| 1849 | MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH | ||
| 1850 | STOSW | ||
| 1851 | MOV AX,BPB_FATSZ ;number of sectors per FAT | ||
| 1852 | MUL BPB_SSZ ;* sector size = length of FAT in bytes | ||
| 1853 | SUB AX,3 ;less the 3 bytes we've stored | ||
| 1854 | MOV CX,AX ;count to CX | ||
| 1855 | XOR AX,AX | ||
| 1856 | REP STOSB ;clear remainder of FAT | ||
| 1857 | POP CX ;get loop counter off stack | ||
| 1858 | LOOP FORMAT_VDISK_A ;loop for all copies of the FAT | ||
| 1859 | |||
| 1860 | ;Format the directory | ||
| 1861 | |||
| 1862 | MOV SI,OFFSET VOL_LABEL ;point to volume label | ||
| 1863 | MOV CX,VOL_LABEL_LEN ;length of volume directory entry | ||
| 1864 | REP MOVSB ;move volume id to directory | ||
| 1865 | MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry | ||
| 1866 | MUL BPB_DIRN ;* number entries = bytes of directory | ||
| 1867 | SUB AX,VOL_LABEL_LEN ;less length of volume label | ||
| 1868 | MOV CX,AX ;CX = length of rest of directory | ||
| 1869 | XOR AX,AX | ||
| 1870 | REP STOSB ;clear directory to nulls | ||
| 1871 | RET | ||
| 1872 | FORMAT_VDISK ENDP | ||
| 1873 | |||
| 1874 | SUBTTL MOVE_VDISK | ||
| 1875 | PAGE | ||
| 1876 | ;-----------------------------------------------------------------------; | ||
| 1877 | ; MOVE_VDISK moves the formatted boot sector, FAT, and directory ; | ||
| 1878 | ; into extended memory. ; | ||
| 1879 | ;-----------------------------------------------------------------------; | ||
| 1880 | |||
| 1881 | MOVE_VDISK PROC | ||
| 1882 | MOV AL,BPB_FATN ;number of FAT copies | ||
| 1883 | CBW ;clear AH | ||
| 1884 | MUL BPB_FATSZ ;number of FAT sectors | ||
| 1885 | ADD AX,BPB_RES ;+ reserved sectors | ||
| 1886 | ADD AX,DIR_SECTORS ;+ directory sectors | ||
| 1887 | MOV MOVE_RHCNT,AX ;store as I/O length | ||
| 1888 | |||
| 1889 | MOV BX,OFFSET MOVE_RH ;DS:BX point to request header | ||
| 1890 | PUSH DS ;make sure DS gets preserved | ||
| 1891 | CALL INOUT ;move to extended memory | ||
| 1892 | POP DS | ||
| 1893 | RET | ||
| 1894 | MOVE_VDISK ENDP | ||
| 1895 | |||
| 1896 | SUBTTL UPDATE_BOOT | ||
| 1897 | PAGE | ||
| 1898 | ;-----------------------------------------------------------------------; | ||
| 1899 | ; UPDATE_BOOT updates the BOOT_EM word in the first extended ; | ||
| 1900 | ; memory VDISK (address 10 001EH) to show the kilobyte address ; | ||
| 1901 | ; of the first extended memory byte not used by any VDISK buffer. ; | ||
| 1902 | ;-----------------------------------------------------------------------; | ||
| 1903 | UPDATE_BOOT PROC | ||
| 1904 | PUSH DS | ||
| 1905 | MOV DS,FIRST_VDISK ;set DS to first VDISK | ||
| 1906 | MOV AX,DS:AVAIL_LO ;24-bit end address of all VDISKs | ||
| 1907 | MOV DL,DS:AVAIL_HI | ||
| 1908 | XOR DH,DH | ||
| 1909 | POP DS | ||
| 1910 | DIV C1024 ;address / 1024 | ||
| 1911 | MOV BOOT_EM,AX ;store in temporary location | ||
| 1912 | |||
| 1913 | MOV AX,2 ;length of block move is 2 bytes | ||
| 1914 | MOV TGT.DESC_LMT,AX | ||
| 1915 | MOV SRC.DESC_LMT,AX | ||
| 1916 | |||
| 1917 | MOV AX,PARA_SIZE ;16 | ||
| 1918 | MOV CX,CS ;our segment address | ||
| 1919 | MUL CX ;16 * segment address | ||
| 1920 | ADD AX,OFFSET BOOT_EM ;+ offset of source data | ||
| 1921 | ADC DL,0 ;pick up any carry | ||
| 1922 | |||
| 1923 | MOV SRC.DESC_BASEL,AX ;store source base address | ||
| 1924 | MOV SRC.DESC_BASEH,DL | ||
| 1925 | |||
| 1926 | MOV TGT.DESC_BASEL,BOOT_EM_OFF ;offset of BOOT_EM | ||
| 1927 | MOV TGT.DESC_BASEH,10H ;1 megabyte | ||
| 1928 | |||
| 1929 | MOV CX,1 ;move 1 word | ||
| 1930 | |||
| 1931 | PUSH CS | ||
| 1932 | POP ES | ||
| 1933 | MOV SI,OFFSET GDT ;ES:DI point to global descriptor table | ||
| 1934 | |||
| 1935 | MOV AH,EM_BLKMOVE ;function code | ||
| 1936 | INT EM_INT ;move BOOT_EM to 10 001EH | ||
| 1937 | RET | ||
| 1938 | UPDATE_BOOT ENDP | ||
| 1939 | |||
| 1940 | SUBTTL STEAL_INT19 | ||
| 1941 | PAGE | ||
| 1942 | ;-----------------------------------------------------------------------; | ||
| 1943 | ; STEAL_INT19 changes the INT 19H vector to point to this VDISK ; | ||
| 1944 | ; so that subsequent extended memory VDISKS may locate the ; | ||
| 1945 | ; AVAIL_HI and AVAIL_LO fields to determine their buffer start ; | ||
| 1946 | ; addresses. ; | ||
| 1947 | ;-----------------------------------------------------------------------; | ||
| 1948 | STEAL_INT19 PROC | ||
| 1949 | PUSH DS | ||
| 1950 | XOR AX,AX | ||
| 1951 | MOV DS,AX ;set DS = 0 | ||
| 1952 | ASSUME DS:INT_VEC | ||
| 1953 | CLI ;disable interrupts | ||
| 1954 | LES DI,DS:BOOT_VEC ;get original vector's content | ||
| 1955 | MOV CS:INTV19O,DI ;save original vector | ||
| 1956 | MOV CS:INTV19S,ES | ||
| 1957 | MOV DS:BOOT_VECO,OFFSET VDISK_INT19 ;offset of new INT routine | ||
| 1958 | MOV DS:BOOT_VECS,CS ;segment of new INT routine | ||
| 1959 | STI ;enable interrupts again | ||
| 1960 | POP DS ;restore DS | ||
| 1961 | RET | ||
| 1962 | STEAL_INT19 ENDP | ||
| 1963 | |||
| 1964 | SUBTTL FILL_RH Fill in Request Header | ||
| 1965 | PAGE | ||
| 1966 | ;-----------------------------------------------------------------------; | ||
| 1967 | ; FILL_RH fills in the Request Header returned to DOS ; | ||
| 1968 | ;-----------------------------------------------------------------------; | ||
| 1969 | ASSUME DS:CSEG | ||
| 1970 | FILL_RH PROC ;fill in INIT Request Header fields | ||
| 1971 | MOV CX,START_BUFFER_PARA ;segment end of VDISK resident code | ||
| 1972 | MOV AX,PARAS_PER_SECTOR ;paragraphs per sector | ||
| 1973 | MUL BPB_SECN ;* number of sectors | ||
| 1974 | ADD AX,CX ;+ starting segment | ||
| 1975 | MOV DX,AX ;DX is segment of end VDISK buffer | ||
| 1976 | CMP EM_SW,0 ;if extended memory not requested | ||
| 1977 | JE FILL_RH_A ;skip DX adjustment | ||
| 1978 | |||
| 1979 | MOV DX,CX ;end of code segment addr | ||
| 1980 | FILL_RH_A: ;DX is proper ending segment address | ||
| 1981 | MOV AL,1 ;number of units | ||
| 1982 | test CS:err_flag2,err_baddos | ||
| 1983 | jnz dont_install | ||
| 1984 | |||
| 1985 | TEST ERR_FLAG,ERR_SYSSZ+ERR_EXTSW ;if bypassing install | ||
| 1986 | JZ FILL_RH_B ;jump if installing driver | ||
| 1987 | |||
| 1988 | dont_install: | ||
| 1989 | MOV DX,CS ;segment of end address | ||
| 1990 | XOR AL,AL ;number of units is zero | ||
| 1991 | FILL_RH_B: | ||
| 1992 | PUSH DS ;preserve DS | ||
| 1993 | LDS BX,RH_PTRA ;get Request Header addr in DS:BX | ||
| 1994 | MOV RH.RH0_NUN,AL ;store number of units (0 or 1) | ||
| 1995 | MOV RH.RH0_ENDO,0 ;end offset is always zero | ||
| 1996 | MOV RH.RH0_ENDS,DX ;end of VDISK or end of buffer | ||
| 1997 | MOV RH.RH0_BPBO,OFFSET BPB_PTR | ||
| 1998 | MOV RH.RH0_BPBS,CS ;BPB array address | ||
| 1999 | POP DS ;restore DS | ||
| 2000 | RET | ||
| 2001 | FILL_RH ENDP | ||
| 2002 | |||
| 2003 | SUBTTL WRITE_MESSAGES and associated routines | ||
| 2004 | PAGE | ||
| 2005 | ;-----------------------------------------------------------------------; | ||
| 2006 | ; WRITE_MESSAGE writes a series of messages to the standard ; | ||
| 2007 | ; output device showing the VDISK parameter values actually used. ; | ||
| 2008 | ;-----------------------------------------------------------------------; | ||
| 2009 | |||
| 2010 | CHAR4 DB 'nnnn$' ;build 4 ASCII decimal digits | ||
| 2011 | |||
| 2012 | ASSUME DS:CSEG | ||
| 2013 | WRITE_MESSAGES PROC ;display all messages | ||
| 2014 | |||
| 2015 | MSG IMSG ;'VDISK virtual disk $' | ||
| 2016 | |||
| 2017 | test CS:err_flag2,err_baddos | ||
| 2018 | jz check_dos_version | ||
| 2019 | |||
| 2020 | msg errm8 | ||
| 2021 | ret | ||
| 2022 | |||
| 2023 | ;If DOS Version 3.x is in use, the Request Header contains a drive code | ||
| 2024 | ;that is displayed to show which drive letter was assigned to this | ||
| 2025 | ;VDISK. This field is not present in the DOS Version 2 Request Header. | ||
| 2026 | |||
| 2027 | check_dos_version: | ||
| 2028 | MOV AH,DOS_VERS ;get DOS version call | ||
| 2029 | INT DOS ;invoke DOS | ||
| 2030 | |||
| 2031 | CMP AL,3 ;DOS Version 3 or greater? | ||
| 2032 | JB WRITE_MESSAGES_A ;no, bypass drive letter | ||
| 2033 | |||
| 2034 | PUSH DS ;preserve DS | ||
| 2035 | LDS BX,RH_PTRA ;get Request Header Address | ||
| 2036 | MOV DL,RH.RH0_DRIV ;get drive code | ||
| 2037 | ADD DL,'A' ;convert to drive letter | ||
| 2038 | POP DS ;restore DS | ||
| 2039 | |||
| 2040 | MOV AH,DOS_PCHR ;function code to write character in DL | ||
| 2041 | INT DOS ;display drive letter | ||
| 2042 | |||
| 2043 | MOV DL,':' ;display trailing colon | ||
| 2044 | INT DOS | ||
| 2045 | |||
| 2046 | WRITE_MESSAGES_A: | ||
| 2047 | MSG MSGCRLF ;end the first line | ||
| 2048 | |||
| 2049 | ;If any of the user specified values has been adjusted, issue an | ||
| 2050 | ;appropriate message | ||
| 2051 | |||
| 2052 | TEST ERR_FLAG,ERR_BSIZE ;was buffersize adjusted? | ||
| 2053 | JZ WRITE_MESSAGES_B ;if not, skip message | ||
| 2054 | |||
| 2055 | MSG ERRM1 ;buffer size adjusted | ||
| 2056 | |||
| 2057 | WRITE_MESSAGES_B: | ||
| 2058 | TEST ERR_FLAG,ERR_SSZ ;was sector size adjusted? | ||
| 2059 | JZ WRITE_MESSAGES_C ;if not, skip message | ||
| 2060 | |||
| 2061 | MSG ERRM2 ;sector size adjusted | ||
| 2062 | |||
| 2063 | WRITE_MESSAGES_C: | ||
| 2064 | TEST ERR_FLAG,ERR_DIRN ;were directory entries adjusted? | ||
| 2065 | JZ WRITE_MESSAGES_D0 ;if not, skip message | ||
| 2066 | |||
| 2067 | MSG ERRM3 ;directory entries adjusted | ||
| 2068 | |||
| 2069 | WRITE_MESSAGES_D0: | ||
| 2070 | TEST ERR_FLAG,ERR_ESIZE ;was transfer size adjusted? | ||
| 2071 | JZ WRITE_MESSAGES_D ;if not, skip message | ||
| 2072 | |||
| 2073 | MSG ERRM7 ;transfer size adjusted | ||
| 2074 | |||
| 2075 | WRITE_MESSAGES_D: | ||
| 2076 | TEST ERR_FLAG,ERR_SWTCH ;was an invalid switch character found? | ||
| 2077 | JZ WRITE_MESSAGES_E ;if not, skip message | ||
| 2078 | |||
| 2079 | MSG ERRM5 ;invalid switch character | ||
| 2080 | |||
| 2081 | WRITE_MESSAGES_E: | ||
| 2082 | TEST ERR_FLAG,ERR_SYSSZ ;is system size too small to install? | ||
| 2083 | JZ WRITE_MESSAGES_F ;if not, bypass error message | ||
| 2084 | |||
| 2085 | MSG ERRM4 ;too large for system storage | ||
| 2086 | RET ;skip messages showing adjusted sizes | ||
| 2087 | |||
| 2088 | WRITE_MESSAGES_F: | ||
| 2089 | TEST ERR_FLAG,ERR_EXTSW ;extender card switches wrong? | ||
| 2090 | JZ WRITE_MESSAGES_G ;if not, bypass error message | ||
| 2091 | |||
| 2092 | MSG ERRM6 ;extender card switches wrong msg | ||
| 2093 | RET ;skip remaining messages | ||
| 2094 | |||
| 2095 | WRITE_MESSAGES_G: ;display adjusted size messages | ||
| 2096 | MSG MSG1 ;buffer size: | ||
| 2097 | |||
| 2098 | MOV DX,BUFF_SIZE ;buffer size in binary | ||
| 2099 | CALL STOR_SIZE ;convert binary to ASCII decimal | ||
| 2100 | MSG CHAR4 ;print 4 decimals | ||
| 2101 | MSG MSG2 ;KB,CR,LF | ||
| 2102 | |||
| 2103 | MSG MSG3 ;sector size: | ||
| 2104 | MOV DX,BPB_SSZ | ||
| 2105 | CALL STOR_SIZE ;convert binary to ASCII decimal | ||
| 2106 | MSG CHAR4 ;print 4 decimals | ||
| 2107 | MSG MSGCRLF ;finish off line | ||
| 2108 | |||
| 2109 | MSG MSG4 ;directory entries: | ||
| 2110 | MOV DX,BPB_DIRN ;number of directory entries | ||
| 2111 | CALL STOR_SIZE | ||
| 2112 | MSG CHAR4 ;print 4 decimals | ||
| 2113 | MSG MSGCRLF ;finish off the line | ||
| 2114 | |||
| 2115 | CMP CS:EM_SW,0 ;extended memory ? | ||
| 2116 | JE END_LINE ; | ||
| 2117 | MSG MSG5 ;transfer size: | ||
| 2118 | MOV DX,MAXSEC_TRF | ||
| 2119 | CALL STOR_SIZE ;convert binary to ASCII decimal | ||
| 2120 | MSG CHAR4 ;print 4 decimals | ||
| 2121 | MSG MSGCRLF ;finish off line | ||
| 2122 | |||
| 2123 | END_LINE: | ||
| 2124 | MSG MSGCRLF ;one more blank line to set it off | ||
| 2125 | RET ;return to INIT_P1 | ||
| 2126 | |||
| 2127 | ;SHOW_MSG displays a string at DS:DX on the standard output device | ||
| 2128 | ;String is terminated by a $ | ||
| 2129 | |||
| 2130 | SHOW_MSG PROC ;display string at DS:DX | ||
| 2131 | PUSH AX ;preserve AX across call | ||
| 2132 | MOV AH,DOS_PSTR ;DOS function code | ||
| 2133 | INT DOS ;invoke DOS print string function | ||
| 2134 | POP AX ;restore AX | ||
| 2135 | RET | ||
| 2136 | SHOW_MSG ENDP | ||
| 2137 | |||
| 2138 | ;STOR_SIZE converts the content of DX to 4 decimal characters in CHAR4 | ||
| 2139 | ;(DX must be <= 9999) | ||
| 2140 | |||
| 2141 | STOR_SIZE PROC ;convert DX to 4 decimals in CHAR4 | ||
| 2142 | ;develop 4 packed decimal digits in AX | ||
| 2143 | XOR AX,AX ;clear result register | ||
| 2144 | MOV CX,16 ;shift count | ||
| 2145 | STOR_SIZE_B: | ||
| 2146 | SHL DX,1 ;shift high bit into carry | ||
| 2147 | ADC AL,AL ;double AL, carry in | ||
| 2148 | DAA ;adjust for packed decimal | ||
| 2149 | XCHG AL,AH | ||
| 2150 | ADC AL,AL ;double high byte, carry in | ||
| 2151 | DAA | ||
| 2152 | XCHG AL,AH | ||
| 2153 | LOOP STOR_SIZE_B ;AX contains 4 packed decimal digits | ||
| 2154 | |||
| 2155 | PUSH CS | ||
| 2156 | POP ES ;point ES:DI to output string | ||
| 2157 | MOV DI,OFFSET CHAR4 | ||
| 2158 | |||
| 2159 | MOV CX,1310H ;10H in CL is difference between blank and zero | ||
| 2160 | ;13H in CH is decremented and ANDed to force | ||
| 2161 | ;last character not to be zero suppressed | ||
| 2162 | PUSH AX ;save AX on stack | ||
| 2163 | MOV DL,AH ;2 decimals to DL | ||
| 2164 | CALL STOR_SIZE_2 ;display DL as 2 decimal characters | ||
| 2165 | POP DX ;bring low 2 decimals into DL | ||
| 2166 | STOR_SIZE_2: ;display DL as 2 decimal characters | ||
| 2167 | MOV DH,DL ;save 2 decimals in DH | ||
| 2168 | SHR DL,1 ;shift high order decimal right to low position | ||
| 2169 | SHR DL,1 | ||
| 2170 | SHR DL,1 | ||
| 2171 | SHR DL,1 | ||
| 2172 | CALL STOR_SIZE_1 ;display low nibble of DL | ||
| 2173 | MOV DL,DH ;get low decimal from pair | ||
| 2174 | STOR_SIZE_1: ;display low nibble of DL as 1 decimal char | ||
| 2175 | AND DL,0FH ;clear high nibble | ||
| 2176 | JZ STOR_SIZE_Z ;if digit is significant, | ||
| 2177 | XOR CL,CL ;defeat zero suppression | ||
| 2178 | STOR_SIZE_Z: | ||
| 2179 | DEC CH ;decrement zero suppress counter | ||
| 2180 | AND CL,CH ;always display least significant digit | ||
| 2181 | OR DL,'0' ;convert packed decimal to ASCII | ||
| 2182 | SUB DL,CL ;zero suppress (nop or change '0' to ' ') | ||
| 2183 | MOV AL,DL ;char to DL | ||
| 2184 | STOSB ;store char at ES:DI, increment DI | ||
| 2185 | RET | ||
| 2186 | STOR_SIZE ENDP | ||
| 2187 | |||
| 2188 | WRITE_MESSAGES ENDP | ||
| 2189 | |||
| 2190 | INIT_P1 ENDP ;end of INIT part one | ||
| 2191 | |||
| 2192 | ;-----------------------------------------------------------------------; | ||
| 2193 | ; VDISK Message definitions ; | ||
| 2194 | ;-----------------------------------------------------------------------; | ||
| 2195 | |||
| 2196 | IMSG DB 'VDISK virtual disk ','$' | ||
| 2197 | |||
| 2198 | ERRM1 DB ' Buffer size adjusted',CR,LF,'$' | ||
| 2199 | ERRM2 DB ' Sector size adjusted',CR,LF,'$' | ||
| 2200 | ERRM3 DB ' Directory entries adjusted',CR,LF,'$' | ||
| 2201 | ERRM4 DB ' VDISK not installed - insufficient memory' | ||
| 2202 | DB CR,LF,CR,LF,BEL,'$' | ||
| 2203 | ERRM5 DB ' Invalid switch character',CR,LF,'$' | ||
| 2204 | ERRM6 DB ' VDISK not installed - Extender Card switches' | ||
| 2205 | DB CR,LF | ||
| 2206 | DB ' do not match system memory size' | ||
| 2207 | DB CR,LF,CR,LF,BEL,'$' | ||
| 2208 | ERRM7 DB ' Transfer size adjusted',CR,LF,'$' | ||
| 2209 | ERRM8 DB ' VDISK not installed - Incorrect DOS version' | ||
| 2210 | DB CR,LF,CR,LF,BEL,'$' | ||
| 2211 | |||
| 2212 | MSG1 DB ' Buffer size: $' | ||
| 2213 | MSG2 DB ' KB' | ||
| 2214 | MSGCRLF DB CR,LF,'$' | ||
| 2215 | MSG3 DB ' Sector size: $' | ||
| 2216 | MSG4 DB ' Directory entries: $' | ||
| 2217 | MSG5 DB ' Transfer size: $' | ||
| 2218 | MSGEND LABEL BYTE ; End of message text | ||
| 2219 | |||
| 2220 | CSEG ENDS | ||
| 2221 | END | ||