2 TITLE VDISK
- Virtual Disk Device Driver
, Version
4.00
4 ;VDISK simulates a disk drive, using Random Access Memory as the storage medium.
6 ;(C) Copyright Microsoft Corporation, 1984 - 1988
7 ;Licensed Material - Program Property of Microsoft Corp.
9 ;Add the following statement to CONFIG.SYS
10 ; DEVICE=[d:][path]VDISK.SYS bbb sss ddd [/E:m]
12 ; where: bbb is the desired buffer size (in kilobytes)
13 ; minimum 1KB, maximum is size of available memory,
16 ; VDISK will leave at least 64KB of available memory,
17 ; although subsequent device drivers (other than VDISK)
18 ; other programs that make themselves resident, and
19 ; COMMAND.COM will result in less than 64KB as shown
22 ; Must be large enough for 1 boot sector + FAT sectors
23 ; + 1 directory sector + at least 1 data cluster,
24 ; or the device driver won't be installed.
26 ; sss is the desired sector size (in bytes)
27 ; 128, 256, or 512, default is 128.
28 ; Will be adjusted if number of FAT entries > 0FE0H
30 ; ddd is the desired number of directory entries
31 ; Minimum 2, maximum 512, default 64.
32 ; Will be rounded upward to sector size boundary.
34 ; /E may only be used if extended memory above 1 megabyte
35 ; is to be used. INT 15H functions 87H and 88H are used
36 ; to read and write this extended memory.
37 ; The m parameter in the /E option specifies the maximum
38 ; number of sectors that the VDISK will transfer at a time.
39 ; Optional values are 1,2,3,4,5,6,7 or 8 sectors, the default
42 ; Brackets indicate optional operands.
46 ; DEVICE=\path\VDISK.SYS 160 512 64
47 ; results in a 160KB VDISK, with 512 byte sectors, 64 directory entries
49 ; DEVICE=VDISK.SYS Buffersize 60 Sectorsize 128 Directory entries 32
50 ; (since only numbers are interpreted, you may comment the line with
51 ; non-numeric characters)
53 ;=========================================================================
56 ; AN000 - ver 4.0 specified changes
57 ; AN001 - DCR 377 Modify VDISK Extended Memory allocation technique
58 ; The allocation technique have been modified to
59 ; allocate EM from the top down. To notify other
60 ; users that EM has been used by VDISK, VDISK
61 ; hooks function 88h, INT 15h.
63 ; AN002 - PTM3214 EMS VDISK needed to be modified for two errors.
64 ; AC002 The first related to VDISK returning the
65 ; "Insufficient Memory" message when in fact
66 ; there was enough EMS memory to support the
68 ; The second related to an EMS VDISK hanging when
69 ; a program was invoked from an EMS VDISK with a
70 ; non-standard sector size, i.e.; 128 bytes/sector,
71 ; etc. This error was caused by the incorrect
72 ; calculation of sectors per EMS page.
74 ; AN003 - PTM3276 EMS VDISK causes a "Divide Overflow" message.
75 ; AC003 This is caused by a byte divide that should
76 ; be performed as a word divide.
78 ; AN004 - PTM3301 EMS VDISK does not properly adjust the buffer
79 ; size when too much EMS memory is requested.
80 ; The code in UPDATE_AVAIL pertaining to EMS
81 ; space allocation has been modified.
83 ; AN005 - DCR474 Convert VDISK to support /E for extended memory
84 ; and /X for expanded memory.
86 ; AN006 - PTM4729 Enable VDISK for the INT 2F call to determine
87 ; the reserved EMS page for VDISK and FASTOPEN
89 ;=========================================================================
91 ;Message text for VDISK is in module VDISKMSG.
97 SUBTTL Structure Definitions
99 ;-----------------------------------------------------------------------;
100 ; Request Header (Common portion) ;
101 ;-----------------------------------------------------------------------;
102 RH EQU
DS:[BX] ;addressability to Request Header structure
104 RHC
STRUC ;fields common to all request types
105 DB ?
;length of Request Header (including data)
106 DB ?
;unit code (subunit)
107 RHC_CMD
DB ?
;command code
109 DQ ?
;reserved for DOS
110 ;;;;; DW ? ;reserved for BIOS message flag ;an006; dms;
111 RHC ENDS
;end of common portion
113 CMD_INPUT EQU
4 ;RHC_CMD is INPUT request
115 ;status values for RHC_STA
117 STAT_DONE EQU
01H ;function complete status (high order byte)
118 STAT_CMDERR EQU 8003H
;invalid command code error
119 STAT_CRC EQU 8004H
;CRC error
120 STAT_SNF EQU 8008H
;sector not found error
121 STAT_BUSY EQU
0200H ;busy bit (9) for Removable Media call
122 ;-----------------------------------------------------------------------;
123 ; Request Header for INIT command ;
124 ;-----------------------------------------------------------------------;
126 DB (TYPE RHC
) DUP (?
) ;common portion
127 RH0_NUN
DB ?
;number of units
128 ;set to 1 if installation succeeds,
129 ;set to 0 to cause installation failure
130 RH0_ENDO
DW ?
;offset of ending address
131 RH0_ENDS
DW ?
;segment of ending address
132 RH0_BPBO
DW ?
;offset of BPB array address
133 RH0_BPBS
DW ?
;segment of BPB array address
134 RH0_DRIV
DB ?
;drive code (DOS 3 only)
135 RH0_FLAG
DW 0 ;initialized to no error ;an000; dms;
138 RH0_BPBA EQU
DWORD PTR RH0_BPBO
;offset/segment of BPB array address
139 ;Note: RH0_BPBA at entry to INIT points to all after DEVICE= on CONFIG.SYS stmt
141 ;-----------------------------------------------------------------------;
142 ; Request Header for MEDIA CHECK Command ;
143 ;-----------------------------------------------------------------------;
145 DB (TYPE RHC
) DUP (?
) ;common portion
146 DB ?
;media descriptor
147 RH1_RET
DB ?
;return information
149 ;-----------------------------------------------------------------------;
150 ; Request Header for BUILD BPB Command ;
151 ;-----------------------------------------------------------------------;
153 DB (TYPE RHC
) DUP(?
) ;common portion
154 DB ?
;media descriptor
155 DW ?
;offset of transfer address
156 DW ?
;segment of transfer address
157 RH2_BPBO
DW ?
;offset of BPB table address
158 RH2_BPBS
DW ?
;segment of BPB table address
160 ;-----------------------------------------------------------------------;
161 ; Request Header for INPUT, OUTPUT, and OUTPUT with verify ;
162 ;-----------------------------------------------------------------------;
164 DB (TYPE RHC
) DUP (?
) ;common portion
165 DB ?
;media descriptor
166 RH4_DTAO
DW ?
;offset of transfer address
167 RH4_DTAS
DW ?
;segment of transfer address
168 RH4_CNT
DW ?
;sector count
169 RH4_SSN
DW ?
;starting sector number
172 RH4_DTAA EQU
DWORD PTR RH4_DTAO
;offset/segment of transfer address
174 ;-----------------------------------------------------------------------;
175 ; Segment Descriptor (part of Global Descriptor Table) ;
176 ;-----------------------------------------------------------------------;
177 DESC
STRUC ;data segment descriptor
178 DESC_LMT
DW 0 ;segment limit (length)
179 DESC_BASEL
DW 0 ;bits 15-0 of physical address
180 DESC_BASEH
DB 0 ;bits 23-16 of physical address
181 DB 0 ;access rights byte
185 SUBTTL Equates
and Macro Definitions
188 MEM_SIZE EQU 12H
;BIOS memory size determination INT
189 ;returns system size in KB in AX
191 EM_INT EQU 15H
;extended memory BIOS interrupt INT
192 EM_BLKMOVE EQU 87H
;block move function
193 EM_MEMSIZE EQU 8800H
;memory size determination in KB
195 DOS EQU 21H
;DOS request INT
196 DOS_PCHR EQU
02H ;print character function
197 DOS_PSTR EQU
09H ;print string function
198 DOS_VERS EQU 30H
;get DOS version
200 TAB EQU
09H ;ASCII tab
201 LF EQU
0AH ;ASCII line feed
202 CR EQU
0DH ;ASCII carriage return
204 PARA_SIZE EQU
16 ;number of bytes in one 8088 paragraph
205 DIR_ENTRY_SIZE EQU
32 ;number of bytes per directory entry
206 MAX_FATE EQU
0FE0H ;largest number of FAT entries allowed
208 ;default values used if parameters are omitted
210 DFLT_BSIZE EQU
64 ;default VDISK buffer size (KB)
211 DFLT_SSZ EQU
128 ;default sector size
212 DFLT_DIRN EQU
64 ;default number of directory entries
213 DFLT_ESS EQU
8 ;default maximum sectors to transfer
215 MIN_DIRN EQU
2 ;minimum number of directory entries
216 MAX_DIRN EQU
512 ;maximum number of directory entries
218 STACK_SIZE EQU
512 ;length of stack during initialization
220 SUBTTL Resident
Data Area
223 ;-----------------------------------------------------------------------;
224 ; Map INT 15H vector in low storage ;
225 ;-----------------------------------------------------------------------;
226 INT_VEC
SEGMENT AT 00H
230 EM_VECS
DW ?
;segment
235 CSEG
SEGMENT PARA
PUBLIC 'CODE'
237 ;-----------------------------------------------------------------------;
238 ; Resident data area. ;
240 ; All variables and constants required after initialization ;
241 ; part one are defined here. ;
242 ;-----------------------------------------------------------------------;
244 START EQU
$ ;begin resident VDISK data & code
246 ;DEVICE HEADER - must be at offset zero within device driver
247 DD -1 ;becomes pointer to next device header
248 DW 0800H ;attribute (IBM format block device)
249 ;supports OPEN/CLOSE/RM calls
250 DW OFFSET STRATEGY
;pointer to device "strategy" routine
251 DW OFFSET IRPT
;pointer to device "interrupt handler"
252 DB 1 ;number of block devices
253 DB 7 DUP (?
) ;7 byte filler (remainder of 8-byte name)
254 ;END OF DEVICE HEADER
256 ;This volume label is placed into the directory of the new VDISK
257 ;This constant is also used to determine if a previous extended memory VDISK
260 VOL_LABEL
DB 'VDISK V4.0' ;00-10 volume name (shows program level)
261 DB 28H
;11-11 attribute (volume label)
263 DW 6000H
;22-23 time=12:00 noon
264 DW 0986H ;24-25 date=12/06/84
265 VOL_LABEL_LEN EQU
$-VOL_LABEL
;length of volume label
267 ;The following field, in the first extended memory VDISK device driver,
268 ;is the 24-bit address of the first free byte of extended memory.
269 ;This address is not in the common offset/segment format.
270 ;The initial value, 10 0000H, is 1 megabyte.
272 AVAIL_LO
DW 0 ;address of first free byte of
273 AVAIL_HI
DB 10H
;extended memory
277 INTV15S
DW ?
;segment
280 PARAS_PER_SECTOR
DW ?
;number of 16-byte paragraphs in one sector
282 START_BUFFER_PARA
DW ?
;segment address of start of VDISK buffer
284 EM_New_Size dw ?
;an001; dms;new size for EM
285 EM_KSize dw ?
;an001; dms;size of EM currently.
287 EM_SW
DB 0 ;NON-ZERO IF EXTENDED MEMORY
289 EM_STAT
DW 0 ;AX from last unsuccessful extended memory I/O
291 START_EM_LO
DW ?
;24-bit address of start of VDISK buffer
292 START_EM_HI
DB ?
;(extended memory only)
294 WPARA_SIZE
DW PARA_SIZE
;number of bytes in one paragraph
296 MAX_CNT
DW ?
;(0FFFFH/BPB_SSZ) truncated, the maximum
297 ;number of sectors that can be transferred
298 ;without worrying about 64KB wrap
300 SECT_LEFT
DW ?
;sectors left to transfer
302 IO_SRCA
LABEL DWORD ;offset/segment of source
304 IO_SRCS
DW ?
;segment
306 IO_TGTA
LABEL DWORD ;offset/segment of target
308 IO_TGTS
DW ?
;segment
310 ;-----------------------------------------------------------------------;
312 ;-----------------------------------------------------------------------;
314 EM_SW2
DB not EMS_Installed_Flag
;ac006;Default if EMS not installed
315 EMS_HANDLE
DW ?
;AN000; EMS handle for reference
316 EMS_FRAME_ADDR
DW ?
;AN000; EMS handle for reference
317 EMS_CURR_SECT
DW ?
;an000; Current EMS sector being addressed
318 CURR_EMS_PAGE
DW ?
;ac002; Current EMS page number
319 SECT_LEFT_IN_FRAME
DW ?
;AN000; Sectors left to transfer in this frame
320 SECT_PER_PAGE
DW ?
;AN000; Sectors per page
321 DOS_Page dw ?
;an006; EMS physical page for VDISK
323 EMS_SAVE_ARRAY
DB 80h
dup(0) ;an000; save current state of ems
324 EMS_SEG_ARRAY
DD ?
;an000; save segment array
326 CURR_DTA_OFF
DW ?
;AN000; DMS;CURRENT OFFSET OF DTA
328 PC_386
DB false
;AN000; DMS;386 machine flag
330 SUBLIST
STRUC ;AN000;SUBLIST STRUCTURE
332 SL_SIZE
DB ?
;AN000;SUBLIST SIZE
333 SL_RES
DB ?
;AN000;RESERVED
334 SL_OFFSET
DW ?
;AN000;PARM OFFSET
335 SL_SEGMENT
DW ?
;AN000;PARM SEGMENT
336 SL_ID
DB ?
;AN000;NUMBER OF PARM
337 SL_FLAG
DB ?
;AN000;DISPLAY TYPE
338 SL_MAXW
DB ?
;AN000;MAXIMUM FIELD WIDTH
339 SL_MINW
DB ?
;AN000;MINIMUM FIELD WIDTH
340 SL_PAD
DB ?
;AN000;PAD CHARACTER
342 SUBLIST ENDS
;AN000;END SUBLIST STRUCTURE
345 BIOS_SYSTEM_DESCRIPTOR
struc ;AN000;SYSTEM TYPE STRUC
347 bios_SD_leng dw ?
;AN000;VECTOR LENGTH
348 bios_SD_modelbyte db ?
;AN000;SYSTEM MODEL TYPE
349 bios_SD_scnd_modelbyte db ?
;AN000;
351 bios_SD_featurebyte1 db ?
;AN000;
354 BIOS_SYSTEM_DESCRIPTOR ends
;AN000;END OF STRUC
356 ;-----------------------------------------------------------------------;
357 ; BIOS Parameter Block (BPB) ;
358 ;-----------------------------------------------------------------------;
359 ;This is where the characteristics of the virtual disk are established.
360 ;A copy of this block is moved into the boot record of the virtual disk.
361 ;DEBUG can be used to read sector zero of the virtual disk to examine the
362 ;boot record copy of this block.
364 BPB
LABEL BYTE ;BIOS Parameter Block (BPB)
365 BPB_SSZ
DW 0 ;number of bytes per disk sector
366 BPB_AUSZ
DB 1 ;sectors per allocation unit
367 BPB_RES
DW 1 ;number of reserved sectors (for boot record)
368 BPB_FATN
DB 1 ;number of File Allocation Table (FAT) copies
369 BPB_DIRN
DW 0 ;number of root directory entries
370 BPB_SECN
DW 1 ;total number of sectors
371 ;computed from buffer size and sector size
372 ;(this includes reserved, FAT, directory,
374 BPB_MCB
DB 0FEH ;media descriptor byte
375 BPB_FATSZ
DW 1 ;number of sectors occupied by a single FAT
376 ;computed from BPBSSZ and BPBSECN
377 BPB_LEN EQU
$-BPB
;length of BIOS parameter block
379 BPB_PTR
DW BPB
;BIOS Parameter Block pointer array (1 entry)
380 ;-----------------------------------------------------------------------;
381 ; Request Header (RH) address, saved here by "strategy" routine ;
382 ;-----------------------------------------------------------------------;
385 RH_PTRS
DW ?
;segment
386 ;-----------------------------------------------------------------------;
387 ; Global Descriptor Table (GDT), used for extended memory moves ;
388 ;-----------------------------------------------------------------------;
389 ;Access Rights Byte (93H) is
390 ; P=1 (segment is mapped into physical memory)
391 ; E=0 (data segment descriptor)
392 ; D=0 (grow up segment, offsets must be <= limit)
393 ; W=1 (data segment may be written into)
394 ; DPL=0 (privilege level 0)
396 GDT
LABEL BYTE ;begin global descriptor table
397 DESC
<> ;dummy descriptor
398 DESC
<> ;descriptor for GDT itself
399 SRC DESC
<,,,93H
,> ;source descriptor
400 TGT DESC
<,,,93H
,> ;target descriptor
401 DESC
<> ;BIOS CS descriptor
402 DESC
<> ;stack segment descriptor
404 SUBTTL
INT 15H
(size
) interrupt handler
406 ;-----------------------------------------------------------------------;
407 ; INT 15H Interrupt Handler routine ;
408 ;-----------------------------------------------------------------------;
410 ;=========================================================================
411 ; VDISK_INT15 : This routine traps the INT 15h requests to perform its
412 ; own unique services. This routine provides 1 INT 15h
413 ; service; function 8800h.
415 ; Service - Function 8800h: Obtains the size of EM from the word
417 ; Call With: AX - 8800h
418 ; Returns : AX - Kbyte size of EM
420 ;=========================================================================
421 VDISK_INT15 PROC
;an001; dms;
423 cmp ah,EM_Size_Get
;an001; dms;function 88h
424 ; $if e ;an001; dms;get size
426 mov ax,cs:EM_KSize
;an001; dms;return size
427 clc ;an001; dms;clear CY
431 jmp cs:INTV15
;an001; dms;jump to org. vector
432 ; $endif ;an001; dms;
437 VDISK_INT15 ENDP
;an001; dms;
442 SUBTTL Device Strategy
& interrupt
entry points
444 ;-----------------------------------------------------------------------;
445 ; Device "strategy" entry point ;
447 ; Retain the Request Header address for use by Interrupt routine ;
448 ;-----------------------------------------------------------------------;
450 MOV CS:RH_PTRO
,BX ;offset
451 MOV CS:RH_PTRS
,ES ;segment
454 ;-----------------------------------------------------------------------;
455 ; Table of command processing routine entry points ;
456 ;-----------------------------------------------------------------------;
458 DW OFFSET INIT_P1
; 0 - Initialization
459 DW OFFSET MEDIA_CHECK
; 1 - Media check
460 DW OFFSET BLD_BPB
; 2 - Build BPB
461 DW OFFSET INPUT_IOCTL
; 3 - IOCTL input
462 DW OFFSET INPUT
; 4 - Input
463 DW OFFSET INPUT_NOWAIT
; 5 - Non destructive input no wait
464 DW OFFSET INPUT_STATUS
; 6 - Input status
465 DW OFFSET INPUT_FLUSH
; 7 - Input flush
466 DW OFFSET OUTPUT
; 8 - Output
467 DW OFFSET OUTPUT_VERIFY
; 9 - Output with verify
468 DW OFFSET OUTPUT_STATUS
;10 - Output status
469 DW OFFSET OUTPUT_FLUSH
;11 - Output flush
470 DW OFFSET OUTPUT_IOCTL
;12 - IOCTL output
471 DW OFFSET DEVICE_OPEN
;13 - Device OPEN
472 DW OFFSET DEVICE_CLOSE
;14 - Device CLOSE
473 MAX_CMD EQU
($-CMD_TABLE
)/2 ;highest valid command follows
474 DW OFFSET REMOVABLE_MEDIA
;15 - Removable media
476 ;-----------------------------------------------------------------------;
477 ; Device "interrupt" entry point ;
478 ;-----------------------------------------------------------------------;
479 IRPT PROC
FAR ;device interrupt entry point
480 PUSH DS ;save all registers modified
488 ;BP isn't used, so it isn't saved
489 CLD ;all moves forward
491 LDS BX,CS:RH_PTRA
;get RH address passed to "strategy" into DS:BX
493 MOV AL,RH
.RHC_CMD
;command code from Request Header
494 CBW ;zero AH (if AL > 7FH, next compare will
497 CMP AL,MAX_CMD
;if command code is too high
498 JA IRPT_CMD_HIGH
;jump to error routine
500 MOV DI,OFFSET IRPT_CMD_EXIT
;return addr from command processor
501 PUSH DI ;push return address onto stack
502 ;command routine issues "RET"
504 ADD AX,AX ;double command code for table offset
505 MOV DI,AX ;put into index register for JMP
507 XOR AX,AX ;initialize return to "no error"
509 ;At entry to command processing routine:
511 ; DS:BX = Request Header address
512 ; CS = VDISK code segment address
515 ; top of stack is return address, IRPT_CMD_EXIT
517 JMP CS:CMD_TABLE
[DI] ;call routine to handle the command
520 IRPT_CMD_ERROR: ;CALLed for unsupported character mode commands
522 INPUT_IOCTL: ;IOCTL input
523 INPUT_NOWAIT: ;Non-destructive input no wait
524 INPUT_STATUS: ;Input status
525 INPUT_FLUSH: ;Input flush
527 OUTPUT_IOCTL: ;IOCTL output
528 OUTPUT_STATUS: ;Output status
529 OUTPUT_FLUSH: ;Output flush
531 POP AX ;pop return address off stack
533 IRPT_CMD_HIGH: ;JMPed to if RHC_CMD > MAX_CMD
534 MOV AX,STAT_CMDERR
;"invalid command" and error
536 IRPT_CMD_EXIT: ;return from command routine
537 ;AX = value to OR into status word
538 LDS BX,CS:RH_PTRA
;restore DS:BX as Request Header pointer
539 OR AH,STAT_DONE
;add "done" bit to status word
540 MOV RH
.RHC_STA
,AX ;store status into request header
541 POP SI ;restore registers
552 SUBTTL Command Processing routines
554 ;-----------------------------------------------------------------------;
555 ; Command Code 1 - Media Check ;
556 ; At entry, DS:BX point to request header, AX = 0 ;
557 ;-----------------------------------------------------------------------;
559 MOV RH
.RH1_RET
,1 ;indicate media not changed
560 RET ;AX = zero, no error
562 ;-----------------------------------------------------------------------;
563 ; Command Code 2 - Build BPB ;
564 ; At entry, DS:BX point to request header, AX = 0 ;
565 ;-----------------------------------------------------------------------;
567 MOV RH
.RH2_BPBO
,OFFSET BPB
;return pointer to our BPB
569 RET ;AX = zero, no error
571 ;-----------------------------------------------------------------------;
572 ; Command Code 13 - Device Open ;
573 ; Command Code 14 - Device Close ;
574 ; Command Code 15 - Removable media ;
575 ; At entry, DS:BX point to request header, AX = 0 ;
576 ;-----------------------------------------------------------------------;
578 MOV AX,STAT_BUSY
;set status bit 9 (busy)
579 ;indicating non-removable media
580 DEVICE_OPEN: ;NOP for device open
581 DEVICE_CLOSE: ;NOP for device close
583 REMOVABLE_MEDIA ENDP
;fall thru to return
584 ;-----------------------------------------------------------------------;
585 ; Command Code 4 - Input ;
586 ; Command Code 8 - Output ;
587 ; Command Code 9 - Output with verify ;
588 ; At entry, DS:BX point to request header, AX = 0 ;
589 ;-----------------------------------------------------------------------;
598 ;;;;; mov bx,0140H ;ICE
601 ;;;;; mov ax,word ptr ds:[bx] ;ICE
602 ;;;;; mov word ptr ds:[bx],ax ;ICE
608 ;Make sure I/O is entirely within the VDISK sector boundaries
610 MOV CX,CS:BPB_SECN
;get total sector count
611 MOV AX,RH
.RH4_SSN
;starting sector number
612 CMP AX,CX ;can't exceed total count
613 JA INOUT_E1
;jump if start > total
615 ADD AX,RH
.RH4_CNT
;start + sector count
616 CMP AX,CX ;can't exceed total count
617 JNA INOUT_A
;jump if start + count <= total
619 INOUT_E1: ;I/O not within VDISK sector boundaries
620 MOV RH
.RH4_CNT
,0 ;set sectors transferred to zero
621 MOV AX,STAT_SNF
;indicate 'Sector not found' error
622 RET ;return with error status in AX
624 INOUT_A: ;I/O within VDISK bounds
625 MOV AX,RH
.RH4_CNT
;get sector count
626 MOV CS:SECT_LEFT
,AX ;save as sectors left to process
628 MOV CS:SECT_LEFT_IN_FRAME
,AX ;AN000; Save as sectors left to process
630 CMP CS:EM_SW
,0 ;extended memory mode?
631 JNE INOUT_EM
;jump to extended memory I/O code
633 ;Compute offset and segment of VDISK buffer for starting segment in CX:SI
635 MOV AX,RH
.RH4_SSN
;starting sector number
636 MUL CS:PARAS_PER_SECTOR
;* length of one sector in paragraphs
637 ADD AX,CS:START_BUFFER_PARA
;+ segment of VDISK buffer sector 0
638 MOV CX,AX ;segment address to CX
639 XOR SI,SI ;offset is zero
641 ;Compute address of caller's Data Transfer Addr in DX:AX with smallest offset,
642 ;so that there is no possibility of overflowing a 64KB boundary moving MAX_CNT
646 MUL RH
.RH4_DTAS
;* segment of caller's DTA in DX,AX
647 ADD AX,RH
.RH4_DTAO
;+ offset of caller's DTA
648 ADC DL,0 ;carry in from addition
649 DIV CS:WPARA_SIZE
;AX is segment of caller's DTA
650 ;DX is smallest offset possible
653 ;AX:DX is caller's DTA segment:offset, CX:SI is VDISK buffer segment:offset
655 ;If this is an OUTPUT request, exchange the source and target addresses
657 CMP RH
.RHC_CMD
,CMD_INPUT
;INPUT operation?
658 JE INOUT_B
;jump if INPUT operation
660 XCHG AX,CX ;swap source and target segment
661 XCHG DX,SI ;swap source and target offset
663 INOUT_B: ;CX:SI is source, AX:DX is target
664 MOV CS:IO_SRCS
,CX ;save source segment
665 MOV CS:IO_SRCO
,SI ;save source offset
666 MOV CS:IO_TGTS
,AX ;save target segment
667 MOV CS:IO_TGTO
,DX ;save target offset
669 JMP SHORT INOUT_E
;AX := SECT_LEFT, test for zero
670 INOUT_C: ;SECT_LEFT in AX, non-zero
672 ; Compute number of sectors to transfer in a single move,
673 ; AX = minimum of (SECT_LEFT, MAX_CNT)
675 ; MAX_CNT is the maximum number of sectors that can be moved without
676 ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
678 MOV CX,CS:MAX_CNT
;MAX sectors with one move
679 CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
680 JBE INOUT_D
;then move SECT_LEFT sectors
682 MOV AX,CX ;else move MAX_CNT sectors
685 CALL INOUT_D_LOW_MEM
;AN000;LOW MEMORY TRANSFER
687 ;Determine if more sectors need to be transferred
689 INOUT_E: ;do while SECT_LEFT <> zero
690 MOV AX,CS:SECT_LEFT
;get sectors left to transfer
692 JNZ INOUT_C
;go back to transfer some sectors
693 RET ;AX = zero, all sectors transferred
695 SUBTTL Extended Memory I
/O routine
697 ;-----------------------------------------------------------------------;
698 ; Extended Memory I/O routine ;
699 ;-----------------------------------------------------------------------;
700 INOUT_EM: ;Extended memory I/O routine
701 ;change to larger stack
702 MOV SI,SS ;save old SS in SI
703 MOV DX,SP ;save old SP in DX
704 CLI ;disable interrupts
706 MOV SS,AX ;set SS = CS
707 MOV SP,OFFSET EM_STACK
;point to new stack
708 STI ;enable interrupts
709 PUSH SI ;save old SS at top of new stack
710 PUSH DX ;save old SP on new stack
712 MOV SI,RH
.RH4_DTAO
;caller's DTA offset
715 CMP EM_SW
,EM_Mem
;AC005; Is EM requested?
716 JE INOUT_EM_A
;AN000;
717 JMP INOUT_EMS
;AN000; Yes, compute page
719 INOUT_EM_A: ;AN000; No, compute 24-bit address
721 ;Compute 24-bit address of VDISK sector in CX (hi) and SI (low)
723 MOV AX,RH
.RH4_SSN
;starting sector number
724 MUL CS:BPB_SSZ
;* sector size = offset within buffer
725 ADD AX,CS:START_EM_LO
;+ base address of this VDISK buffer
726 ADC DL,CS:START_EM_HI
727 MOV CX,DX ;save high byte
728 MOV SI,AX ;save low word
730 ;Compute 24-bit address of caller's DTA in DX (hi) and AX (low)
733 MUL RH
.RH4_DTAS
;* segment of caller's DTA
734 ADD AX,RH
.RH4_DTAO
;+ offset of caller's DTA
735 ADC DL,0 ;carry in from addition
737 ;Caller's DTA address is in CX,SI, VDISK buffer address is in DX,AX.
739 ;If this is an OUTPUT request, exchange the source and target addresses
741 CMP RH
.RHC_CMD
,CMD_INPUT
;INPUT operation?
742 JE INOUT_EM_B
;jump if INPUT operation
744 XCHG DX,CX ;swap source and target high byte
745 XCHG AX,SI ;swap source and target low word
747 INOUT_EM_B: ;CX,SI is source, DX,AX is target
749 MOV SRC
.DESC_BASEL
,SI ;low 16 bits of source address
750 MOV SRC
.DESC_BASEH
,CL ;high 8 bits of source address
752 MOV TGT
.DESC_BASEL
,AX ;low 16 bits of target address
753 MOV TGT
.DESC_BASEH
,DL ;high 8 bits of target address
755 JMP SHORT INOUT_EM_E
;AX := SECT_LEFT, test for zero
756 INOUT_EM_C: ;SECT_LEFT in AX, non-zero
758 ; Compute number of sectors to transfer in a single move,
759 ; AX = minimum of (SECT_LEFT, MAX_CNT)
761 ; MAX_CNT is the maximum number of sectors that can be moved without
762 ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
764 MOV CX,CS:MAX_CNT
;MAX sectors with one move
765 CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
766 JBE INOUT_EM_D
;then move SECT_LEFT sectors
768 MOV AX,CX ;else move MAX_CNT sectors
770 SUB CS:SECT_LEFT
,AX ;reduce number of sectors left to move
772 ;Move AX sectors from source to target
774 MUL CS:BPB_SSZ
;sectors * sector size = byte count
775 ;(cannot overflow into DX)
776 MOV TGT
.DESC_LMT
,AX ;store segment limit (byte count)
779 PUSH AX ;preserve byte count on stack
781 SHR AX,1 ;/2 = word count
782 MOV CX,AX ;word count to CX
786 MOV SI,OFFSET GDT
;ES:SI point to GDT
788 MOV AH,EM_BLKMOVE
;function is block move
789 INT EM_INT
;move an even number of words
791 POP CX ;get byte count back from stack
793 OR AH,AH ;get error code
796 JMP INOUT_EM_XE
;jump if I/O error encountered
800 ;Update source and target addresses
802 ADD SRC
.DESC_BASEL
,CX ;add bytes moved to source
803 ADC SRC
.DESC_BASEH
,0 ;pick up any carry
805 ADD TGT
.DESC_BASEL
,CX ;add bytes moved to target
806 ADC TGT
.DESC_BASEH
,0 ;pick up any carry
808 ;Determine if more sectors need to be transferred
810 INOUT_EM_E: ;do while SECT_LEFT <> zero
811 MOV AX,CS:SECT_LEFT
;get sectors left to transfer
813 JNZ INOUT_EM_C
;go back to transfer some sectors
815 JMP INOUT_EM_X2
;AN000; All done . . . exit
816 ;-----------------------------------------------------------------------;
817 ; EMS Support ;RPS; ;
818 ;-----------------------------------------------------------------------;
822 ; Save EMS state in case anyone is using it
823 PUSH AX ;AN000; DMS;SAVE IT
824 PUSH BX ;AN000; DMS;SAVE IT
825 PUSH DX ;AN000; DMS;SAVE IT
826 push di ;an000; dms;save it
827 push si ;an000; dms;save it
828 push ds ;an000; dms;save it
829 push es ;an000; dms;save it
830 mov ax,cs ;an000; dms;transfer cs to ds/es
831 mov ds,ax ;an000; dms;
832 mov es,ax ;an000; dms;
834 mov di,offset
cs:EMS_SAVE_ARRAY
;an000; point to save area
835 mov si,offset
cs:EMS_SEG_ARRAY
;an000; point to segment area
836 mov word ptr cs:EMS_SEG_ARRAY
,0001h ;an000; 1 segment to save
837 mov ax,cs:EMS_Frame_Addr
;an000; get segment
838 mov word ptr cs:EMS_SEG_ARRAY
+2,ax ;an000; segment
839 MOV AX,EMS_SAVE_STATE
;AN000; Function code to save active handle state
842 pop es ;an000; dms;restore
843 pop ds ;an000; dms;restore
844 pop si ;an000; dms;restore
845 pop di ;an000; dms;restore
846 POP DX ;AN000; DMS;RESTORE
847 POP BX ;AN000; DMS;RESTORE
848 POP AX ;AN000; DMS;RESTORE
850 ; Compute offset and segment of VDISK frame for starting segment in CX:SI
851 ; and page containing VDISK starting sector
853 push ds ;an000; dms;save ds
854 push es ;an000; dms;save es
856 mov cs:curr_dta_off
,0 ;an000; dms;current offset = 0
857 mov ax,rh
.rh4_ssn
;an000; dms;get 1st. sector
858 mov cs:ems_curr_sect
,ax ;an000; dms;save it
859 call ems_page_off_calc
;an000; dms;calc page and off.
860 call ems_dta_calc
;an000; dms;calc DTA
861 call ems_src_tgt
;an000; dms;get src & tgt
863 ; $do ;an000; dms;while sectors left
865 call map_frame
;an000; dms;map a page
866 call ems_trf
;an000; dms;transfer data
867 dec cs:sect_left
;an000; dms;sect_left - 1
868 cmp cs:sect_left
,0 ;an000; dms;continue?
869 ; $leave e ;an000; dms;no - exit
872 mov ax,cs:ems_curr_sect
;an000; dms;get current sector
873 call ems_page_off_calc
;an000; dms;calc page and off.
874 call ems_dta_adj
;an000; dms;adjust DTA
875 call ems_src_tgt
;an000; dms;get src & tgt
876 ; $enddo ;an000; dms;end while
880 pop es ;an000; dms;restore es
881 pop ds ;an000; dms;restore ds
883 ; Restore EMS state in case anyone was using it
885 PUSH AX ;AN000; DMS;SAVE IT
886 PUSH BX ;AN000; DMS;SAVE IT
887 PUSH DX ;AN000; DMS;SAVE IT
888 PUSH SI ;AN000; DMS;SAVE IT
889 push ds ;an000; dms;save it
891 mov ax,cs ;an000; dms;get cs
892 mov ds,ax ;an000; dms;put in ds
893 MOV AX,EMS_RESTORE_STATE
;AN000; Function code to restore active handle state
894 MOV SI,OFFSET
CS:EMS_SAVE_ARRAY
;AN000; POINT TO SAVE ARRAY
897 pop ds ;an000; dms;restore
898 POP SI ;AN000; DMS;RESTORE
899 POP DX ;AN000; DMS;RESTORE
900 POP BX ;AN000; DMS;RESTORE
901 POP AX ;AN000; DMS;RESTORE
903 ;-----------------------------------------------------------------------;
905 INOUT_EM_X2: ;revert to original stack
908 CLI ;disable interrupts
909 MOV SS,SI ;restore old SS
910 MOV SP,DI ;restore old SP
911 STI ;enable interrupts
912 RET ;return to IRPT_EXIT
914 INOUT_EM_XE: ;some error with INT 15H
915 MOV CS:EM_STAT
,AX ;save error status for debugging
916 MOV RH
.RH4_CNT
,0 ;indicate no sectors transferred
917 MOV AX,STAT_CRC
;indicate CRC error
918 JMP INOUT_EM_X2
;fix stack and exit
922 ;=========================================================================
923 ; EMS_PAGE_OFF_CALC : Calculates the current ems page to use and
924 ; the offset of the requested sector in that
927 ; Inputs: AX - Sector for input/output
928 ; SECT_PER_PAGE - # of sectors/ems page
929 ; BPB_SSZ - Size in bytes of a sector
930 ; EMS_FRAME_ADDR - Segment of ems page
932 ; Outputs: CURR_EMS_PAGE - Currently active ems page
933 ; CX:SI - Segment:Offset of logical sector
934 ;=========================================================================
936 ems_page_off_calc proc
near ;an000; dms;calc page/offset
938 xor dx,dx ;an002; dms;clear high word
939 div cs:sect_per_page
;an000; dms;determine page
940 mov cs:curr_ems_page
,ax ;an002; dms;save page
941 mov ax,dx ;an002; dms;offset calc
942 mul cs:bpb_ssz
;an000; dms;calc offset
943 mov si,ax ;an000; dms;save sector offset
944 mov cx,cs:ems_frame_addr
;an000; dms;obtain sector seg
948 ems_page_off_calc endp
;an000; dms;
951 ;=========================================================================
952 ; EMS_DTA_CALC : Calculate the DTA buffer to be used.
954 ; Inputs: PARA_SIZE - 16
955 ; RH4_DTAS - Segment of DTA from request packet
956 ; RH4_DTA0 - Offset of DTA from request packet
959 ; Outputs: AX:DX - Segment:Offset of DTA buffer
960 ;=========================================================================
962 ems_dta_calc proc
near ;an000; dms;calc DTA buffer
964 xor dx,dx ;an002; dms;clear high word
965 mov ax,para_size
;an000; dms;get para size
966 mul rh
.rh4_dtas
;an000; dms;times DTA segment
967 add ax,rh
.rh4_dtao
;an000; dms;+ DTA offset
968 adc dx,0 ;an002; dms;pick up carry
969 div cs:wpara_size
;an000; dms;/16
973 ems_dta_calc endp
;an000; dms;
976 ;=========================================================================
977 ; EMS_DTA_ADJ : Adjust DTA for the number of sectors having
980 ; External Calls : EMS_DTA_CALC
982 ; Inputs: CURR_DTA_OFF - Current offset value to be adjusted.
984 ; Outputs: CURR_DTA_OFF - Adjusted offset value into DTA
985 ; DX - Adjusted offset value into DTA
986 ;=========================================================================
988 ems_dta_adj proc
near ;an000; dms;adjust DTA
990 call ems_dta_calc
;an000; dms;
991 push ax ;an000; dms;save reg
992 mov ax,cs:curr_dta_off
;an000; dms;get current off.
993 add ax,cs:bpb_ssz
;an000; dms;adjust up
994 mov cs:curr_dta_off
,ax ;an000; dms;save new off
995 add dx,ax ;an000; dms;set dx to new off
996 pop ax ;an000; dms;restore reg
999 ems_dta_adj endp
;an000; dms;
1001 ;=========================================================================
1002 ; EMS_SRC_TGT : Determine the source and target segments for
1005 ; Inputs: RHC_CMD - Request packet command identifier
1007 ; CX:SI - EMS page/sector
1009 ; Outputs: IO_SRCS - Segment of source of trf
1010 ; IO_SRCO - Offset of source of trf
1011 ; IO_TGTS - Segment of target for trf
1012 ; IO_TGTO - Offset of target for trf
1013 ;=========================================================================
1015 ems_src_tgt proc
near ;an000; dms;src/tgt calc
1017 cmp rh
.rhc_cmd
,cmd_input
;an000; dms;input/output?
1018 ; $if ne ;an000; dms;
1020 xchg ax,cx ;an000; dms;swap src/tgt seg
1021 xchg dx,si ;an000; dms;swap src/tgt off
1022 ; $endif ;an000; dms;
1025 mov cs:io_srcs
,cx ;an000; dms;save src seg
1026 mov cs:io_srco
,si ;an000; dms;save src off
1027 mov cs:io_tgts
,ax ;an000; dms;save tgt seg
1028 mov cs:io_tgto
,dx ;an000; dms;save tgt off
1031 ems_src_tgt endp
;an000; dms;
1034 ;=========================================================================
1035 ; EMS_TRF : Perform the sector transfer of data.
1037 ; Inputs: BPB_SSZ - Sector size
1038 ; IO_SRCA - Source address
1039 ; IO_TGTA - Target address
1041 ; Outputs: Transferred data
1042 ; EMS_CURR_SECT - Incremented 1
1043 ;=========================================================================
1045 ems_trf proc
near ;an000; dms;transfer data
1047 mov ax,cs:bpb_ssz
;an000; dms;set to sector size
1048 shr ax,1 ;an000; dms;make words
1049 mov cx,ax ;an000; dms;set loop counter
1050 push ds ;an000; dms;save regs
1051 push es ;an000; dms;
1053 lds si,cs:io_srca
;an000; dms;get src address
1054 les di,cs:io_tgta
;an000; dms;get tgt address
1056 CMP CS:PC_386
,TRUE
;AN000; DO WE HAVE A 386 MACHINE?
1059 SHR CX,1 ;AN000; /2 = DW COUNT
1060 DB 66H
;AN000; SIMULATE A MOVSDW
1063 rep movsw ;an000; dms;perform transfer
1065 pop es ;an000; dms;restore regs
1067 inc cs:ems_curr_sect
;an000; dms;increment sector
1071 ems_trf endp
;an000; dms;
1075 MAP_FRAME PROC
NEAR ;AN000;
1077 PUSH BX ;AN000; DMS;
1078 mov ax,cs:DOS_Page
;an000; get physical page
1079 MOV AH,EMS_MAP_HANDLE
;AN000; EMS function to map page
1080 MOV BX,CS:CURR_EMS_PAGE
;AN000; Page number
1081 MOV DX,CS:EMS_HANDLE
;AN000; EMS handle
1086 MAP_FRAME ENDP
;AN000;
1089 INOUT_D_LOW_MEM PROC
NEAR ;AN000; LOW MEMORY TRANSFER
1091 SUB CS:SECT_LEFT
,AX ;reduce number of sectors left to move
1093 ;Move AX sectors from source to target
1095 MUL CS:BPB_SSZ
;sectors * sector size = byte count
1096 ;(cannot overflow into DX)
1097 SHR AX,1 ;/2 = word count
1098 MOV CX,AX ;word count to CX for \REP MOVSW
1100 LDS SI,CS:IO_SRCA
;source segment/offset to DS:SI
1101 LES DI,CS:IO_TGTA
;target segment/offset to ES:DI
1103 CMP CS:PC_386
,TRUE
;AN000; DO WE HAVE A 386 MACHINE?
1106 SHR CX,1 ;AN000; /2 = DW COUNT
1107 DB 66H
;AN000; SIMULATE A MOVSDW
1110 REP MOVSW ;AN000; PERFORM DOUBLE WORD MOVE
1112 ;Update source and target paragraph addresses
1113 ;AX has number of words moved
1115 SHR AX,1 ;words moved / 8 = paragraphs moved
1119 ADD CS:IO_SRCS
,AX ;add paragraphs moved to source segment
1120 ADD CS:IO_TGTS
,AX ;add paragraphs moved to target segment
1124 INOUT_D_LOW_MEM ENDP
1128 DW 40 DUP (?
) ;stack for extended memory I/O
1133 ;-----------------------------------------------------------------------;
1134 ; Adjust the assembly-time instruction counter to a paragraph ;
1136 ;-----------------------------------------------------------------------;
1139 ORG ($-START
) + 16 - (($-START
) MOD 16)
1142 VDISK EQU
$ ;start of virtual disk buffer
1143 VDISKP EQU
($-START
) / PARA_SIZE
;length of program in paragraphs
1144 ;-----------------------------------------------------------------------;
1145 ; If this VDISK is in extended memory, this address is passed ;
1146 ; back to DOS as the end address that is to remain resident. ;
1148 ; It this VDISK is not in extended memory, the VDISK buffer ;
1149 ; begins at this address, and the address passed back to DOS ;
1150 ; as the end address that is to remain resident is this address ;
1151 ; plus the length of the VDISK buffer. ;
1152 ;-----------------------------------------------------------------------;
1154 BOOT_RECORD
LABEL BYTE ;Format of Boot Record documented in
1155 ;DOS Technical Reference Manual
1156 DB 0,0,0 ;3-byte jump to boot code (not bootable)
1157 DB 'VDISKx.x' ;8-byte vendor identification
1158 BOOT_BPB
LABEL BYTE ;boot record copy of BIOS parameter block
1159 DW ?
;number of bytes per disk sector
1160 DB ?
;sectors per allocation unit
1161 DW ?
;number of reserved sectors (for boot record)
1162 DB ?
;number of File Allocation Table (FAT) copies
1163 DW ?
;number of root directory entries
1164 DW ?
;total number of sectors
1165 DB ?
;media descriptor byte
1166 DW ?
;number of sectors occupied by a single FAT
1167 ;end of boot record BIOS Parameter block
1169 ;The following three words mean nothing to VDISK, they are placed here
1170 ;to conform to the DOS standard for boot records.
1171 DW 8 ;sectors per track
1172 DW 1 ;number of heads
1173 DW 0 ;number of hidden sectors
1174 ;The following word is the 16-bit kilobyte address of the first byte in
1175 ;extended memory that is not occupied by a VDISK buffer
1176 ;It is placed into this location so that other users of extended memory
1177 ;may find where all the VDISKs end.
1179 ;This field may be accessed by moving the boot record of the First extended
1180 ;memory VDISK from absolute location 10 0000H. Before assuming that the
1181 ;value below is valid, the vendor ID (constant VDISK) should be verified
1182 ;to make sure that SOME VDISK has been installed.
1184 ;For example, if two VDISKs are installed, one 320KB and one 64KB, the
1185 ;address calculations are as follows:
1187 ;Extended memory start address = 100000H (1024KB)
1188 ;Start addr of 1st VDISK buffer = 100000H (1024KB)
1189 ;Length of 1st VDISK buffer = 050000H ( 320KB)
1190 ;End addr of 1st VDISK buffer = 14FFFFH
1191 ;Start addr of 2nd VDISK buffer = 150000H (1344KB)
1192 ;Length of 2nd VDISK buffer = 010000H ( 64KB)
1193 ;End addr of 2nd VDISK buffer = 15FFFFH
1194 ;First byte after all VDISKs = 160000H (1408KB)
1195 ;Divide by 1024 = 0580H (1408D)
1197 ;-----------------------------------------------------------------------;
1198 ; Part 2 of Initialization (executed last) ;
1199 ;-----------------------------------------------------------------------;
1200 ;Initialization is divided into two parts.
1202 ;INIT_P1 is overlaid by the virtual disk buffer
1204 ;INIT_P1 is executed first, then jumps to INIT_P2. INIT_P2 returns to caller.
1206 ;Exercise caution if extending the initialization part 2 code.
1207 ;It overlays the area immediately following the boot sector.
1208 ;If this section of code must be expanded, make sure it fits into the minimum
1209 ;sector size of 128 bytes.
1210 ;Label TEST_LENGTH must equate to a non-negative value (TEST_LENGTH >= 0).
1211 ;If this code it must be extended beyond the 128 byte length of the boot sector,
1212 ;move all of INIT_P2 before label VDISK.
1214 ;Registers at entry to INIT_P2 (set up at end of INIT_P1):
1215 ; BL = media control byte from BPB (for FAT)
1216 ; CX = number of FAT copies
1217 ; DX = number of bytes in one FAT - 3
1218 ; SI = OFFSET of Volume Label field
1219 ; ES:DI = VDISK buffer address of first FAT sector
1220 ; CS = DS = VDISK code segment
1222 INIT_P2 PROC
;second part of initialization
1223 ASSUME
DS:CSEG
;DS set in INIT_P1
1225 ;Initialize File Allocation Table(s) (FATs)
1227 INIT_P2_FAT: ;set up one FAT, sector number in AX
1229 PUSH CX ;save loop counter on stack
1230 MOV AL,BL ;media control byte
1231 STOSB ;store media control byte, increment DI
1232 MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
1235 MOV CX,DX ;FAT size in bytes - 3
1236 XOR AX,AX ;value to store in remainder of FAT
1237 REP STOSB ;clear remainder of FAT
1239 POP CX ;get loop counter off stack
1240 LOOP INIT_P2_FAT
;loop for all copies of the FAT
1242 ;Put the volume label in the first directory entry
1244 MOV CX,VOL_LABEL_LEN
;length of volume directory entry
1245 REP MOVSB ;move volume id to directory
1247 ;Zero the remainder of the directory
1249 MOV AX,DIR_ENTRY_SIZE
;length of 1 directory entry
1250 MUL BPB_DIRN
;* number entries = bytes of directory
1251 SUB AX,VOL_LABEL_LEN
;less length of volume label
1252 MOV CX,AX ;length of rest of directory
1254 REP STOSB ;clear directory to nulls
1255 RET ;return with AX=0
1258 PATCH_AREA
DB 5 DUP ('PATCH AREA ')
1259 TEST_LENGTH EQU
128-($-VDISK
) ;if negative, boot record has too much
1260 ;data area, move some fields below VDISK
1261 ;-----------------------------------------------------------------------;
1262 ; All fields that must remain resident after device driver ;
1263 ; initialization must be defined before this point. ;
1264 ;-----------------------------------------------------------------------;
1269 MAXSEC_TRF
DW 0 ;maximum number of sectors to transfer when
1272 BUFF_SIZE
DW 0 ;desired VDISK buffer size in kilobytes
1274 MIN_MEMORY_LEFT
DW 100 ;minimum amount of system memory (kilobytes)
1275 ;that must remain after VDISK is installed
1277 PARA_PER_KB
DW 1024/PARA_SIZE
;paragraphs in one kilobyte
1278 C1024
DW 1024 ;bytes in one kilobyte
1279 DIRE_SIZE
DW DIR_ENTRY_SIZE
;bytes in one directory entry
1280 DIR_SECTORS
DW ?
;number of sectors of directory
1282 ERR_FLAG
DB 0 ;error indicators to condition messages
1283 ERR_BSIZE EQU 80H
;buffer size adjusted
1284 ERR_SSZ EQU 40H
;sector size adjusted
1285 ERR_DIRN EQU 20H
;number of directory entries adjusted
1286 ERR_PASS EQU 10H
;some adjustment made that requires
1287 ;recomputation of values previously computed
1288 ERR_SSZB EQU ERR_SSZ
+ERR_PASS
;sector size altered this pass
1289 ERR_SYSSZ EQU
08H ;system storage too small for VDISK
1290 ERR_SWTCH EQU
04H ;invalid switch character
1291 ERR_EXTSW EQU
02H ;extender card switches don't match memory size
1292 ERR_ESIZE EQU
01H ;Transfer size adjusted
1294 DOS_PG_SZ
DB DOS_PAGE_SZ
;AN000;
1295 DOS_Page_Size_Word dw DOS_Page_Sz
;an000;
1298 err_baddos equ
01h ; Invalid DOS Version
1300 ;-----------------------------------------------------------------------;
1301 ; SUBLIST definitions and EQUATES for Message Retreiver ;
1302 ;-----------------------------------------------------------------------;
1303 ;AN000; Message Number
1304 INCORRECT_DOS EQU
1 ;AN000;
1305 SYS_TOO_SMALL EQU
2 ;AN000;
1306 VDISK_TITLE EQU
3 ;AN000;
1307 BUFFER_ADJUSTED EQU
4 ;AN000;
1308 SECTOR_ADJUSTED EQU
5 ;AN000;
1309 DIR_ADJUSTED EQU
6 ;AN000;
1310 INVALID_SW_CHAR EQU
7 ;AN000;
1311 TRANS_ADJUSTED EQU
8 ;AN000;
1312 BUF_SZ EQU
9 ;AN000;
1313 SEC_SZ EQU
10 ;AN000;
1314 DIR_ENTRIES EQU
11 ;AN000;
1315 TRANS_SZ EQU
12 ;AN000;
1316 VDISK_NOT_INST EQU
13 ;AN000;
1317 EXTEND_CARD_WRONG EQU
14 ;AN000;
1319 NO_REPLACE EQU
0 ;AN000; CX = 0 -> No replacement
1320 ONE_REPLACE EQU
1 ;AN000; CX = 1 -> One replacement
1321 UNLIMITED_MAX EQU
0 ;AN000; MAX field - unlimited
1322 SMALLEST_MIN EQU
1 ;AN000; MIN field - 1 character long
1323 PAD_BLANK EQU 20H
;AN000; PAD character is a blank
1326 DRIVE_CODE
DB ?
;AN000;
1327 DB ":",NULL
;AN000; ASCIIZ string for drive code
1329 ; For the message: "VDISK Version 4.00 virtual disk %1",CR,LF
1331 TITLE_SUBLIST
LABEL BYTE
1333 TT_SIZE
DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1334 TT_RESV
DB 0 ;AN000; RESERVED
1335 TT_VALUEO
DW DRIVE_CODE
;AN000; Offset to ASCIIZ string
1336 TT_VALUES
DW ?
;AN000; SEGMENT TO ASCIIZ STRING
1337 TT_ID
DB 1 ;AN000; n of %n
1338 TT_FLAG
DB Left_Align
+Char_Field_ASCIIZ
1339 TT_MAXW
DB UNLIMITED_MAX
;AN000; Maximum field width
1340 TT_MINW
DB SMALLEST_MIN
;AN000; Minimum field width
1341 TT_PAD
DB PAD_BLANK
;AN000; Character for Pad field
1343 ; For the message: "Buffer size: %1 KB",CR,LF
1345 BUF_SZ_SUBLIST
LABEL BYTE
1347 B_SIZE
DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1348 B_RESV
DB 0 ;AN000; RESERVED
1349 B_VALUEO
DW BUFF_SIZE
;AN000; Offset to binary number
1350 B_VALUES
DW ?
;AN000; SEGMENT TO BINARY NUMBER
1351 B_ID
DB 1 ;AN000; n of %n
1352 B_FLAG
DB Left_Align
+Unsgn_Bin_Word
1353 B_MAXW
DB UNLIMITED_MAX
;AN000; Maximum field width
1354 B_MINW
DB SMALLEST_MIN
;AN000; Minimum field width
1355 B_PAD
DB PAD_BLANK
;AN000; Character for Pad field
1357 ; For the message: "Sector size: %1",CR,LF
1359 SEC_SZ_SUBLIST
LABEL BYTE
1361 S_SIZE
DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1362 S_RESV
DB 0 ;AN000; RESERVED
1363 S_VALUEO
DW BPB_SSZ
;AN000; Offset to binary number
1364 S_VALUES
DW ?
;AN000; SEGMENT TO BINARY NUMBER
1365 S_ID
DB 1 ;AN000; n of %n
1366 S_FLAG
DB Left_Align
+Unsgn_Bin_Word
1367 S_MAXW
DB UNLIMITED_MAX
;AN000; Maximum field width
1368 S_MINW
DB SMALLEST_MIN
;AN000; Minimum field width
1369 S_PAD
DB PAD_BLANK
;AN000; Character for Pad field
1371 ; For the message: "Directory entries: %1",CR,LF
1373 DIR_ENT_SUBLIST
LABEL BYTE
1375 D_SIZE
DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1376 D_RESV
DB 0 ;AN000; RESERVED
1377 D_VALUEO
DW BPB_DIRN
;AN000; Offset to binary number
1378 D_VALUES
DW ?
;AN000; SEGMENT TO BINARY NUMBER
1379 D_ID
DB 1 ;AN000; n of %n
1380 D_FLAG
DB Left_Align
+Unsgn_Bin_Word
1381 D_MAXW
DB UNLIMITED_MAX
;AN000; Maximum field width
1382 D_MINW
DB SMALLEST_MIN
;AN000; Minimum field width
1383 D_PAD
DB PAD_BLANK
;AN000; Character for Pad field
1385 ; For the message: "Transfer size: %1",CR,LF
1387 TRANS_SZ_SUBLIST
LABEL BYTE
1389 T_SIZE
DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1390 T_RESV
DB 0 ;AN000; RESERVED
1391 T_VALUEO
DW MAXSEC_TRF
;AN000; Offset to binary number
1392 T_VALUES
DW ?
;AN000; SEGMENT TO BINARY NUMBER
1393 T_ID
DB 1 ;AN000; n of %n
1394 T_FLAG
DB Left_Align
+Unsgn_Bin_Word
1395 T_MAXW
DB UNLIMITED_MAX
;AN000; Maximum field width
1396 T_MINW
DB SMALLEST_MIN
;AN000; Minimum field width
1397 T_PAD
DB PAD_BLANK
;AN000; Character for Pad field
1399 ;-----------------------------------------------------------------------;
1401 ;-----------------------------------------------------------------------;
1403 FRAME_BUFFER
DB 10 DUP(0) ;AN000;
1404 VDISK_Name db "VDISK " ;an000; dms;
1409 SUBTTL Initialization
, Part one
1411 ;-----------------------------------------------------------------------;
1412 ; Command Code 0 - Initialization ;
1413 ; At entry, DS:BX point to request header, AX = 0 ;
1414 ;-----------------------------------------------------------------------;
1415 ;Initialization is divided into two parts.
1416 ;This part, executed first, is later overlaid by the VDISK buffer.
1418 INIT_P1 PROC
;first part of initialization
1424 ;;;;; mov bx,0140H ;ICE
1425 ;;;;; xor ax,ax ;ICE
1426 ;;;;; mov ds,ax ;ICE
1427 ;;;;; mov ax,word ptr ds:[bx] ;ICE
1428 ;;;;; mov word ptr ds:[bx],ax ;ICE
1434 MOV DX,SS ;save stack segment register
1435 MOV CX,SP ;save stack pointer register
1436 CLI ;inhibit interrupts while changing SS:SP
1437 MOV AX,CS ;move CS to SS through AX
1439 MOV SP,OFFSET MSGEND
;end of VDISKMSG
1440 ADD SP,STACK_SIZE
;+ length of our stack
1442 STI ;allow interrupts
1444 PUSH DX ;save old SS register on new stack
1445 PUSH CX ;SAVE OLD SP REGISTER ON NEW STACK
1449 PUSH DS ;AN000;SAVE REGS
1452 PUSH CS ;AN000;TRANSFER TO DS
1457 ASSUME
DS:CSEG
,ES:CSEG
;AN000;
1459 CALL SYSLOADMSG
;AN000; LOAD messages and do DOS version check
1460 JNC VDISK_CONTINUE_1
;AN000; Did we load OK?
1461 or cs:err_flag2
,err_baddos
1463 push ds ;an006; dms;save ds
1464 push bx ;an006; dms;save bx
1465 lds bx,cs:RH_Ptra
;an006; dms;point to request header
1466 mov RH
.RH0_Flag
,-1 ;an006; dms;signal BIO and error occurred
1467 pop bx ;an006; dms;restore bx
1468 pop ds ;an006; dms;restore ds
1470 MOV AX,VDISK_NOT_INST
;AN000;VDISK UNABLE TO BE INSTALLED
1471 MOV BX,NO_HANDLE
;AN000;NO DISPLAY HANDLE
1472 CALL SYSDISPMSG
;AN000;DISPLAY THE MESSAGE
1473 MOV AX,INCORRECT_DOS
;AN000;BAD DOS VERSION
1474 MOV BX,NO_HANDLE
;AN000;NO DISPLAY HANDLE
1475 CALL SYSDISPMSG
;AN000;DISPLAY THE MESSAGE
1477 VDISK_CONTINUE_1: ;AN000;
1479 POP ES ;AN000;RESTORE REGS
1481 ASSUME
DS:NOTHING
,ES:NOTHING
;AN000;
1483 CALL PC_386_CHK
;AN000;SEE IF WE HAVE A 386 PC
1485 CALL GET_PARMS
;get parameters from CONFIG.SYS line
1489 ASSUME
DS:CSEG
,ES:CSEG
1491 CALL APPLY_DEFAULTS
;supply any values not specified
1492 CALL DETERMINE_START
;compute start address of VDISK buffer
1493 CALL VALIDATE
;validate parameters
1494 CALL COPY_BPB
;Copy BIOS Parameter Block to boot record
1496 CALL VERIFY_EXTENDER
;Verify that extender card switches are right
1498 TEST ERR_FLAG
,ERR_EXTSW
;are switches wrong?
1499 JNZ INIT_P1_A
;if so, exit with messages
1501 test cs:err_flag2
,err_baddos
1504 CMP EM_SW
,0 ;EXTENDED MEMORY REQUEST?
1505 JE INIT_P1_A
;jump if not
1507 TEST ERR_FLAG
,ERR_SYSSZ
;is system too small for VDISK?
1508 JNZ INIT_P1_A
;if so, don't do extended memory init
1510 CALL UPDATE_AVAIL
;update AVAIL_HI and AVAIL_LO to reflect
1511 ;addition of extended memory VDISK
1512 CALL FORMAT_VDISK
;construct a boot record, FATs and
1513 ;directory in storage immediately
1514 ;following this device driver
1515 CALL MOVE_VDISK
;move formatted boot record, FATs,
1516 ;and directory to extended memory
1519 CALL FILL_RH
;fill in INIT request header
1520 CALL WRITE_MESSAGES
;display all messages
1521 POP CX ;get old SP from stack
1522 POP DX ;get old SS from stack
1523 CLI ;disable interrupts while changing SS:SP
1524 MOV SS,DX ;restore stack segment register
1525 MOV SP,CX ;restore stack pointer register
1526 STI ;enable interrupts
1527 ;-----------------------------------------------------------------------;
1528 ; INIT_P2 must be short enough to fit into the boot sector ;
1529 ; (minimum size of boot sector is 128 bytes), so we set up ;
1530 ; as many pointers as we can to help keep INIT_P2 short. ;
1532 ; ES:DI = storage address of first FAT sector ;
1533 ; BL = media control byte ;
1534 ; CX = number of FAT copies ;
1535 ; DX = number of bytes in one FAT, less 3 ;
1536 ; SI = offset of VOL label field ;
1537 ;-----------------------------------------------------------------------;
1538 MOV ES,START_BUFFER_PARA
;start paragraph of VDISK buffer
1540 MOV AX,BPB_RES
;number of reserved sectors
1541 MUL BPB_SSZ
;* sector size
1542 MOV DI,AX ;ES:DI point to FAT start
1544 MOV BL,BPB_MCB
;media control byte
1546 MOV CL,BPB_FATN
;number of FAT copies
1549 MOV AX,BPB_FATSZ
;FAT size in sectors
1550 MUL BPB_SSZ
;* sector size = total FAT bytes
1552 SUB AX,3 ;-3 (FEFFFF stored by code)
1555 MOV SI,OFFSET VOL_LABEL
;point to VOL label directory entry
1556 JMP INIT_P2
;jump to second part of initialization
1557 ;this is redundant if the VDISK is in
1558 ;extended memory, but is executed anyway
1564 ;=========================================================================
1565 ; PC_386_CHK : QUERIES THE BIOS TO DETERMINE WHAT TYPE OF
1566 ; MACHINE WE ARE ON. WE ARE LOOKING FOR A 386.
1567 ; THIS WILL BE USED TO DETERMINE IF A DW MOVE
1568 ; IS TO BE PERFORMED.
1572 ; OUTPUTS : PC_386 - FLAG SIGNALS IF WE ARE ON A 386 MACHINE.
1573 ;=========================================================================
1575 PC_386_CHK PROC
NEAR ;AN000;DETERMINE MACHINE TYPE
1577 PUSH AX ;AN000;SAVE AFFECTED REGS
1581 MOV CS:PC_386
,FALSE
;AN000;INITIALIZE TO FALSE
1583 MOV AH,0C0H ;AN000;RETURN SYSTEM CONFIGURATION
1586 ; $IF NC ;AN000;IF A GOOD RETURN
1588 CMP AH,0 ;AN000;IS IT NEW FORMAT FOR CONFIG.
1591 MOV AL,ES:[BX.BIOS_SD_MODELBYTE
] ;AN000;CHECK MODEL
1592 CMP AL,0F8H ;AN000;IS IT A 386 MACHINE?
1595 MOV CS:PC_386
,TRUE
;AN000;SIGNAL A 386
1603 POP ES ;AN000;RESTORE REGS.
1609 PC_386_CHK ENDP
;AN000;
1612 SUBTTL GET_PARMS Parameter Line Scan
1614 ;-----------------------------------------------------------------------;
1615 ;GET_PARMS gets the parameters from the CONFIG.SYS statement ;
1618 ; DS:SI indexes parameter string ;
1619 ; AL contains character from parameter string ;
1620 ; CX value from GET_NUMBER ;
1621 ;-----------------------------------------------------------------------;
1622 ASSUME
DS:NOTHING
;DS:BX point to Request Header
1623 GET_PARMS PROC
;get parameters from CONFIG.SYS line
1625 LDS SI,RH
.RH0_BPBA
;DS:SI point to all after DEVICE=
1627 XOR AL,AL ;not at end of line
1629 ;Skip until first delimiter is found. There may be digits in the path string.
1631 ;DS:SI points to \pathstring\VDISK.SYS nn nn nn
1632 ;The character following VDISK.SYS may have been changed to a null (00H).
1633 ;All letters have been changed to uppercase.
1635 GET_PARMS_A: ;skip to DOS delimiter character
1636 CALL GET_PCHAR
;get parameter character into AL
1637 JZ Get_Parms_X_Exit
;get out if end of line encountered
1638 OR AL,AL ;test for null
1651 JNE GET_PARMS_A
;skip until delimiter or CR
1656 PUSH SI ;save to rescan
1657 MOV CS:EM_SW
,0 ;INDICATE NO /E FOUND
1658 JMP GET_SLASH
;see if current character is an slash
1660 GET_PARMS_D: ;scan for /
1662 JZ GET_PARMS_B
;exit if end of line
1664 GET_SLASH: ;check for slash
1665 CMP AL,'/' ;found slash?
1666 JNE GET_PARMS_D
;no, continue scan
1668 CALL GET_PCHAR
;get char following slash
1669 CMP AL,'E' ;don't have to test for lower case E,
1670 ;letters have been changed to upper case
1671 JNE CHECK_FOR_X
;not 'E' ;AN005;
1672 CMP CS:EM_SW
,'X' ;Was /X already defined? ;AN005;
1673 JE GET_PARMS_E
;indicate invalid switch ;AN005;
1674 MOV CS:EM_SW
,AL ;indicate /E found ;AN005;
1675 JMP SHORT GOT_E_OR_X
;AN005;
1677 CHECK_FOR_X: ;AN005;
1678 CMP AL,'X' ;don't have to test for lower case X, ;AN005;
1679 ;letters have been changed to upper case ;AN005;
1680 JNE GET_PARMS_E
;not 'X' ;AN005;
1681 CMP CS:EM_SW
,'E' ;Was /E already defined? ;AN005;
1682 JE GET_PARMS_E
;indicate invalid switch ;AN005;
1683 MOV CS:EM_SW
,'X' ;indicate /X found ;AN005;
1686 CALL GET_PCHAR
;get char following E or X ;AN005;
1687 CMP AL,':' ;is it a delimeter ?
1688 JNE GET_PARMS_D
;not a ':'
1691 CALL GET_MAXSIZE
;get maximum sector size
1694 JMP GET_PARMS_D
;continue forward scan
1696 GET_PARMS_E: ;/ found, not 'E'
1697 OR CS:ERR_FLAG
,ERR_SWTCH
;indicate invalid switch character
1698 JMP GET_PARMS_D
;continue scan
1702 GET_PARMS_B: ;now pointing to first delimiter
1703 POP SI ;get pointer, used to rescan for /E
1704 XOR AL,AL ;not at EOL now
1705 CALL GET_PCHAR
;get first character
1706 CALL SKIP_TO_DIGIT
;skip to first digit
1710 JZ GET_PARMS_X
;found EOL, no digits remain
1712 CALL GET_NUMBER
;extract digits, convert to binary
1713 MOV CS:BUFF_SIZE
,CX ;store buffer size
1715 CALL SKIP_TO_DIGIT
;skip to next digit
1716 JZ GET_PARMS_X
;found EOL, no digits remain
1718 CALL GET_NUMBER
;extract digits, convert to binary
1719 MOV CS:BPB_SSZ
,CX ;store sector size
1721 CALL SKIP_TO_DIGIT
;skip to next digit
1722 JZ GET_PARMS_X
;found EOL, no digits remain
1724 CALL GET_NUMBER
;extract digits, convert to binary
1725 MOV CS:BPB_DIRN
,CX ;store number of directory entries
1729 GET_PARMS_X: ;premature end of line
1730 TEST cs:ERR_FLAG
,ERR_SWTCH
;was an invalid switch character found?
1731 ; $if nz ;yes - set flag to regular VDISK ;an000; dms;
1733 ; this is consistent with DOS 3.3
1734 mov cs:EM_SW
,0 ;set flag to regular VDISK ;an000; dms;
1735 ; $endif ; ;an000; dms;
1741 GET_MAXSIZE PROC
;get maximum sector size
1743 CALL GET_PCHAR
;get next character
1744 CALL CHECK_NUM
;is it a number ?
1745 JZ GET_NEXTNUM
;yes, go get next number
1746 OR CS:ERR_FLAG
,ERR_ESIZE
;indicate invalid sector size
1748 GET_NEXTNUM: ;get next number
1749 CALL GET_NUMBER
;extract digits and convert to binary
1750 MOV CS:MAXSEC_TRF
,CX ;save maximum sector size to transfer
1756 GET_PCHAR PROC
;internal proc to get next character into AL
1757 CMP AL,CR
;carriage return already encountered?
1758 JE GET_PCHAR_X
;don't read past end of line
1759 CMP AL,LF
;line feed already encountered?
1760 JE GET_PCHAR_X
;don't read past end of line
1761 LODSB ;get char from DS:SI, increment SI
1762 CMP AL,CR
;is the char a carriage return?
1763 JE GET_PCHAR_X
;yes, set Z flag at end of line
1764 CMP AL,LF
;no, is it a line feed?
1765 GET_PCHAR_X: ;attempted read past end of line
1767 GET_PCHAR ENDP
;returns char in AL
1770 CHECK_NUM PROC
;check AL for ASCII digit
1772 JB CHECK_NUM_X
;exit if it is
1775 JA CHECK_NUM_X
;exit if it is
1777 CMP AL,AL ;set Z flag to indicate numeric
1779 RET ;Z set if numeric, NZ if not numeric
1783 SKIP_TO_DIGIT PROC
;skip to first numeric character
1784 CALL CHECK_NUM
;is current char a digit?
1785 JZ SKIP_TO_DIGIT_X
;if so, skip is complete
1787 CALL GET_PCHAR
;get next character from line
1788 JNZ SKIP_TO_DIGIT
;loop until first digit or CR or LF
1789 RET ;character is CR or LF
1792 CMP AL,0 ;digit found, force NZ
1797 GN_ERR
DB ?
;zero if no overflow in accumulation
1799 GET_NUMBER PROC
;convert string of digits to binary value
1800 XOR CX,CX ;accumulate number in CX
1801 MOV CS:GN_ERR
,CL ;no overflow yet
1802 GET_NUMBER_A: ;accumulate next digit
1803 SUB AL,'0' ;convert ASCII to binary
1805 XCHG AX,CX ;previous accumulation in AX, new digit in CL
1806 MUL CS:C10
;DX:AX := AX*10
1807 OR CS:GN_ERR
,DL ;set GN_ERR <> 0 if overflow
1808 ADD AX,CX ;add new digit from
1809 XCHG AX,CX ;number now in CX
1810 DEC SI ;back up to prior entry
1811 MOV AL,' ' ;blank out prior entry
1813 INC SI ;set to current entry
1814 CALL GET_PCHAR
;get next character
1815 CALL CHECK_NUM
;see if it was numeric
1816 JZ GET_NUMBER_A
;continue accumulating
1817 CMP CS:GN_ERR
,0 ;did we overflow?
1818 JE GET_NUMBER_B
;if not, we're done
1819 XOR CX,CX ;return zero (always invalid) if overflow
1821 RET ;number in CX, next char in AL
1826 SUBTTL APPLY_DEFAULTS
1828 ;-----------------------------------------------------------------------;
1829 ; APPLY_DEFAULTS supplies any parameter values that the user ;
1830 ; failed to specify ;
1831 ;-----------------------------------------------------------------------;
1835 CMP BUFF_SIZE
,AX ;is buffer size zero?
1836 JNE APPLY_DEFAULTS_A
;no, user specified something
1838 MOV BUFF_SIZE
,DFLT_BSIZE
;supply default buffer size
1839 OR ERR_FLAG
,ERR_BSIZE
;indicate buffersize adjusted
1842 CMP BPB_SSZ
,AX ;is sector size zero?
1843 JNE APPLY_DEFAULTS_B
;no, user specified something
1845 MOV BPB_SSZ
,DFLT_SSZ
;supply default sector size
1846 OR ERR_FLAG
,ERR_SSZ
;indicate sector size adjusted
1849 CMP BPB_DIRN
,AX ;are directory entries zero?
1850 JNE APPLY_DEFAULTS_C
;no, user specified something
1852 MOV BPB_DIRN
,DFLT_DIRN
;supply default directory entries
1853 OR ERR_FLAG
,ERR_DIRN
;indicate directory entries adjusted
1856 CMP EM_SW
,0 ;EXTENDED MEMORY
1857 JE APPLY_DEFAULTS_D
;no, jump around
1858 CMP MAXSEC_TRF
,AX ;is maximum sectors zero?
1859 JNE APPLY_DEFAULTS_D
;no, user specified something
1861 MOV MAXSEC_TRF
,DFLT_ESS
;supply default maximum number of
1863 OR ERR_FLAG
,ERR_ESIZE
;indicate transfer size adjusted
1868 SUBTTL DETERMINE_START address of VDISK buffer
1870 ;-----------------------------------------------------------------------;
1871 ; DETERMINE_START figures out the starting address of the VDISK ;
1873 ;-----------------------------------------------------------------------;
1875 DETERMINE_START PROC
1877 ;If extended memory is NOT being used, the VDISK buffer immediately
1878 ;follows the resident code.
1880 ;If extended memory IS being used, START_BUFFER_PARA becomes the
1881 ;end of device driver address passed back to DOS.
1883 MOV AX,CS ;start para of VDISK code
1884 ADD AX,VDISKP
;+ length of resident code
1885 MOV START_BUFFER_PARA
,AX ;save as buffer start para
1887 CMP EM_SW
,0 ;IS EXTENDED MEMORY REQUESTED?
1888 JE DETERMINE_START_X
;if not, we're done here
1890 ;-----------------------------------------------------------------------;AN000;
1891 ;If EMS is not installed, the calculation to determine the starting address
1892 ;of the VDISK will remain the same.
1894 ;If EMS is installed we really don't need this calculation, the EMM will
1895 ;manage the expanded memory insuring mutiple VDISKs may reside concurrently.
1896 ;-----------------------------------------------------------------------;AN000;
1898 cmp EM_SW
,EMS_Mem
;EMS requested? ;an005; dms;
1899 je Determine_Start_X
;yes - leave routine ;an005; dms;
1900 ;no - continue routine
1902 clc ;an001; dms;clear carry for INT
1903 MOV AX,EM_MEMSIZE
;an001; dms; get EM memory size
1904 INT EM_INT
;an001; dms; INT 15h
1905 JC Determine_Start_X
;an001; dms; no extended memory installed
1906 or ax,ax ;an001; dms;see if memory returned
1907 jz Determine_Start_X
;an001; dms;signal no memory
1909 xor dx,dx ;an001; dms;clear dx
1910 sub ax,cs:Buff_Size
;an001; dms;get starting KB location
1911 jc Determine_Start_X
;an001; dms;buffer too large
1913 mov cs:EM_New_Size
,ax ;an001; dms;save new size of EM for later use
1914 mul C1024
;an001; dms;get total byte count
1915 add ax,cs:Avail_Lo
;an001; dms;add in low word of EM start
1916 adc dl,cs:Avail_Hi
;an001; dms;add in high word of EM start
1918 mov cs:Avail_Lo
,ax ;an001; dms;save new low beginning word
1919 mov cs:Avail_Hi
,dl ;an001; dms;save new high beginning word
1921 mov cs:Start_EM_Lo
,ax ;an001; dms;load in new beginning word
1922 mov cs:Start_EM_Hi
,dl ;an001; dms;load in new beginning byte
1927 DETERMINE_START ENDP
1929 SUBTTL VALIDATE parameters
1931 ;-----------------------------------------------------------------------;
1932 ; VALIDATE adjusts parameters as necessary ;
1933 ;-----------------------------------------------------------------------;
1934 VAL_SSZ_TBL
LABEL WORD ;table of valid sector sizes
1935 VAL_SSZ_S
DW 128 ;smallest valid sector size
1937 VAL_SSZ_L
DW 512 ;largest valid sector size
1938 VAL_SSZ_N EQU
($-VAL_SSZ_TBL
)/2 ;number of table entries
1941 VALIDATE PROC
;validate parameters
1946 ;;ice mov bx,0140H ;ICE
1947 ;;ice xor ax,ax ;ICE
1948 ;;ice mov ds,ax ;ICE
1949 ;;ice mov ax,word ptr ds:[bx] ;ICE
1950 ;;ice mov word ptr ds:[bx],ax ;ICE
1955 MOV BPB_AUSZ
,1 ;initial allocation unit is 1 sector
1957 CALL VAL_BSIZE
;validate buffer size
1959 CALL VAL_SSZ
;validate (adjust if necessary) BPB_SSZ
1962 AND ERR_FLAG
,255-ERR_PASS
;indicate nothing changed this pass
1964 MOV AX,BPB_SSZ
;sector size
1965 CWD ;clear DX for division
1966 DIV WPARA_SIZE
;sector size/para size
1967 MOV PARAS_PER_SECTOR
,AX ;number of paragraphs/sector
1969 mov ax,EMS_Page_Size
;an002; dms;EMS page size
1970 xor dx,dx ;an002; dms;clear high word
1971 div BPB_SSZ
;an002; dms;get sectors/page
1972 mov Sect_Per_Page
,ax ;an002; dms;save sectors/page
1974 ;;;;; MOV AX,BPB_SSZ ;AN000; Sector size
1975 ;;;;; xor dx,dx ;an001; clear high word
1976 ;;;;; DIV DOS_Page_Size_Word ;an001; Sector size/page size
1977 ;;;;; MOV SECT_PER_PAGE,AX ;an001; Number of sectors/page
1979 MOV AX,BUFF_SIZE
;requested buffersize in KB
1980 MUL C1024
;DX:AX = buffer size in bytes
1981 DIV BPB_SSZ
;/sector size = # sectors
1982 MOV BPB_SECN
,AX ;store number of sectors
1984 CALL VAL_DIRN
;validate number of directory entries
1986 TEST ERR_FLAG
,ERR_PASS
;may have reset sector size
1987 JNZ VALIDATE_A
;recompute directory & FAT sizes
1989 CALL VAL_FAT
;compute FAT entries, validity test
1991 TEST ERR_FLAG
,ERR_PASS
;if cluster size altered this pass
1992 JNZ VALIDATE_A
;recompute directory & FAT sizes
1994 ;Make certain buffer size is large enough to contain:
1997 ; directory sector(s)
1998 ; at least 1 data cluster
2000 MOV AL,BPB_FATN
;number of FAT copies
2002 MUL BPB_FATSZ
;* sectors for 1 FAT = FAT sectors
2003 ADD AX,BPB_RES
;+ reserved sectors
2004 ADD AX,DIR_SECTORS
;+ directory sectors
2005 MOV CL,BPB_AUSZ
;get sectors/cluster
2006 XOR CH,CH ;CX = sectors in one cluster
2007 ADD AX,CX ;+ one data cluster
2008 CMP BPB_SECN
,AX ;compare with sectors available
2009 JAE VALIDATE_X
;jump if enough sectors
2011 CMP DIR_SECTORS
,1 ;down to 1 directory sector?
2012 JBE VALIDATE_C
;can't let it go below 1
2014 MOV AX,BPB_SSZ
;sector size
2015 CWD ;clear DX for division
2016 DIV DIRE_SIZE
;sectorsize/dir entry size = entries/sector
2017 SUB BPB_DIRN
,AX ;reduce directory entries by 1 sector
2019 OR ERR_FLAG
,ERR_DIRN
;indicate directory entries adjusted
2020 JMP VALIDATE_A
;retry with new directory entries number
2022 VALIDATE_C: ;not enough space for any VDISK
2023 OR ERR_FLAG
,ERR_SYSSZ
2027 SUBTTL VAL_BSIZE Validate buffer size
2029 ;-----------------------------------------------------------------------;
2030 ; VAL_BSIZE adjusts the buffer size as necessary ;
2031 ;-----------------------------------------------------------------------;
2033 CALL GET_MSIZE
;determine memory available to VDISK
2034 ;returns available KB in AX
2035 OR AX,AX ;is any memory available at all?
2036 JNZ VAL_BSIZE_B
;yes, continue
2038 OR ERR_FLAG
,ERR_SYSSZ
;indicate system too small for VDISK
2039 MOV BUFF_SIZE
,1 ;set up minimal values to continue init
2040 MOV AX,VAL_SSZ_S
;smallest possible sector size
2042 MOV BPB_DIRN
,4 ;4 directory entries
2045 VAL_BSIZE_B: ;some memory is available
2046 CMP AX,BUFF_SIZE
;is available memory >= requested?
2047 JAE VAL_BSIZE_C
;if so, we're done
2049 MOV BUFF_SIZE
,AX ;give all available memory
2050 mov cs:EM_New_Size
,0 ;an001; dms;save new size of EM for later use
2051 mov ax,cs:Avail_Lo
;an001; dms;get low word of EM start
2052 mov dl,cs:Avail_Hi
;an001; dms;get high byte of EM start
2054 mov cs:Start_EM_Lo
,ax ;an001; dms;load in new beginning word
2055 mov cs:Start_EM_Hi
,dl ;an001; dms;load in new beginning byte
2056 OR ERR_FLAG
,ERR_BSIZE
;indicate buffersize adjusted
2063 GET_MSIZE PROC
;determine memory available to VDISK
2064 ;returns KB available in AX
2065 CMP EM_SW
,0 ;EXTENDED MEMORY?
2066 JE GET_MSIZE_2
;use non-extended memory routine
2068 cmp EM_SW
,EM_Mem
;Extended memory requested? ;an005; dms;
2069 je Use_Extended_Support
;yes ;an005; dms;
2070 ;no - check for EMS availability
2073 CALL EMS_CHECK
;AN000; Check if EMS is installed
2074 JC GET_MSIZE_Z
;AN000; Yes, it is installed but in error
2075 ; then notify caller by setting AX to zero
2076 CMP AH,NOT EMS_INSTALLED_FLAG
;AN000;
2077 JE Get_Msize_Z
;ac005; flag an error occurred
2078 MOV EM_SW2
,AH ;AN000; Set EMS flag
2079 CALL EMS_GET_PAGES
;AN000; Get count of total number of pages
2080 xor dx,dx ;an002; clear high word
2081 MUL DOS_Page_Size_Word
;ac002; Number of pages * KB per page
2082 RET ;AN000; Return with AX = number of whole free kilobytes
2084 USE_EXTENDED_SUPPORT: ;AN000; No, EMS is not installed
2086 MOV AX,EM_MEMSIZE
;function code to AH
2087 INT EM_INT
;get extended memory size in AX
2088 JC GET_MSIZE_Z
;if error, no extended memory installed
2089 or ax,ax ;an000; dms;see if memory returned
2090 jz GET_MSIZE_Z
;an000; dms;signal no memory
2094 GET_MSIZE_2: ;non-extended memory size determination
2096 ;Compute AX = total system size, - (VDISK end address + 64KB)
2098 MOV AX,START_BUFFER_PARA
;paragraph end of VDISK code
2099 XOR DX,DX ;clear for division
2100 DIV PARA_PER_KB
;KB address of load point
2101 ADD DX,0FFFFH ;round upward to KB boundary
2102 ADC AX,MIN_MEMORY_LEFT
;pick up CY and the 64KB we should leave
2103 PUSH AX ;save across interrupt
2104 INT MEM_SIZE
;get total system size
2105 POP DX ;amount of total that we can't use
2106 SUB AX,DX ;available space to VDISK
2107 JNC GET_MSIZE_X
;exit if positive
2110 XOR AX,AX ;indicate no memory available
2111 GET_MSIZE_X: ;exit from memory size determination
2119 EMS_CHECK PROC
NEAR ;AN000;
2121 CALL EMS_CHECK1
;AN000; SEE IF EMS INSTALLED
2122 JNC EMS_INSTALLED
;AN000; No,
2123 MOV AH,NOT EMS_INSTALLED_FLAG
;AN000; Flag EMS not installed
2124 CLC ;AN000; Make sure carry is Clear
2125 JMP SHORT EMS_CHECK_EXIT
;AN000; Leave check routine
2127 EMS_INSTALLED: ;AN000; Yes,
2129 push es ;an000; save es - call destroys it
2130 push di ;an006; save di
2132 mov ah,EMS_2F_Handler
;an006;see if our 2Fh is there
2135 cmp al,0ffh ;an006;2Fh handler there?
2138 mov ah,EMS_2F_Handler
;an006;get EMS page for VDISK
2143 or ah,ah ;an006;page available?
2146 mov cs:EMS_Frame_Addr
,es ;an006;save segment value
2147 mov cs:DOS_Page
,di ;an006;save physical page #
2148 clc ;an006;flag memory available
2149 mov ah,EMS_INSTALLED_FLAG
;an000;signal EMS here
2150 ; $else ;an006;no memory avail.
2153 mov ah,not EMS_INSTALLED_FLAG
;an000;signal no EMS
2160 mov ah,not EMS_INSTALLED_FLAG
;AN000;signal no EMS
2161 stc ;an006;signal not there
2165 pop di ;an006;restore di
2166 pop es ;an000;restore es
2172 EMS_CHECK ENDP
;AN000;
2176 ;=========================================================================
2177 ; EMS_CHECK1 : THIS MODULE DETERMINES WHETHER OR NOT EMS IS
2178 ; INSTALLED FOR THIS SESSION.
2182 ; OUTPUTS : ES:BX - FRAME ARRAY
2183 ; CY - EMS NOT AVAILABLE
2184 ; NC - EMS AVAILABLE
2185 ;=========================================================================
2187 EMS_CHECK1 PROC
NEAR ;AN000;EMS INSTALL CHECK
2189 push ds ;an000;save ds - we stomp it
2190 mov ax,00h ;an000;set ax to 0
2191 mov ds,ax ;an000;set ds to 0
2192 cmp ds:word ptr[067h*4+0],0 ;an000;see if int 67h is there
2193 pop ds ;an000;restore ds
2194 ; $IF NE ;AN000;EMS VECTOR CONTAINS DATA
2196 MOV AH,EMS_STATUS
;AN000;see if EMS installed
2197 XOR AL,AL ;AN000;CLEAR AL
2199 OR AH,AH ;AN000;EMS INSTALLED?
2202 MOV AH,EMS_VERSION
;AN000;GET VERSION NUMBER
2203 XOR AL,AL ;AN000;CLEAR AL
2205 CMP AL,EMS_VERSION_LEVEL
;AN000;CORRECT VERSION?
2208 CLC ;AN000;FLAG IT AS GOOD EMS
2218 STC ;AN000;EMS NOT INSTALLED
2224 STC ;AN000;EMS VECTOR NOT THERE
2228 RET ;AN000;RETURN TO CALLER
2230 EMS_CHECK1 ENDP
;AN000;
2233 EMS_GET_PAGES PROC
NEAR ;AN000;
2235 MOV AH,EMS_GET_NUM_PAGES
;AN000; Query EMS for page count
2237 OR AH,AH ;AN000; Has EMS returned page count?
2238 JNZ EMS_GET_ERROR
;AN000; Yes,
2239 MOV AX,BX ;AN000; Get number of pages
2242 EMS_GET_ERROR: ;AN000;
2248 SUBTTL VAL_SSZ Validate Sector Size
2250 ;-----------------------------------------------------------------------;
2251 ; VAL_SSZ validates sector size, adjusting if necessary ;
2252 ;-----------------------------------------------------------------------;
2253 VAL_SSZ PROC
;validate sector size
2254 CMP CS:EM_SW
,0 ;EXTENDED MEMORY?
2255 JE VAL_SSZ_ST
;no,go check sector size
2256 MOV BX,MAXSEC_TRF
;move number of sectors to transfer
2257 CMP BX,1 ;> or equal to 1 ?
2258 JB DFLT_TRF
;set default if it is
2259 CMP BX,8 ;> than 8 ?
2260 JA DFLT_TRF
;set default if it is
2261 JMP VAL_SSZ_ST
;continue processing
2263 DFLT_TRF: ;set default
2264 MOV MAXSEC_TRF
,DFLT_ESS
;
2266 OR CS:ERR_FLAG
,ERR_ESIZE
;indicate transfer size adjusted
2268 VAL_SSZ_ST: ;validate sector size
2269 MOV MAX_CNT
,BX ;initialize maximum number of sectors
2270 ;to transfer for extended memory case
2271 MOV BX,BPB_SSZ
;requested sector size
2272 MOV CX,VAL_SSZ_N
;number of table entries
2273 MOV SI,OFFSET VAL_SSZ_TBL
;DS:SI point to table start
2275 LODSW ;get table entry, step table pointer
2276 CMP AX,BX ;is value in table?
2277 JE VAL_SSZ_X
;exit if value found
2278 LOOP VAL_SSZ_A
;loop until table end
2280 MOV BX,DFLT_SSZ
;get default sector size
2281 MOV BPB_SSZ
,BX ;set sector size to default value
2282 OR ERR_FLAG
,ERR_SSZ
;indicate sector size adjusted
2285 ;Compute the maximum number of sectors that can be moved in 64KB (less one)
2286 ;Restricting moves to this amount avoids 64KB boundary problems.
2288 CMP CS:EM_SW
,0 ;EXTENDED MEMORY?
2289 JNE SIZE_DONE
;yes, we are done
2291 MOV AX,0FFFFH ;64KB - 1
2292 DIV BX ;/sector size
2293 MOV MAX_CNT
,AX ;max sectors in one move
2298 SUBTTL VAL_DIRN Validate number of directory entries
2300 ;-----------------------------------------------------------------------;
2301 ; VAL_DIRN validates and adjusts the number of directory entries. ;
2303 ; Minimum is MIN_DIRN, maximum is MAX_DIRN. If outside these ;
2304 ; limits, DFLT_DIRN is used. ;
2306 ; The number of directory entries is rounded upward to fill ;
2308 ;-----------------------------------------------------------------------;
2310 MOV AX,BPB_DIRN
;requested directory entries
2311 CMP AX,MIN_DIRN
;if less than minimum
2312 JB VAL_DIRN_A
;use default instead
2314 CMP AX,MAX_DIRN
;if <= maximum
2315 JBE VAL_DIRN_B
;accept value as provided
2318 MOV AX,DFLT_DIRN
;use default directory entries
2319 OR ERR_FLAG
,ERR_DIRN
;indicate directory entries adjusted
2320 VAL_DIRN_B: ;AX is number of directory entries
2321 MUL DIRE_SIZE
;* 32 = bytes of directory requested
2322 DIV BPB_SSZ
;/ sector size = # of directory sectors
2323 OR DX,DX ;test remainder for zero
2324 JZ VAL_DIRN_C
;jump if exact fit
2326 INC AX ;increment directory sectors
2327 OR ERR_FLAG
,ERR_DIRN
;indicate directory entries adjusted
2328 VAL_DIRN_C: ;make sure enough sectors available
2329 MOV DX,BPB_SECN
;total sectors on media
2330 SUB DX,BPB_RES
;less reserved sectors
2331 SUB DX,2 ;less minimum FAT and 1 data sector
2332 CMP AX,DX ;if directory sectors <= available
2333 JLE VAL_DIRN_D
;use requested amount
2335 MOV AX,1 ;use only one directory sector
2336 OR ERR_FLAG
,ERR_DIRN
;indicate directory entries adjusted
2338 MOV DIR_SECTORS
,AX ;save number of directory sectors
2339 MUL BPB_SSZ
;dir sectors * sector size = dir bytes
2340 DIV DIRE_SIZE
;dir bytes / entry size = entries
2341 MOV BPB_DIRN
,AX ;store adjusted directory entries
2345 SUBTTL VAL_FAT Validate
File Allocation Table
(FAT
)
2347 ;-----------------------------------------------------------------------;
2348 ;VAL_FAT computes: ;
2349 ;BPB_FATSZ, the number of sectors required per FAT copy ;
2351 ;Each FAT entry is 12 bits long, for a maximum of 4095 FAT entries. ;
2352 ;(A few FAT entries are reserved, so the highest number of FAT entries ;
2353 ;we permit is 0FE0H.) With large buffer sizes and small sector sizes, ;
2354 ;we have more allocation units to describe than a 12-bit entry will ;
2355 ;describe. If the number of FAT entries is too large, the sector size ;
2356 ;is increased (up to a maximum of 512 bytes), and then the allocation ;
2357 ;unit (cluster) size is doubled, until we have few enough allocation ;
2358 ;units to be properly described in 12 bits. ;
2360 ;This computation is slightly conservative in that the FAT entries ;
2361 ;necessary to describe the FAT sectors are included in the computation. ;
2362 ;-----------------------------------------------------------------------;
2364 MOV AX,BPB_SECN
;total number of sectors
2365 SUB AX,BPB_RES
;don't count boot sector(s)
2366 SUB AX,DIR_SECTORS
;don't count directory sectors
2368 CMP AX,0000h ;an000; dms; fix ptm 112; any left?
2369 JA VAL_FAT_A
;an000; dms; fix ptm 112; yes
2371 ;;;;; JG VAL_FAT_A ;jump if some remaining
2372 MOV BPB_SSZ
,DFLT_SSZ
;force default sector size
2373 OR ERR_FLAG
,ERR_SSZ
+ERR_PASS
;indicate sector size adjusted
2374 JMP SHORT VAL_FAT_X
;recompute all values
2376 XOR DX,DX ;clear DX for division
2377 MOV CL,BPB_AUSZ
;CX = sectors/cluster
2379 DIV CX ;whole number of clusters in AX
2380 ADD DX,0FFFFH ;set carry if remainder
2381 ADC AX,0 ;increment AX if remainder
2382 CMP AX,MAX_FATE
;number of FAT entries too large?
2383 JBE VAL_FAT_C
;no, continue
2385 MOV AX,BPB_SSZ
;pick up current sector size
2386 CMP AX,VAL_SSZ_L
;already at largest permitted?
2387 JE VAL_FAT_B
;yes, can't make it any larger
2389 SHL BPB_SSZ
,1 ;double sector size
2390 OR ERR_FLAG
,ERR_SSZB
;indicate sector size adjusted
2391 JMP SHORT VAL_FAT_X
;recompute all sizes with new BPBSSZ
2393 VAL_FAT_B: ;sector size is at maximum
2394 SHL BPB_AUSZ
,1 ;double allocation unit size
2395 OR ERR_FLAG
,ERR_PASS
;indicate another pass required
2396 JMP SHORT VAL_FAT_X
;recompute values
2398 VAL_FAT_C: ;FAT size = 1.5 * number of clusters
2399 MOV CX,AX ;number of clusters
2403 ADC AX,3 ;add 3 bytes for first 2 FAT entries
2404 ;(media descriptor and FFFFH), and CY
2405 XOR DX,DX ;clear DX for division
2406 DIV BPB_SSZ
;FAT size/sector size
2407 ADD DX,0FFFFH ;set carry if remainder
2408 ADC AX,0 ;round upward
2409 MOV BPB_FATSZ
,AX ;number of sectors for 1 FAT copy
2417 SUBTTL COPY_BPB Copy BPB to Boot Record
2419 ;-----------------------------------------------------------------------;
2420 ; COPY_BPB copies the BIOS Parameter Block (BPB) ;
2421 ; to the VDISK Boot Record ;
2422 ;-----------------------------------------------------------------------;
2424 COPY_BPB PROC
;Copy BBP to Boot Record
2428 MOV CX,BPB_LEN
;length of BPB
2429 MOV SI,OFFSET BPB
;source offset
2430 MOV DI,OFFSET BOOT_BPB
;target offset
2431 REP MOVSB ;copy BPB to boot record
2435 SUBTTL VERIFY_EXTENDER
2437 ;-----------------------------------------------------------------------;
2438 ; VERIFY_EXTENDER makes sure that if an Expansion Unit is ;
2439 ; installed, the memory size switches on the Extender Card ;
2440 ; are correctly set. ;
2441 ;-----------------------------------------------------------------------;
2445 EXT_P210 EQU
0210H ;write to latch expansion bus data
2446 ;read to verify expansion bus data
2447 EXT_P213 EQU
0213H ;Expansion Unit status
2449 VERIFY_EXTENDER PROC
2453 MOV DX,EXT_P210
;Expansion bus data port address
2455 MOV AX,5555H
;set data pattern
2456 OUT DX,AL ;write 55H to control port
2460 JMP SHORT $+2 ;Let the I/O circuits catch up
2461 IN AL,020h ;Clear the CMOS bus drivers!
2463 IN AL,DX ;recover data
2464 CMP AH,AL ;did we recover the same data?
2465 JNE VERIFY_EXTENDER_X
;if not, no extender card
2467 NOT AX ;set AX = 0AAAAH
2468 OUT DX,AL ;write 0AAH to control port
2469 PUSH DX ;load data line
2470 POP DX ;load data line
2472 JMP SHORT $+2 ;Let the I/O circuits catch up
2473 IN AL,020h ;Clear the CMOS bus drivers!
2475 IN AL,DX ;recover data
2476 CMP AH,AL ;did we recover the same data?
2477 JNE VERIFY_EXTENDER_X
;if not, no extender card
2479 ;Expansion Unit is present.
2481 ;Determine what the switch settings should be on the Extender Card
2483 INT MEM_SIZE
;get system memory size in KB in AX
2484 ADD AX,63D ;memory size + 63K
2486 SHR AX,CL ;divide by 64
2487 ;AX is highest segment address
2488 MOV AH,AL ;save number of segments
2490 ;Read Expander card switch settings
2492 MOV DX,EXT_P213
;expansion unit status
2493 IN AL,DX ;read status
2494 ;bits 7-4 (hi nibble) are switches
2495 MOV CL,4 ;shift count
2496 SHR AL,CL ;shift switches to bits 3-0 of AL
2498 CMP AH,AL ;do switches match memory size?
2499 JE VERIFY_EXTENDER_X
;yes, exit normally
2501 OR ERR_FLAG
,ERR_EXTSW
;indicate switch settings are wrong
2505 VERIFY_EXTENDER ENDP
2509 ;-----------------------------------------------------------------------;
2510 ; UPDATE_AVAIL updates the address of the first byte in extended ;
2511 ; memory not used by any VDISK buffer ;
2512 ;-----------------------------------------------------------------------;
2513 ;If EMS is installed, we must allocate memory here and obtain the ;
2514 ;handle which we will use throughout our existance. AVAIL_LO and _HI ;
2515 ;really mean nothing to us. ;
2516 ;-----------------------------------------------------------------------;
2519 MOV AX,BUFF_SIZE
;number of KB of VDISK buffer
2521 CMP EM_SW2
,EMS_INSTALLED_FLAG
;AN000; Is EMS installed?
2522 JNE USE_INT15_LOGIC
;ac006; Yes,
2523 xor dx,dx ;an003; clear high word
2524 div DOS_Page_Size_Word
;ac003; Calculate number of pages needed
2525 or dx,dx ;an004; remainder?
2526 ; $if nz ;an004; yes
2528 inc ax ;an004; need 1 extra page
2531 MOV BX,AX ;AN000; Prepare for EMS call
2533 MOV AH,EMS_ALLOC_PAGES
;AN000; Allocate requested pages
2535 OR AH,AH ;AN000; Was there an error allocating?
2536 JNZ ALLOC_ERROR
;AN000; No,
2537 MOV EMS_HANDLE
,DX ;AN000; Save EMS handle for this VDISK
2538 call EMS_Build_Handle_Name
;an000; dms;
2542 ALLOC_ERROR: ;AN000;
2543 MOV ERR_FLAG
,EMS_ALLOC_ERROR
;AN000; ?????? *RPS
2546 USE_INT15_LOGIC: ;AN000;
2548 call Modify_CMOS_EM
;an001; dms;adjust EM for new size
2554 ;=========================================================================
2555 ; Modify_CMOS_EM : This routine modifies the size of extended
2556 ; memory. By modifying the size of extended
2557 ; memory other users will not have the potential
2558 ; to overlay a VDISK residing in EM.
2560 ; Inputs : EM_New_Size - The new size that EM will be after
2561 ; creation of this VDISK.
2562 ; Outputs : Modified data in CMOS for EM. Bytes 17h & 18h at
2564 ;=========================================================================
2566 Modify_CMOS_EM Proc
Near ;an001; dms;
2568 push ax ;an001; dms;save ax
2569 call Steal_Int15
;an001; dms;get INT 15h vector
2571 mov ax,word ptr cs:EM_New_Size
;an001; dms;transfer new size
2572 mov word ptr cs:EM_KSize
,ax ;an001; dms;set EM size to new size
2573 pop ax ;an001; dms;restore ax
2577 Modify_CMOS_EM endp
;an001; dms;
2579 ;=========================================================================
2580 ; EMS_Build_Handle_Name - This routine will build an EMS handle's
2584 ; Inputs : DX - Handle to have associated name
2586 ; Outputs : Handle name
2587 ;=========================================================================
2589 EMS_Build_Handle_Name proc
near ;an000; dms;
2591 push si ;an000; dms;save si
2592 push cx ;an000; dms;save cx
2594 push ds ;an000; dms;save ds
2595 push bx ;an000; dms;save bx
2596 lds bx,RH_Ptra
;an000; dms;point to request header
2597 mov ch,RH
.RH0_Driv
;an000; dms;get drive number
2598 add ch,'A' ;an000; dms;convert to drive letter
2599 pop bx ;an000; dms;restore bx
2600 pop ds ;an000; dms;restore ds
2602 mov si,offset VDISK_Name
;an000; dms;point to "VDISK " literal
2603 mov byte ptr [si+6],ch ;an000; dms;put drive letter in string
2604 mov byte ptr [si+7],":" ;an000; dms;colon terminate it
2606 mov ax,EMS_Set_Handle_Name
;an000; dms;set the handle's name
2607 int EMS_INT
;an000; dms;
2609 pop cx ;an000; dms;restore cx
2610 pop si ;an000; dms;restore si
2614 EMS_Build_Handle_Name endp
;an000; dms;
2618 ;-----------------------------------------------------------------------;
2619 ; This Request Header is used by MOVE_VDISK to move the ;
2620 ; first few sectors of the virtual disk (boot, FAT, and ;
2621 ; Directory) into extended memory. ;
2622 ;-----------------------------------------------------------------------;
2624 MOVE_RH
DB MOVE_RH_L
;length of request header
2626 DB 8 ;output operation
2628 DQ ?
;reserved for DOS
2629 DB ?
;media descriptor byte
2630 MOVE_RHO
DW ?
;offset of data transfer address
2631 MOVE_RHS
DW ?
;segment of data transfer address
2632 MOVE_RHCNT
DW ?
;count of sectors to transfer
2633 DW 0 ;starting sector number
2634 MOVE_RH_L EQU
$-MOVE_RH
;length of request header
2636 ;-----------------------------------------------------------------------;
2637 ; FORMAT_VDISK formats the boot sector, FAT, and directory of an ;
2638 ; extended memory VDISK in storage immediately following ;
2639 ; VDISK code, in preparation for moving to extended memory. ;
2640 ;-----------------------------------------------------------------------;
2641 FORMAT_VDISK PROC
;format boot record, FATs and directory
2643 MOV AX,CS ;compute 20-bit address
2644 MUL WPARA_SIZE
;16 * segment
2645 ADD AX,OFFSET MSGEND
;+ offset
2646 ADC DL,0 ;pick up carry
2647 ADD AX,STACK_SIZE
;plus stack size
2648 ADC DL,0 ;pick up carry
2650 DIV WPARA_SIZE
;split into segment(AX)&offset(DX)
2651 MOV MOVE_RHS
,AX ;save in Request Header for move
2654 MOV DI,DX ;offset to DI
2655 MOV ES,AX ;segment to ES
2657 ;copy the boot record
2659 MOV SI,OFFSET BOOT_RECORD
;point to source field
2660 MOV AX,BPB_RES
;number of reserved sectors
2661 MUL BPB_SSZ
;* sector size = length of boot records
2662 MOV CX,AX ;length to CX for move
2663 REP MOVSB ;move boot record(s)
2667 MOV CL,BPB_FATN
;number of FATs
2669 FORMAT_VDISK_A: ;set up one FAT
2670 PUSH CX ;save loop counter on stack
2671 MOV AL,BPB_MCB
;media control byte
2672 STOSB ;store media control byte, increment DI
2673 MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
2675 MOV AX,BPB_FATSZ
;number of sectors per FAT
2676 MUL BPB_SSZ
;* sector size = length of FAT in bytes
2677 SUB AX,3 ;less the 3 bytes we've stored
2678 MOV CX,AX ;count to CX
2680 REP STOSB ;clear remainder of FAT
2681 POP CX ;get loop counter off stack
2682 LOOP FORMAT_VDISK_A
;loop for all copies of the FAT
2684 ;Format the directory
2686 MOV SI,OFFSET VOL_LABEL
;point to volume label
2687 MOV CX,VOL_LABEL_LEN
;length of volume directory entry
2688 REP MOVSB ;move volume id to directory
2689 MOV AX,DIR_ENTRY_SIZE
;length of 1 directory entry
2690 MUL BPB_DIRN
;* number entries = bytes of directory
2691 SUB AX,VOL_LABEL_LEN
;less length of volume label
2692 MOV CX,AX ;CX = length of rest of directory
2694 REP STOSB ;clear directory to nulls
2700 ;-----------------------------------------------------------------------;
2701 ; STEAL_INT15 changes the INT 15H vector to point to this VDISK ;
2702 ; so that subsequent calls to INT15H may determine the actual ;
2703 ; size of EM after VDISK's allocation of it. ;
2704 ;-----------------------------------------------------------------------;
2708 MOV DS,AX ;set DS = 0
2710 CLI ;disable interrupts
2711 LES DI,DS:EM_VEC
;get original vector's content
2712 MOV CS:INTV15O
,DI ;save original vector
2714 MOV DS:EM_VECO
,OFFSET VDISK_INT15
;offset of new INT routine
2715 MOV DS:EM_VECS
,CS ;segment of new INT routine
2716 STI ;enable interrupts again
2725 ;-----------------------------------------------------------------------;
2726 ; MOVE_VDISK moves the formatted boot sector, FAT, and directory ;
2727 ; into extended memory. ;
2728 ;-----------------------------------------------------------------------;
2731 MOV AL,cs:BPB_FATN
;number of FAT copies
2733 MUL cs:BPB_FATSZ
;number of FAT sectors
2734 ADD AX,cs:BPB_RES
;+ reserved sectors
2735 ADD AX,cs:DIR_SECTORS
;+ directory sectors
2736 MOV cs:MOVE_RHCNT
,AX ;store as I/O length
2738 MOV BX,OFFSET MOVE_RH
;DS:BX point to request header
2739 PUSH DS ;make sure DS gets preserved
2740 CALL INOUT
;move to extended memory
2745 SUBTTL FILL_RH Fill
in Request Header
2747 ;-----------------------------------------------------------------------;
2748 ; FILL_RH fills in the Request Header returned to DOS ;
2749 ;-----------------------------------------------------------------------;
2751 FILL_RH PROC
;fill in INIT Request Header fields
2752 MOV CX,START_BUFFER_PARA
;segment end of VDISK resident code
2753 MOV AX,PARAS_PER_SECTOR
;paragraphs per sector
2754 MUL BPB_SECN
;* number of sectors
2755 ADD AX,CX ;+ starting segment
2756 MOV DX,AX ;DX is segment of end VDISK buffer
2757 CMP EM_SW
,0 ;AC000; DMS; IF EM NOT REQUESTED
2758 ; $IF NE ;AN000; DMS; EM REQUESTED
2760 MOV DX,CX ;AN000; DMS;END OF CODE SEGMENT ADDR
2761 ; $ENDIF ;AN000; DMS;
2764 FILL_RH_A: ;DX is proper ending segment address
2765 MOV AL,1 ;number of units
2766 test CS:err_flag2
,err_baddos
2769 TEST ERR_FLAG
,ERR_SYSSZ
+ERR_EXTSW
;if bypassing install
2770 JZ FILL_RH_B
;jump if installing driver
2773 MOV DX,CS ;segment of end address
2774 XOR AL,AL ;number of units is zero
2776 PUSH DS ;preserve DS
2777 LDS BX,RH_PTRA
;get Request Header addr in DS:BX
2778 MOV RH
.RH0_NUN
,AL ;store number of units (0 or 1)
2779 MOV RH
.RH0_ENDO
,0 ;end offset is always zero
2780 MOV RH
.RH0_ENDS
,DX ;end of VDISK or end of buffer
2781 MOV RH
.RH0_BPBO
,OFFSET BPB_PTR
2782 MOV RH
.RH0_BPBS
,CS ;BPB array address
2787 SUBTTL WRITE_MESSAGES
and associated routines
2789 ;-----------------------------------------------------------------------;
2790 ; WRITE_MESSAGE writes a series of messages to the standard ;
2791 ; output device showing the VDISK parameter values actually used. ;
2792 ;-----------------------------------------------------------------------;
2795 WRITE_MESSAGES PROC
;display all messages
2798 test cs:err_flag2
,err_baddos
;AN000;
2799 JZ DISPLAY_ALL_MESSAGES
;AN000;
2802 DISPLAY_ALL_MESSAGES: ;AN000; No, then display messages
2804 PUSH DS ;preserve DS
2805 LDS BX,RH_PTRA
;get Request Header Address
2806 MOV CL,RH
.RH0_DRIV
;get drive code
2807 ADD CL,'A' ;convert to drive letter
2810 MOV AX,VDISK_TITLE
;AN000; 'VDISK Version 3.3 virtual disk $'
2811 LEA SI,TITLE_SUBLIST
;AN000; Specify SUBLIST to use for replacement
2812 MOV DRIVE_CODE
,CL ;AN000; Save drive code
2813 MOV CX,ONE_REPLACE
;AN000; Notify SYSDISPMSG of 1 replacement
2814 CALL DISPLAY_MESSAGE
;AN000; Display the message
2815 JNC WRITE_MESSAGES_A
;AN000; Was there an error?
2816 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2818 ;If any of the user specified values has been adjusted, issue an
2819 ;appropriate message
2821 WRITE_MESSAGES_A: ;AN000; NO,
2822 TEST ERR_FLAG
,ERR_BSIZE
;was buffersize adjusted?
2823 JZ WRITE_MESSAGES_B
;if not, skip message
2825 MOV AX,BUFFER_ADJUSTED
;AN000; "Buffer size adjusted",CR,LF
2826 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2827 CALL DISPLAY_MESSAGE
;AN000; Display the message
2829 WRITE_MESSAGES_B: ;AN000; NO,
2830 TEST ERR_FLAG
,ERR_SSZ
;was sector size adjusted?
2831 JZ WRITE_MESSAGES_C
;if not, skip message
2833 MOV AX,SECTOR_ADJUSTED
;AN000; "Sector size adjusted",CR,LF
2834 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2835 CALL DISPLAY_MESSAGE
;AN000; Display the message
2836 JNC WRITE_MESSAGES_C
;AN000; Was there an error?
2837 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2840 TEST ERR_FLAG
,ERR_DIRN
;were directory entries adjusted?
2841 JZ WRITE_MESSAGES_D0
;if not, skip message
2843 MOV AX,DIR_ADJUSTED
;AN000; "Directory entries adjusted",CR,LF
2844 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2845 CALL DISPLAY_MESSAGE
;AN000; Display the message
2846 JNC WRITE_MESSAGES_D0
;AN000; Was there an error?
2847 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2850 TEST ERR_FLAG
,ERR_ESIZE
;was transfer size adjusted?
2851 JZ WRITE_MESSAGES_D
;if not, skip message
2853 MOV AX,TRANS_ADJUSTED
;AN000; "Transfer size adjusted",CR,LF
2854 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2855 CALL DISPLAY_MESSAGE
;AN000; Display the message
2856 JNC WRITE_MESSAGES_D
;AN000; Was there an error?
2857 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2860 TEST ERR_FLAG
,ERR_SWTCH
;was an invalid switch character found?
2861 JZ WRITE_MESSAGES_E
;if not, skip message
2863 MOV AX,INVALID_SW_CHAR
;AN000; "Invalid switch character",CR,LF
2864 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2865 CALL DISPLAY_MESSAGE
;AN000; Display the message
2866 JNC WRITE_MESSAGES_E
;AN000; Was there an error?
2867 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2870 TEST ERR_FLAG
,ERR_SYSSZ
;is system size too small to install?
2871 JZ WRITE_MESSAGES_F
;if not, bypass error message
2873 MOV AX,VDISK_NOT_INST
;AN000; "VDISK not installed - "
2874 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2875 CALL DISPLAY_MESSAGE
;AN000; Display the message
2876 MOV AX,SYS_TOO_SMALL
;AN000; "Insufficient memory",CR,LF
2877 CALL DISPLAY_MESSAGE
;AN000; Display the message
2878 JNC WRITE_MESSAGES_RET
;AN000; Was there an error?
2879 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2881 RET ;skip messages showing adjusted sizes
2884 TEST ERR_FLAG
,ERR_EXTSW
;extender card switches wrong?
2885 JZ WRITE_MESSAGES_G
;if not, bypass error message
2887 MOV AX,VDISK_NOT_INST
;AN000; "VDISK not installed - "
2888 MOV CX,NO_REPLACE
;AN000; Notify SYSDISPMSG of no replacement
2889 CALL DISPLAY_MESSAGE
;AN000; Display the message
2890 MOV AX,EXTEND_CARD_WRONG
;AN000; "Extender Card switches",CR,LF,"do not match system memory size",CR,LF,CR,LF
2891 CALL DISPLAY_MESSAGE
;AN000; Display the message
2892 JNC WRITE_MESSAGES_RET
;AN000; Was there an error?
2893 JMP SYSDISP_ERROR
;AN000; YES, display the extended error
2895 WRITE_MESSAGES_G: ;display adjusted size messages
2896 MOV AX,BUF_SZ
;AN000; "Buffer size: %1 KB",CR,LF
2897 LEA SI,BUF_SZ_SUBLIST
;AN000; Specify SUBLIST to use for replacement
2898 MOV CX,ONE_REPLACE
;AN000; Notify SYSDISPMSG of 1 replacement
2899 CALL DISPLAY_MESSAGE
;AN000; Display the message
2900 JC SYSDISP_ERROR
;AN000;
2902 MOV AX,SEC_SZ
;AN000; "Sector size: %1",CR,LF
2903 LEA SI,SEC_SZ_SUBLIST
;AN000; Specify SUBLIST to use for replacement
2904 CALL DISPLAY_MESSAGE
;AN000; Display the message
2905 JC SYSDISP_ERROR
;AN000;
2907 MOV AX,DIR_ENTRIES
;AN000; "Directory entries: %1",CR,LF
2908 LEA SI,DIR_ENT_SUBLIST
;AN000; Specify SUBLIST to use for replacement
2909 CALL DISPLAY_MESSAGE
;AN000; Display the message
2910 JC SYSDISP_ERROR
;AN000;
2912 CMP CS:EM_SW
,0 ;extended memory ?
2914 MOV AX,TRANS_SZ
;AN000; "Transfer size: %1",CR,LF,CR,LF
2915 LEA SI,TRANS_SZ_SUBLIST
;AN000; Specify SUBLIST to use for replacement
2916 CALL DISPLAY_MESSAGE
;AN000; Display the message
2917 JC SYSDISP_ERROR
;AN000;
2921 RET ;return to INIT_P1
2925 push ds ;an006; dms;save ds
2926 push bx ;an006; dms;save bx
2927 lds bx,cs:RH_Ptra
;an006; dms;point to request header
2928 mov RH
.RH0_Flag
,-1 ;an006; dms;signal BIO and error occurred
2929 pop bx ;an006; dms;restore bx
2930 pop ds ;an006; dms;restore ds
2932 ;AN000; Set error conditions
2933 MOV BX,NO_HANDLE
;AN000; Write to NO_HANDLE
2934 MOV CX,NO_REPLACE
;AN000;
2935 MOV DH,EXT_ERR_CLASS
;AN000;
2936 MOV DL,NO_INPUT
;AN000;
2938 PUSH DS ;AN000;SET UP ADDRESSIBILITY TO MSG
2941 PUSH CS ;AN000;TRANSFER CS
2942 POP DS ;AN000; TO DS
2943 PUSH CX ;AN000;TRANSFER CS
2944 POP ES ;AN000; TO ES
2946 ASSUME
DS:CSEG
,ES:CSEG
;AN000;
2947 CALL GET_PARM_SEGMENT
;AN000;OBTAIN PARM SEGMENT
2949 CALL SYSDISPMSG
;AN000;
2951 POP ES ;AN000;RESTORE REG
2952 POP DS ;AN000;RESTORE REG
2953 ASSUME
DS:NOTHING
,ES:NOTHING
;AN000;
2960 DISPLAY_MESSAGE PROC
NEAR
2961 ;AN000; Set default values
2962 MOV BX,NO_HANDLE
;AN000; Output handle is NO_HANDLE
2963 MOV DH,UTILITY_MSG_CLASS
;AN000; Utility class message
2964 MOV DL,NO_INPUT
;AN000; No input is requested
2965 PUSH DS ;AN000;SET UP ADDRESSIBILITY TO MSG
2968 PUSH CS ;AN000;TRANSFER CS
2969 POP DS ;AN000; TO DS
2970 PUSH CS ;AN000;TRANSFER CS
2971 POP ES ;AN000; TO ES
2973 ASSUME
DS:CSEG
,ES:CSEG
;AN000;
2974 CALL GET_PARM_SEGMENT
;AN000;OBTAIN PARM SEGMENT
2976 CALL SYSDISPMSG
;AN000;
2978 POP ES ;AN000;RESTORE REG
2979 POP DS ;AN000;RESTORE REG
2980 ASSUME
DS:NOTHING
,ES:NOTHING
;AN000;
2984 DISPLAY_MESSAGE ENDP
2986 GET_PARM_SEGMENT PROC
;AN000;OBTAIN PARM SEGMENT
2988 PUSH CX ;AN000;SAVE CX - WE STOMP IT
2989 PUSH SI ;AN000;SAVE SI - WE STOMP IT
2991 CMP CX,00H ;AN000;SEE IF REPLACEMENT IS REQUIRED
2992 JE GPS_END
;AN000;END IF ZERO
2994 GPS_CONTINUE: ;AN000;LOOP CONTINUE
2996 MOV [SI].SL_SEGMENT
,DS ;AN000;SET UP SEGMENT
2997 ADD SI,11 ;AN000;INCREASE SI BY TABLE SZ
2999 LOOP GPS_CONTINUE
;AN000;CONTINUE LOOP IF CX NOT ZERO
3001 GPS_END: ;AN000;EXIT POINT
3003 POP SI ;AN000;RESTORE SI
3004 POP CX ;AN000;RESTORE CX
3006 RET ;AN000;RETURN TO CALLER
3008 GET_PARM_SEGMENT ENDP
;AN000;
3013 INIT_P1 ENDP
;end of INIT part one
3015 MSG_SERVICES
<MSGDATA
> ;AN000:
3016 MSG_SERVICES
<LOADmsg
> ;AN000;
3017 MSG_SERVICES
<DISPLAYmsg
,CHARmsg
,NUMmsg
> ;AN000;
3018 MSG_SERVICES
<VDISK
.CL1
,VDISK
.CL2
,VDISK
.CLA
> ;AN000;
3020 MSGEND
LABEL BYTE ;AN000;