summaryrefslogtreecommitdiff
path: root/v4.0/src/DEV/VDISK
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/DEV/VDISK')
-rw-r--r--v4.0/src/DEV/VDISK/MAKEFILE33
-rw-r--r--v4.0/src/DEV/VDISK/SLM.INI4
-rw-r--r--v4.0/src/DEV/VDISK/VDISK.ASM2221
-rw-r--r--v4.0/src/DEV/VDISK/VDISK.INC28
-rw-r--r--v4.0/src/DEV/VDISK/VDISK.LNK3
-rw-r--r--v4.0/src/DEV/VDISK/VDISK.SKL36
-rw-r--r--v4.0/src/DEV/VDISK/VDISKMSG.ASM27
-rw-r--r--v4.0/src/DEV/VDISK/VDISKSYS.ASM3024
-rw-r--r--v4.0/src/DEV/VDISK/VDISKSYS.INC37
9 files changed, 5413 insertions, 0 deletions
diff --git a/v4.0/src/DEV/VDISK/MAKEFILE b/v4.0/src/DEV/VDISK/MAKEFILE
new file mode 100644
index 0000000..cbbf7ed
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/MAKEFILE
@@ -0,0 +1,33 @@
1#************************ Makefile for vdisk **************************
2
3inc =..\..\inc
4msg =..\..\messages
5dos =..\..\dos
6hinc =..\..\hinc
7
8#
9####################### Dependencies begin here. #######################
10#
11
12all: vdisk.sys
13
14vdisk.ctl: vdisk.skl \
15 $(msg)\$(COUNTRY).msg \
16 makefile
17
18
19vdisksys.obj: vdisksys.asm \
20 vdisksys.inc \
21 vdisk.ctl \
22 vdisk.cl2 \
23 vdisk.cla \
24 vdisk.cl1 \
25 $(inc)\msgserv.asm \
26 $(inc)\sysmsg.inc \
27 makefile
28
29vdisk.sys: vdisksys.obj \
30 vdisk.lnk
31 link @vdisk.lnk
32 exe2bin vdisk.exe vdisk.sys
33 del vdisk.exe
diff --git a/v4.0/src/DEV/VDISK/SLM.INI b/v4.0/src/DEV/VDISK/SLM.INI
new file mode 100644
index 0000000..be11bcd
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/SLM.INI
@@ -0,0 +1,4 @@
1project = 340
2slm root = //WINSRC/CORE
3user root = //D:WINBLD1-D/MSDOS/340/SRC
4sub dir = /dev/VDISK
diff --git a/v4.0/src/DEV/VDISK/VDISK.ASM b/v4.0/src/DEV/VDISK/VDISK.ASM
new file mode 100644
index 0000000..5994111
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISK.ASM
@@ -0,0 +1,2221 @@
1 PAGE ,132
2 TITLE VDISK - Virtual Disk Device Driver
3
4;VDISK simulates a disk drive, using Random Access Memory as the storage medium.
5
6;This program is meant to serve as an example of a device driver. It does not
7;reflect the current level of VDISK.SYS.
8
9;(C) Copyright 1988 Microsoft
10;Licensed Material - Program Property of Microsoft
11
12;Add the following statement to CONFIG.SYS
13; DEVICE=[d:][path]VDISK.SYS bbb sss ddd [/E:m]
14
15; where: bbb is the desired buffer size (in kilobytes)
16; minimum 1KB, maximum is size of available memory,
17; default is 64KB.
18
19; VDISK will leave at least 64KB of available memory,
20; although subsequent device drivers (other than VDISK)
21; other programs that make themselves resident, and
22; COMMAND.COM will result in less than 64KB as shown
23; by CHKDSK.
24
25; Must be large enough for 1 boot sector + FAT sectors
26; + 1 directory sector + at least 1 data cluster,
27; or the device driver won't be installed.
28
29; sss is the desired sector size (in bytes)
30; 128, 256, or 512, default is 128.
31; Will be adjusted if number of FAT entries > 0FE0H
32
33; ddd is the desired number of directory entries
34; Minimum 2, maximum 512, default 64.
35; Will be rounded upward to sector size boundary.
36
37; /E may only be used if extended memory above 1 megabyte
38; is to be used. INT 15H functions 87H and 88H are used
39; to read and write this extended memory.
40; The m parameter in the /E option specifies the maximum
41; number of sectors that the VDISK will transfer at a time.
42; Optional values are 1,2,3,4,5,6,7 or 8 sectors, the default
43; is 8 sectors.
44
45; Brackets indicate optional operands.
46
47
48; Samples:
49; DEVICE=\path\VDISK.SYS 160 512 64
50; results in a 160KB VDISK, with 512 byte sectors, 64 directory entries
51
52; DEVICE=VDISK.SYS Buffersize 60 Sectorsize 128 Directory entries 32
53; (since only numbers are interpreted, you may comment the line with
54; non-numeric characters)
55
56 SUBTTL Structure Definitions
57 PAGE
58;-----------------------------------------------------------------------;
59; Request Header (Common portion) ;
60;-----------------------------------------------------------------------;
61RH EQU DS:[BX] ;addressability to Request Header structure
62
63RHC STRUC ;fields common to all request types
64 DB ? ;length of Request Header (including data)
65 DB ? ;unit code (subunit)
66RHC_CMD DB ? ;command code
67RHC_STA DW ? ;status
68 DQ ? ;reserved for DOS
69RHC ENDS ;end of common portion
70
71CMD_INPUT EQU 4 ;RHC_CMD is INPUT request
72
73;status values for RHC_STA
74
75STAT_DONE EQU 01H ;function complete status (high order byte)
76STAT_CMDERR EQU 8003H ;invalid command code error
77STAT_CRC EQU 8004H ;CRC error
78STAT_SNF EQU 8008H ;sector not found error
79STAT_BUSY EQU 0200H ;busy bit (9) for Removable Media call
80;-----------------------------------------------------------------------;
81; Request Header for INIT command ;
82;-----------------------------------------------------------------------;
83RH0 STRUC
84 DB (TYPE RHC) DUP (?) ;common portion
85RH0_NUN DB ? ;number of units
86 ;set to 1 if installation succeeds,
87 ;set to 0 to cause installation failure
88RH0_ENDO DW ? ;offset of ending address
89RH0_ENDS DW ? ;segment of ending address
90RH0_BPBO DW ? ;offset of BPB array address
91RH0_BPBS DW ? ;segment of BPB array address
92RH0_DRIV DB ? ;drive code (DOS 3 only)
93RH0 ENDS
94
95RH0_BPBA EQU DWORD PTR RH0_BPBO ;offset/segment of BPB array address
96;Note: RH0_BPBA at entry to INIT points to all after DEVICE= on CONFIG.SYS stmt
97
98;-----------------------------------------------------------------------;
99; Request Header for MEDIA CHECK Command ;
100;-----------------------------------------------------------------------;
101RH1 STRUC
102 DB (TYPE RHC) DUP (?) ;common portion
103 DB ? ;media descriptor
104RH1_RET DB ? ;return information
105RH1 ENDS
106;-----------------------------------------------------------------------;
107; Request Header for BUILD BPB Command ;
108;-----------------------------------------------------------------------;
109RH2 STRUC
110 DB (TYPE RHC) DUP(?) ;common portion
111 DB ? ;media descriptor
112 DW ? ;offset of transfer address
113 DW ? ;segment of transfer address
114RH2_BPBO DW ? ;offset of BPB table address
115RH2_BPBS DW ? ;segment of BPB table address
116RH2 ENDS
117;-----------------------------------------------------------------------;
118; Request Header for INPUT, OUTPUT, and OUTPUT with verify ;
119;-----------------------------------------------------------------------;
120RH4 STRUC
121 DB (TYPE RHC) DUP (?) ;common portion
122 DB ? ;media descriptor
123RH4_DTAO DW ? ;offset of transfer address
124RH4_DTAS DW ? ;segment of transfer address
125RH4_CNT DW ? ;sector count
126RH4_SSN DW ? ;starting sector number
127RH4 ENDS
128
129RH4_DTAA EQU DWORD PTR RH4_DTAO ;offset/segment of transfer address
130
131;-----------------------------------------------------------------------;
132; Segment Descriptor (part of Global Descriptor Table) ;
133;-----------------------------------------------------------------------;
134DESC STRUC ;data segment descriptor
135DESC_LMT DW 0 ;segment limit (length)
136DESC_BASEL DW 0 ;bits 15-0 of physical address
137DESC_BASEH DB 0 ;bits 23-16 of physical address
138 DB 0 ;access rights byte
139 DW 0 ;reserved
140DESC ENDS
141
142 SUBTTL Equates and Macro Definitions
143 PAGE
144
145MEM_SIZE EQU 12H ;BIOS memory size determination INT
146 ;returns system size in KB in AX
147
148EM_INT EQU 15H ;extended memory BIOS interrupt INT
149EM_BLKMOVE EQU 87H ;block move function
150EM_MEMSIZE EQU 88H ;memory size determination in KB
151
152BOOT_INT EQU 19H ;bootstrap DOS
153
154DOS EQU 21H ;DOS request INT
155DOS_PCHR EQU 02H ;print character function
156DOS_PSTR EQU 09H ;print string function
157DOS_VERS EQU 30H ;get DOS version
158
159TAB EQU 09H ;ASCII tab
160LF EQU 0AH ;ASCII line feed
161CR EQU 0DH ;ASCII carriage return
162BEL EQU 07H ;ASCII bell
163
164PARA_SIZE EQU 16 ;number of bytes in one 8088 paragraph
165DIR_ENTRY_SIZE EQU 32 ;number of bytes per directory entry
166MAX_FATE EQU 0FE0H ;largest number of FAT entries allowed
167
168;default values used if parameters are omitted
169
170DFLT_BSIZE EQU 64 ;default VDISK buffer size (KB)
171DFLT_SSZ EQU 128 ;default sector size
172DFLT_DIRN EQU 64 ;default number of directory entries
173DFLT_ESS EQU 8 ;default maximum sectors to transfer
174
175MIN_DIRN EQU 2 ;minimum number of directory entries
176MAX_DIRN EQU 512 ;maximum number of directory entries
177
178STACK_SIZE EQU 512 ;length of stack during initialization
179
180;-----------------------------------------------------------------------;
181; MSG invokes the console message subroutine ;
182;-----------------------------------------------------------------------;
183
184MSG MACRO TEXT
185 PUSH DX ;;save DX across call
186 MOV DX,OFFSET TEXT ;;point to message
187 CALL SHOW_MSG ;;issue message
188 POP DX
189 ENDM
190
191
192 SUBTTL Resident Data Area
193 PAGE
194;-----------------------------------------------------------------------;
195; Map INT 19H vector in low storage ;
196;-----------------------------------------------------------------------;
197INT_VEC SEGMENT AT 00H
198 ORG 4*BOOT_INT
199BOOT_VEC LABEL DWORD
200BOOT_VECO DW ? ;offset
201BOOT_VECS DW ? ;segment
202INT_VEC ENDS
203
204
205CSEG SEGMENT PARA PUBLIC 'CODE'
206 ASSUME CS:CSEG
207;-----------------------------------------------------------------------;
208; Resident data area. ;
209; ;
210; All variables and constants required after initialization ;
211; part one are defined here. ;
212;-----------------------------------------------------------------------;
213
214START EQU $ ;begin resident VDISK data & code
215
216;DEVICE HEADER - must be at offset zero within device driver
217 DD -1 ;becomes pointer to next device header
218 DW 0800H ;attribute (IBM format block device)
219 ;supports OPEN/CLOSE/RM calls
220 DW OFFSET STRATEGY ;pointer to device "strategy" routine
221 DW OFFSET IRPT ;pointer to device "interrupt handler"
222 DB 1 ;number of block devices
223 DB 7 DUP (?) ;7 byte filler (remainder of 8-byte name)
224;END OF DEVICE HEADER
225
226;This volume label is placed into the directory of the new VDISK
227;This constant is also used to determine if a previous extended memory VDISK
228;has been installed.
229
230VOL_LABEL DB 'VDISK ' ;00-10 volume name (shows program level)
231 DB 28H ;11-11 attribute (volume label)
232 DT 0 ;12-21 reserved
233 DW 6000H ;22-23 time=12:00 noon
234 DW 0986H ;24-25 date=12/06/84
235VOL_LABEL_LEN EQU $-VOL_LABEL ;length of volume label
236
237;The following field, in the first extended memory VDISK device driver,
238;is the 24-bit address of the first free byte of extended memory.
239;This address is not in the common offset/segment format.
240;The initial value, 10 0000H, is 1 megabyte.
241
242AVAIL_LO DW 0 ;address of first free byte of
243AVAIL_HI DB 10H ;extended memory
244
245;The INT 19H vector is "stolen" by the first VDISK installed in extended memory.
246;The original content of the interrupt vector is saved here.
247
248INTV19 LABEL DWORD
249INTV19O DW ? ;offset
250INTV19S DW ? ;segment
251
252
253PARAS_PER_SECTOR DW ? ;number of 16-byte paragraphs in one sector
254
255START_BUFFER_PARA DW ? ;segment address of start of VDISK buffer
256 ;for extended memory, this segment address
257 ;is the end of the VDISK device driver.
258
259EM_SW DB 0 ;non-zero if Extended Memory
260
261EM_STAT DW 0 ;AX from last unsuccessful extended memory I/O
262
263START_EM_LO DW ? ;24-bit address of start of VDISK buffer
264START_EM_HI DB ? ;(extended memory only)
265
266WPARA_SIZE DW PARA_SIZE ;number of bytes in one paragraph
267
268MAX_CNT DW ? ;(0FFFFH/BPB_SSZ) truncated, the maximum
269 ;number of sectors that can be transferred
270 ;without worrying about 64KB wrap
271
272SECT_LEFT DW ? ;sectors left to transfer
273
274IO_SRCA LABEL DWORD ;offset/segment of source
275IO_SRCO DW ? ;offset
276IO_SRCS DW ? ;segment
277
278IO_TGTA LABEL DWORD ;offset/segment of target
279IO_TGTO DW ? ;offset
280IO_TGTS DW ? ;segment
281
282;-----------------------------------------------------------------------;
283; BIOS Parameter Block (BPB) ;
284;-----------------------------------------------------------------------;
285;This is where the characteristics of the virtual disk are established.
286;A copy of this block is moved into the boot record of the virtual disk.
287;DEBUG can be used to read sector zero of the virtual disk to examine the
288;boot record copy of this block.
289
290BPB LABEL BYTE ;BIOS Parameter Block (BPB)
291BPB_SSZ DW 0 ;number of bytes per disk sector
292BPB_AUSZ DB 1 ;sectors per allocation unit
293BPB_RES DW 1 ;number of reserved sectors (for boot record)
294BPB_FATN DB 1 ;number of File Allocation Table (FAT) copies
295BPB_DIRN DW 0 ;number of root directory entries
296BPB_SECN DW 1 ;total number of sectors
297 ;computed from buffer size and sector size
298 ;(this includes reserved, FAT, directory,
299 ;and data sectors)
300BPB_MCB DB 0FEH ;media descriptor byte
301BPB_FATSZ DW 1 ;number of sectors occupied by a single FAT
302 ;computed from BPBSSZ and BPBSECN
303BPB_LEN EQU $-BPB ;length of BIOS parameter block
304
305BPB_PTR DW BPB ;BIOS Parameter Block pointer array (1 entry)
306;-----------------------------------------------------------------------;
307; Request Header (RH) address, saved here by "strategy" routine ;
308;-----------------------------------------------------------------------;
309RH_PTRA LABEL DWORD
310RH_PTRO DW ? ;offset
311RH_PTRS DW ? ;segment
312;-----------------------------------------------------------------------;
313; Global Descriptor Table (GDT), used for extended memory moves ;
314;-----------------------------------------------------------------------;
315;Access Rights Byte (93H) is
316; P=1 (segment is mapped into physical memory)
317; E=0 (data segment descriptor)
318; D=0 (grow up segment, offsets must be <= limit)
319; W=1 (data segment may be written into)
320; DPL=0 (privilege level 0)
321
322GDT LABEL BYTE ;begin global descriptor table
323 DESC <> ;dummy descriptor
324 DESC <> ;descriptor for GDT itself
325SRC DESC <,,,93H,> ;source descriptor
326TGT DESC <,,,93H,> ;target descriptor
327 DESC <> ;BIOS CS descriptor
328 DESC <> ;stack segment descriptor
329
330 SUBTTL INT 19H (boot) interrupt handler
331 PAGE
332;-----------------------------------------------------------------------;
333; INT 19H Interrupt Handler routine ;
334;-----------------------------------------------------------------------;
335;The INT 19H vector is altered by VDISK initialization to point to this
336;routine within the first extended memory VDISK device driver.
337
338;The vector points to the device driver so that subsequent VDISKs installed
339;in extended memory can find the first one to determine what memory has
340;already been allocated to VDISKs.
341
342;This routine restores the original INT 19H vector's content, then jumps
343;to the original routine.
344
345;INT 19H, the "Boot" INT, is always altered when DOS is booted.
346
347;This routine is entered with interrupts disabled.
348
349VDISK_INT19 PROC ;INT 19H received
350 PUSH DS ;save registers we're going to alter
351 PUSH AX
352
353 XOR AX,AX
354 MOV DS,AX ;set DS = 0
355 ASSUME DS:INT_VEC
356
357 MOV AX,CS:INTV19O ;get offset of saved vector
358 MOV DS:BOOT_VECO,AX ;store offset in interrupt vector
359
360 MOV AX,CS:INTV19S ;get segment of saved vector
361 MOV DS:BOOT_VECS,AX ;store segment in interrupt vector
362
363 POP AX
364 POP DS
365
366 JMP CS:INTV19 ;go to original interrupt routine
367
368VDISK_INT19 ENDP
369
370 ASSUME DS:NOTHING
371
372 SUBTTL Device Strategy & interrupt entry points
373 PAGE
374;-----------------------------------------------------------------------;
375; Device "strategy" entry point ;
376; ;
377; Retain the Request Header address for use by Interrupt routine ;
378;-----------------------------------------------------------------------;
379STRATEGY PROC FAR
380 MOV CS:RH_PTRO,BX ;offset
381 MOV CS:RH_PTRS,ES ;segment
382 RET
383STRATEGY ENDP
384;-----------------------------------------------------------------------;
385; Table of command processing routine entry points ;
386;-----------------------------------------------------------------------;
387CMD_TABLE LABEL WORD
388 DW OFFSET INIT_P1 ; 0 - Initialization
389 DW OFFSET MEDIA_CHECK ; 1 - Media check
390 DW OFFSET BLD_BPB ; 2 - Build BPB
391 DW OFFSET INPUT_IOCTL ; 3 - IOCTL input
392 DW OFFSET INPUT ; 4 - Input
393 DW OFFSET INPUT_NOWAIT ; 5 - Non destructive input no wait
394 DW OFFSET INPUT_STATUS ; 6 - Input status
395 DW OFFSET INPUT_FLUSH ; 7 - Input flush
396 DW OFFSET OUTPUT ; 8 - Output
397 DW OFFSET OUTPUT_VERIFY ; 9 - Output with verify
398 DW OFFSET OUTPUT_STATUS ;10 - Output status
399 DW OFFSET OUTPUT_FLUSH ;11 - Output flush
400 DW OFFSET OUTPUT_IOCTL ;12 - IOCTL output
401 DW OFFSET DEVICE_OPEN ;13 - Device OPEN
402 DW OFFSET DEVICE_CLOSE ;14 - Device CLOSE
403MAX_CMD EQU ($-CMD_TABLE)/2 ;highest valid command follows
404 DW OFFSET REMOVABLE_MEDIA ;15 - Removable media
405
406;-----------------------------------------------------------------------;
407; Device "interrupt" entry point ;
408;-----------------------------------------------------------------------;
409IRPT PROC FAR ;device interrupt entry point
410 PUSH DS ;save all registers Revised
411 PUSH ES
412 PUSH AX
413 PUSH BX
414 PUSH CX
415 PUSH DX
416 PUSH DI
417 PUSH SI
418 ;BP isn't used, so it isn't saved
419 CLD ;all moves forward
420
421 LDS BX,CS:RH_PTRA ;get RH address passed to "strategy" into DS:BX
422
423 MOV AL,RH.RHC_CMD ;command code from Request Header
424 CBW ;zero AH (if AL > 7FH, next compare will
425 ;catch that error)
426
427 CMP AL,MAX_CMD ;if command code is too high
428 JA IRPT_CMD_HIGH ;jump to error routine
429
430 MOV DI,OFFSET IRPT_CMD_EXIT ;return addr from command processor
431 PUSH DI ;push return address onto stack
432 ;command routine issues "RET"
433
434 ADD AX,AX ;double command code for table offset
435 MOV DI,AX ;put into index register for JMP
436
437 XOR AX,AX ;initialize return to "no error"
438
439;At entry to command processing routine:
440
441; DS:BX = Request Header address
442; CS = VDISK code segment address
443; AX = 0
444
445; top of stack is return address, IRPT_CMD_EXIT
446
447 JMP CS:CMD_TABLE[DI] ;call routine to handle the command
448
449
450IRPT_CMD_ERROR: ;CALLed for unsupported character mode commands
451
452INPUT_IOCTL: ;IOCTL input
453INPUT_NOWAIT: ;Non-destructive input no wait
454INPUT_STATUS: ;Input status
455INPUT_FLUSH: ;Input flush
456
457OUTPUT_IOCTL: ;IOCTL output
458OUTPUT_STATUS: ;Output status
459OUTPUT_FLUSH: ;Output flush
460
461 POP AX ;pop return address off stack
462
463IRPT_CMD_HIGH: ;JMPed to if RHC_CMD > MAX_CMD
464 MOV AX,STAT_CMDERR ;"invalid command" and error
465
466IRPT_CMD_EXIT: ;return from command routine
467 ;AX = value to OR into status word
468 LDS BX,CS:RH_PTRA ;restore DS:BX as Request Header pointer
469 OR AH,STAT_DONE ;add "done" bit to status word
470 MOV RH.RHC_STA,AX ;store status into request header
471 POP SI ;restore registers
472 POP DI
473 POP DX
474 POP CX
475 POP BX
476 POP AX
477 POP ES
478 POP DS
479 RET
480IRPT ENDP
481
482 SUBTTL Command Processing routines
483 PAGE
484;-----------------------------------------------------------------------;
485; Command Code 1 - Media Check ;
486; At entry, DS:BX point to request header, AX = 0 ;
487;-----------------------------------------------------------------------;
488MEDIA_CHECK PROC
489 MOV RH.RH1_RET,1 ;indicate media not changed
490 RET ;AX = zero, no error
491MEDIA_CHECK ENDP
492;-----------------------------------------------------------------------;
493; Command Code 2 - Build BPB ;
494; At entry, DS:BX point to request header, AX = 0 ;
495;-----------------------------------------------------------------------;
496BLD_BPB PROC
497 MOV RH.RH2_BPBO,OFFSET BPB ;return pointer to our BPB
498 MOV RH.RH2_BPBS,CS
499 RET ;AX = zero, no error
500BLD_BPB ENDP
501;-----------------------------------------------------------------------;
502; Command Code 13 - Device Open ;
503; Command Code 14 - Device Close ;
504; Command Code 15 - Removable media ;
505; At entry, DS:BX point to request header, AX = 0 ;
506;-----------------------------------------------------------------------;
507REMOVABLE_MEDIA PROC
508 MOV AX,STAT_BUSY ;set status bit 9 (busy)
509 ;indicating non-removable media
510DEVICE_OPEN: ;NOP for device open
511DEVICE_CLOSE: ;NOP for device close
512 RET
513REMOVABLE_MEDIA ENDP ;fall thru to return
514;-----------------------------------------------------------------------;
515; Command Code 4 - Input ;
516; Command Code 8 - Output ;
517; Command Code 9 - Output with verify ;
518; At entry, DS:BX point to request header, AX = 0 ;
519;-----------------------------------------------------------------------;
520INOUT PROC
521INPUT:
522OUTPUT:
523OUTPUT_VERIFY:
524
525;Make sure I/O is entirely within the VDISK sector boundaries
526
527 MOV CX,CS:BPB_SECN ;get total sector count
528 MOV AX,RH.RH4_SSN ;starting sector number
529 CMP AX,CX ;can't exceed total count
530 JA INOUT_E1 ;jump if start > total
531
532 ADD AX,RH.RH4_CNT ;start + sector count
533 CMP AX,CX ;can't exceed total count
534 JNA INOUT_A ;jump if start + count <= total
535
536INOUT_E1: ;I/O not within VDISK sector boundaries
537 MOV RH.RH4_CNT,0 ;set sectors transferred to zero
538 MOV AX,STAT_SNF ;indicate 'Sector not found' error
539 RET ;return with error status in AX
540
541INOUT_A: ;I/O within VDISK bounds
542 MOV AX,RH.RH4_CNT ;get sector count
543 MOV CS:SECT_LEFT,AX ;save as sectors left to process
544
545 CMP CS:EM_SW,0 ;extended memory mode?
546 JNE INOUT_EM ;jump to extended memory I/O code
547
548;Compute offset and segment of VDISK buffer for starting segment in CX:SI
549
550 MOV AX,RH.RH4_SSN ;starting sector number
551 MUL CS:PARAS_PER_SECTOR ;* length of one sector in paragraphs
552 ADD AX,CS:START_BUFFER_PARA ;+ segment of VDISK buffer sector 0
553 MOV CX,AX ;segment address to CX
554 XOR SI,SI ;offset is zero
555
556;Compute address of caller's Data Transfer Addr in DX:AX with smallest offset,
557;so that there is no possibility of overflowing a 64KB boundary moving MAX_CNT
558;sectors.
559
560 MOV AX,PARA_SIZE ;16
561 MUL RH.RH4_DTAS ;* segment of caller's DTA in DX,AX
562 ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA
563 ADC DL,0 ;carry in from addition
564 DIV CS:WPARA_SIZE ;AX is segment of caller's DTA
565 ;DX is smallest offset possible
566 ;AX:DX = DTA address
567
568;AX:DX is caller's DTA segment:offset, CX:SI is VDISK buffer segment:offset
569
570;If this is an OUTPUT request, exchange the source and target addresses
571
572 CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
573 JE INOUT_B ;jump if INPUT operation
574
575 XCHG AX,CX ;swap source and target segment
576 XCHG DX,SI ;swap source and target offset
577
578INOUT_B: ;CX:SI is source, AX:DX is target
579 MOV CS:IO_SRCS,CX ;save source segment
580 MOV CS:IO_SRCO,SI ;save source offset
581 MOV CS:IO_TGTS,AX ;save target segment
582 MOV CS:IO_TGTO,DX ;save target offset
583
584 JMP SHORT INOUT_E ;AX := SECT_LEFT, test for zero
585INOUT_C: ;SECT_LEFT in AX, non-zero
586
587; Compute number of sectors to transfer in a single move,
588; AX = minimum of (SECT_LEFT, MAX_CNT)
589
590; MAX_CNT is the maximum number of sectors that can be moved without
591; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
592
593 MOV CX,CS:MAX_CNT ;MAX sectors with one move
594 CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
595 JBE INOUT_D ;then move SECT_LEFT sectors
596
597 MOV AX,CX ;else move MAX_CNT sectors
598INOUT_D:
599 SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
600
601;Move AX sectors from source to target
602
603 MUL CS:BPB_SSZ ;sectors * sector size = byte count
604 ;(cannot overflow into DX)
605 SHR AX,1 ;/2 = word count
606 MOV CX,AX ;word count to CX for REP MOVSW
607
608 LDS SI,CS:IO_SRCA ;source segment/offset to DS:SI
609 LES DI,CS:IO_TGTA ;target segment/offset to ES:DI
610
611 REP MOVSW ;move MOV_CNT sectors
612
613;Update source and target paragraph addresses
614;AX has number of words moved
615
616 SHR AX,1 ;words moved / 8 = paragraphs moved
617 SHR AX,1
618 SHR AX,1
619
620 ADD CS:IO_SRCS,AX ;add paragraphs moved to source segment
621 ADD CS:IO_TGTS,AX ;add paragraphs moved to target segment
622
623;Determine if more sectors need to be transferred
624
625INOUT_E: ;do while SECT_LEFT <> zero
626 MOV AX,CS:SECT_LEFT ;get sectors left to transfer
627 OR AX,AX ;set flags
628 JNZ INOUT_C ;go back to transfer some sectors
629 RET ;AX = zero, all sectors transferred
630
631 SUBTTL Extended Memory I/O routine
632 PAGE
633;-----------------------------------------------------------------------;
634; Extended Memory I/O routine ;
635;-----------------------------------------------------------------------;
636INOUT_EM: ;Extended memory I/O routine
637 ;change to larger stack
638 MOV SI,SS ;save old SS in SI
639 MOV DX,SP ;save old SP in DX
640 CLI ;disable interrupts
641 MOV AX,CS
642 MOV SS,AX ;set SS = CS
643 MOV SP,OFFSET EM_STACK ;point to new stack
644 STI ;enable interrupts
645 PUSH SI ;save old SS at top of new stack
646 PUSH DX ;save old SP on new stack
647
648 MOV SI,RH.RH4_DTAO ;caller's DTA offset
649
650;Compute 24-bit address of VDISK sector in CX (hi) and SI (low)
651
652 MOV AX,RH.RH4_SSN ;starting sector number
653 MUL CS:BPB_SSZ ;* sector size = offset within buffer
654 ADD AX,CS:START_EM_LO ;+ base address of this VDISK buffer
655 ADC DL,CS:START_EM_HI
656 MOV CX,DX ;save high byte
657 MOV SI,AX ;save low word
658
659;Compute 24-bit address of caller's DTA in DX (hi) and AX (low)
660
661 MOV AX,PARA_SIZE ;16
662 MUL RH.RH4_DTAS ;* segment of caller's DTA
663 ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA
664 ADC DL,0 ;carry in from addition
665
666;Caller's DTA address is in CX,SI, VDISK buffer address is in DX,AX.
667
668;If this is an OUTPUT request, exchange the source and target addresses
669
670 CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
671 JE INOUT_EM_B ;jump if INPUT operation
672
673 XCHG DX,CX ;swap source and target high byte
674 XCHG AX,SI ;swap source and target low word
675
676INOUT_EM_B: ;CX,SI is source, DX,AX is target
677
678 MOV SRC.DESC_BASEL,SI ;low 16 bits of source address
679 MOV SRC.DESC_BASEH,CL ;high 8 bits of source address
680
681 MOV TGT.DESC_BASEL,AX ;low 16 bits of target address
682 MOV TGT.DESC_BASEH,DL ;high 8 bits of target address
683
684 JMP SHORT INOUT_EM_E ;AX := SECT_LEFT, test for zero
685INOUT_EM_C: ;SECT_LEFT in AX, non-zero
686
687; Compute number of sectors to transfer in a single move,
688; AX = minimum of (SECT_LEFT, MAX_CNT)
689
690; MAX_CNT is the maximum number of sectors that can be moved without
691; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
692
693 MOV CX,CS:MAX_CNT ;MAX sectors with one move
694 CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
695 JBE INOUT_EM_D ;then move SECT_LEFT sectors
696
697 MOV AX,CX ;else move MAX_CNT sectors
698INOUT_EM_D:
699 SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
700
701;Move AX sectors from source to target
702
703 MUL CS:BPB_SSZ ;sectors * sector size = byte count
704 ;(cannot overflow into DX)
705 MOV TGT.DESC_LMT,AX ;store segment limit (byte count)
706 MOV SRC.DESC_LMT,AX
707
708 PUSH AX ;preserve byte count on stack
709
710 SHR AX,1 ;/2 = word count
711 MOV CX,AX ;word count to CX
712
713 PUSH CS
714 POP ES ;set ES = CS
715 MOV SI,OFFSET GDT ;ES:SI point to GDT
716
717 MOV AH,EM_BLKMOVE ;function is block move
718 INT EM_INT ;move an even number of words
719
720 POP CX ;get byte count back from stack
721
722 OR AH,AH ;get error code
723
724 JNZ INOUT_EM_XE ;jump if I/O error encountered
725
726;Update source and target addresses
727
728 ADD SRC.DESC_BASEL,CX ;add bytes moved to source
729 ADC SRC.DESC_BASEH,0 ;pick up any carry
730
731 ADD TGT.DESC_BASEL,CX ;add bytes moved to target
732 ADC TGT.DESC_BASEH,0 ;pick up any carry
733
734;Determine if more sectors need to be transferred
735
736INOUT_EM_E: ;do while SECT_LEFT <> zero
737 MOV AX,CS:SECT_LEFT ;get sectors left to transfer
738 OR AX,AX ;set flags
739 JNZ INOUT_EM_C ;go back to transfer some sectors
740
741INOUT_EM_X2: ;revert to original stack
742 POP DI ;get old SP
743 POP SI ;get old SS
744 CLI ;disable interrupts
745 MOV SS,SI ;restore old SS
746 MOV SP,DI ;restore old SP
747 STI ;enable interrupts
748 RET ;return to IRPT_EXIT
749
750INOUT_EM_XE: ;some error with INT 15H
751 MOV CS:EM_STAT,AX ;save error status for debugging
752 MOV RH.RH4_CNT,0 ;indicate no sectors transferred
753 MOV AX,STAT_CRC ;indicate CRC error
754 JMP INOUT_EM_X2 ;fix stack and exit
755INOUT ENDP
756
757 DW 40 DUP (?) ;stack for extended memory I/O
758EM_STACK LABEL WORD
759
760 SUBTTL Boot Record
761 PAGE
762;-----------------------------------------------------------------------;
763; Adjust the assembly-time instruction counter to a paragraph ;
764; boundary ;
765;-----------------------------------------------------------------------;
766
767 IF ($-START) MOD 16
768 ORG ($-START) + 16 - (($-START) MOD 16)
769 ENDIF
770
771VDISK EQU $ ;start of virtual disk buffer
772VDISKP EQU ($-START) / PARA_SIZE ;length of program in paragraphs
773;-----------------------------------------------------------------------;
774; If this VDISK is in extended memory, this address is passed ;
775; back to DOS as the end address that is to remain resident. ;
776; ;
777; It this VDISK is not in extended memory, the VDISK buffer ;
778; begins at this address, and the address passed back to DOS ;
779; as the end address that is to remain resident is this address ;
780; plus the length of the VDISK buffer. ;
781;-----------------------------------------------------------------------;
782
783BOOT_RECORD LABEL BYTE ;Format of Boot Record documented in
784 ;DOS Technical Reference Manual
785 DB 0,0,0 ;3-byte jump to boot code (not bootable)
786 DB 'VDISK ' ;8-byte vendor identification
787BOOT_BPB LABEL BYTE ;boot record copy of BIOS parameter block
788 DW ? ;number of bytes per disk sector
789 DB ? ;sectors per allocation unit
790 DW ? ;number of reserved sectors (for boot record)
791 DB ? ;number of File Allocation Table (FAT) copies
792 DW ? ;number of root directory entries
793 DW ? ;total number of sectors
794 DB ? ;media descriptor byte
795 DW ? ;number of sectors occupied by a single FAT
796;end of boot record BIOS Parameter block
797
798;The following three words mean nothing to VDISK, they are placed here
799;to conform to the DOS standard for boot records.
800 DW 8 ;sectors per track
801 DW 1 ;number of heads
802 DW 0 ;number of hidden sectors
803;The following word is the 16-bit kilobyte address of the first byte in
804;extended memory that is not occupied by a VDISK buffer
805;It is placed into this location so that other users of extended memory
806;may find where all the VDISKs end.
807
808;This field may be accessed by moving the boot record of the First extended
809;memory VDISK from absolute location 10 0000H. Before assuming that the
810;value below is valid, the vendor ID (constant VDISK) should be verified
811;to make sure that SOME VDISK has been installed.
812
813;For example, if two VDISKs are installed, one 320KB and one 64KB, the
814;address calculations are as follows:
815
816;Extended memory start address = 100000H (1024KB)
817;Start addr of 1st VDISK buffer = 100000H (1024KB)
818;Length of 1st VDISK buffer = 050000H ( 320KB)
819;End addr of 1st VDISK buffer = 14FFFFH
820;Start addr of 2nd VDISK buffer = 150000H (1344KB)
821;Length of 2nd VDISK buffer = 010000H ( 64KB)
822;End addr of 2nd VDISK buffer = 15FFFFH
823;First byte after all VDISKs = 160000H (1408KB)
824;Divide by 1024 = 0580H (1408D)
825
826;Content of BOOT_EM = 0580H
827
828BOOT_EM_OFF EQU $-BOOT_RECORD ;offset from 10 0000H of the following word
829BOOT_EM DW 1024 ;KB addr of first free byte of extended memory
830;-----------------------------------------------------------------------;
831; Part 2 of Initialization (executed last) ;
832;-----------------------------------------------------------------------;
833;Initialization is divided into two parts.
834
835;INIT_P1 is overlaid by the virtual disk buffer
836
837;INIT_P1 is executed first, then jumps to INIT_P2. INIT_P2 returns to caller.
838
839;Exercise caution if extending the initialization part 2 code.
840;It overlays the area immediately following the boot sector.
841;If this section of code must be expanded, make sure it fits into the minimum
842;sector size of 128 bytes.
843;Label TEST_LENGTH must equate to a non-negative value (TEST_LENGTH >= 0).
844;If this code it must be extended beyond the 128 byte length of the boot sector,
845;move all of INIT_P2 before label VDISK.
846
847;Registers at entry to INIT_P2 (set up at end of INIT_P1):
848; BL = media control byte from BPB (for FAT)
849; CX = number of FAT copies
850; DX = number of bytes in one FAT - 3
851; SI = OFFSET of Volume Label field
852; ES:DI = VDISK buffer address of first FAT sector
853; CS = DS = VDISK code segment
854
855INIT_P2 PROC ;second part of initialization
856 ASSUME DS:CSEG ;DS set in INIT_P1
857
858;Initialize File Allocation Table(s) (FATs)
859
860INIT_P2_FAT: ;set up one FAT, sector number in AX
861
862 PUSH CX ;save loop counter on stack
863 MOV AL,BL ;media control byte
864 STOSB ;store media control byte, increment DI
865 MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
866 STOSW
867
868 MOV CX,DX ;FAT size in bytes - 3
869 XOR AX,AX ;value to store in remainder of FAT
870 REP STOSB ;clear remainder of FAT
871
872 POP CX ;get loop counter off stack
873 LOOP INIT_P2_FAT ;loop for all copies of the FAT
874
875;Put the volume label in the first directory entry
876
877 MOV CX,VOL_LABEL_LEN ;length of volume directory entry
878 REP MOVSB ;move volume id to directory
879
880;Zero the remainder of the directory
881
882 MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry
883 MUL BPB_DIRN ;* number entries = bytes of directory
884 SUB AX,VOL_LABEL_LEN ;less length of volume label
885 MOV CX,AX ;length of rest of directory
886 XOR AX,AX
887 REP STOSB ;clear directory to nulls
888 RET ;return with AX=0
889INIT_P2 ENDP
890
891PATCH_AREA DB 5 DUP ('PATCH AREA ')
892TEST_LENGTH EQU 128-($-VDISK) ;if negative, boot record has too much
893 ;data area, move some fields below VDISK
894;-----------------------------------------------------------------------;
895; All fields that must remain resident after device driver ;
896; initialization must be defined before this point. ;
897;-----------------------------------------------------------------------;
898 DB 'MS DOS Version 4.00 - Virtual Disk Device Driver'
899 DB '-------- Licensed Material ---------'
900 DB 'Program Property of Microsoft Corporation. '
901 DB '(C)Copyright 1988 Microsoft'
902 DB 'Thank You For Your '
903 DB ' Support '
904
905MAXSEC_TRF DW 0 ;maximum number of sectors to transfer when
906 ;in extended memory
907
908BUFF_SIZE DW 0 ;desired VDISK buffer size in kilobytes
909
910MIN_MEMORY_LEFT DW 64 ;minimum amount of system memory (kilobytes)
911 ;that must remain after VDISK is installed
912
913FIRST_EM_SW DB ? ;0FFH if this is the first device driver
914 ;to be installed in extended memory
915 ;00H if another VDISK extended memory driver
916 ;has been installed
917
918FIRST_VDISK DW ? ;segment address of 1st VDISK device driver
919PARA_PER_KB DW 1024/PARA_SIZE ;paragraphs in one kilobyte
920C1024 DW 1024 ;bytes in one kilobyte
921DIRE_SIZE DW DIR_ENTRY_SIZE ;bytes in one directory entry
922DIR_SECTORS DW ? ;number of sectors of directory
923
924ERR_FLAG DB 0 ;error indicators to condition messages
925ERR_BSIZE EQU 80H ;buffer size adjusted
926ERR_SSZ EQU 40H ;sector size adjusted
927ERR_DIRN EQU 20H ;number of directory entries adjusted
928ERR_PASS EQU 10H ;some adjustment made that requires
929 ;recomputation of values previously computed
930ERR_SSZB EQU ERR_SSZ+ERR_PASS ;sector size altered this pass
931ERR_SYSSZ EQU 08H ;system storage too small for VDISK
932ERR_SWTCH EQU 04H ;invalid switch character
933ERR_EXTSW EQU 02H ;extender card switches don't match memory size
934ERR_ESIZE EQU 01H ;Transfer size adjusted
935
936; additional errors added - kwc
937
938major_version equ 4 ;Major DOS version
939minor_version equ 00 ;Minor DOS Version
940
941expected_version equ (MINOR_VERSION SHL 8)+MAJOR_VERSION
942
943err_flag2 db 0
944err_baddos equ 01h ; Invalid DOS Version
945
946 SUBTTL Initialization, Part one
947 PAGE
948;-----------------------------------------------------------------------;
949; Command Code 0 - Initialization ;
950; At entry, DS:BX point to request header, AX = 0 ;
951;-----------------------------------------------------------------------;
952;Initialization is divided into two parts.
953;This part, executed first, is later overlaid by the VDISK buffer.
954
955INIT_P1 PROC ;first part of initialization
956 MOV DX,SS ;save stack segment register
957 MOV CX,SP ;save stack pointer register
958 CLI ;inhibit interrupts while changing SS:SP
959 MOV AX,CS ;move CS to SS through AX
960 MOV SS,AX
961 MOV SP,OFFSET MSGEND ;end of VDISKMSG
962 ADD SP,STACK_SIZE ;+ length of our stack
963 STI ;allow interrupts
964 PUSH DX ;save old SS register on new stack
965 PUSH CX ;save old SP register on new stack
966
967 push bx ;secure registers before DOS int
968 push cx ;secure registers before DOS int
969
970; add version check - kwc
971
972 mov ah,030h
973 int 21h
974 pop cx ;restore pointer values
975 pop bx ;restore pointer values
976 cmp ax,expected_version
977 je okdos
978
979 or cs:err_flag2,err_baddos
980
981okdos:
982 CALL GET_PARMS ;get parameters from CONFIG.SYS line
983
984 PUSH CS
985 POP DS ;set DS = CS
986 ASSUME DS:CSEG
987
988 CALL APPLY_DEFAULTS ;supply any values not specified
989 CALL DETERMINE_START ;compute start address of VDISK buffer
990 CALL VALIDATE ;validate parameters
991 CALL COPY_BPB ;Copy BIOS Parameter Block to boot record
992
993 CALL VERIFY_EXTENDER ;Verify that extender card switches are right
994
995 TEST ERR_FLAG,ERR_EXTSW ;are switches wrong?
996 JNZ INIT_P1_A ;if so, exit with messages
997
998 test CS:err_flag2,err_baddos
999 jnz init_p1_a
1000
1001 CMP EM_SW,0 ;extended memory requested?
1002 JE INIT_P1_A ;jump if not
1003
1004 TEST ERR_FLAG,ERR_SYSSZ ;is system too small for VDISK?
1005 JNZ INIT_P1_A ;if so, don't do extended memory init
1006
1007 CALL UPDATE_AVAIL ;update AVAIL_HI and AVAIL_LO to reflect
1008 ;addition of extended memory VDISK
1009 CALL FORMAT_VDISK ;construct a boot record, FATs and
1010 ;directory in storage immediately
1011 ;following this device driver
1012 CALL MOVE_VDISK ;move formatted boot record, FATs,
1013 ;and directory to extended memory
1014 CALL UPDATE_BOOT ;place the end address of ALL VDISKs
1015 ;in the boot record of the first VDISK
1016 CMP FIRST_EM_SW,0 ;is this the first extended memory VDISK?
1017 JE INIT_P1_A ;no, exit
1018
1019 CALL STEAL_INT19 ;point INT 19H to this VDISK
1020INIT_P1_A:
1021 CALL FILL_RH ;fill in INIT request header
1022 CALL WRITE_MESSAGES ;display all messages
1023 POP CX ;get old SP from stack
1024 POP DX ;get old SS from stack
1025 CLI ;disable interrupts while changing SS:SP
1026 MOV SS,DX ;restore stack segment register
1027 MOV SP,CX ;restore stack pointer register
1028 STI ;enable interrupts
1029;-----------------------------------------------------------------------;
1030; INIT_P2 must be short enough to fit into the boot sector ;
1031; (minimum size of boot sector is 128 bytes), so we set up ;
1032; as many pointers as we can to help keep INIT_P2 short. ;
1033; ;
1034; ES:DI = storage address of first FAT sector ;
1035; BL = media control byte ;
1036; CX = number of FAT copies ;
1037; DX = number of bytes in one FAT, less 3 ;
1038; SI = offset of VOL label field ;
1039;-----------------------------------------------------------------------;
1040 MOV ES,START_BUFFER_PARA ;start paragraph of VDISK buffer
1041
1042 MOV AX,BPB_RES ;number of reserved sectors
1043 MUL BPB_SSZ ;* sector size
1044 MOV DI,AX ;ES:DI point to FAT start
1045
1046 MOV BL,BPB_MCB ;media control byte
1047
1048 MOV CL,BPB_FATN ;number of FAT copies
1049 XOR CH,CH
1050
1051 MOV AX,BPB_FATSZ ;FAT size in sectors
1052 MUL BPB_SSZ ;* sector size = total FAT bytes
1053
1054 SUB AX,3 ;-3 (FEFFFF stored by code)
1055 MOV DX,AX
1056
1057 MOV SI,OFFSET VOL_LABEL ;point to VOL label directory entry
1058 JMP INIT_P2 ;jump to second part of initialization
1059 ;this is redundant if the VDISK is in
1060 ;extended memory, but is executed anyway
1061
1062 SUBTTL GET_PARMS Parameter Line Scan
1063 PAGE
1064;-----------------------------------------------------------------------;
1065;GET_PARMS gets the parameters from the CONFIG.SYS statement ;
1066; ;
1067;Register usage: ;
1068; DS:SI indexes parameter string ;
1069; AL contains character from parameter string ;
1070; CX value from GET_NUMBER ;
1071;-----------------------------------------------------------------------;
1072 ASSUME DS:NOTHING ;DS:BX point to Request Header
1073GET_PARMS PROC ;get parameters from CONFIG.SYS line
1074 PUSH DS ;save DS
1075 LDS SI,RH.RH0_BPBA ;DS:SI point to all after DEVICE=
1076 ;in CONFIG.SYS line
1077 XOR AL,AL ;not at end of line
1078
1079;Skip until first delimiter is found. There may be digits in the path string.
1080
1081;DS:SI points to \pathstring\VDISK.SYS nn nn nn
1082;The character following VDISK.SYS may have been changed to a null (00H).
1083;All letters have been changed to uppercase.
1084
1085GET_PARMS_A: ;skip to DOS delimiter character
1086 CALL GET_PCHAR ;get parameter character into AL
1087 JZ GET_PARMS_X ;get out if end of line encountered
1088 OR AL,AL ;test for null
1089 JZ GET_PARMS_C ;
1090 CMP AL,' '
1091 JE GET_PARMS_C ;
1092 CMP AL,','
1093 JE GET_PARMS_C ;
1094 CMP AL,';'
1095 JE GET_PARMS_C ;
1096 CMP AL,'+'
1097 JE GET_PARMS_C ;
1098 CMP AL,'='
1099 JE GET_PARMS_C ;
1100 CMP AL,TAB
1101 JNE GET_PARMS_A ;skip until delimiter or CR
1102
1103
1104
1105GET_PARMS_C:
1106 PUSH SI ;save to rescan
1107 MOV CS:EM_SW,0 ;indicate no /E found
1108 JMP GET_SLASH ;see if current character is an slash
1109
1110GET_PARMS_D: ;scan for /
1111 CALL GET_PCHAR
1112 JZ GET_PARMS_B ;exit if end of line
1113
1114GET_SLASH: ;check for slash
1115 CMP AL,'/' ;found slash?
1116 JNE GET_PARMS_D ;no, continue scan
1117
1118 CALL GET_PCHAR ;get char following slash
1119 CMP AL,'E' ;don't have to test for lower case E,
1120 ;letters have been changed to upper case
1121 JNE GET_PARMS_E ;not 'E'
1122 MOV CS:EM_SW,AL ;indicate /E found
1123
1124 CALL GET_PCHAR ;get char following E
1125 CMP AL,':' ;is it a delimeter ?
1126 JNE GET_PARMS_D ;not a ':'
1127
1128
1129 CALL GET_MAXSIZE ;get maximum sector size
1130
1131
1132 JMP GET_PARMS_D ;continue forward scan
1133
1134GET_PARMS_E: ;/ found, not 'E'
1135 OR CS:ERR_FLAG,ERR_SWTCH ;indicate invalid switch character
1136 JMP GET_PARMS_D ;continue scan
1137
1138
1139
1140GET_PARMS_B: ;now pointing to first delimiter
1141 POP SI ;get pointer, used to rescan for /E
1142 XOR AL,AL ;not at EOL now
1143 CALL GET_PCHAR ;get first character
1144 CALL SKIP_TO_DIGIT ;skip to first digit
1145 JZ GET_PARMS_X ;found EOL, no digits remain
1146
1147 CALL GET_NUMBER ;extract digits, convert to binary
1148 MOV CS:BUFF_SIZE,CX ;store buffer size
1149
1150 CALL SKIP_TO_DIGIT ;skip to next digit
1151 JZ GET_PARMS_X ;found EOL, no digits remain
1152
1153 CALL GET_NUMBER ;extract digits, convert to binary
1154 MOV CS:BPB_SSZ,CX ;store sector size
1155
1156 CALL SKIP_TO_DIGIT ;skip to next digit
1157 JZ GET_PARMS_X ;found EOL, no digits remain
1158
1159 CALL GET_NUMBER ;extract digits, convert to binary
1160 MOV CS:BPB_DIRN,CX ;store number of directory entries
1161
1162
1163
1164GET_PARMS_X: ;premature end of line
1165 POP DS ;restore DS
1166 RET
1167
1168
1169
1170GET_MAXSIZE PROC ;get maximum sector size
1171
1172 CALL GET_PCHAR ;get next character
1173 CALL CHECK_NUM ;is it a number ?
1174 JZ GET_NEXTNUM ;yes, go get next number
1175 OR CS:ERR_FLAG,ERR_ESIZE ;indicate invalid sector size
1176 RET ;
1177GET_NEXTNUM: ;get next number
1178 CALL GET_NUMBER ;extract digits and convert to binary
1179 MOV CS:MAXSEC_TRF,CX ;save maximum sector size to transfer
1180 RET
1181GET_MAXSIZE ENDP
1182
1183
1184
1185GET_PCHAR PROC ;internal proc to get next character into AL
1186 CMP AL,CR ;carriage return already encountered?
1187 JE GET_PCHAR_X ;don't read past end of line
1188 CMP AL,LF ;line feed already encountered?
1189 JE GET_PCHAR_X ;don't read past end of line
1190 LODSB ;get char from DS:SI, increment SI
1191 CMP AL,CR ;is the char a carriage return?
1192 JE GET_PCHAR_X ;yes, set Z flag at end of line
1193 CMP AL,LF ;no, is it a line feed?
1194GET_PCHAR_X: ;attempted read past end of line
1195 RET
1196GET_PCHAR ENDP ;returns char in AL
1197
1198
1199CHECK_NUM PROC ;check AL for ASCII digit
1200 CMP AL,'0' ;< '0'?
1201 JB CHECK_NUM_X ;exit if it is
1202
1203 CMP AL,'9' ;> '9'?
1204 JA CHECK_NUM_X ;exit if it is
1205
1206 CMP AL,AL ;set Z flag to indicate numeric
1207CHECK_NUM_X:
1208 RET ;Z set if numeric, NZ if not numeric
1209CHECK_NUM ENDP
1210
1211
1212SKIP_TO_DIGIT PROC ;skip to first numeric character
1213 CALL CHECK_NUM ;is current char a digit?
1214 JZ SKIP_TO_DIGIT_X ;if so, skip is complete
1215
1216 CALL GET_PCHAR ;get next character from line
1217 JNZ SKIP_TO_DIGIT ;loop until first digit or CR or LF
1218 RET ;character is CR or LF
1219
1220SKIP_TO_DIGIT_X:
1221 CMP AL,0 ;digit found, force NZ
1222 RET
1223SKIP_TO_DIGIT ENDP
1224
1225C10 DW 10
1226GN_ERR DB ? ;zero if no overflow in accumulation
1227
1228GET_NUMBER PROC ;convert string of digits to binary value
1229 XOR CX,CX ;accumulate number in CX
1230 MOV CS:GN_ERR,CL ;no overflow yet
1231GET_NUMBER_A: ;accumulate next digit
1232 SUB AL,'0' ;convert ASCII to binary
1233 CBW ;clear AH
1234 XCHG AX,CX ;previous accumulation in AX, new digit in CL
1235 MUL CS:C10 ;DX:AX := AX*10
1236 OR CS:GN_ERR,DL ;set GN_ERR <> 0 if overflow
1237 ADD AX,CX ;add new digit from
1238 XCHG AX,CX ;number now in CX
1239 DEC SI ;back up to prior entry
1240 MOV AL,' ' ;blank out prior entry
1241 MOV [SI],AL ;
1242 INC SI ;set to current entry
1243 CALL GET_PCHAR ;get next character
1244 CALL CHECK_NUM ;see if it was numeric
1245 JZ GET_NUMBER_A ;continue accumulating
1246 CMP CS:GN_ERR,0 ;did we overflow?
1247 JE GET_NUMBER_B ;if not, we're done
1248 XOR CX,CX ;return zero (always invalid) if overflow
1249GET_NUMBER_B:
1250 RET ;number in CX, next char in AL
1251GET_NUMBER ENDP
1252
1253GET_PARMS ENDP
1254
1255 SUBTTL APPLY_DEFAULTS
1256 PAGE
1257;-----------------------------------------------------------------------;
1258; APPLY_DEFAULTS supplies any parameter values that the user ;
1259; failed to specify ;
1260;-----------------------------------------------------------------------;
1261 ASSUME DS:CSEG
1262APPLY_DEFAULTS PROC
1263 XOR AX,AX
1264 CMP BUFF_SIZE,AX ;is buffer size zero?
1265 JNE APPLY_DEFAULTS_A ;no, user specified something
1266
1267 MOV BUFF_SIZE,DFLT_BSIZE ;supply default buffer size
1268 OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted
1269
1270APPLY_DEFAULTS_A:
1271 CMP BPB_SSZ,AX ;is sector size zero?
1272 JNE APPLY_DEFAULTS_B ;no, user specified something
1273
1274 MOV BPB_SSZ,DFLT_SSZ ;supply default sector size
1275 OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted
1276
1277APPLY_DEFAULTS_B:
1278 CMP BPB_DIRN,AX ;are directory entries zero?
1279 JNE APPLY_DEFAULTS_C ;no, user specified something
1280
1281 MOV BPB_DIRN,DFLT_DIRN ;supply default directory entries
1282 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1283
1284APPLY_DEFAULTS_C: ;
1285 CMP EM_SW,0 ;extended memory ?
1286 JE APPLY_DEFAULTS_D ;no, jump around
1287 CMP MAXSEC_TRF,AX ;is maximum sectors zero?
1288 JNE APPLY_DEFAULTS_D ;no, user specified something
1289
1290 MOV MAXSEC_TRF,DFLT_ESS ;supply default maximum number of
1291 ;sector to transfer
1292 OR ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted
1293APPLY_DEFAULTS_D:
1294 RET
1295APPLY_DEFAULTS ENDP
1296
1297 SUBTTL DETERMINE_START address of VDISK buffer
1298 PAGE
1299;-----------------------------------------------------------------------;
1300; DETERMINE_START figures out the starting address of the VDISK ;
1301; buffer ;
1302;-----------------------------------------------------------------------;
1303 ASSUME DS:CSEG
1304DETERMINE_START PROC
1305
1306;If extended memory is NOT being used, the VDISK buffer immediately
1307;follows the resident code.
1308
1309;If extended memory IS being used, START_BUFFER_PARA becomes the
1310;end of device driver address passed back to DOS.
1311
1312 MOV AX,CS ;start para of VDISK code
1313 ADD AX,VDISKP ;+ length of resident code
1314 MOV START_BUFFER_PARA,AX ;save as buffer start para
1315
1316 CMP EM_SW,0 ;is extended memory requested?
1317 JE DETERMINE_START_X ;if not, we're done here
1318
1319;If this is the first extended memory VDISK device driver to be installed,
1320;the start address for I/O is 1 megabyte.
1321
1322;If one or more extended memory VDISK device drivers have been installed,
1323;the start address for I/O for THIS device driver is acquired from the
1324;fields AVAIL_LO and AVAIL_HI in the FIRST VDISK device driver.
1325
1326;The first extended memory VDISK device driver is located by INT 19H's vector.
1327
1328 MOV FIRST_EM_SW,0FFH ;indicate first VDISK device driver
1329 MOV FIRST_VDISK,CS ;segment addr of first VDISK
1330
1331 PUSH DS ;preserve DS
1332 XOR AX,AX
1333 MOV DS,AX ;set DS = 0
1334 ASSUME DS:INT_VEC
1335
1336 MOV AX,DS:BOOT_VECS ;get segment addr of INT 19H routine
1337 MOV DS,AX ;to DS
1338 ASSUME DS:NOTHING
1339
1340 PUSH CS
1341 POP ES ;set ES = CS
1342 MOV SI,OFFSET VOL_LABEL ;DS:SI point to VOL label field
1343 ;in first VDISK (if present)
1344 MOV DI,SI ;ES:DI point to VOL label field of
1345 ;this VDISK
1346
1347 MOV CX,VOL_LABEL_LEN ;length of volume label
1348 REP CMPSB ;does INT 19H vector point to a VDISK
1349 ;device driver?
1350 JNE DETERMINE_START_A ;jump if this is the first VDISK
1351
1352;Another extended memory VDISK device driver has been installed.
1353;Its AVAIL_LO and AVAIL_HI are the first free byte of extended memory.
1354
1355 MOV CS:FIRST_EM_SW,0 ;indicate not first device driver
1356 MOV CS:FIRST_VDISK,DS ;save pointer to 1st device driver
1357
1358;Copy AVAIL_LO and AVAIL_HI from first VDISK to this VDISK
1359
1360 MOV SI,OFFSET AVAIL_LO ;DS:SI point to AVAIL_LO in first VDISK
1361 MOV DI,SI ;ES:DI point to AVAIL_LO in this VDISK
1362 MOVSW ;copy AVAIL_LO from first to this VDISK
1363 MOVSB ;copy AVAIL_HI
1364
1365DETERMINE_START_A: ;copy AVAIL_LO and AVAIL_HI to START_EM
1366 POP DS ;set DS = CS
1367
1368 MOV SI,OFFSET AVAIL_LO ;source offset
1369 MOV DI,OFFSET START_EM_LO ;destination offset
1370
1371 MOVSW ;move AVAIL_LO to START_EM_LO
1372 MOVSB ;move AVAIL_HI to START_EM_HI
1373DETERMINE_START_X:
1374 RET
1375DETERMINE_START ENDP
1376
1377 SUBTTL VALIDATE parameters
1378 PAGE
1379;-----------------------------------------------------------------------;
1380; VALIDATE adjusts parameters as necessary ;
1381;-----------------------------------------------------------------------;
1382VAL_SSZ_TBL LABEL WORD ;table of valid sector sizes
1383VAL_SSZ_S DW 128 ;smallest valid sector size
1384 DW 256
1385VAL_SSZ_L DW 512 ;largest valid sector size
1386VAL_SSZ_N EQU ($-VAL_SSZ_TBL)/2 ;number of table entries
1387
1388 ASSUME DS:CSEG
1389VALIDATE PROC ;validate parameters
1390 MOV BPB_AUSZ,1 ;initial allocation unit is 1 sector
1391
1392 CALL VAL_BSIZE ;validate buffer size
1393
1394 CALL VAL_SSZ ;validate (adjust if necessary) BPB_SSZ
1395
1396VALIDATE_A:
1397 AND ERR_FLAG,255-ERR_PASS ;indicate nothing changed this pass
1398
1399 MOV AX,BPB_SSZ ;sector size
1400 CWD ;clear DX for division
1401 DIV WPARA_SIZE ;sector size/para size
1402 MOV PARAS_PER_SECTOR,AX ;number of paragraphs/sector
1403
1404 MOV AX,BUFF_SIZE ;requested buffersize in KB
1405 MUL C1024 ;DX:AX = buffer size in bytes
1406 DIV BPB_SSZ ;/sector size = # sectors
1407 MOV BPB_SECN,AX ;store number of sectors
1408
1409 CALL VAL_DIRN ;validate number of directory entries
1410
1411 TEST ERR_FLAG,ERR_PASS ;may have reset sector size
1412 JNZ VALIDATE_A ;recompute directory & FAT sizes
1413
1414 CALL VAL_FAT ;compute FAT entries, validity test
1415
1416 TEST ERR_FLAG,ERR_PASS ;if cluster size altered this pass
1417 JNZ VALIDATE_A ;recompute directory & FAT sizes
1418
1419;Make certain buffer size is large enough to contain:
1420; boot sector(s)
1421; FAT sector(s)
1422; directory sector(s)
1423; at least 1 data cluster
1424
1425 MOV AL,BPB_FATN ;number of FAT copies
1426 CBW ;clear AH
1427 MUL BPB_FATSZ ;* sectors for 1 FAT = FAT sectors
1428 ADD AX,BPB_RES ;+ reserved sectors
1429 ADD AX,DIR_SECTORS ;+ directory sectors
1430 MOV CL,BPB_AUSZ ;get sectors/cluster
1431 XOR CH,CH ;CX = sectors in one cluster
1432 ADD AX,CX ;+ one data cluster
1433 CMP BPB_SECN,AX ;compare with sectors available
1434 JAE VALIDATE_X ;jump if enough sectors
1435
1436 CMP DIR_SECTORS,1 ;down to 1 directory sector?
1437 JBE VALIDATE_C ;can't let it go below 1
1438
1439 MOV AX,BPB_SSZ ;sector size
1440 CWD ;clear DX for division
1441 DIV DIRE_SIZE ;sectorsize/dir entry size = entries/sector
1442 SUB BPB_DIRN,AX ;reduce directory entries by 1 sector
1443
1444 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1445 JMP VALIDATE_A ;retry with new directory entries number
1446
1447VALIDATE_C: ;not enough space for any VDISK
1448 OR ERR_FLAG,ERR_SYSSZ
1449VALIDATE_X:
1450 RET
1451
1452 SUBTTL VAL_BSIZE Validate buffer size
1453 PAGE
1454;-----------------------------------------------------------------------;
1455; VAL_BSIZE adjusts the buffer size as necessary ;
1456;-----------------------------------------------------------------------;
1457VAL_BSIZE PROC
1458 CALL GET_MSIZE ;determine memory available to VDISK
1459 ;returns available KB in AX
1460 OR AX,AX ;is any memory available at all?
1461 JNZ VAL_BSIZE_B ;yes, continue
1462
1463 OR ERR_FLAG,ERR_SYSSZ ;indicate system too small for VDISK
1464 MOV BUFF_SIZE,1 ;set up minimal values to continue init
1465 MOV AX,VAL_SSZ_S ;smallest possible sector size
1466 MOV BPB_SSZ,AX
1467 MOV BPB_DIRN,4 ;4 directory entries
1468 RET
1469
1470VAL_BSIZE_B: ;some memory is available
1471 CMP AX,BUFF_SIZE ;is available memory >= requested?
1472 JAE VAL_BSIZE_C ;if so, we're done
1473
1474 MOV BUFF_SIZE,AX ;give all available memory
1475 OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted
1476VAL_BSIZE_C:
1477 RET
1478
1479
1480GET_MSIZE PROC ;determine memory available to VDISK
1481 ;returns KB available in AX
1482 CMP EM_SW,0 ;extended memory?
1483 JE GET_MSIZE_2 ;use non-extended memory routine
1484
1485 MOV AH,EM_MEMSIZE ;function code to AH
1486 INT EM_INT ;get extended memory size in AX
1487 JC GET_MSIZE_Z ;if error, no extended memory installed
1488
1489 MUL C1024 ;DX,AX = bytes of extended memory
1490 ADD DX,10H ;DX,AX = high addr of extended memory+1
1491 SUB AX,AVAIL_LO ;- address of first available byte
1492 SBB DL,AVAIL_HI ;is number of free bytes
1493 DIV C1024 ;AX = number of whole free kilobytes
1494 RET
1495
1496GET_MSIZE_2: ;non-extended memory size determination
1497
1498;Compute AX = total system size, - (VDISK end address + 64KB)
1499
1500 MOV AX,START_BUFFER_PARA ;paragraph end of VDISK code
1501 XOR DX,DX ;clear for division
1502 DIV PARA_PER_KB ;KB address of load point
1503 ADD DX,0FFFFH ;round upward to KB boundary
1504 ADC AX,MIN_MEMORY_LEFT ;pick up CY and the 64KB we should leave
1505 PUSH AX ;save across interrupt
1506 INT MEM_SIZE ;get total system size
1507 POP DX ;amount of total that we can't use
1508 SUB AX,DX ;available space to VDISK
1509 JNC GET_MSIZE_X ;exit if positive
1510
1511GET_MSIZE_Z:
1512 XOR AX,AX ;indicate no memory available
1513GET_MSIZE_X: ;exit from memory size determination
1514 RET
1515GET_MSIZE ENDP
1516
1517VAL_BSIZE ENDP
1518
1519 SUBTTL VAL_SSZ Validate Sector Size
1520 PAGE
1521;-----------------------------------------------------------------------;
1522; VAL_SSZ validates sector size, adjusting if necessary ;
1523;-----------------------------------------------------------------------;
1524VAL_SSZ PROC ;validate sector size
1525 CMP CS:EM_SW,0 ;extended memory ?
1526 JE VAL_SSZ_ST ;no,go check sector size
1527 MOV BX,MAXSEC_TRF ;move number of sectors to transfer
1528 CMP BX,1 ;> or equal to 1 ?
1529 JB DFLT_TRF ;set default if it is
1530 CMP BX,8 ;> than 8 ?
1531 JA DFLT_TRF ;set default if it is
1532 JMP VAL_SSZ_ST ;continue processing
1533
1534DFLT_TRF: ;set default
1535 MOV MAXSEC_TRF,DFLT_ESS ;
1536 MOV BX,MAXSEC_TRF ;
1537 OR CS:ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted
1538
1539VAL_SSZ_ST: ;validate sector size
1540 MOV MAX_CNT,BX ;initialize maximum number of sectors
1541 ;to transfer for extended memory case
1542 MOV BX,BPB_SSZ ;requested sector size
1543 MOV CX,VAL_SSZ_N ;number of table entries
1544 MOV SI,OFFSET VAL_SSZ_TBL ;DS:SI point to table start
1545VAL_SSZ_A:
1546 LODSW ;get table entry, step table pointer
1547 CMP AX,BX ;is value in table?
1548 JE VAL_SSZ_X ;exit if value found
1549 LOOP VAL_SSZ_A ;loop until table end
1550
1551 MOV BX,DFLT_SSZ ;get default sector size
1552 MOV BPB_SSZ,BX ;set sector size to default value
1553 OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted
1554VAL_SSZ_X:
1555
1556;Compute the maximum number of sectors that can be moved in 64KB (less one)
1557;Restricting moves to this amount avoids 64KB boundary problems.
1558
1559 CMP CS:EM_SW,0 ;extended memory ?
1560 JNE SIZE_DONE ;yes, we are done
1561 XOR DX,DX
1562 MOV AX,0FFFFH ;64KB - 1
1563 DIV BX ;/sector size
1564 MOV MAX_CNT,AX ;max sectors in one move
1565SIZE_DONE:
1566 RET
1567VAL_SSZ ENDP
1568
1569 SUBTTL VAL_DIRN Validate number of directory entries
1570 PAGE
1571;-----------------------------------------------------------------------;
1572; VAL_DIRN validates and adjusts the number of directory entries. ;
1573; ;
1574; Minimum is MIN_DIRN, maximum is MAX_DIRN. If outside these ;
1575; limits, DFLT_DIRN is used. ;
1576; ;
1577; The number of directory entries is rounded upward to fill ;
1578; a sector ;
1579;-----------------------------------------------------------------------;
1580VAL_DIRN PROC
1581 MOV AX,BPB_DIRN ;requested directory entries
1582 CMP AX,MIN_DIRN ;if less than minimum
1583 JB VAL_DIRN_A ;use default instead
1584
1585 CMP AX,MAX_DIRN ;if <= maximum
1586 JBE VAL_DIRN_B ;accept value as provided
1587
1588VAL_DIRN_A:
1589 MOV AX,DFLT_DIRN ;use default directory entries
1590 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1591VAL_DIRN_B: ;AX is number of directory entries
1592 MUL DIRE_SIZE ;* 32 = bytes of directory requested
1593 DIV BPB_SSZ ;/ sector size = # of directory sectors
1594 OR DX,DX ;test remainder for zero
1595 JZ VAL_DIRN_C ;jump if exact fit
1596
1597 INC AX ;increment directory sectors
1598 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1599VAL_DIRN_C: ;make sure enough sectors available
1600 MOV DX,BPB_SECN ;total sectors on media
1601 SUB DX,BPB_RES ;less reserved sectors
1602 SUB DX,2 ;less minimum FAT and 1 data sector
1603 CMP AX,DX ;if directory sectors <= available
1604 JLE VAL_DIRN_D ;use requested amount
1605
1606 MOV AX,1 ;use only one directory sector
1607 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1608VAL_DIRN_D:
1609 MOV DIR_SECTORS,AX ;save number of directory sectors
1610 MUL BPB_SSZ ;dir sectors * sector size = dir bytes
1611 DIV DIRE_SIZE ;dir bytes / entry size = entries
1612 MOV BPB_DIRN,AX ;store adjusted directory entries
1613 RET
1614VAL_DIRN ENDP
1615
1616 SUBTTL VAL_FAT Validate File Allocation Table (FAT)
1617 PAGE
1618;-----------------------------------------------------------------------;
1619;VAL_FAT computes: ;
1620;BPB_FATSZ, the number of sectors required per FAT copy ;
1621; ;
1622;Each FAT entry is 12 bits long, for a maximum of 4095 FAT entries. ;
1623;(A few FAT entries are reserved, so the highest number of FAT entries ;
1624;we permit is 0FE0H.) With large buffer sizes and small sector sizes, ;
1625;we have more allocation units to describe than a 12-bit entry will ;
1626;describe. If the number of FAT entries is too large, the sector size ;
1627;is increased (up to a maximum of 512 bytes), and then the allocation ;
1628;unit (cluster) size is doubled, until we have few enough allocation ;
1629;units to be properly described in 12 bits. ;
1630; ;
1631;This computation is slightly conservative in that the FAT entries ;
1632;necessary to describe the FAT sectors are included in the computation. ;
1633;-----------------------------------------------------------------------;
1634VAL_FAT PROC
1635 MOV AX,BPB_SECN ;total number of sectors
1636 SUB AX,BPB_RES ;don't count boot sector(s)
1637 SUB AX,DIR_SECTORS ;don't count directory sectors
1638 JG VAL_FAT_A ;jump if some remaining
1639 MOV BPB_SSZ,DFLT_SSZ ;force default sector size
1640 OR ERR_FLAG,ERR_SSZ+ERR_PASS ;indicate sector size adjusted
1641 JMP SHORT VAL_FAT_X ;recompute all values
1642VAL_FAT_A:
1643 XOR DX,DX ;clear DX for division
1644 MOV CL,BPB_AUSZ ;CX = sectors/cluster
1645 XOR CH,CH
1646 DIV CX ;whole number of clusters in AX
1647 ADD DX,0FFFFH ;set carry if remainder
1648 ADC AX,0 ;increment AX if remainder
1649 CMP AX,MAX_FATE ;number of FAT entries too large?
1650 JBE VAL_FAT_C ;no, continue
1651
1652 MOV AX,BPB_SSZ ;pick up current sector size
1653 CMP AX,VAL_SSZ_L ;already at largest permitted?
1654 JE VAL_FAT_B ;yes, can't make it any larger
1655
1656 SHL BPB_SSZ,1 ;double sector size
1657 OR ERR_FLAG,ERR_SSZB ;indicate sector size adjusted
1658 JMP SHORT VAL_FAT_X ;recompute all sizes with new BPBSSZ
1659
1660VAL_FAT_B: ;sector size is at maximum
1661 SHL BPB_AUSZ,1 ;double allocation unit size
1662 OR ERR_FLAG,ERR_PASS ;indicate another pass required
1663 JMP SHORT VAL_FAT_X ;recompute values
1664
1665VAL_FAT_C: ;FAT size = 1.5 * number of clusters
1666 MOV CX,AX ;number of clusters
1667 SHL AX,1 ;* 2
1668 ADD AX,CX ;* 3
1669 SHR AX,1 ;* 1.5
1670 ADC AX,3 ;add 3 bytes for first 2 FAT entries
1671 ;(media descriptor and FFFFH), and CY
1672 XOR DX,DX ;clear DX for division
1673 DIV BPB_SSZ ;FAT size/sector size
1674 ADD DX,0FFFFH ;set carry if remainder
1675 ADC AX,0 ;round upward
1676 MOV BPB_FATSZ,AX ;number of sectors for 1 FAT copy
1677VAL_FAT_X:
1678 RET
1679VAL_FAT ENDP
1680
1681
1682VALIDATE ENDP
1683
1684 SUBTTL COPY_BPB Copy BPB to Boot Record
1685 PAGE
1686;-----------------------------------------------------------------------;
1687; COPY_BPB copies the BIOS Parameter Block (BPB) ;
1688; to the VDISK Boot Record ;
1689;-----------------------------------------------------------------------;
1690 ASSUME DS:CSEG
1691COPY_BPB PROC ;Copy BBP to Boot Record
1692 PUSH DS
1693 POP ES ;set ES = DS
1694
1695 MOV CX,BPB_LEN ;length of BPB
1696 MOV SI,OFFSET BPB ;source offset
1697 MOV DI,OFFSET BOOT_BPB ;target offset
1698 REP MOVSB ;copy BPB to boot record
1699 RET
1700COPY_BPB ENDP
1701
1702 SUBTTL VERIFY_EXTENDER
1703 PAGE
1704;-----------------------------------------------------------------------;
1705; VERIFY_EXTENDER makes sure that if an Expansion Unit is ;
1706; installed, the memory size switches on the Extender Card ;
1707; are correctly set. ;
1708;-----------------------------------------------------------------------;
1709
1710
1711 ASSUME DS:CSEG
1712EXT_P210 EQU 0210H ;write to latch expansion bus data
1713 ;read to verify expansion bus data
1714EXT_P213 EQU 0213H ;Expansion Unit status
1715
1716VERIFY_EXTENDER PROC
1717
1718 NOP
1719
1720 MOV DX,EXT_P210 ;Expansion bus data port address
1721
1722 MOV AX,5555H ;set data pattern
1723 OUT DX,AL ;write 55H to control port
1724 PUSH DX
1725 POP DX
1726
1727 JMP SHORT $+2 ;Let the I/O circuits catch up
1728 IN AL,020h ;Clear the CMOS bus drivers!
1729
1730 IN AL,DX ;recover data
1731 CMP AH,AL ;did we recover the same data?
1732 JNE VERIFY_EXTENDER_X ;if not, no extender card
1733
1734 NOT AX ;set AX = 0AAAAH
1735 OUT DX,AL ;write 0AAH to control port
1736 PUSH DX ;load data line
1737 POP DX ;load data line
1738
1739 JMP SHORT $+2 ;Let the I/O circuits catch up
1740 IN AL,020h ;Clear the CMOS bus drivers!
1741
1742 IN AL,DX ;recover data
1743 CMP AH,AL ;did we recover the same data?
1744 JNE VERIFY_EXTENDER_X ;if not, no extender card
1745
1746;Expansion Unit is present.
1747
1748;Determine what the switch settings should be on the Extender Card
1749
1750 INT MEM_SIZE ;get system memory size in KB in AX
1751 ADD AX,63D ;memory size + 63K
1752 MOV CL,6 ;2^6 = 64
1753 SHR AX,CL ;divide by 64
1754 ;AX is highest segment address
1755 MOV AH,AL ;save number of segments
1756
1757;Read Expander card switch settings
1758
1759 MOV DX,EXT_P213 ;expansion unit status
1760 IN AL,DX ;read status
1761 ;bits 7-4 (hi nibble) are switches
1762 MOV CL,4 ;shift count
1763 SHR AL,CL ;shift switches to bits 3-0 of AL
1764
1765 CMP AH,AL ;do switches match memory size?
1766 JE VERIFY_EXTENDER_X ;yes, exit normally
1767
1768 OR ERR_FLAG,ERR_EXTSW ;indicate switch settings are wrong
1769
1770VERIFY_EXTENDER_X:
1771 RET
1772VERIFY_EXTENDER ENDP
1773
1774 SUBTTL UPDATE_AVAIL
1775 PAGE
1776;-----------------------------------------------------------------------;
1777; UPDATE_AVAIL updates the address of the first byte in extended ;
1778; memory not used by any VDISK buffer ;
1779;-----------------------------------------------------------------------;
1780UPDATE_AVAIL PROC ;update AVAIL_LO and AVAIL_HI of first VDISK
1781 MOV AX,BUFF_SIZE ;number of KB of VDISK buffer
1782 MUL C1024 ;DX,AX = number of bytes of VDISK buffer
1783
1784 PUSH DS
1785 MOV DS,FIRST_VDISK ;set DS to first VDISK
1786 ADD DS:AVAIL_LO,AX ;update first available byte location
1787 ADC DS:AVAIL_HI,DL
1788 POP DS
1789 RET
1790UPDATE_AVAIL ENDP
1791
1792 SUBTTL FORMAT_VDISK
1793 PAGE
1794;-----------------------------------------------------------------------;
1795; This Request Header is used by MOVE_VDISK to move the ;
1796; first few sectors of the virtual disk (boot, FAT, and ;
1797; Directory) into extended memory. ;
1798;-----------------------------------------------------------------------;
1799
1800MOVE_RH DB MOVE_RH_L ;length of request header
1801 DB 0 ;sub unit
1802 DB 8 ;output operation
1803 DW 0 ;status
1804 DQ ? ;reserved for DOS
1805 DB ? ;media descriptor byte
1806MOVE_RHO DW ? ;offset of data transfer address
1807MOVE_RHS DW ? ;segment of data transfer address
1808MOVE_RHCNT DW ? ;count of sectors to transfer
1809 DW 0 ;starting sector number
1810MOVE_RH_L EQU $-MOVE_RH ;length of request header
1811
1812;-----------------------------------------------------------------------;
1813; FORMAT_VDISK formats the boot sector, FAT, and directory of an ;
1814; extended memory VDISK in storage immediately following ;
1815; VDISK code, in preparation for moving to extended memory. ;
1816;-----------------------------------------------------------------------;
1817FORMAT_VDISK PROC ;format boot record, FATs and directory
1818
1819 MOV AX,CS ;compute 20-bit address
1820 MUL WPARA_SIZE ;16 * segment
1821 ADD AX,OFFSET MSGEND ;+ offset
1822 ADC DL,0 ;pick up carry
1823 ADD AX,STACK_SIZE ;plus stack size
1824 ADC DL,0 ;pick up carry
1825
1826 DIV WPARA_SIZE ;split into segment(AX)&offset(DX)
1827 MOV MOVE_RHS,AX ;save in Request Header for move
1828 MOV MOVE_RHO,DX
1829
1830 MOV DI,DX ;offset to DI
1831 MOV ES,AX ;segment to ES
1832
1833;copy the boot record
1834
1835 MOV SI,OFFSET BOOT_RECORD ;point to source field
1836 MOV AX,BPB_RES ;number of reserved sectors
1837 MUL BPB_SSZ ;* sector size = length of boot records
1838 MOV CX,AX ;length to CX for move
1839 REP MOVSB ;move boot record(s)
1840
1841;format the FAT(s)
1842
1843 MOV CL,BPB_FATN ;number of FATs
1844 XOR CH,CH
1845FORMAT_VDISK_A: ;set up one FAT
1846 PUSH CX ;save loop counter on stack
1847 MOV AL,BPB_MCB ;media control byte
1848 STOSB ;store media control byte, increment DI
1849 MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
1850 STOSW
1851 MOV AX,BPB_FATSZ ;number of sectors per FAT
1852 MUL BPB_SSZ ;* sector size = length of FAT in bytes
1853 SUB AX,3 ;less the 3 bytes we've stored
1854 MOV CX,AX ;count to CX
1855 XOR AX,AX
1856 REP STOSB ;clear remainder of FAT
1857 POP CX ;get loop counter off stack
1858 LOOP FORMAT_VDISK_A ;loop for all copies of the FAT
1859
1860;Format the directory
1861
1862 MOV SI,OFFSET VOL_LABEL ;point to volume label
1863 MOV CX,VOL_LABEL_LEN ;length of volume directory entry
1864 REP MOVSB ;move volume id to directory
1865 MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry
1866 MUL BPB_DIRN ;* number entries = bytes of directory
1867 SUB AX,VOL_LABEL_LEN ;less length of volume label
1868 MOV CX,AX ;CX = length of rest of directory
1869 XOR AX,AX
1870 REP STOSB ;clear directory to nulls
1871 RET
1872FORMAT_VDISK ENDP
1873
1874 SUBTTL MOVE_VDISK
1875 PAGE
1876;-----------------------------------------------------------------------;
1877; MOVE_VDISK moves the formatted boot sector, FAT, and directory ;
1878; into extended memory. ;
1879;-----------------------------------------------------------------------;
1880
1881MOVE_VDISK PROC
1882 MOV AL,BPB_FATN ;number of FAT copies
1883 CBW ;clear AH
1884 MUL BPB_FATSZ ;number of FAT sectors
1885 ADD AX,BPB_RES ;+ reserved sectors
1886 ADD AX,DIR_SECTORS ;+ directory sectors
1887 MOV MOVE_RHCNT,AX ;store as I/O length
1888
1889 MOV BX,OFFSET MOVE_RH ;DS:BX point to request header
1890 PUSH DS ;make sure DS gets preserved
1891 CALL INOUT ;move to extended memory
1892 POP DS
1893 RET
1894MOVE_VDISK ENDP
1895
1896 SUBTTL UPDATE_BOOT
1897 PAGE
1898;-----------------------------------------------------------------------;
1899; UPDATE_BOOT updates the BOOT_EM word in the first extended ;
1900; memory VDISK (address 10 001EH) to show the kilobyte address ;
1901; of the first extended memory byte not used by any VDISK buffer. ;
1902;-----------------------------------------------------------------------;
1903UPDATE_BOOT PROC
1904 PUSH DS
1905 MOV DS,FIRST_VDISK ;set DS to first VDISK
1906 MOV AX,DS:AVAIL_LO ;24-bit end address of all VDISKs
1907 MOV DL,DS:AVAIL_HI
1908 XOR DH,DH
1909 POP DS
1910 DIV C1024 ;address / 1024
1911 MOV BOOT_EM,AX ;store in temporary location
1912
1913 MOV AX,2 ;length of block move is 2 bytes
1914 MOV TGT.DESC_LMT,AX
1915 MOV SRC.DESC_LMT,AX
1916
1917 MOV AX,PARA_SIZE ;16
1918 MOV CX,CS ;our segment address
1919 MUL CX ;16 * segment address
1920 ADD AX,OFFSET BOOT_EM ;+ offset of source data
1921 ADC DL,0 ;pick up any carry
1922
1923 MOV SRC.DESC_BASEL,AX ;store source base address
1924 MOV SRC.DESC_BASEH,DL
1925
1926 MOV TGT.DESC_BASEL,BOOT_EM_OFF ;offset of BOOT_EM
1927 MOV TGT.DESC_BASEH,10H ;1 megabyte
1928
1929 MOV CX,1 ;move 1 word
1930
1931 PUSH CS
1932 POP ES
1933 MOV SI,OFFSET GDT ;ES:DI point to global descriptor table
1934
1935 MOV AH,EM_BLKMOVE ;function code
1936 INT EM_INT ;move BOOT_EM to 10 001EH
1937 RET
1938UPDATE_BOOT ENDP
1939
1940 SUBTTL STEAL_INT19
1941 PAGE
1942;-----------------------------------------------------------------------;
1943; STEAL_INT19 changes the INT 19H vector to point to this VDISK ;
1944; so that subsequent extended memory VDISKS may locate the ;
1945; AVAIL_HI and AVAIL_LO fields to determine their buffer start ;
1946; addresses. ;
1947;-----------------------------------------------------------------------;
1948STEAL_INT19 PROC
1949 PUSH DS
1950 XOR AX,AX
1951 MOV DS,AX ;set DS = 0
1952 ASSUME DS:INT_VEC
1953 CLI ;disable interrupts
1954 LES DI,DS:BOOT_VEC ;get original vector's content
1955 MOV CS:INTV19O,DI ;save original vector
1956 MOV CS:INTV19S,ES
1957 MOV DS:BOOT_VECO,OFFSET VDISK_INT19 ;offset of new INT routine
1958 MOV DS:BOOT_VECS,CS ;segment of new INT routine
1959 STI ;enable interrupts again
1960 POP DS ;restore DS
1961 RET
1962STEAL_INT19 ENDP
1963
1964 SUBTTL FILL_RH Fill in Request Header
1965 PAGE
1966;-----------------------------------------------------------------------;
1967; FILL_RH fills in the Request Header returned to DOS ;
1968;-----------------------------------------------------------------------;
1969 ASSUME DS:CSEG
1970FILL_RH PROC ;fill in INIT Request Header fields
1971 MOV CX,START_BUFFER_PARA ;segment end of VDISK resident code
1972 MOV AX,PARAS_PER_SECTOR ;paragraphs per sector
1973 MUL BPB_SECN ;* number of sectors
1974 ADD AX,CX ;+ starting segment
1975 MOV DX,AX ;DX is segment of end VDISK buffer
1976 CMP EM_SW,0 ;if extended memory not requested
1977 JE FILL_RH_A ;skip DX adjustment
1978
1979 MOV DX,CX ;end of code segment addr
1980FILL_RH_A: ;DX is proper ending segment address
1981 MOV AL,1 ;number of units
1982 test CS:err_flag2,err_baddos
1983 jnz dont_install
1984
1985 TEST ERR_FLAG,ERR_SYSSZ+ERR_EXTSW ;if bypassing install
1986 JZ FILL_RH_B ;jump if installing driver
1987
1988dont_install:
1989 MOV DX,CS ;segment of end address
1990 XOR AL,AL ;number of units is zero
1991FILL_RH_B:
1992 PUSH DS ;preserve DS
1993 LDS BX,RH_PTRA ;get Request Header addr in DS:BX
1994 MOV RH.RH0_NUN,AL ;store number of units (0 or 1)
1995 MOV RH.RH0_ENDO,0 ;end offset is always zero
1996 MOV RH.RH0_ENDS,DX ;end of VDISK or end of buffer
1997 MOV RH.RH0_BPBO,OFFSET BPB_PTR
1998 MOV RH.RH0_BPBS,CS ;BPB array address
1999 POP DS ;restore DS
2000 RET
2001FILL_RH ENDP
2002
2003 SUBTTL WRITE_MESSAGES and associated routines
2004 PAGE
2005;-----------------------------------------------------------------------;
2006; WRITE_MESSAGE writes a series of messages to the standard ;
2007; output device showing the VDISK parameter values actually used. ;
2008;-----------------------------------------------------------------------;
2009
2010CHAR4 DB 'nnnn$' ;build 4 ASCII decimal digits
2011
2012 ASSUME DS:CSEG
2013WRITE_MESSAGES PROC ;display all messages
2014
2015 MSG IMSG ;'VDISK virtual disk $'
2016
2017 test CS:err_flag2,err_baddos
2018 jz check_dos_version
2019
2020 msg errm8
2021 ret
2022
2023;If DOS Version 3.x is in use, the Request Header contains a drive code
2024;that is displayed to show which drive letter was assigned to this
2025;VDISK. This field is not present in the DOS Version 2 Request Header.
2026
2027check_dos_version:
2028 MOV AH,DOS_VERS ;get DOS version call
2029 INT DOS ;invoke DOS
2030
2031 CMP AL,3 ;DOS Version 3 or greater?
2032 JB WRITE_MESSAGES_A ;no, bypass drive letter
2033
2034 PUSH DS ;preserve DS
2035 LDS BX,RH_PTRA ;get Request Header Address
2036 MOV DL,RH.RH0_DRIV ;get drive code
2037 ADD DL,'A' ;convert to drive letter
2038 POP DS ;restore DS
2039
2040 MOV AH,DOS_PCHR ;function code to write character in DL
2041 INT DOS ;display drive letter
2042
2043 MOV DL,':' ;display trailing colon
2044 INT DOS
2045
2046WRITE_MESSAGES_A:
2047 MSG MSGCRLF ;end the first line
2048
2049;If any of the user specified values has been adjusted, issue an
2050;appropriate message
2051
2052 TEST ERR_FLAG,ERR_BSIZE ;was buffersize adjusted?
2053 JZ WRITE_MESSAGES_B ;if not, skip message
2054
2055 MSG ERRM1 ;buffer size adjusted
2056
2057WRITE_MESSAGES_B:
2058 TEST ERR_FLAG,ERR_SSZ ;was sector size adjusted?
2059 JZ WRITE_MESSAGES_C ;if not, skip message
2060
2061 MSG ERRM2 ;sector size adjusted
2062
2063WRITE_MESSAGES_C:
2064 TEST ERR_FLAG,ERR_DIRN ;were directory entries adjusted?
2065 JZ WRITE_MESSAGES_D0 ;if not, skip message
2066
2067 MSG ERRM3 ;directory entries adjusted
2068
2069WRITE_MESSAGES_D0:
2070 TEST ERR_FLAG,ERR_ESIZE ;was transfer size adjusted?
2071 JZ WRITE_MESSAGES_D ;if not, skip message
2072
2073 MSG ERRM7 ;transfer size adjusted
2074
2075WRITE_MESSAGES_D:
2076 TEST ERR_FLAG,ERR_SWTCH ;was an invalid switch character found?
2077 JZ WRITE_MESSAGES_E ;if not, skip message
2078
2079 MSG ERRM5 ;invalid switch character
2080
2081WRITE_MESSAGES_E:
2082 TEST ERR_FLAG,ERR_SYSSZ ;is system size too small to install?
2083 JZ WRITE_MESSAGES_F ;if not, bypass error message
2084
2085 MSG ERRM4 ;too large for system storage
2086 RET ;skip messages showing adjusted sizes
2087
2088WRITE_MESSAGES_F:
2089 TEST ERR_FLAG,ERR_EXTSW ;extender card switches wrong?
2090 JZ WRITE_MESSAGES_G ;if not, bypass error message
2091
2092 MSG ERRM6 ;extender card switches wrong msg
2093 RET ;skip remaining messages
2094
2095WRITE_MESSAGES_G: ;display adjusted size messages
2096 MSG MSG1 ;buffer size:
2097
2098 MOV DX,BUFF_SIZE ;buffer size in binary
2099 CALL STOR_SIZE ;convert binary to ASCII decimal
2100 MSG CHAR4 ;print 4 decimals
2101 MSG MSG2 ;KB,CR,LF
2102
2103 MSG MSG3 ;sector size:
2104 MOV DX,BPB_SSZ
2105 CALL STOR_SIZE ;convert binary to ASCII decimal
2106 MSG CHAR4 ;print 4 decimals
2107 MSG MSGCRLF ;finish off line
2108
2109 MSG MSG4 ;directory entries:
2110 MOV DX,BPB_DIRN ;number of directory entries
2111 CALL STOR_SIZE
2112 MSG CHAR4 ;print 4 decimals
2113 MSG MSGCRLF ;finish off the line
2114
2115 CMP CS:EM_SW,0 ;extended memory ?
2116 JE END_LINE ;
2117 MSG MSG5 ;transfer size:
2118 MOV DX,MAXSEC_TRF
2119 CALL STOR_SIZE ;convert binary to ASCII decimal
2120 MSG CHAR4 ;print 4 decimals
2121 MSG MSGCRLF ;finish off line
2122
2123END_LINE:
2124 MSG MSGCRLF ;one more blank line to set it off
2125 RET ;return to INIT_P1
2126
2127;SHOW_MSG displays a string at DS:DX on the standard output device
2128;String is terminated by a $
2129
2130SHOW_MSG PROC ;display string at DS:DX
2131 PUSH AX ;preserve AX across call
2132 MOV AH,DOS_PSTR ;DOS function code
2133 INT DOS ;invoke DOS print string function
2134 POP AX ;restore AX
2135 RET
2136SHOW_MSG ENDP
2137
2138;STOR_SIZE converts the content of DX to 4 decimal characters in CHAR4
2139;(DX must be <= 9999)
2140
2141STOR_SIZE PROC ;convert DX to 4 decimals in CHAR4
2142 ;develop 4 packed decimal digits in AX
2143 XOR AX,AX ;clear result register
2144 MOV CX,16 ;shift count
2145STOR_SIZE_B:
2146 SHL DX,1 ;shift high bit into carry
2147 ADC AL,AL ;double AL, carry in
2148 DAA ;adjust for packed decimal
2149 XCHG AL,AH
2150 ADC AL,AL ;double high byte, carry in
2151 DAA
2152 XCHG AL,AH
2153 LOOP STOR_SIZE_B ;AX contains 4 packed decimal digits
2154
2155 PUSH CS
2156 POP ES ;point ES:DI to output string
2157 MOV DI,OFFSET CHAR4
2158
2159 MOV CX,1310H ;10H in CL is difference between blank and zero
2160 ;13H in CH is decremented and ANDed to force
2161 ;last character not to be zero suppressed
2162 PUSH AX ;save AX on stack
2163 MOV DL,AH ;2 decimals to DL
2164 CALL STOR_SIZE_2 ;display DL as 2 decimal characters
2165 POP DX ;bring low 2 decimals into DL
2166STOR_SIZE_2: ;display DL as 2 decimal characters
2167 MOV DH,DL ;save 2 decimals in DH
2168 SHR DL,1 ;shift high order decimal right to low position
2169 SHR DL,1
2170 SHR DL,1
2171 SHR DL,1
2172 CALL STOR_SIZE_1 ;display low nibble of DL
2173 MOV DL,DH ;get low decimal from pair
2174STOR_SIZE_1: ;display low nibble of DL as 1 decimal char
2175 AND DL,0FH ;clear high nibble
2176 JZ STOR_SIZE_Z ;if digit is significant,
2177 XOR CL,CL ;defeat zero suppression
2178STOR_SIZE_Z:
2179 DEC CH ;decrement zero suppress counter
2180 AND CL,CH ;always display least significant digit
2181 OR DL,'0' ;convert packed decimal to ASCII
2182 SUB DL,CL ;zero suppress (nop or change '0' to ' ')
2183 MOV AL,DL ;char to DL
2184 STOSB ;store char at ES:DI, increment DI
2185 RET
2186STOR_SIZE ENDP
2187
2188WRITE_MESSAGES ENDP
2189
2190INIT_P1 ENDP ;end of INIT part one
2191
2192;-----------------------------------------------------------------------;
2193; VDISK Message definitions ;
2194;-----------------------------------------------------------------------;
2195
2196IMSG DB 'VDISK virtual disk ','$'
2197
2198ERRM1 DB ' Buffer size adjusted',CR,LF,'$'
2199ERRM2 DB ' Sector size adjusted',CR,LF,'$'
2200ERRM3 DB ' Directory entries adjusted',CR,LF,'$'
2201ERRM4 DB ' VDISK not installed - insufficient memory'
2202 DB CR,LF,CR,LF,BEL,'$'
2203ERRM5 DB ' Invalid switch character',CR,LF,'$'
2204ERRM6 DB ' VDISK not installed - Extender Card switches'
2205 DB CR,LF
2206 DB ' do not match system memory size'
2207 DB CR,LF,CR,LF,BEL,'$'
2208ERRM7 DB ' Transfer size adjusted',CR,LF,'$'
2209ERRM8 DB ' VDISK not installed - Incorrect DOS version'
2210 DB CR,LF,CR,LF,BEL,'$'
2211
2212MSG1 DB ' Buffer size: $'
2213MSG2 DB ' KB'
2214MSGCRLF DB CR,LF,'$'
2215MSG3 DB ' Sector size: $'
2216MSG4 DB ' Directory entries: $'
2217MSG5 DB ' Transfer size: $'
2218MSGEND LABEL BYTE ; End of message text
2219
2220CSEG ENDS
2221 END
diff --git a/v4.0/src/DEV/VDISK/VDISK.INC b/v4.0/src/DEV/VDISK/VDISK.INC
new file mode 100644
index 0000000..202a008
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISK.INC
@@ -0,0 +1,28 @@
1EMS_STATUS EQU 40H
2EMS_GET_NUM_PAGES EQU 42H
3EMS_ALLOC_PAGES EQU 43H
4EMS_MAP_HANDLE EQU 44H
5EMS_VERSION EQU 46H
6EMS_SAVE_STATE EQU 47H
7EMS_RESTORE_STATE EQU 48H
8EMS_GET_FRAME_ADDR EQU 5100H
9EMS_INT EQU 67H
10
11EMS_EXPECTED_VERSION EQU 34H
12EMS_LOW_ERROR EQU 80H
13EMS_INSTALLED_FLAG EQU -1
14
15EMS_ALLOC_ERROR EQU -1 ; ***RPS ??
16SINGLE_SEGMENT EQU 1
17DOS_PAGE1 EQU 0FEH
18DOS_PAGE2 EQU 0FFH
19DOS_PAGE_SZ EQU 16
20
21GET_PAGE_FRAME_STRUC STRUC
22 START_PAGE DB ?
23 NUM_PAGE DB ?
24 FRAME_SEGMENT DW ?
25GET_PAGE_FRAME_STRUC ENDS
26BUFFER_ENTRY_SIZE EQU TYPE GET_PAGE_FRAME_STRUC
27
28 \ No newline at end of file
diff --git a/v4.0/src/DEV/VDISK/VDISK.LNK b/v4.0/src/DEV/VDISK/VDISK.LNK
new file mode 100644
index 0000000..74989ed
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISK.LNK
@@ -0,0 +1,3 @@
1VDISKSYS.OBJ
2VDISK.EXE;
3 \ No newline at end of file
diff --git a/v4.0/src/DEV/VDISK/VDISK.SKL b/v4.0/src/DEV/VDISK/VDISK.SKL
new file mode 100644
index 0000000..9555298
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISK.SKL
@@ -0,0 +1,36 @@
1; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2; VDISK Message Skeleton file
3; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4
5:util VDISK ;AN000;
6
7:class 2 ;AN000;
8:use PARSE1 ;AN000;
9:use PARSE2 ;AN000;
10:use PARSE3 ;AN000;
11:use PARSE4 ;AN000;
12:use PARSE6 ;AN000;
13:use PARSE7 ;AN000;
14:use PARSE8 ;AN000;
15
16:class A ;AN000;
17:use 1 COMMON1 ;AN000; "Incorrect DOS version"
18:def 2 "Insufficient memory",CR,LF ;AN000; "Insufficient memory"
19
20:def 3 "VDISK Version 4.00 virtual disk %1",CR,LF ;AN000;
21:def 4 " Buffer size adjusted",CR,LF ;AN000;
22:def 5 " Sector size adjusted",CR,LF ;AN000;
23:def 6 " Directory entries adjusted",CR,LF ;AN000;
24:def 7 " Invalid switch character",CR,LF ;AN000;
25:def 8 " Transfer size adjusted",CR,LF ;AN000;
26:def 9 " Buffer size: %1 KB",CR,LF ;AN000;
27:def 10 " Sector size: %1",CR,LF ;AN000;
28:def 11 " Directory entries: %1",CR,LF ;AN000;
29:def 12 " Transfer size: %1",CR,LF ;AN000;
30:def 13 "VDISK not installed - " ;AN000;
31:def 14 " Extender Card switches",CR,LF ;AN000;
32 "do not match system memory size",CR,LF,CR,LF ;AN000;
33
34:end ;AN000;
35
36
diff --git a/v4.0/src/DEV/VDISK/VDISKMSG.ASM b/v4.0/src/DEV/VDISK/VDISKMSG.ASM
new file mode 100644
index 0000000..4b43a31
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISKMSG.ASM
@@ -0,0 +1,27 @@
1 PAGE ,132
2 TITLE VDISKMSG - VDISK message library
3
4;All messages issued by VDISK are defined here for ease in
5;translation for international use.
6
7;Each message should end with a '$' to delimit the end of the string.
8
9CSEG SEGMENT PARA PUBLIC 'CODE'
10
11 PUBLIC IMSG
12 PUBLIC ERRM1,ERRM2,ERRM3,ERRM4,ERRM5,ERRM6,ERRM7,errm8
13 PUBLIC MSG1,MSG2,MSG3,MSG4,MSG5,MSGCRLF
14 PUBLIC MSGEND
15
16;ASCII equates
17
18BEL EQU 07H ;alarm
19LF EQU 0AH ;line feed
20CR EQU 0DH ;carriage return
21
22
23include vdiskmsg.inc
24
25MSGEND LABEL BYTE ;must be last in module
26CSEG ENDS
27 END
diff --git a/v4.0/src/DEV/VDISK/VDISKSYS.ASM b/v4.0/src/DEV/VDISK/VDISKSYS.ASM
new file mode 100644
index 0000000..544c610
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISKSYS.ASM
@@ -0,0 +1,3024 @@
1 PAGE ,132
2 TITLE VDISK - Virtual Disk Device Driver, Version 4.00
3
4;VDISK simulates a disk drive, using Random Access Memory as the storage medium.
5
6;(C) Copyright Microsoft Corporation, 1984 - 1988
7;Licensed Material - Program Property of Microsoft Corp.
8
9;Add the following statement to CONFIG.SYS
10; DEVICE=[d:][path]VDISK.SYS bbb sss ddd [/E:m]
11
12; where: bbb is the desired buffer size (in kilobytes)
13; minimum 1KB, maximum is size of available memory,
14; default is 64KB.
15
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
20; by CHKDSK.
21
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.
25
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
29
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.
33
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
40; is 8 sectors.
41
42; Brackets indicate optional operands.
43
44
45; Samples:
46; DEVICE=\path\VDISK.SYS 160 512 64
47; results in a 160KB VDISK, with 512 byte sectors, 64 directory entries
48
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)
52;
53;=========================================================================
54; Change List
55;
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.
62;
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
67; requested VDISK.
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.
73;
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.
77;
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.
82;
83; AN005 - DCR474 Convert VDISK to support /E for extended memory
84; and /X for expanded memory.
85;
86; AN006 - PTM4729 Enable VDISK for the INT 2F call to determine
87; the reserved EMS page for VDISK and FASTOPEN
88;
89;=========================================================================
90
91;Message text for VDISK is in module VDISKMSG.
92.xlist
93 INCLUDE VDISKSYS.INC
94 INCLUDE SYSMSG.INC
95 MSG_UTILNAME<VDISK>
96.list
97 SUBTTL Structure Definitions
98 PAGE
99;-----------------------------------------------------------------------;
100; Request Header (Common portion) ;
101;-----------------------------------------------------------------------;
102RH EQU DS:[BX] ;addressability to Request Header structure
103
104RHC STRUC ;fields common to all request types
105 DB ? ;length of Request Header (including data)
106 DB ? ;unit code (subunit)
107RHC_CMD DB ? ;command code
108RHC_STA DW ? ;status
109 DQ ? ;reserved for DOS
110;;;;; DW ? ;reserved for BIOS message flag ;an006; dms;
111RHC ENDS ;end of common portion
112
113CMD_INPUT EQU 4 ;RHC_CMD is INPUT request
114
115;status values for RHC_STA
116
117STAT_DONE EQU 01H ;function complete status (high order byte)
118STAT_CMDERR EQU 8003H ;invalid command code error
119STAT_CRC EQU 8004H ;CRC error
120STAT_SNF EQU 8008H ;sector not found error
121STAT_BUSY EQU 0200H ;busy bit (9) for Removable Media call
122;-----------------------------------------------------------------------;
123; Request Header for INIT command ;
124;-----------------------------------------------------------------------;
125RH0 STRUC
126 DB (TYPE RHC) DUP (?) ;common portion
127RH0_NUN DB ? ;number of units
128 ;set to 1 if installation succeeds,
129 ;set to 0 to cause installation failure
130RH0_ENDO DW ? ;offset of ending address
131RH0_ENDS DW ? ;segment of ending address
132RH0_BPBO DW ? ;offset of BPB array address
133RH0_BPBS DW ? ;segment of BPB array address
134RH0_DRIV DB ? ;drive code (DOS 3 only)
135RH0_FLAG DW 0 ;initialized to no error ;an000; dms;
136RH0 ENDS
137
138RH0_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
140
141;-----------------------------------------------------------------------;
142; Request Header for MEDIA CHECK Command ;
143;-----------------------------------------------------------------------;
144RH1 STRUC
145 DB (TYPE RHC) DUP (?) ;common portion
146 DB ? ;media descriptor
147RH1_RET DB ? ;return information
148RH1 ENDS
149;-----------------------------------------------------------------------;
150; Request Header for BUILD BPB Command ;
151;-----------------------------------------------------------------------;
152RH2 STRUC
153 DB (TYPE RHC) DUP(?) ;common portion
154 DB ? ;media descriptor
155 DW ? ;offset of transfer address
156 DW ? ;segment of transfer address
157RH2_BPBO DW ? ;offset of BPB table address
158RH2_BPBS DW ? ;segment of BPB table address
159RH2 ENDS
160;-----------------------------------------------------------------------;
161; Request Header for INPUT, OUTPUT, and OUTPUT with verify ;
162;-----------------------------------------------------------------------;
163RH4 STRUC
164 DB (TYPE RHC) DUP (?) ;common portion
165 DB ? ;media descriptor
166RH4_DTAO DW ? ;offset of transfer address
167RH4_DTAS DW ? ;segment of transfer address
168RH4_CNT DW ? ;sector count
169RH4_SSN DW ? ;starting sector number
170RH4 ENDS
171
172RH4_DTAA EQU DWORD PTR RH4_DTAO ;offset/segment of transfer address
173
174;-----------------------------------------------------------------------;
175; Segment Descriptor (part of Global Descriptor Table) ;
176;-----------------------------------------------------------------------;
177DESC STRUC ;data segment descriptor
178DESC_LMT DW 0 ;segment limit (length)
179DESC_BASEL DW 0 ;bits 15-0 of physical address
180DESC_BASEH DB 0 ;bits 23-16 of physical address
181 DB 0 ;access rights byte
182 DW 0 ;reserved
183DESC ENDS
184
185 SUBTTL Equates and Macro Definitions
186 PAGE
187
188MEM_SIZE EQU 12H ;BIOS memory size determination INT
189 ;returns system size in KB in AX
190
191EM_INT EQU 15H ;extended memory BIOS interrupt INT
192EM_BLKMOVE EQU 87H ;block move function
193EM_MEMSIZE EQU 8800H ;memory size determination in KB
194
195DOS EQU 21H ;DOS request INT
196DOS_PCHR EQU 02H ;print character function
197DOS_PSTR EQU 09H ;print string function
198DOS_VERS EQU 30H ;get DOS version
199
200TAB EQU 09H ;ASCII tab
201LF EQU 0AH ;ASCII line feed
202CR EQU 0DH ;ASCII carriage return
203
204PARA_SIZE EQU 16 ;number of bytes in one 8088 paragraph
205DIR_ENTRY_SIZE EQU 32 ;number of bytes per directory entry
206MAX_FATE EQU 0FE0H ;largest number of FAT entries allowed
207
208;default values used if parameters are omitted
209
210DFLT_BSIZE EQU 64 ;default VDISK buffer size (KB)
211DFLT_SSZ EQU 128 ;default sector size
212DFLT_DIRN EQU 64 ;default number of directory entries
213DFLT_ESS EQU 8 ;default maximum sectors to transfer
214
215MIN_DIRN EQU 2 ;minimum number of directory entries
216MAX_DIRN EQU 512 ;maximum number of directory entries
217
218STACK_SIZE EQU 512 ;length of stack during initialization
219
220 SUBTTL Resident Data Area
221 PAGE
222
223;-----------------------------------------------------------------------;
224; Map INT 15H vector in low storage ;
225;-----------------------------------------------------------------------;
226INT_VEC SEGMENT AT 00H
227 ORG 4*EM_INT
228EM_VEC LABEL DWORD
229EM_VECO DW ? ;offset
230EM_VECS DW ? ;segment
231INT_VEC ENDS
232
233
234
235CSEG SEGMENT PARA PUBLIC 'CODE'
236 ASSUME CS:CSEG
237;-----------------------------------------------------------------------;
238; Resident data area. ;
239; ;
240; All variables and constants required after initialization ;
241; part one are defined here. ;
242;-----------------------------------------------------------------------;
243
244START EQU $ ;begin resident VDISK data & code
245
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
255
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
258;has been installed.
259
260VOL_LABEL DB 'VDISK V4.0' ;00-10 volume name (shows program level)
261 DB 28H ;11-11 attribute (volume label)
262 DT 0 ;12-21 reserved
263 DW 6000H ;22-23 time=12:00 noon
264 DW 0986H ;24-25 date=12/06/84
265VOL_LABEL_LEN EQU $-VOL_LABEL ;length of volume label
266
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.
271
272AVAIL_LO DW 0 ;address of first free byte of
273AVAIL_HI DB 10H ;extended memory
274
275INTV15 LABEL DWORD
276INTV15O DW ? ;offset
277INTV15S DW ? ;segment
278
279
280PARAS_PER_SECTOR DW ? ;number of 16-byte paragraphs in one sector
281
282START_BUFFER_PARA DW ? ;segment address of start of VDISK buffer
283
284EM_New_Size dw ? ;an001; dms;new size for EM
285EM_KSize dw ? ;an001; dms;size of EM currently.
286
287EM_SW DB 0 ;NON-ZERO IF EXTENDED MEMORY
288
289EM_STAT DW 0 ;AX from last unsuccessful extended memory I/O
290
291START_EM_LO DW ? ;24-bit address of start of VDISK buffer
292START_EM_HI DB ? ;(extended memory only)
293
294WPARA_SIZE DW PARA_SIZE ;number of bytes in one paragraph
295
296MAX_CNT DW ? ;(0FFFFH/BPB_SSZ) truncated, the maximum
297 ;number of sectors that can be transferred
298 ;without worrying about 64KB wrap
299
300SECT_LEFT DW ? ;sectors left to transfer
301
302IO_SRCA LABEL DWORD ;offset/segment of source
303IO_SRCO DW ? ;offset
304IO_SRCS DW ? ;segment
305
306IO_TGTA LABEL DWORD ;offset/segment of target
307IO_TGTO DW ? ;offset
308IO_TGTS DW ? ;segment
309
310;-----------------------------------------------------------------------;
311; EMS Support ;
312;-----------------------------------------------------------------------;
313
314EM_SW2 DB not EMS_Installed_Flag ;ac006;Default if EMS not installed
315EMS_HANDLE DW ? ;AN000; EMS handle for reference
316EMS_FRAME_ADDR DW ? ;AN000; EMS handle for reference
317EMS_CURR_SECT DW ? ;an000; Current EMS sector being addressed
318CURR_EMS_PAGE DW ? ;ac002; Current EMS page number
319SECT_LEFT_IN_FRAME DW ? ;AN000; Sectors left to transfer in this frame
320SECT_PER_PAGE DW ? ;AN000; Sectors per page
321DOS_Page dw ? ;an006; EMS physical page for VDISK
322
323EMS_SAVE_ARRAY DB 80h dup(0) ;an000; save current state of ems
324EMS_SEG_ARRAY DD ? ;an000; save segment array
325
326CURR_DTA_OFF DW ? ;AN000; DMS;CURRENT OFFSET OF DTA
327
328PC_386 DB false ;AN000; DMS;386 machine flag
329
330SUBLIST STRUC ;AN000;SUBLIST STRUCTURE
331
332SL_SIZE DB ? ;AN000;SUBLIST SIZE
333SL_RES DB ? ;AN000;RESERVED
334SL_OFFSET DW ? ;AN000;PARM OFFSET
335SL_SEGMENT DW ? ;AN000;PARM SEGMENT
336SL_ID DB ? ;AN000;NUMBER OF PARM
337SL_FLAG DB ? ;AN000;DISPLAY TYPE
338SL_MAXW DB ? ;AN000;MAXIMUM FIELD WIDTH
339SL_MINW DB ? ;AN000;MINIMUM FIELD WIDTH
340SL_PAD DB ? ;AN000;PAD CHARACTER
341
342SUBLIST ENDS ;AN000;END SUBLIST STRUCTURE
343
344
345BIOS_SYSTEM_DESCRIPTOR struc ;AN000;SYSTEM TYPE STRUC
346
347bios_SD_leng dw ? ;AN000;VECTOR LENGTH
348bios_SD_modelbyte db ? ;AN000;SYSTEM MODEL TYPE
349bios_SD_scnd_modelbyte db ? ;AN000;
350 db ? ;AN000;
351bios_SD_featurebyte1 db ? ;AN000;
352 db 4 dup (?) ;AN000;
353
354BIOS_SYSTEM_DESCRIPTOR ends ;AN000;END OF STRUC
355
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.
363
364BPB LABEL BYTE ;BIOS Parameter Block (BPB)
365BPB_SSZ DW 0 ;number of bytes per disk sector
366BPB_AUSZ DB 1 ;sectors per allocation unit
367BPB_RES DW 1 ;number of reserved sectors (for boot record)
368BPB_FATN DB 1 ;number of File Allocation Table (FAT) copies
369BPB_DIRN DW 0 ;number of root directory entries
370BPB_SECN DW 1 ;total number of sectors
371 ;computed from buffer size and sector size
372 ;(this includes reserved, FAT, directory,
373 ;and data sectors)
374BPB_MCB DB 0FEH ;media descriptor byte
375BPB_FATSZ DW 1 ;number of sectors occupied by a single FAT
376 ;computed from BPBSSZ and BPBSECN
377BPB_LEN EQU $-BPB ;length of BIOS parameter block
378
379BPB_PTR DW BPB ;BIOS Parameter Block pointer array (1 entry)
380;-----------------------------------------------------------------------;
381; Request Header (RH) address, saved here by "strategy" routine ;
382;-----------------------------------------------------------------------;
383RH_PTRA LABEL DWORD
384RH_PTRO DW ? ;offset
385RH_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)
395
396GDT LABEL BYTE ;begin global descriptor table
397 DESC <> ;dummy descriptor
398 DESC <> ;descriptor for GDT itself
399SRC DESC <,,,93H,> ;source descriptor
400TGT DESC <,,,93H,> ;target descriptor
401 DESC <> ;BIOS CS descriptor
402 DESC <> ;stack segment descriptor
403
404 SUBTTL INT 15H (size) interrupt handler
405 PAGE
406;-----------------------------------------------------------------------;
407; INT 15H Interrupt Handler routine ;
408;-----------------------------------------------------------------------;
409
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.
414;
415; Service - Function 8800h: Obtains the size of EM from the word
416; value EM_KSize
417; Call With: AX - 8800h
418; Returns : AX - Kbyte size of EM
419;
420;=========================================================================
421VDISK_INT15 PROC ;an001; dms;
422
423 cmp ah,EM_Size_Get ;an001; dms;function 88h
424; $if e ;an001; dms;get size
425 JNE $$IF1
426 mov ax,cs:EM_KSize ;an001; dms;return size
427 clc ;an001; dms;clear CY
428; $else ;an001; dms;
429 JMP SHORT $$EN1
430$$IF1:
431 jmp cs:INTV15 ;an001; dms;jump to org. vector
432; $endif ;an001; dms;
433$$EN1:
434
435 iret ;an001; dms;
436
437VDISK_INT15 ENDP ;an001; dms;
438
439
440 ASSUME DS:NOTHING
441
442 SUBTTL Device Strategy & interrupt entry points
443 PAGE
444;-----------------------------------------------------------------------;
445; Device "strategy" entry point ;
446; ;
447; Retain the Request Header address for use by Interrupt routine ;
448;-----------------------------------------------------------------------;
449STRATEGY PROC FAR
450 MOV CS:RH_PTRO,BX ;offset
451 MOV CS:RH_PTRS,ES ;segment
452 RET
453STRATEGY ENDP
454;-----------------------------------------------------------------------;
455; Table of command processing routine entry points ;
456;-----------------------------------------------------------------------;
457CMD_TABLE LABEL WORD
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
473MAX_CMD EQU ($-CMD_TABLE)/2 ;highest valid command follows
474 DW OFFSET REMOVABLE_MEDIA ;15 - Removable media
475
476;-----------------------------------------------------------------------;
477; Device "interrupt" entry point ;
478;-----------------------------------------------------------------------;
479IRPT PROC FAR ;device interrupt entry point
480 PUSH DS ;save all registers modified
481 PUSH ES
482 PUSH AX
483 PUSH BX
484 PUSH CX
485 PUSH DX
486 PUSH DI
487 PUSH SI
488 ;BP isn't used, so it isn't saved
489 CLD ;all moves forward
490
491 LDS BX,CS:RH_PTRA ;get RH address passed to "strategy" into DS:BX
492
493 MOV AL,RH.RHC_CMD ;command code from Request Header
494 CBW ;zero AH (if AL > 7FH, next compare will
495 ;catch that error)
496
497 CMP AL,MAX_CMD ;if command code is too high
498 JA IRPT_CMD_HIGH ;jump to error routine
499
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"
503
504 ADD AX,AX ;double command code for table offset
505 MOV DI,AX ;put into index register for JMP
506
507 XOR AX,AX ;initialize return to "no error"
508
509;At entry to command processing routine:
510
511; DS:BX = Request Header address
512; CS = VDISK code segment address
513; AX = 0
514
515; top of stack is return address, IRPT_CMD_EXIT
516
517 JMP CS:CMD_TABLE[DI] ;call routine to handle the command
518
519
520IRPT_CMD_ERROR: ;CALLed for unsupported character mode commands
521
522INPUT_IOCTL: ;IOCTL input
523INPUT_NOWAIT: ;Non-destructive input no wait
524INPUT_STATUS: ;Input status
525INPUT_FLUSH: ;Input flush
526
527OUTPUT_IOCTL: ;IOCTL output
528OUTPUT_STATUS: ;Output status
529OUTPUT_FLUSH: ;Output flush
530
531 POP AX ;pop return address off stack
532
533IRPT_CMD_HIGH: ;JMPed to if RHC_CMD > MAX_CMD
534 MOV AX,STAT_CMDERR ;"invalid command" and error
535
536IRPT_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
542 POP DI
543 POP DX
544 POP CX
545 POP BX
546 POP AX
547 POP ES
548 POP DS
549 RET
550IRPT ENDP
551
552 SUBTTL Command Processing routines
553 PAGE
554;-----------------------------------------------------------------------;
555; Command Code 1 - Media Check ;
556; At entry, DS:BX point to request header, AX = 0 ;
557;-----------------------------------------------------------------------;
558MEDIA_CHECK PROC
559 MOV RH.RH1_RET,1 ;indicate media not changed
560 RET ;AX = zero, no error
561MEDIA_CHECK ENDP
562;-----------------------------------------------------------------------;
563; Command Code 2 - Build BPB ;
564; At entry, DS:BX point to request header, AX = 0 ;
565;-----------------------------------------------------------------------;
566BLD_BPB PROC
567 MOV RH.RH2_BPBO,OFFSET BPB ;return pointer to our BPB
568 MOV RH.RH2_BPBS,CS
569 RET ;AX = zero, no error
570BLD_BPB ENDP
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;-----------------------------------------------------------------------;
577REMOVABLE_MEDIA PROC
578 MOV AX,STAT_BUSY ;set status bit 9 (busy)
579 ;indicating non-removable media
580DEVICE_OPEN: ;NOP for device open
581DEVICE_CLOSE: ;NOP for device close
582 RET
583REMOVABLE_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;-----------------------------------------------------------------------;
590INOUT PROC
591INPUT:
592OUTPUT:
593OUTPUT_VERIFY:
594;;;;; PUSH DS ;ICE
595;;;;; push bx ;ICE
596;;;;; push ax ;ICE
597
598;;;;; mov bx,0140H ;ICE
599;;;;; xor ax,ax ;ICE
600;;;;; mov ds,ax ;ICE
601;;;;; mov ax,word ptr ds:[bx] ;ICE
602;;;;; mov word ptr ds:[bx],ax ;ICE
603
604;;;;; pop ax ;ICE
605;;;;; pop bx ;ICE
606;;;;; POP DS ;ICE
607
608;Make sure I/O is entirely within the VDISK sector boundaries
609
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
614
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
618
619INOUT_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
623
624INOUT_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
627
628 MOV CS:SECT_LEFT_IN_FRAME,AX ;AN000; Save as sectors left to process
629
630 CMP CS:EM_SW,0 ;extended memory mode?
631 JNE INOUT_EM ;jump to extended memory I/O code
632
633;Compute offset and segment of VDISK buffer for starting segment in CX:SI
634
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
640
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
643;sectors.
644
645 MOV AX,PARA_SIZE ;16
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
651 ;AX:DX = DTA address
652
653;AX:DX is caller's DTA segment:offset, CX:SI is VDISK buffer segment:offset
654
655;If this is an OUTPUT request, exchange the source and target addresses
656
657 CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
658 JE INOUT_B ;jump if INPUT operation
659
660 XCHG AX,CX ;swap source and target segment
661 XCHG DX,SI ;swap source and target offset
662
663INOUT_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
668
669 JMP SHORT INOUT_E ;AX := SECT_LEFT, test for zero
670INOUT_C: ;SECT_LEFT in AX, non-zero
671
672; Compute number of sectors to transfer in a single move,
673; AX = minimum of (SECT_LEFT, MAX_CNT)
674
675; MAX_CNT is the maximum number of sectors that can be moved without
676; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
677
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
681
682 MOV AX,CX ;else move MAX_CNT sectors
683INOUT_D:
684
685 CALL INOUT_D_LOW_MEM ;AN000;LOW MEMORY TRANSFER
686
687;Determine if more sectors need to be transferred
688
689INOUT_E: ;do while SECT_LEFT <> zero
690 MOV AX,CS:SECT_LEFT ;get sectors left to transfer
691 OR AX,AX ;set flags
692 JNZ INOUT_C ;go back to transfer some sectors
693 RET ;AX = zero, all sectors transferred
694
695 SUBTTL Extended Memory I/O routine
696 PAGE
697;-----------------------------------------------------------------------;
698; Extended Memory I/O routine ;
699;-----------------------------------------------------------------------;
700INOUT_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
705 MOV AX,CS
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
711
712 MOV SI,RH.RH4_DTAO ;caller's DTA offset
713
714
715 CMP EM_SW,EM_Mem ;AC005; Is EM requested?
716 JE INOUT_EM_A ;AN000;
717 JMP INOUT_EMS ;AN000; Yes, compute page
718
719INOUT_EM_A: ;AN000; No, compute 24-bit address
720
721;Compute 24-bit address of VDISK sector in CX (hi) and SI (low)
722
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
729
730;Compute 24-bit address of caller's DTA in DX (hi) and AX (low)
731
732 MOV AX,PARA_SIZE ;16
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
736
737;Caller's DTA address is in CX,SI, VDISK buffer address is in DX,AX.
738
739;If this is an OUTPUT request, exchange the source and target addresses
740
741 CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
742 JE INOUT_EM_B ;jump if INPUT operation
743
744 XCHG DX,CX ;swap source and target high byte
745 XCHG AX,SI ;swap source and target low word
746
747INOUT_EM_B: ;CX,SI is source, DX,AX is target
748
749 MOV SRC.DESC_BASEL,SI ;low 16 bits of source address
750 MOV SRC.DESC_BASEH,CL ;high 8 bits of source address
751
752 MOV TGT.DESC_BASEL,AX ;low 16 bits of target address
753 MOV TGT.DESC_BASEH,DL ;high 8 bits of target address
754
755 JMP SHORT INOUT_EM_E ;AX := SECT_LEFT, test for zero
756INOUT_EM_C: ;SECT_LEFT in AX, non-zero
757
758; Compute number of sectors to transfer in a single move,
759; AX = minimum of (SECT_LEFT, MAX_CNT)
760
761; MAX_CNT is the maximum number of sectors that can be moved without
762; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
763
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
767
768 MOV AX,CX ;else move MAX_CNT sectors
769INOUT_EM_D:
770 SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
771
772;Move AX sectors from source to target
773
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)
777 MOV SRC.DESC_LMT,AX
778
779 PUSH AX ;preserve byte count on stack
780
781 SHR AX,1 ;/2 = word count
782 MOV CX,AX ;word count to CX
783
784 PUSH CS
785 POP ES ;set ES = CS
786 MOV SI,OFFSET GDT ;ES:SI point to GDT
787
788 MOV AH,EM_BLKMOVE ;function is block move
789 INT EM_INT ;move an even number of words
790
791 POP CX ;get byte count back from stack
792
793 OR AH,AH ;get error code
794
795 JZ INOUT_UPDATE ;
796 JMP INOUT_EM_XE ;jump if I/O error encountered
797
798INOUT_UPDATE:
799
800;Update source and target addresses
801
802 ADD SRC.DESC_BASEL,CX ;add bytes moved to source
803 ADC SRC.DESC_BASEH,0 ;pick up any carry
804
805 ADD TGT.DESC_BASEL,CX ;add bytes moved to target
806 ADC TGT.DESC_BASEH,0 ;pick up any carry
807
808;Determine if more sectors need to be transferred
809
810INOUT_EM_E: ;do while SECT_LEFT <> zero
811 MOV AX,CS:SECT_LEFT ;get sectors left to transfer
812 OR AX,AX ;set flags
813 JNZ INOUT_EM_C ;go back to transfer some sectors
814
815 JMP INOUT_EM_X2 ;AN000; All done . . . exit
816;-----------------------------------------------------------------------;
817; EMS Support ;RPS; ;
818;-----------------------------------------------------------------------;
819
820INOUT_EMS: ;AN000;
821
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;
833
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
840 INT EMS_INT ;AN000;
841
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
849
850; Compute offset and segment of VDISK frame for starting segment in CX:SI
851; and page containing VDISK starting sector
852
853 push ds ;an000; dms;save ds
854 push es ;an000; dms;save es
855
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
862
863; $do ;an000; dms;while sectors left
864$$DO4:
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
870 JE $$EN4
871 ; yes - continue
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
877 JMP SHORT $$DO4
878$$EN4:
879
880 pop es ;an000; dms;restore es
881 pop ds ;an000; dms;restore ds
882
883; Restore EMS state in case anyone was using it
884 ;AN000; No,
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
890
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
895 INT EMS_INT ;AN000;
896
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
902
903;-----------------------------------------------------------------------;
904
905INOUT_EM_X2: ;revert to original stack
906 POP DI ;get old SP
907 POP SI ;get old SS
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
913
914INOUT_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
919INOUT ENDP
920
921
922;=========================================================================
923; EMS_PAGE_OFF_CALC : Calculates the current ems page to use and
924; the offset of the requested sector in that
925; page.
926;
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
931;
932; Outputs: CURR_EMS_PAGE - Currently active ems page
933; CX:SI - Segment:Offset of logical sector
934;=========================================================================
935
936ems_page_off_calc proc near ;an000; dms;calc page/offset
937
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
945
946 ret ;an000; dms;
947
948ems_page_off_calc endp ;an000; dms;
949
950
951;=========================================================================
952; EMS_DTA_CALC : Calculate the DTA buffer to be used.
953;
954; Inputs: PARA_SIZE - 16
955; RH4_DTAS - Segment of DTA from request packet
956; RH4_DTA0 - Offset of DTA from request packet
957; WPARA_SIZE- 16
958;
959; Outputs: AX:DX - Segment:Offset of DTA buffer
960;=========================================================================
961
962ems_dta_calc proc near ;an000; dms;calc DTA buffer
963
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
970
971 ret ;an000; dms;
972
973ems_dta_calc endp ;an000; dms;
974
975
976;=========================================================================
977; EMS_DTA_ADJ : Adjust DTA for the number of sectors having
978; been transferred.
979;
980; External Calls : EMS_DTA_CALC
981;
982; Inputs: CURR_DTA_OFF - Current offset value to be adjusted.
983;
984; Outputs: CURR_DTA_OFF - Adjusted offset value into DTA
985; DX - Adjusted offset value into DTA
986;=========================================================================
987
988ems_dta_adj proc near ;an000; dms;adjust DTA
989
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
997 ret ;an000; dms;
998
999ems_dta_adj endp ;an000; dms;
1000
1001;=========================================================================
1002; EMS_SRC_TGT : Determine the source and target segments for
1003; data transfer.
1004;
1005; Inputs: RHC_CMD - Request packet command identifier
1006; AX:DX - DTA
1007; CX:SI - EMS page/sector
1008;
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;=========================================================================
1014
1015ems_src_tgt proc near ;an000; dms;src/tgt calc
1016
1017 cmp rh.rhc_cmd,cmd_input ;an000; dms;input/output?
1018; $if ne ;an000; dms;
1019 JE $$IF7
1020 xchg ax,cx ;an000; dms;swap src/tgt seg
1021 xchg dx,si ;an000; dms;swap src/tgt off
1022; $endif ;an000; dms;
1023$$IF7:
1024
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
1029 ret ;an000; dms;
1030
1031ems_src_tgt endp ;an000; dms;
1032
1033
1034;=========================================================================
1035; EMS_TRF : Perform the sector transfer of data.
1036;
1037; Inputs: BPB_SSZ - Sector size
1038; IO_SRCA - Source address
1039; IO_TGTA - Target address
1040;
1041; Outputs: Transferred data
1042; EMS_CURR_SECT - Incremented 1
1043;=========================================================================
1044
1045ems_trf proc near ;an000; dms;transfer data
1046
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;
1052
1053 lds si,cs:io_srca ;an000; dms;get src address
1054 les di,cs:io_tgta ;an000; dms;get tgt address
1055
1056 CMP CS:PC_386,TRUE ;AN000; DO WE HAVE A 386 MACHINE?
1057; $IF E ;AN000; YES
1058 JNE $$IF9
1059 SHR CX,1 ;AN000; /2 = DW COUNT
1060 DB 66H ;AN000; SIMULATE A MOVSDW
1061; $ENDIF ;AN000;
1062$$IF9:
1063 rep movsw ;an000; dms;perform transfer
1064
1065 pop es ;an000; dms;restore regs
1066 pop ds ;an000; dms;
1067 inc cs:ems_curr_sect ;an000; dms;increment sector
1068
1069 ret ;an000; dms;
1070
1071ems_trf endp ;an000; dms;
1072
1073
1074
1075MAP_FRAME PROC NEAR ;AN000;
1076
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
1082 INT EMS_INT ;AN000;
1083 POP BX ;AN000; DMS;
1084 RET ;AN000;
1085
1086MAP_FRAME ENDP ;AN000;
1087
1088
1089INOUT_D_LOW_MEM PROC NEAR ;AN000; LOW MEMORY TRANSFER
1090
1091 SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
1092
1093;Move AX sectors from source to target
1094
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
1099
1100 LDS SI,CS:IO_SRCA ;source segment/offset to DS:SI
1101 LES DI,CS:IO_TGTA ;target segment/offset to ES:DI
1102
1103 CMP CS:PC_386,TRUE ;AN000; DO WE HAVE A 386 MACHINE?
1104; $IF E ;AN000; YES
1105 JNE $$IF11
1106 SHR CX,1 ;AN000; /2 = DW COUNT
1107 DB 66H ;AN000; SIMULATE A MOVSDW
1108; $ENDIF ;AN000;
1109$$IF11:
1110 REP MOVSW ;AN000; PERFORM DOUBLE WORD MOVE
1111
1112;Update source and target paragraph addresses
1113;AX has number of words moved
1114
1115 SHR AX,1 ;words moved / 8 = paragraphs moved
1116 SHR AX,1
1117 SHR AX,1
1118
1119 ADD CS:IO_SRCS,AX ;add paragraphs moved to source segment
1120 ADD CS:IO_TGTS,AX ;add paragraphs moved to target segment
1121
1122 RET
1123
1124INOUT_D_LOW_MEM ENDP
1125
1126
1127
1128 DW 40 DUP (?) ;stack for extended memory I/O
1129EM_STACK LABEL WORD
1130
1131 SUBTTL Boot Record
1132 PAGE
1133;-----------------------------------------------------------------------;
1134; Adjust the assembly-time instruction counter to a paragraph ;
1135; boundary ;
1136;-----------------------------------------------------------------------;
1137
1138 IF ($-START) MOD 16
1139 ORG ($-START) + 16 - (($-START) MOD 16)
1140 ENDIF
1141
1142VDISK EQU $ ;start of virtual disk buffer
1143VDISKP 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. ;
1147; ;
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;-----------------------------------------------------------------------;
1153
1154BOOT_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
1158BOOT_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
1168
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.
1178
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.
1183
1184;For example, if two VDISKs are installed, one 320KB and one 64KB, the
1185;address calculations are as follows:
1186
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)
1196
1197;-----------------------------------------------------------------------;
1198; Part 2 of Initialization (executed last) ;
1199;-----------------------------------------------------------------------;
1200;Initialization is divided into two parts.
1201
1202;INIT_P1 is overlaid by the virtual disk buffer
1203
1204;INIT_P1 is executed first, then jumps to INIT_P2. INIT_P2 returns to caller.
1205
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.
1213
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
1221
1222INIT_P2 PROC ;second part of initialization
1223 ASSUME DS:CSEG ;DS set in INIT_P1
1224
1225;Initialize File Allocation Table(s) (FATs)
1226
1227INIT_P2_FAT: ;set up one FAT, sector number in AX
1228
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
1233 STOSW
1234
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
1238
1239 POP CX ;get loop counter off stack
1240 LOOP INIT_P2_FAT ;loop for all copies of the FAT
1241
1242;Put the volume label in the first directory entry
1243
1244 MOV CX,VOL_LABEL_LEN ;length of volume directory entry
1245 REP MOVSB ;move volume id to directory
1246
1247;Zero the remainder of the directory
1248
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
1253 XOR AX,AX
1254 REP STOSB ;clear directory to nulls
1255 RET ;return with AX=0
1256INIT_P2 ENDP
1257
1258PATCH_AREA DB 5 DUP ('PATCH AREA ')
1259TEST_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;-----------------------------------------------------------------------;
1265 DB ' '
1266 DB ' '
1267 DB ' '
1268
1269MAXSEC_TRF DW 0 ;maximum number of sectors to transfer when
1270 ;in extended memory
1271
1272BUFF_SIZE DW 0 ;desired VDISK buffer size in kilobytes
1273
1274MIN_MEMORY_LEFT DW 100 ;minimum amount of system memory (kilobytes)
1275 ;that must remain after VDISK is installed
1276
1277PARA_PER_KB DW 1024/PARA_SIZE ;paragraphs in one kilobyte
1278C1024 DW 1024 ;bytes in one kilobyte
1279DIRE_SIZE DW DIR_ENTRY_SIZE ;bytes in one directory entry
1280DIR_SECTORS DW ? ;number of sectors of directory
1281
1282ERR_FLAG DB 0 ;error indicators to condition messages
1283ERR_BSIZE EQU 80H ;buffer size adjusted
1284ERR_SSZ EQU 40H ;sector size adjusted
1285ERR_DIRN EQU 20H ;number of directory entries adjusted
1286ERR_PASS EQU 10H ;some adjustment made that requires
1287 ;recomputation of values previously computed
1288ERR_SSZB EQU ERR_SSZ+ERR_PASS ;sector size altered this pass
1289ERR_SYSSZ EQU 08H ;system storage too small for VDISK
1290ERR_SWTCH EQU 04H ;invalid switch character
1291ERR_EXTSW EQU 02H ;extender card switches don't match memory size
1292ERR_ESIZE EQU 01H ;Transfer size adjusted
1293
1294DOS_PG_SZ DB DOS_PAGE_SZ ;AN000;
1295DOS_Page_Size_Word dw DOS_Page_Sz ;an000;
1296
1297err_flag2 db 0
1298err_baddos equ 01h ; Invalid DOS Version
1299
1300;-----------------------------------------------------------------------;
1301; SUBLIST definitions and EQUATES for Message Retreiver ;
1302;-----------------------------------------------------------------------;
1303 ;AN000; Message Number
1304INCORRECT_DOS EQU 1 ;AN000;
1305SYS_TOO_SMALL EQU 2 ;AN000;
1306VDISK_TITLE EQU 3 ;AN000;
1307BUFFER_ADJUSTED EQU 4 ;AN000;
1308SECTOR_ADJUSTED EQU 5 ;AN000;
1309DIR_ADJUSTED EQU 6 ;AN000;
1310INVALID_SW_CHAR EQU 7 ;AN000;
1311TRANS_ADJUSTED EQU 8 ;AN000;
1312BUF_SZ EQU 9 ;AN000;
1313SEC_SZ EQU 10 ;AN000;
1314DIR_ENTRIES EQU 11 ;AN000;
1315TRANS_SZ EQU 12 ;AN000;
1316VDISK_NOT_INST EQU 13 ;AN000;
1317EXTEND_CARD_WRONG EQU 14 ;AN000;
1318
1319NO_REPLACE EQU 0 ;AN000; CX = 0 -> No replacement
1320ONE_REPLACE EQU 1 ;AN000; CX = 1 -> One replacement
1321UNLIMITED_MAX EQU 0 ;AN000; MAX field - unlimited
1322SMALLEST_MIN EQU 1 ;AN000; MIN field - 1 character long
1323PAD_BLANK EQU 20H ;AN000; PAD character is a blank
1324
1325
1326DRIVE_CODE DB ? ;AN000;
1327 DB ":",NULL ;AN000; ASCIIZ string for drive code
1328
1329; For the message: "VDISK Version 4.00 virtual disk %1",CR,LF
1330
1331TITLE_SUBLIST LABEL BYTE
1332
1333TT_SIZE DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1334TT_RESV DB 0 ;AN000; RESERVED
1335TT_VALUEO DW DRIVE_CODE ;AN000; Offset to ASCIIZ string
1336TT_VALUES DW ? ;AN000; SEGMENT TO ASCIIZ STRING
1337TT_ID DB 1 ;AN000; n of %n
1338TT_FLAG DB Left_Align+Char_Field_ASCIIZ
1339TT_MAXW DB UNLIMITED_MAX ;AN000; Maximum field width
1340TT_MINW DB SMALLEST_MIN ;AN000; Minimum field width
1341TT_PAD DB PAD_BLANK ;AN000; Character for Pad field
1342
1343; For the message: "Buffer size: %1 KB",CR,LF
1344
1345BUF_SZ_SUBLIST LABEL BYTE
1346
1347B_SIZE DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1348B_RESV DB 0 ;AN000; RESERVED
1349B_VALUEO DW BUFF_SIZE ;AN000; Offset to binary number
1350B_VALUES DW ? ;AN000; SEGMENT TO BINARY NUMBER
1351B_ID DB 1 ;AN000; n of %n
1352B_FLAG DB Left_Align+Unsgn_Bin_Word
1353B_MAXW DB UNLIMITED_MAX ;AN000; Maximum field width
1354B_MINW DB SMALLEST_MIN ;AN000; Minimum field width
1355B_PAD DB PAD_BLANK ;AN000; Character for Pad field
1356
1357; For the message: "Sector size: %1",CR,LF
1358
1359SEC_SZ_SUBLIST LABEL BYTE
1360
1361S_SIZE DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1362S_RESV DB 0 ;AN000; RESERVED
1363S_VALUEO DW BPB_SSZ ;AN000; Offset to binary number
1364S_VALUES DW ? ;AN000; SEGMENT TO BINARY NUMBER
1365S_ID DB 1 ;AN000; n of %n
1366S_FLAG DB Left_Align+Unsgn_Bin_Word
1367S_MAXW DB UNLIMITED_MAX ;AN000; Maximum field width
1368S_MINW DB SMALLEST_MIN ;AN000; Minimum field width
1369S_PAD DB PAD_BLANK ;AN000; Character for Pad field
1370
1371; For the message: "Directory entries: %1",CR,LF
1372
1373DIR_ENT_SUBLIST LABEL BYTE
1374
1375D_SIZE DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1376D_RESV DB 0 ;AN000; RESERVED
1377D_VALUEO DW BPB_DIRN ;AN000; Offset to binary number
1378D_VALUES DW ? ;AN000; SEGMENT TO BINARY NUMBER
1379D_ID DB 1 ;AN000; n of %n
1380D_FLAG DB Left_Align+Unsgn_Bin_Word
1381D_MAXW DB UNLIMITED_MAX ;AN000; Maximum field width
1382D_MINW DB SMALLEST_MIN ;AN000; Minimum field width
1383D_PAD DB PAD_BLANK ;AN000; Character for Pad field
1384
1385; For the message: "Transfer size: %1",CR,LF
1386
1387TRANS_SZ_SUBLIST LABEL BYTE
1388
1389T_SIZE DB 11 ;AN000; SUBLIST size (PTR to next SUBLIST)
1390T_RESV DB 0 ;AN000; RESERVED
1391T_VALUEO DW MAXSEC_TRF ;AN000; Offset to binary number
1392T_VALUES DW ? ;AN000; SEGMENT TO BINARY NUMBER
1393T_ID DB 1 ;AN000; n of %n
1394T_FLAG DB Left_Align+Unsgn_Bin_Word
1395T_MAXW DB UNLIMITED_MAX ;AN000; Maximum field width
1396T_MINW DB SMALLEST_MIN ;AN000; Minimum field width
1397T_PAD DB PAD_BLANK ;AN000; Character for Pad field
1398
1399;-----------------------------------------------------------------------;
1400; EMS Support ;
1401;-----------------------------------------------------------------------;
1402
1403FRAME_BUFFER DB 10 DUP(0) ;AN000;
1404VDISK_Name db "VDISK " ;an000; dms;
1405
1406four DB 4
1407
1408
1409 SUBTTL Initialization, Part one
1410 PAGE
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.
1417
1418INIT_P1 PROC ;first part of initialization
1419
1420;;;;; PUSH DS ;ICE
1421;;;;; push bx ;ICE
1422;;;;; push ax ;ICE
1423
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
1429
1430;;;;; pop ax ;ICE
1431;;;;; pop bx ;ICE
1432;;;;; POP DS ;ICE
1433
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
1438 MOV SS,AX
1439 MOV SP,OFFSET MSGEND ;end of VDISKMSG
1440 ADD SP,STACK_SIZE ;+ length of our stack
1441
1442 STI ;allow interrupts
1443
1444 PUSH DX ;save old SS register on new stack
1445 PUSH CX ;SAVE OLD SP REGISTER ON NEW STACK
1446
1447
1448
1449 PUSH DS ;AN000;SAVE REGS
1450 PUSH ES ;AN000;
1451
1452 PUSH CS ;AN000;TRANSFER TO DS
1453 POP DS ;AN000;
1454 PUSH CS ;AN000;
1455 POP ES ;AN000;
1456
1457 ASSUME DS:CSEG,ES:CSEG ;AN000;
1458
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
1462
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
1469
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
1476
1477VDISK_CONTINUE_1: ;AN000;
1478
1479 POP ES ;AN000;RESTORE REGS
1480 POP DS ;AN000;
1481 ASSUME DS:NOTHING,ES:NOTHING ;AN000;
1482
1483 CALL PC_386_CHK ;AN000;SEE IF WE HAVE A 386 PC
1484 ; Yes, continue
1485 CALL GET_PARMS ;get parameters from CONFIG.SYS line
1486
1487 PUSH CS
1488 POP DS ;set DS = CS
1489 ASSUME DS:CSEG,ES:CSEG
1490
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
1495
1496 CALL VERIFY_EXTENDER ;Verify that extender card switches are right
1497
1498 TEST ERR_FLAG,ERR_EXTSW ;are switches wrong?
1499 JNZ INIT_P1_A ;if so, exit with messages
1500
1501 test cs:err_flag2,err_baddos
1502 jnz init_p1_a
1503
1504 CMP EM_SW,0 ;EXTENDED MEMORY REQUEST?
1505 JE INIT_P1_A ;jump if not
1506
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
1509
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
1517
1518INIT_P1_A:
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. ;
1531; ;
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
1539
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
1543
1544 MOV BL,BPB_MCB ;media control byte
1545
1546 MOV CL,BPB_FATN ;number of FAT copies
1547 XOR CH,CH
1548
1549 MOV AX,BPB_FATSZ ;FAT size in sectors
1550 MUL BPB_SSZ ;* sector size = total FAT bytes
1551
1552 SUB AX,3 ;-3 (FEFFFF stored by code)
1553 MOV DX,AX
1554
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
1559
1560
1561
1562 SUBTTL PC_386_CHK
1563 PAGE
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.
1569;
1570; INPUTS : NONE
1571;
1572; OUTPUTS : PC_386 - FLAG SIGNALS IF WE ARE ON A 386 MACHINE.
1573;=========================================================================
1574
1575PC_386_CHK PROC NEAR ;AN000;DETERMINE MACHINE TYPE
1576
1577 PUSH AX ;AN000;SAVE AFFECTED REGS
1578 PUSH BX ;AN000;
1579 PUSH ES ;AN000;
1580
1581 MOV CS:PC_386,FALSE ;AN000;INITIALIZE TO FALSE
1582
1583 MOV AH,0C0H ;AN000;RETURN SYSTEM CONFIGURATION
1584 INT 15H ;AN000;
1585
1586; $IF NC ;AN000;IF A GOOD RETURN
1587 JC $$IF13
1588 CMP AH,0 ;AN000;IS IT NEW FORMAT FOR CONFIG.
1589; $IF E ;AN000;YES
1590 JNE $$IF14
1591 MOV AL,ES:[BX.BIOS_SD_MODELBYTE] ;AN000;CHECK MODEL
1592 CMP AL,0F8H ;AN000;IS IT A 386 MACHINE?
1593; $IF E ;AN000;YES
1594 JNE $$IF15
1595 MOV CS:PC_386,TRUE ;AN000;SIGNAL A 386
1596; $ENDIF ;AN000;
1597$$IF15:
1598; $ENDIF ;AN000;
1599$$IF14:
1600; $ENDIF ;AN000;
1601$$IF13:
1602
1603 POP ES ;AN000;RESTORE REGS.
1604 POP BX ;AN000;
1605 POP AX ;AN000;
1606
1607 RET ;AN000;
1608
1609PC_386_CHK ENDP ;AN000;
1610
1611
1612 SUBTTL GET_PARMS Parameter Line Scan
1613 PAGE
1614;-----------------------------------------------------------------------;
1615;GET_PARMS gets the parameters from the CONFIG.SYS statement ;
1616; ;
1617;Register usage: ;
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
1623GET_PARMS PROC ;get parameters from CONFIG.SYS line
1624 PUSH DS ;save DS
1625 LDS SI,RH.RH0_BPBA ;DS:SI point to all after DEVICE=
1626 ;in CONFIG.SYS line
1627 XOR AL,AL ;not at end of line
1628
1629;Skip until first delimiter is found. There may be digits in the path string.
1630
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.
1634
1635GET_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
1639 JZ GET_PARMS_C ;
1640 CMP AL,' '
1641 JE GET_PARMS_C ;
1642 CMP AL,','
1643 JE GET_PARMS_C ;
1644 CMP AL,';'
1645 JE GET_PARMS_C ;
1646 CMP AL,'+'
1647 JE GET_PARMS_C ;
1648 CMP AL,'='
1649 JE GET_PARMS_C ;
1650 CMP AL,TAB
1651 JNE GET_PARMS_A ;skip until delimiter or CR
1652
1653
1654
1655GET_PARMS_C:
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
1659
1660GET_PARMS_D: ;scan for /
1661 CALL GET_PCHAR
1662 JZ GET_PARMS_B ;exit if end of line
1663
1664GET_SLASH: ;check for slash
1665 CMP AL,'/' ;found slash?
1666 JNE GET_PARMS_D ;no, continue scan
1667
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;
1676 ;AN005;
1677CHECK_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;
1684 ;AN005;
1685GOT_E_OR_X: ;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 ':'
1689
1690
1691 CALL GET_MAXSIZE ;get maximum sector size
1692
1693
1694 JMP GET_PARMS_D ;continue forward scan
1695
1696GET_PARMS_E: ;/ found, not 'E'
1697 OR CS:ERR_FLAG,ERR_SWTCH ;indicate invalid switch character
1698 JMP GET_PARMS_D ;continue scan
1699
1700
1701
1702GET_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
1707
1708Get_Parms_X_Exit:
1709
1710 JZ GET_PARMS_X ;found EOL, no digits remain
1711
1712 CALL GET_NUMBER ;extract digits, convert to binary
1713 MOV CS:BUFF_SIZE,CX ;store buffer size
1714
1715 CALL SKIP_TO_DIGIT ;skip to next digit
1716 JZ GET_PARMS_X ;found EOL, no digits remain
1717
1718 CALL GET_NUMBER ;extract digits, convert to binary
1719 MOV CS:BPB_SSZ,CX ;store sector size
1720
1721 CALL SKIP_TO_DIGIT ;skip to next digit
1722 JZ GET_PARMS_X ;found EOL, no digits remain
1723
1724 CALL GET_NUMBER ;extract digits, convert to binary
1725 MOV CS:BPB_DIRN,CX ;store number of directory entries
1726
1727
1728
1729GET_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;
1732 JZ $$IF19
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;
1736$$IF19:
1737 POP DS ;restore DS
1738 RET
1739
1740
1741GET_MAXSIZE PROC ;get maximum sector size
1742
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
1747 RET ;
1748GET_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
1751 RET
1752GET_MAXSIZE ENDP
1753
1754
1755
1756GET_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?
1765GET_PCHAR_X: ;attempted read past end of line
1766 RET
1767GET_PCHAR ENDP ;returns char in AL
1768
1769
1770CHECK_NUM PROC ;check AL for ASCII digit
1771 CMP AL,'0' ;< '0'?
1772 JB CHECK_NUM_X ;exit if it is
1773
1774 CMP AL,'9' ;> '9'?
1775 JA CHECK_NUM_X ;exit if it is
1776
1777 CMP AL,AL ;set Z flag to indicate numeric
1778CHECK_NUM_X:
1779 RET ;Z set if numeric, NZ if not numeric
1780CHECK_NUM ENDP
1781
1782
1783SKIP_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
1786
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
1790
1791SKIP_TO_DIGIT_X:
1792 CMP AL,0 ;digit found, force NZ
1793 RET
1794SKIP_TO_DIGIT ENDP
1795
1796C10 DW 10
1797GN_ERR DB ? ;zero if no overflow in accumulation
1798
1799GET_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
1802GET_NUMBER_A: ;accumulate next digit
1803 SUB AL,'0' ;convert ASCII to binary
1804 CBW ;clear AH
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
1812 MOV [SI],AL ;
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
1820GET_NUMBER_B:
1821 RET ;number in CX, next char in AL
1822GET_NUMBER ENDP
1823
1824GET_PARMS ENDP
1825
1826 SUBTTL APPLY_DEFAULTS
1827 PAGE
1828;-----------------------------------------------------------------------;
1829; APPLY_DEFAULTS supplies any parameter values that the user ;
1830; failed to specify ;
1831;-----------------------------------------------------------------------;
1832 ASSUME DS:CSEG
1833APPLY_DEFAULTS PROC
1834 XOR AX,AX
1835 CMP BUFF_SIZE,AX ;is buffer size zero?
1836 JNE APPLY_DEFAULTS_A ;no, user specified something
1837
1838 MOV BUFF_SIZE,DFLT_BSIZE ;supply default buffer size
1839 OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted
1840
1841APPLY_DEFAULTS_A:
1842 CMP BPB_SSZ,AX ;is sector size zero?
1843 JNE APPLY_DEFAULTS_B ;no, user specified something
1844
1845 MOV BPB_SSZ,DFLT_SSZ ;supply default sector size
1846 OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted
1847
1848APPLY_DEFAULTS_B:
1849 CMP BPB_DIRN,AX ;are directory entries zero?
1850 JNE APPLY_DEFAULTS_C ;no, user specified something
1851
1852 MOV BPB_DIRN,DFLT_DIRN ;supply default directory entries
1853 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
1854
1855APPLY_DEFAULTS_C: ;
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
1860
1861 MOV MAXSEC_TRF,DFLT_ESS ;supply default maximum number of
1862 ;sector to transfer
1863 OR ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted
1864APPLY_DEFAULTS_D:
1865 RET
1866APPLY_DEFAULTS ENDP
1867
1868 SUBTTL DETERMINE_START address of VDISK buffer
1869 PAGE
1870;-----------------------------------------------------------------------;
1871; DETERMINE_START figures out the starting address of the VDISK ;
1872; buffer ;
1873;-----------------------------------------------------------------------;
1874 ASSUME DS:CSEG
1875DETERMINE_START PROC
1876
1877;If extended memory is NOT being used, the VDISK buffer immediately
1878;follows the resident code.
1879
1880;If extended memory IS being used, START_BUFFER_PARA becomes the
1881;end of device driver address passed back to DOS.
1882
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
1886
1887 CMP EM_SW,0 ;IS EXTENDED MEMORY REQUESTED?
1888 JE DETERMINE_START_X ;if not, we're done here
1889
1890;-----------------------------------------------------------------------;AN000;
1891;If EMS is not installed, the calculation to determine the starting address
1892;of the VDISK will remain the same.
1893
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;
1897
1898 cmp EM_SW,EMS_Mem ;EMS requested? ;an005; dms;
1899 je Determine_Start_X ;yes - leave routine ;an005; dms;
1900 ;no - continue routine
1901
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
1908
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
1912
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
1917
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
1920
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
1923
1924DETERMINE_START_X:
1925
1926 RET
1927DETERMINE_START ENDP
1928
1929 SUBTTL VALIDATE parameters
1930 PAGE
1931;-----------------------------------------------------------------------;
1932; VALIDATE adjusts parameters as necessary ;
1933;-----------------------------------------------------------------------;
1934VAL_SSZ_TBL LABEL WORD ;table of valid sector sizes
1935VAL_SSZ_S DW 128 ;smallest valid sector size
1936 DW 256
1937VAL_SSZ_L DW 512 ;largest valid sector size
1938VAL_SSZ_N EQU ($-VAL_SSZ_TBL)/2 ;number of table entries
1939
1940 ASSUME DS:CSEG
1941VALIDATE PROC ;validate parameters
1942;;ice PUSH DS ;ICE
1943;;ice push bx ;ICE
1944;;ice push ax ;ICE
1945
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
1951
1952;;ice pop ax ;ICE
1953;;ice pop bx ;ICE
1954;;ice POP DS ;ICE
1955 MOV BPB_AUSZ,1 ;initial allocation unit is 1 sector
1956
1957 CALL VAL_BSIZE ;validate buffer size
1958
1959 CALL VAL_SSZ ;validate (adjust if necessary) BPB_SSZ
1960
1961VALIDATE_A:
1962 AND ERR_FLAG,255-ERR_PASS ;indicate nothing changed this pass
1963
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
1968
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
1973
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
1978
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
1983
1984 CALL VAL_DIRN ;validate number of directory entries
1985
1986 TEST ERR_FLAG,ERR_PASS ;may have reset sector size
1987 JNZ VALIDATE_A ;recompute directory & FAT sizes
1988
1989 CALL VAL_FAT ;compute FAT entries, validity test
1990
1991 TEST ERR_FLAG,ERR_PASS ;if cluster size altered this pass
1992 JNZ VALIDATE_A ;recompute directory & FAT sizes
1993
1994;Make certain buffer size is large enough to contain:
1995; boot sector(s)
1996; FAT sector(s)
1997; directory sector(s)
1998; at least 1 data cluster
1999
2000 MOV AL,BPB_FATN ;number of FAT copies
2001 CBW ;clear AH
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
2010
2011 CMP DIR_SECTORS,1 ;down to 1 directory sector?
2012 JBE VALIDATE_C ;can't let it go below 1
2013
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
2018
2019 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
2020 JMP VALIDATE_A ;retry with new directory entries number
2021
2022VALIDATE_C: ;not enough space for any VDISK
2023 OR ERR_FLAG,ERR_SYSSZ
2024VALIDATE_X:
2025 RET
2026
2027 SUBTTL VAL_BSIZE Validate buffer size
2028 PAGE
2029;-----------------------------------------------------------------------;
2030; VAL_BSIZE adjusts the buffer size as necessary ;
2031;-----------------------------------------------------------------------;
2032VAL_BSIZE PROC
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
2037
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
2041 MOV BPB_SSZ,AX
2042 MOV BPB_DIRN,4 ;4 directory entries
2043 RET
2044
2045VAL_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
2048
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
2053
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
2057VAL_BSIZE_C:
2058
2059
2060 RET
2061
2062
2063GET_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
2067
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
2071
2072
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
2083 ;
2084USE_EXTENDED_SUPPORT: ;AN000; No, EMS is not installed
2085
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
2091
2092 RET
2093
2094GET_MSIZE_2: ;non-extended memory size determination
2095
2096;Compute AX = total system size, - (VDISK end address + 64KB)
2097
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
2108
2109GET_MSIZE_Z:
2110 XOR AX,AX ;indicate no memory available
2111GET_MSIZE_X: ;exit from memory size determination
2112 RET
2113GET_MSIZE ENDP
2114
2115VAL_BSIZE ENDP
2116
2117
2118
2119EMS_CHECK PROC NEAR ;AN000;
2120
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
2126
2127EMS_INSTALLED: ;AN000; Yes,
2128
2129 push es ;an000; save es - call destroys it
2130 push di ;an006; save di
2131
2132 mov ah,EMS_2F_Handler ;an006;see if our 2Fh is there
2133 xor al,al ;an006;
2134 int 2Fh ;an006;
2135 cmp al,0ffh ;an006;2Fh handler there?
2136; $if e ;an006;yes
2137 JNE $$IF21
2138 mov ah,EMS_2F_Handler ;an006;get EMS page for VDISK
2139 mov al,0FFh ;an006;
2140 mov di,0FEh ;an006;
2141 int 2Fh ;ac006;
2142
2143 or ah,ah ;an006;page available?
2144; $if z ;an006;yes
2145 JNZ $$IF22
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.
2151 JMP SHORT $$EN22
2152$$IF22:
2153 mov ah,not EMS_INSTALLED_FLAG ;an000;signal no EMS
2154 stc ;an006;flag it
2155; $endif ;an006;
2156$$EN22:
2157; $else
2158 JMP SHORT $$EN21
2159$$IF21:
2160 mov ah,not EMS_INSTALLED_FLAG ;AN000;signal no EMS
2161 stc ;an006;signal not there
2162; $endif
2163$$EN21:
2164
2165 pop di ;an006;restore di
2166 pop es ;an000;restore es
2167
2168EMS_Check_Exit:
2169
2170 RET ;AN000; Return
2171
2172EMS_CHECK ENDP ;AN000;
2173
2174
2175
2176;=========================================================================
2177; EMS_CHECK1 : THIS MODULE DETERMINES WHETHER OR NOT EMS IS
2178; INSTALLED FOR THIS SESSION.
2179;
2180; INPUTS : NONE
2181;
2182; OUTPUTS : ES:BX - FRAME ARRAY
2183; CY - EMS NOT AVAILABLE
2184; NC - EMS AVAILABLE
2185;=========================================================================
2186
2187EMS_CHECK1 PROC NEAR ;AN000;EMS INSTALL CHECK
2188
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
2195 JE $$IF27
2196 MOV AH,EMS_STATUS ;AN000;see if EMS installed
2197 XOR AL,AL ;AN000;CLEAR AL
2198 INT EMS_INT ;AN000;
2199 OR AH,AH ;AN000;EMS INSTALLED?
2200; $IF Z ;AN000;YES
2201 JNZ $$IF28
2202 MOV AH,EMS_VERSION ;AN000;GET VERSION NUMBER
2203 XOR AL,AL ;AN000;CLEAR AL
2204 INT EMS_INT ;AN000;
2205 CMP AL,EMS_VERSION_LEVEL ;AN000;CORRECT VERSION?
2206; $IF AE ;AN000;YES
2207 JNAE $$IF29
2208 CLC ;AN000;FLAG IT AS GOOD EMS
2209; $ELSE ;AN000;
2210 JMP SHORT $$EN29
2211$$IF29:
2212 STC ;AN000;BAD EMS
2213; $ENDIF ;AN000;
2214$$EN29:
2215; $ELSE ;AN000;
2216 JMP SHORT $$EN28
2217$$IF28:
2218 STC ;AN000;EMS NOT INSTALLED
2219; $ENDIF ;AN000;
2220$$EN28:
2221; $ELSE ;AN000;
2222 JMP SHORT $$EN27
2223$$IF27:
2224 STC ;AN000;EMS VECTOR NOT THERE
2225; $ENDIF ;AN000;
2226$$EN27:
2227
2228 RET ;AN000;RETURN TO CALLER
2229
2230EMS_CHECK1 ENDP ;AN000;
2231
2232
2233EMS_GET_PAGES PROC NEAR ;AN000;
2234
2235 MOV AH,EMS_GET_NUM_PAGES ;AN000; Query EMS for page count
2236 INT EMS_INT ;AN000;
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
2240 RET ;AN000;
2241
2242EMS_GET_ERROR: ;AN000;
2243 STC ;AN000;
2244 RET ;AN000;
2245
2246EMS_GET_PAGES ENDP
2247
2248 SUBTTL VAL_SSZ Validate Sector Size
2249 PAGE
2250;-----------------------------------------------------------------------;
2251; VAL_SSZ validates sector size, adjusting if necessary ;
2252;-----------------------------------------------------------------------;
2253VAL_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
2262
2263DFLT_TRF: ;set default
2264 MOV MAXSEC_TRF,DFLT_ESS ;
2265 MOV BX,MAXSEC_TRF ;
2266 OR CS:ERR_FLAG,ERR_ESIZE ;indicate transfer size adjusted
2267
2268VAL_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
2274VAL_SSZ_A:
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
2279
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
2283VAL_SSZ_X:
2284
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.
2287
2288 CMP CS:EM_SW,0 ;EXTENDED MEMORY?
2289 JNE SIZE_DONE ;yes, we are done
2290 XOR DX,DX
2291 MOV AX,0FFFFH ;64KB - 1
2292 DIV BX ;/sector size
2293 MOV MAX_CNT,AX ;max sectors in one move
2294SIZE_DONE:
2295 RET
2296VAL_SSZ ENDP
2297
2298 SUBTTL VAL_DIRN Validate number of directory entries
2299 PAGE
2300;-----------------------------------------------------------------------;
2301; VAL_DIRN validates and adjusts the number of directory entries. ;
2302; ;
2303; Minimum is MIN_DIRN, maximum is MAX_DIRN. If outside these ;
2304; limits, DFLT_DIRN is used. ;
2305; ;
2306; The number of directory entries is rounded upward to fill ;
2307; a sector ;
2308;-----------------------------------------------------------------------;
2309VAL_DIRN PROC
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
2313
2314 CMP AX,MAX_DIRN ;if <= maximum
2315 JBE VAL_DIRN_B ;accept value as provided
2316
2317VAL_DIRN_A:
2318 MOV AX,DFLT_DIRN ;use default directory entries
2319 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
2320VAL_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
2325
2326 INC AX ;increment directory sectors
2327 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
2328VAL_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
2334
2335 MOV AX,1 ;use only one directory sector
2336 OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
2337VAL_DIRN_D:
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
2342 RET
2343VAL_DIRN ENDP
2344
2345 SUBTTL VAL_FAT Validate File Allocation Table (FAT)
2346 PAGE
2347;-----------------------------------------------------------------------;
2348;VAL_FAT computes: ;
2349;BPB_FATSZ, the number of sectors required per FAT copy ;
2350; ;
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. ;
2359; ;
2360;This computation is slightly conservative in that the FAT entries ;
2361;necessary to describe the FAT sectors are included in the computation. ;
2362;-----------------------------------------------------------------------;
2363VAL_FAT PROC
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
2367
2368 CMP AX,0000h ;an000; dms; fix ptm 112; any left?
2369 JA VAL_FAT_A ;an000; dms; fix ptm 112; yes
2370
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
2375VAL_FAT_A:
2376 XOR DX,DX ;clear DX for division
2377 MOV CL,BPB_AUSZ ;CX = sectors/cluster
2378 XOR CH,CH
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
2384
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
2388
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
2392
2393VAL_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
2397
2398VAL_FAT_C: ;FAT size = 1.5 * number of clusters
2399 MOV CX,AX ;number of clusters
2400 SHL AX,1 ;* 2
2401 ADD AX,CX ;* 3
2402 SHR AX,1 ;* 1.5
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
2410VAL_FAT_X:
2411 RET
2412VAL_FAT ENDP
2413
2414
2415VALIDATE ENDP
2416
2417 SUBTTL COPY_BPB Copy BPB to Boot Record
2418 PAGE
2419;-----------------------------------------------------------------------;
2420; COPY_BPB copies the BIOS Parameter Block (BPB) ;
2421; to the VDISK Boot Record ;
2422;-----------------------------------------------------------------------;
2423 ASSUME DS:CSEG
2424COPY_BPB PROC ;Copy BBP to Boot Record
2425 PUSH DS
2426 POP ES ;set ES = DS
2427
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
2432 RET
2433COPY_BPB ENDP
2434
2435 SUBTTL VERIFY_EXTENDER
2436 PAGE
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;-----------------------------------------------------------------------;
2442
2443
2444 ASSUME DS:CSEG
2445EXT_P210 EQU 0210H ;write to latch expansion bus data
2446 ;read to verify expansion bus data
2447EXT_P213 EQU 0213H ;Expansion Unit status
2448
2449VERIFY_EXTENDER PROC
2450
2451 NOP
2452
2453 MOV DX,EXT_P210 ;Expansion bus data port address
2454
2455 MOV AX,5555H ;set data pattern
2456 OUT DX,AL ;write 55H to control port
2457 PUSH DX
2458 POP DX
2459
2460 JMP SHORT $+2 ;Let the I/O circuits catch up
2461 IN AL,020h ;Clear the CMOS bus drivers!
2462
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
2466
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
2471
2472 JMP SHORT $+2 ;Let the I/O circuits catch up
2473 IN AL,020h ;Clear the CMOS bus drivers!
2474
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
2478
2479;Expansion Unit is present.
2480
2481;Determine what the switch settings should be on the Extender Card
2482
2483 INT MEM_SIZE ;get system memory size in KB in AX
2484 ADD AX,63D ;memory size + 63K
2485 MOV CL,6 ;2^6 = 64
2486 SHR AX,CL ;divide by 64
2487 ;AX is highest segment address
2488 MOV AH,AL ;save number of segments
2489
2490;Read Expander card switch settings
2491
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
2497
2498 CMP AH,AL ;do switches match memory size?
2499 JE VERIFY_EXTENDER_X ;yes, exit normally
2500
2501 OR ERR_FLAG,ERR_EXTSW ;indicate switch settings are wrong
2502
2503VERIFY_EXTENDER_X:
2504 RET
2505VERIFY_EXTENDER ENDP
2506
2507 SUBTTL UPDATE_AVAIL
2508 PAGE
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;-----------------------------------------------------------------------;
2517
2518UPDATE_AVAIL PROC
2519 MOV AX,BUFF_SIZE ;number of KB of VDISK buffer
2520
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
2527 JZ $$IF36
2528 inc ax ;an004; need 1 extra page
2529; $endif ;an004;
2530$$IF36:
2531 MOV BX,AX ;AN000; Prepare for EMS call
2532
2533 MOV AH,EMS_ALLOC_PAGES ;AN000; Allocate requested pages
2534 INT EMS_INT ;AN000;
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;
2539
2540 RET ;AN000;
2541 ;AN000;
2542ALLOC_ERROR: ;AN000;
2543 MOV ERR_FLAG,EMS_ALLOC_ERROR ;AN000; ?????? *RPS
2544 RET ;AN000;
2545 ;AN000;
2546USE_INT15_LOGIC: ;AN000;
2547
2548 call Modify_CMOS_EM ;an001; dms;adjust EM for new size
2549
2550 RET
2551UPDATE_AVAIL ENDP
2552
2553
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.
2559;
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
2563; port 71h.
2564;=========================================================================
2565
2566Modify_CMOS_EM Proc Near ;an001; dms;
2567
2568 push ax ;an001; dms;save ax
2569 call Steal_Int15 ;an001; dms;get INT 15h vector
2570
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
2574
2575 ret ;an001; dms;
2576
2577Modify_CMOS_EM endp ;an001; dms;
2578
2579;=========================================================================
2580; EMS_Build_Handle_Name - This routine will build an EMS handle's
2581; name as follows:
2582; VDISK D:
2583;
2584; Inputs : DX - Handle to have associated name
2585;
2586; Outputs : Handle name
2587;=========================================================================
2588
2589EMS_Build_Handle_Name proc near ;an000; dms;
2590
2591 push si ;an000; dms;save si
2592 push cx ;an000; dms;save cx
2593
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
2601
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
2605
2606 mov ax,EMS_Set_Handle_Name ;an000; dms;set the handle's name
2607 int EMS_INT ;an000; dms;
2608
2609 pop cx ;an000; dms;restore cx
2610 pop si ;an000; dms;restore si
2611
2612 ret ;an000; dms;
2613
2614EMS_Build_Handle_Name endp ;an000; dms;
2615
2616 SUBTTL FORMAT_VDISK
2617 PAGE
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;-----------------------------------------------------------------------;
2623
2624MOVE_RH DB MOVE_RH_L ;length of request header
2625 DB 0 ;sub unit
2626 DB 8 ;output operation
2627 DW 0 ;status
2628 DQ ? ;reserved for DOS
2629 DB ? ;media descriptor byte
2630MOVE_RHO DW ? ;offset of data transfer address
2631MOVE_RHS DW ? ;segment of data transfer address
2632MOVE_RHCNT DW ? ;count of sectors to transfer
2633 DW 0 ;starting sector number
2634MOVE_RH_L EQU $-MOVE_RH ;length of request header
2635
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;-----------------------------------------------------------------------;
2641FORMAT_VDISK PROC ;format boot record, FATs and directory
2642
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
2649
2650 DIV WPARA_SIZE ;split into segment(AX)&offset(DX)
2651 MOV MOVE_RHS,AX ;save in Request Header for move
2652 MOV MOVE_RHO,DX
2653
2654 MOV DI,DX ;offset to DI
2655 MOV ES,AX ;segment to ES
2656
2657;copy the boot record
2658
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)
2664
2665;format the FAT(s)
2666
2667 MOV CL,BPB_FATN ;number of FATs
2668 XOR CH,CH
2669FORMAT_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
2674 STOSW
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
2679 XOR AX,AX
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
2683
2684;Format the directory
2685
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
2693 XOR AX,AX
2694 REP STOSB ;clear directory to nulls
2695 RET
2696FORMAT_VDISK ENDP
2697
2698 SUBTTL STEAL_INT15
2699 PAGE
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;-----------------------------------------------------------------------;
2705STEAL_INT15 PROC
2706 PUSH DS
2707 XOR AX,AX
2708 MOV DS,AX ;set DS = 0
2709 ASSUME DS:INT_VEC
2710 CLI ;disable interrupts
2711 LES DI,DS:EM_VEC ;get original vector's content
2712 MOV CS:INTV15O,DI ;save original vector
2713 MOV CS:INTV15S,ES
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
2717 POP DS ;restore DS
2718 RET
2719STEAL_INT15 ENDP
2720
2721
2722
2723 SUBTTL MOVE_VDISK
2724 PAGE
2725;-----------------------------------------------------------------------;
2726; MOVE_VDISK moves the formatted boot sector, FAT, and directory ;
2727; into extended memory. ;
2728;-----------------------------------------------------------------------;
2729
2730MOVE_VDISK PROC
2731 MOV AL,cs:BPB_FATN ;number of FAT copies
2732 CBW ;clear AH
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
2737
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
2741 POP DS
2742 RET
2743MOVE_VDISK ENDP
2744
2745 SUBTTL FILL_RH Fill in Request Header
2746 PAGE
2747;-----------------------------------------------------------------------;
2748; FILL_RH fills in the Request Header returned to DOS ;
2749;-----------------------------------------------------------------------;
2750 ASSUME DS:CSEG
2751FILL_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
2759 JE $$IF38
2760 MOV DX,CX ;AN000; DMS;END OF CODE SEGMENT ADDR
2761; $ENDIF ;AN000; DMS;
2762$$IF38:
2763
2764FILL_RH_A: ;DX is proper ending segment address
2765 MOV AL,1 ;number of units
2766 test CS:err_flag2,err_baddos
2767 jnz dont_install
2768
2769 TEST ERR_FLAG,ERR_SYSSZ+ERR_EXTSW ;if bypassing install
2770 JZ FILL_RH_B ;jump if installing driver
2771
2772dont_install:
2773 MOV DX,CS ;segment of end address
2774 XOR AL,AL ;number of units is zero
2775FILL_RH_B:
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
2783 POP DS ;restore DS
2784 RET
2785FILL_RH ENDP
2786
2787 SUBTTL WRITE_MESSAGES and associated routines
2788 PAGE
2789;-----------------------------------------------------------------------;
2790; WRITE_MESSAGE writes a series of messages to the standard ;
2791; output device showing the VDISK parameter values actually used. ;
2792;-----------------------------------------------------------------------;
2793
2794 ASSUME DS:CSEG
2795WRITE_MESSAGES PROC ;display all messages
2796
2797
2798 test cs:err_flag2,err_baddos ;AN000;
2799 JZ DISPLAY_ALL_MESSAGES ;AN000;
2800 RET
2801
2802DISPLAY_ALL_MESSAGES: ;AN000; No, then display messages
2803
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
2808 POP DS ;restore DS
2809
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
2817
2818;If any of the user specified values has been adjusted, issue an
2819;appropriate message
2820
2821WRITE_MESSAGES_A: ;AN000; NO,
2822 TEST ERR_FLAG,ERR_BSIZE ;was buffersize adjusted?
2823 JZ WRITE_MESSAGES_B ;if not, skip message
2824
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
2828
2829WRITE_MESSAGES_B: ;AN000; NO,
2830 TEST ERR_FLAG,ERR_SSZ ;was sector size adjusted?
2831 JZ WRITE_MESSAGES_C ;if not, skip message
2832
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
2838
2839WRITE_MESSAGES_C:
2840 TEST ERR_FLAG,ERR_DIRN ;were directory entries adjusted?
2841 JZ WRITE_MESSAGES_D0 ;if not, skip message
2842
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
2848
2849WRITE_MESSAGES_D0:
2850 TEST ERR_FLAG,ERR_ESIZE ;was transfer size adjusted?
2851 JZ WRITE_MESSAGES_D ;if not, skip message
2852
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
2858
2859WRITE_MESSAGES_D:
2860 TEST ERR_FLAG,ERR_SWTCH ;was an invalid switch character found?
2861 JZ WRITE_MESSAGES_E ;if not, skip message
2862
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
2868
2869WRITE_MESSAGES_E:
2870 TEST ERR_FLAG,ERR_SYSSZ ;is system size too small to install?
2871 JZ WRITE_MESSAGES_F ;if not, bypass error message
2872
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
2880WRITE_MESSAGES_RET:
2881 RET ;skip messages showing adjusted sizes
2882
2883WRITE_MESSAGES_F:
2884 TEST ERR_FLAG,ERR_EXTSW ;extender card switches wrong?
2885 JZ WRITE_MESSAGES_G ;if not, bypass error message
2886
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
2894
2895WRITE_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;
2901
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;
2906
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;
2911
2912 CMP CS:EM_SW,0 ;extended memory ?
2913 JE END_LINE ;
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;
2918
2919
2920END_LINE:
2921 RET ;return to INIT_P1
2922
2923SYSDISP_ERROR:
2924
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
2931
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;
2937
2938 PUSH DS ;AN000;SET UP ADDRESSIBILITY TO MSG
2939 PUSH ES ;AN000;
2940
2941 PUSH CS ;AN000;TRANSFER CS
2942 POP DS ;AN000; TO DS
2943 PUSH CX ;AN000;TRANSFER CS
2944 POP ES ;AN000; TO ES
2945
2946 ASSUME DS:CSEG,ES:CSEG ;AN000;
2947 CALL GET_PARM_SEGMENT ;AN000;OBTAIN PARM SEGMENT
2948
2949 CALL SYSDISPMSG ;AN000;
2950
2951 POP ES ;AN000;RESTORE REG
2952 POP DS ;AN000;RESTORE REG
2953 ASSUME DS:NOTHING,ES:NOTHING ;AN000;
2954
2955 RET ;AN000;
2956
2957WRITE_MESSAGES ENDP
2958
2959
2960DISPLAY_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
2966 PUSH ES ;AN000;
2967
2968 PUSH CS ;AN000;TRANSFER CS
2969 POP DS ;AN000; TO DS
2970 PUSH CS ;AN000;TRANSFER CS
2971 POP ES ;AN000; TO ES
2972
2973 ASSUME DS:CSEG,ES:CSEG ;AN000;
2974 CALL GET_PARM_SEGMENT ;AN000;OBTAIN PARM SEGMENT
2975
2976 CALL SYSDISPMSG ;AN000;
2977
2978 POP ES ;AN000;RESTORE REG
2979 POP DS ;AN000;RESTORE REG
2980 ASSUME DS:NOTHING,ES:NOTHING ;AN000;
2981
2982 RET ;AN000;
2983
2984DISPLAY_MESSAGE ENDP
2985
2986GET_PARM_SEGMENT PROC ;AN000;OBTAIN PARM SEGMENT
2987
2988 PUSH CX ;AN000;SAVE CX - WE STOMP IT
2989 PUSH SI ;AN000;SAVE SI - WE STOMP IT
2990
2991 CMP CX,00H ;AN000;SEE IF REPLACEMENT IS REQUIRED
2992 JE GPS_END ;AN000;END IF ZERO
2993
2994 GPS_CONTINUE: ;AN000;LOOP CONTINUE
2995
2996 MOV [SI].SL_SEGMENT,DS ;AN000;SET UP SEGMENT
2997 ADD SI,11 ;AN000;INCREASE SI BY TABLE SZ
2998
2999 LOOP GPS_CONTINUE ;AN000;CONTINUE LOOP IF CX NOT ZERO
3000
3001 GPS_END: ;AN000;EXIT POINT
3002
3003 POP SI ;AN000;RESTORE SI
3004 POP CX ;AN000;RESTORE CX
3005
3006 RET ;AN000;RETURN TO CALLER
3007
3008GET_PARM_SEGMENT ENDP ;AN000;
3009
3010
3011
3012
3013INIT_P1 ENDP ;end of INIT part one
3014.xlist
3015MSG_SERVICES <MSGDATA> ;AN000:
3016MSG_SERVICES <LOADmsg> ;AN000;
3017MSG_SERVICES <DISPLAYmsg,CHARmsg,NUMmsg> ;AN000;
3018MSG_SERVICES <VDISK.CL1,VDISK.CL2,VDISK.CLA> ;AN000;
3019.list
3020MSGEND LABEL BYTE ;AN000;
3021
3022CSEG ENDS
3023 END
3024 \ No newline at end of file
diff --git a/v4.0/src/DEV/VDISK/VDISKSYS.INC b/v4.0/src/DEV/VDISK/VDISKSYS.INC
new file mode 100644
index 0000000..c9a6c30
--- /dev/null
+++ b/v4.0/src/DEV/VDISK/VDISKSYS.INC
@@ -0,0 +1,37 @@
1EMS_STATUS EQU 40H
2EMS_GET_NUM_PAGES EQU 42H
3EMS_ALLOC_PAGES EQU 43H
4EMS_MAP_HANDLE EQU 44H
5EMS_VERSION EQU 46H
6EMS_SAVE_STATE EQU 4F00H
7EMS_RESTORE_STATE EQU 4F01H
8EMS_SET_HANDLE_NAME EQU 5301H
9EMS_FRAME_SEG EQU 5800H
10EMS_INT EQU 67H
11EMS_VERSION_LEVEL EQU 40H
12EMS_2F_Handler EQU 1Bh
13
14EMS_Mem EQU 'X' ;an005; dms;
15EM_Mem EQU 'E' ;an005; dms;
16
17EMS_EXPECTED_VERSION EQU 34H
18EMS_LOW_ERROR EQU 80H
19EMS_INSTALLED_FLAG EQU 00h ;ac006; dms;
20
21EMS_ALLOC_ERROR EQU -1 ; ***RPS ??
22SINGLE_SEGMENT EQU 1
23;;;DOS_PAGE1 EQU 0FFH
24;;;DOS_PAGE2 EQU 0FEH
25DOS_PAGE_SZ EQU 16
26EMS_Page_Size EQU 4000h ;an002; dms;
27
28EM_Size_Get EQU 88h ;an001; dms;
29
30
31GET_PAGE_FRAME_STRUC STRUC
32 FRAME_SEGMENT DW ?
33 START_PAGE DB ?
34 NUM_PAGE DB ?
35GET_PAGE_FRAME_STRUC ENDS
36BUFFER_ENTRY_SIZE EQU TYPE GET_PAGE_FRAME_STRUC
37