summaryrefslogtreecommitdiff
path: root/v4.0/src/DEV/SMARTDRV
diff options
context:
space:
mode:
authorGravatar Mark Zbikowski2024-04-25 21:24:10 +0100
committerGravatar Microsoft Open Source2024-04-25 22:32:27 +0000
commit2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch)
tree80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/DEV/SMARTDRV
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0/src/DEV/SMARTDRV')
-rw-r--r--v4.0/src/DEV/SMARTDRV/ABOVE.ASM62
-rw-r--r--v4.0/src/DEV/SMARTDRV/AB_MACRO.ASM180
-rw-r--r--v4.0/src/DEV/SMARTDRV/CMACROS.INC932
-rw-r--r--v4.0/src/DEV/SMARTDRV/DEVSYM.ASM128
-rw-r--r--v4.0/src/DEV/SMARTDRV/DIRENT.ASM56
-rw-r--r--v4.0/src/DEV/SMARTDRV/EMM.ASM223
-rw-r--r--v4.0/src/DEV/SMARTDRV/FL13.ASM148
-rw-r--r--v4.0/src/DEV/SMARTDRV/FLMES.ASM86
-rw-r--r--v4.0/src/DEV/SMARTDRV/FLUSH13.C686
-rw-r--r--v4.0/src/DEV/SMARTDRV/FLUSH13.LNK4
-rw-r--r--v4.0/src/DEV/SMARTDRV/INT13.DOC369
-rw-r--r--v4.0/src/DEV/SMARTDRV/LOADALL.ASM35
-rw-r--r--v4.0/src/DEV/SMARTDRV/MAKEFILE19
-rw-r--r--v4.0/src/DEV/SMARTDRV/MI.ASM18
-rw-r--r--v4.0/src/DEV/SMARTDRV/OLI.CMP464
-rw-r--r--v4.0/src/DEV/SMARTDRV/SMARTDRV.ASM7587
-rw-r--r--v4.0/src/DEV/SMARTDRV/SMARTDRV.LNK3
-rw-r--r--v4.0/src/DEV/SMARTDRV/SYSCALL.ASM147
18 files changed, 11147 insertions, 0 deletions
diff --git a/v4.0/src/DEV/SMARTDRV/ABOVE.ASM b/v4.0/src/DEV/SMARTDRV/ABOVE.ASM
new file mode 100644
index 0000000..058124b
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/ABOVE.ASM
@@ -0,0 +1,62 @@
1BREAK <ABOVE BOARD Equates>
2
3;
4; Assorted equates for use with Intel Above Board
5;
6
7;
8; EMM INT 67H Function codes
9;
10ABOVE_STATUS EQU 40H
11ABOVE_GET_SEG EQU 41H
12ABOVE_GET_FREE EQU 42H
13ABOVE_ALLOC EQU 43H
14ABOVE_MAP EQU 44H
15ABOVE_DEALLOC EQU 45H
16ABOVE_GET_VERSION EQU 46H
17ABOVE_SAVE_MAP_PID EQU 47H
18ABOVE_RESTORE_MAP_PID EQU 48H
19
20;
21; NEW call not implemented in version 1.00 Above Board
22;
23ABOVE_GETSET_MAP EQU 4EH
24;
25; 4EH AX equates for subfunctions
26;
27ABOVE_GETSET_GET EQU 4E00H
28ABOVE_GETSET_SET EQU 4E01H
29ABOVE_GETSET_GETSET EQU 4E02H
30
31
32;
33; "Maintenance" calls
34;
35ABOVE_GET_IOPORT EQU 49H
36ABOVE_GET_MAP_ARRAY EQU 4AH
37ABOVE_GET_PIDS EQU 4BH
38ABOVE_GET_PAGES EQU 4CH
39ABOVE_GET_ALLOC EQU 4DH
40ABOVE_REALLOCATE_PID EQU 51H
41
42
43;
44; EMM INT 67H AH return values
45;
46ABOVE_SUCCESSFUL EQU 0
47ABOVE_ERROR_SOFTWARE EQU 80H
48ABOVE_ERROR_HARDWARE EQU 81H
49ABOVE_ERROR_BUSY EQU 82H
50ABOVE_ERROR_BAD_PID EQU 83H
51ABOVE_ERROR_BAD_FUNC EQU 84H
52ABOVE_ERROR_OUT_OF_PIDS EQU 85H
53ABOVE_ERROR_MAP_CNTXT EQU 86H
54ABOVE_ERROR_INSUFF_MEM EQU 87H
55ABOVE_ERROR_INSUFF_FREE EQU 88H
56ABOVE_ERROR_ALLOC_ZERO EQU 89H
57ABOVE_ERROR_LOG_INVALID EQU 8AH
58ABOVE_ERROR_PHYS_INVALID EQU 8BH
59ABOVE_ERROR_CNTXT_NO_STACK EQU 8CH
60ABOVE_ERROR_SECOND_SAVE EQU 8DH
61ABOVE_ERROR_NO_CNTXT EQU 8EH
62ABOVE_ERROR_BAD_PARM EQU 8FH
diff --git a/v4.0/src/DEV/SMARTDRV/AB_MACRO.ASM b/v4.0/src/DEV/SMARTDRV/AB_MACRO.ASM
new file mode 100644
index 0000000..f15367a
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/AB_MACRO.ASM
@@ -0,0 +1,180 @@
1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2;
3; MACRO definitions for expanded memory manager
4;
5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6;
7; 1. MACRO to save mapping context in case somebody else has
8; mapped the page registers.
9;
10save_mapping_context macro
11local save_agn_m,save_err_m,save_ok_m,save_exit_m
12;
13; the save mapping call for the above board -->
14;
15; mov ah,47h
16; mov dx,handle
17; int 67h
18;
19; on return ax = 0 signifies success
20;
21;
22 push ax ; save registers
23 push dx
24;
25; set up emm registers and execute call to save mapping context
26;
27save_agn_m:
28 mov dx,cs:[above_pid] ; get emm handle
29 mov ah,above_save_map_pid ; save map call
30 int 67h ; call the manager
31 or ah,ah ; is there an error?
32 jz save_ok_m ; if not we are done
33;
34; error in saving mapping context, check for error
35;
36 cmp ah,above_error_busy ; if the emm manager was busy
37 jz save_agn_m ; we would like to try again
38;
39; unrecoverable error, indicate error type in al
40;
41 pop dx
42 pop dx ; pop the regs off the stack
43;
44 mov al,0aah ; drive not ready
45 cmp ah,above_error_cntxt_no_stack ;
46 jz save_err_m
47 cmp ah,above_error_second_save ;
48 ja save_err_m
49 mov al,0bbh ; general failure
50save_err_m:
51 stc
52 jmp short save_exit_m
53save_ok_m:
54 clc
55 pop dx
56 pop ax ; restore registers
57save_exit_m:
58 endm
59;
60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
61;
62; 2. MACRO to restore the mapping context saved earlier
63;
64restore_mapping_context macro
65local rest_agn_m, rest_ok_m, rest_exit_m
66;
67; the restore above map call -->
68;
69; mov ah,48h
70; mov dx,handle
71; int 67h
72; ah = 0 is success
73;
74;
75 push ax
76 pushf
77;
78rest_agn_m:
79 mov dx,cs:[above_pid] ; get emm handle
80 mov ah,above_restore_map_pid ; restore map call
81 int 67h ; call manager
82 or ah,ah ; is there any error
83 jz rest_ok_m ; if not go to finish up
84;
85; error condition, check for recoverable error
86;
87 cmp ah,above_error_busy ; if manager was busy
88 jz rest_agn_m ; we sure can try again
89 cmp ah,above_error_no_cntxt ;
90 jz rest_ok_m ; ignore invalid pid error
91;
92; unrecoverable error
93;
94 pop dx
95 pop dx
96 mov al,0bbh ; general failure
97 stc
98 jmp short rest_exit_m
99;
100rest_ok_m:
101 popf
102 pop ax
103rest_exit_m:
104;
105 endm
106;
107;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
108;
109; 3. MACRO to map a page in the physical page map onto a logical
110; page.
111;
112; the map above page requires
113; mov ah,44h
114; mov dx,handle
115; mov al,physical_page# (0-3)
116; mov bx,logical_page#
117; int 67H
118; ah = 0 success and this routine zaps ax,dx and bx
119;
120map_page macro
121local map_agn_m,map_exit_m,map_fin_m
122;
123 mov ah,above_map ; function map page
124 mov dx,cs:[above_pid] ; get emm handle
125;
126 push ax
127;
128map_agn_m:
129 pop ax
130 push ax
131 push bx
132 push dx ; "damn call above_map zaps these registers"
133;
134 int 67h ; map call
135 pop dx
136 pop bx
137;
138 or ah,ah ; is there an error?
139 jz map_fin_m ; if not go to finish up
140;
141; error condition - check for recoverable error
142;
143 cmp ah,above_error_busy ; if manager was busy
144 jz map_agn_m ; we sure can try again
145;
146; unrecoverable error
147;
148 pop ax
149 mov al,0aah ; device not ready error
150 stc
151 jmp short map_exit_m
152;
153; exit point
154;
155map_fin_m:
156 clc
157 pop ax
158map_exit_m:
159;
160 endm
161;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
162;
163; OTHER MACROS
164;
165;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
166;
167; 1) MACRO to switch es:di with ds:si
168;
169src_dest_switch macro
170;
171 push ds
172 push es
173 push si
174 mov si,di
175 pop di
176 pop ds
177 pop es
178;
179 endm
180;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/v4.0/src/DEV/SMARTDRV/CMACROS.INC b/v4.0/src/DEV/SMARTDRV/CMACROS.INC
new file mode 100644
index 0000000..28dcb1b
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/CMACROS.INC
@@ -0,0 +1,932 @@
1comment $
2cmacros - assembly macros for interfacing to HHLs
3(C)Copyright 1988 Microsoft Corporation
4$
5if1
6outif MACRO name,defval,onmsg,offmsg
7 ifndef name
8 ifb <defval>
9 name=0
10 else
11 name=defval
12 endif
13 endif
14 if name
15 name=1
16 ifnb <onmsg>
17 %out ! onmsg
18 endif
19 else
20 ifnb <offmsg>
21 %out ! offmsg
22 endif
23 endif
24endm
25
26error MACRO msg
27bug
28%out E r r o r ----- msg
29ENDM
30%out cMacros Version 1.04
31outif memS,0,<Small Model>
32outif memM,0,<Medium Model>
33outif memL,0,<Large Model>
34outif memC,0,<Compact Model>
35outif memH,0,<Huge Model>
36memMOD= memS + memM + memL + memC + memH
37if memMOD ne 1
38if memMOD eq 0
39memS= 1
40outif memS,0,<Small Model>
41else
42error <Must have only 1 memory model selected>
43endif
44endif
45sizeC= memM + memL + memH
46sizeD= memL + memC + (memH*2)
47outif ?DF,0,<No segments or groups will be defined>
48outif ?WIN,0,<Windows Support>
49outif ?PLM,0,<PLM calling convention>
50endif
51 .XCREF
52 .XCREF ?N,?AX,?AH,?AL,?BX,?BH
53 .XCREF ?BL,?CX,?CH,?CL,?DX,?DH
54 .XCREF ?DL,?SI,?DI,?ES,?DS,?BP
55 .XCREF ?SP,?SS,?CS
56 .XCREF ?RSL,?CPD,?argl,?argc,?BA
57 .XCREF ?ACB,???,?PO
58 .XCREF ?PAS,?PC
59 .XCREF Uconcat,mPush,mPop
60 .XCREF ?RI,?pp,?pp1,?al1
61 .XCREF ?aD,?AP,?Atal,?pd,?dd,?dd1,?ex1,?cas
62 .XCREF ?pg,?pg1,?aloc,?cs1,?cs2
63 .XCREF ?lb1,?lblpu
64 .XCREF ?DF,?PLM,?WIN,?IA,?PU,?ADJ
65 .CREF
66?RSL = 0
67?CPD = 0
68?ArgL = 0
69?ArgC = 0
70?BA = 0
71?ACB = 0
72??? = 0
73?PO = 0
74?PAS = 0
75?PC = 0
76?IA = 0
77?PU = 0
78?ADJ = 0
79?lblpu = 0
80?N = 0000000000000000B
81?AX = 0000000000000011B
82?AH = 0000000000000001B
83?AL = 0000000000000010B
84?BX = 0000000000001100B
85?BH = 0000000000000100B
86?BL = 0000000000001000B
87?CX = 0000000000110000B
88?CH = 0000000000010000B
89?CL = 0000000000100000B
90?DX = 0000000011000000B
91?DH = 0000000001000000B
92?DL = 0000000010000000B
93?SI = 0000000100000000B
94?DI = 0000001000000000B
95?ES = 0000010000000000B
96?DS = 0000100000000000B
97?BP = 0001000000000000B
98?SP = 0010000000000000B
99?SS = 0100000000000000B
100?CS = 1000000000000000B
101uconcat macro n1,n2,o1,o2,p1,p2
102n1&n2 o1&o2 p1&p2
103endm
104mpush macro rV
105irp x,<ax,bx,cx,dx,si,di,es,ds,bp,sp,ss,cs>
106if rV AND ?&&x
107push x
108endif
109endm
110endm
111mpop macro rV
112irp x,<cs,ss,sp,bp,ds,es,di,si,dx,cx,bx,ax>
113if rV AND ?&&x
114pop x
115endif
116endm
117endm
118SAVE macro rL
119?RSL = 0
120?RI ?RSL,<rL>
121endm
122smashes macro n,rL
123 .xcref
124 .xcref ?SM&n
125 .cref
126?SM&n = 0
127?RI ?SM&n,<rL>
128endm
129?RI macro n,rL
130irp x,<rL>
131ifdef ?&&x
132n = n or ?&&x
133endif
134endm
135endm
136parmB macro nl
137?pp <&nL>,<byte>,2,1
138endm
139parmW macro nl
140?pp <&nL>,<word>,2,2
141endm
142parmD macro nl
143ife ?PLM
144irp x,<nL>
145?pp <&&x>,<DWORD>,0,4
146?pp <Off_&&x>,<WORD>,2,2
147?pp <Seg_&&x>,<WORD>,2,2
148endm
149else
150irp x,<nL>
151?pp <Seg_&&x>,<WORD>,2,2
152?pp <Off_&&x>,<WORD>,2,2
153?pp <&&x>,<DWORD>,0,4
154endm
155endif
156endm
157parmQ macro nl
158?pp <&nL>,<QWORD>,8,8
159endm
160parmT macro nl
161?pp <&nL>,<TBYTE>,10,10
162endm
163if sizeC
164parmCP macro nl
165parmD <nl>
166endm
167else
168parmCP macro nl
169parmW <nl>
170endm
171endif
172if sizeD
173parmDP macro nl
174parmD <nl>
175endm
176else
177parmDP macro nl
178parmW <nl>
179endm
180endif
181?pp macro nL,t,l,s
182if ?CPD
183 .xcref
184ife ?PLM
185irp x,<nL>
186?pp1 x,<t>,%?PO,%?adj,%(?PO+?adj)
187?PO = ?PO + l
188 .xcref ?T&&x
189?T&&x = s
190endm
191else
192irp x,<nL>
193?PO = ?PO + l
194?pp1 x,<t>,%?PO,%?adj,%(?PO+?adj)
195 .xcref ?T&&x
196?T&&x = s
197endm
198endif
199 .cref
200else
201%out Parm(s) "&nl" declared outside proc def.
202endif
203endm
204?pp1 macro n,t,o,a,b
205ife ?PLM
206n equ t ptr [bp+b]
207else
208n equ t ptr [bp+a+?PO-o]
209endif
210endm
211localB macro nL
212?aLoc <&nL>,<BYTE ptr>,1,1,0
213endm
214localW macro nL
215?aLoc <&nL>,<WORD PTR>,2,2,1
216endm
217localD macro nL
218irp x,<nL>
219?aLoc <Seg_&&x>,<WORD PTR>,2,2,1
220?aLoc <Off_&&x>,<WORD PTR>,2,2,1
221?aLoc <&&x>,<DWORD PTR>,0,4,1
222endm
223endm
224localQ macro nL
225?aLoc <&nL>,<QWORD PTR>,8,8,1
226endm
227localT macro nL
228?aLoc <&nL>,<TBYTE PTR>,10,10,1
229endm
230if sizeC
231localCP macro nL
232localD <nL>
233endm
234else
235localCP macro nL
236localW <nL>
237endm
238endif
239if sizeD
240localDP macro nL
241localD <nL>
242endm
243else
244localDP macro nL
245localW <nL>
246endm
247endif
248localV macro n,a
249?aLoc <&n>,,%(&a),0,1
250endm
251?aLoc macro nL,t,l,s,a
252if ?CPD
253 .xcref
254??? = ??? + l
255if a
256??? = ((??? + 1) AND 0FFFEH)
257endif
258irp x,<nL>
259?aL1 x,<t>,%???
260 .xcref ?T&&x
261?T&&x = s
262endm
263 .cref
264else
265%out Locals "&nl" declared outside procedure def.
266endif
267endm
268?aL1 macro n,t,o
269if ?IA
270n equ t [bp-?IA-o]
271else
272n equ t [bp-o]
273endif
274endm
275globalB macro n,i,s
276?aD <n>,1
277?dd n,1,<BYTE>,<DB>,<i>,<s>
278endm
279globalW macro n,i,s
280?aD <n>,2
281?dd n,1,<WORD>,<DW>,<i>,<s>
282endm
283globalD macro n,i,s
284?aD <n>,4
285?dd n,1,<DWORD>,<DD>,<i>,<s>
286endm
287globalQ macro n,i,s
288?aD <n>,8
289?dd n,1,<QWORD>,<DQ>,<i>,<s>
290endm
291globalT macro n,i,s
292?aD <n>,10
293?dd n,1,<TBYTE>,<DT>,<i>,<s>
294endm
295if sizeC
296globalCP macro n,i,s
297globalD n,<i>,<s>
298endm
299else
300globalCP macro n,i,s
301globalW n,<i>,<s>
302endm
303endif
304if sizeD
305globalDP macro n,i,s
306globalD n,<i>,<s>
307endm
308else
309globalDP macro n,i,s
310globalW n,<i>,<s>
311endm
312endif
313staticB macro n,i,s
314?aD <n>,1
315?dd n,0,<BYTE>,<DB>,<i>,<s>
316endm
317staticW macro n,i,s
318?aD <n>,2
319?dd n,0,<WORD>,<DW>,<i>,<s>
320endm
321staticD macro n,i,s
322?aD <n>,4
323?dd n,0,<DWORD>,<DD>,<i>,<s>
324endm
325staticQ macro n,i,s
326?aD <n>,8
327?dd n,0,<QWORD>,<DQ>,<i>,<s>
328endm
329staticT macro n,i,s
330?aD <n>,10
331?dd n,0,<TBYTE>,<DT>,<i>,<s>
332endm
333if sizeC
334staticCP macro n,i,s
335staticD n,<i>,<s>
336endm
337else
338staticCP macro n,i,s
339staticW n,<i>,<s>
340endm
341endif
342if sizeD
343staticDP macro n,i,s
344staticD n,<i>,<s>
345endm
346else
347staticDP macro n,i,s
348staticW n,<i>,<s>
349endm
350endif
351?dd macro n,p,t,d,i,s
352ife ?PLM
353n label t
354?dd1 _&n,p,<d>,<i>,<s>
355else
356?dd1 n,p,<d>,<i>,<s>
357endif
358endm
359?dd1 macro n,p,d,i,s
360if p
361PUBLIC n
362endif
363ifb <s>
364n d i
365else
366ifb <i>
367n d s DUP (?)
368else
369n d s DUP (i)
370endif
371endif
372endm
373externB macro nL
374?ex1 <&nL>,1,<BYTE>
375endm
376externW macro nL
377?ex1 <&nL>,2,<WORD>
378endm
379externD macro nL
380?ex1 <&nL>,4,<DWORD>
381endm
382externQ macro nL
383?ex1 <&nL>,8,<QWORD>
384endm
385externT macro nL
386?ex1 <&nL>,10,<TBYTE>
387endm
388externNP macro nL
389?ex1 <&nL>,2,<NEAR>
390endm
391externFP macro nL
392?ex1 <&nL>,4,<FAR>
393endm
394if sizeC
395externP macro nL
396?ex1 <&nL>,4,<FAR>
397endm
398else
399externP macro nL
400?ex1 <&nL>,2,<NEAR>
401endm
402endif
403if sizeC
404externCP macro nL
405?ex1 <&nL>,4,<DWORD>
406endm
407else
408externCP macro nL
409?ex1 <&nL>,2,<WORD>
410endm
411endif
412if sizeD
413externDP macro nL
414?ex1 <&nL>,4,<DWORD>
415endm
416else
417externDP macro nL
418?ex1 <&nL>,2,<WORD>
419endm
420endif
421?ex1 macro nL,s,d
422irp x,<nL>
423 .xcref
424 .xcref ?T&&x
425 .cref
426?T&&x = s
427ife ?PLM
428extrn _&&x:&d
429x equ _&&x
430else
431extrn x:&d
432endif
433endm
434endm
435labelB macro nL
436?lb1 <&nL>,1,<BYTE>
437endm
438labelW macro nL
439?lb1 <&nL>,2,<WORD>
440endm
441labelD macro nL
442?lb1 <&nL>,4,<DWORD>
443endm
444labelQ macro nL
445?lb1 <&nL>,8,<QWORD>
446endm
447labelT macro nL
448?lb1 <&nL>,10,<TBYTE>
449endm
450labelNP macro nL
451?lb1 <&nL>,2,<NEAR>
452endm
453labelFP macro nL
454?lb1 <&nL>,4,<FAR>
455endm
456if sizeC
457labelP macro nL
458?lb1 <&nL>,4,<FAR>
459endm
460else
461labelP macro nL
462?lb1 <&nL>,2,<NEAR>
463endm
464endif
465if sizeC
466labelCP macro nL
467?lb1 <&nL>,4,<DWORD>
468endm
469else
470labelCP macro nL
471?lb1 <&nL>,2,<WORD>
472endm
473endif
474if sizeD
475labelDP macro nL
476?lb1 <&nL>,4,<DWORD>
477endm
478else
479labelDP macro nL
480?lb1 <&nL>,2,<WORD>
481endm
482endif
483?lb1 macro nL,s,d
484?lblpu = 0
485irp x,<nL>
486ifidn <x>,<PUBLIC>
487?lblpu = 1
488else
489 .xcref
490 .xcref ?T&&x
491 .cref
492?T&&x = s
493ife ?PLM
494if ?lblpu
495public _&&x
496endif
497_&&x label &d
498x equ _&&x
499else
500if ?lblpu
501public x
502endif
503x label &d
504endif
505endif
506endm
507endm
508defB macro nL
509?aD <&nL>,1
510endm
511defW macro nL
512?aD <&nL>,2
513endm
514defD macro nL
515?aD <&nL>,4
516endm
517defQ macro nL
518?aD <&nL>,8
519endm
520defT macro nL
521?aD <&nL>,10
522endm
523if sizeC
524defCP macro nL
525defD <nL>
526endm
527else
528defCP macro nL
529defW <nL>
530endm
531endif
532if sizeD
533defDP macro nL
534defD <nL>
535endm
536else
537defDP macro nL
538defW <nL>
539endm
540endif
541?aD macro nL,s
542irp x,<nL>
543 .xcref
544 .xcref ?T&&x
545 .cref
546?T&&x = s
547endm
548endm
549regPtr macro n,S,O
550 .xcref
551 .xcref ?T&n,?SR&n,?OR&n
552 .cref
553?T&n = 0FFFFH
554?SR&n = 0
555?RI ?SR&n,<&S>
556?OR&n = 0
557?RI ?OR&n,<&O>
558endm
559arg macro aL
560irp x,<aL>
561?argc = ?argc + 1
562?Atal <x>,%?argc
563endm
564endm
565?Atal macro n,i
566 .xcref
567 .xcref ?ALI&i
568 .cref
569?ALI&i &macro
570?AP n
571&endm
572endm
573?AP macro n
574?argl = ?argl + 2
575ifdef ?T&n
576ife ?T&n-1
577push word ptr (n)
578exitm
579endif
580ife ?T&n-2
581push n
582exitm
583endif
584ife ?T&n-4
585push word ptr (n)+2
586push word ptr (n)
587?argl = ?argl + 2
588exitm
589endif
590ife ?T&n-8
591push word ptr (n)+6
592push word ptr (n)+4
593push word ptr (n)+2
594push word ptr (n)
595?argl = ?argl + 6
596exitm
597endif
598ife ?T&n-0FFFFH
599mpush %(?SR&n),1
600mpush %(?OR&n),1
601?argl = ?argl + 2
602exitm
603endif
604ife ?T&n
605push word ptr (n)
606exitm
607endif
608endif
609push n
610endm
611ife ?PLM
612ccall macro n,a,sleaze
613ifnb <a>
614Arg <a>
615endif
616ifdef ?SM&n
617?RSL = ?RSL AND ?SM&n
618endif
619mpush %?RSL
620?argl = 0
621?ACB = ?argc
622rept ?argc
623uconcat <?ALI>,%?ACB
624uconcat <purge>,,<?ALI>,%?ACB
625?ACB = ?ACB - 1
626endm
627ife ?PLM
628ifb <sleaze>
629call _&n
630else
631call n
632endif
633else
634call n
635endif
636if ?argl
637add sp,?argl
638endif
639mpop %?RSL
640?RSL = 0
641?argc = 0
642?argl = 0
643endm
644else
645ccall macro n,a
646ifnb <a>
647Arg <a>
648endif
649ifdef ?SM&n
650?RSL = ?RSL AND ?SM&n
651endif
652mpush %?RSL
653?argl = 0
654?ACB = 1
655rept ?argc
656uconcat <?ALI>,%?ACB
657uconcat <purge>,,<?ALI>,%?ACB
658?ACB = ?ACB + 1
659endm
660ife ?PLM
661call _&n
662else
663call n
664endif
665mpop %?RSL
666?RSL = 0
667?argc = 0
668?argl = 0
669endm
670endif
671cProc macro n,cl,s
672?pd n,<cl>,<s>,4
673endm
674?pd macro n,c,a,i
675if ?CPD
676?UTPE
677endif
678?CPD = 1
679??? = 0
680?argc = 0
681?BA = 0
682?PO = 0
683?PU = 0
684?IA = 0
685?adj = i
686?PAS = 0
687ifnb <a>
688?RI ?PAS,<a>
689endif
690?PC = sizeC
691irp x,<c>
692ifidn <x>,<FAR>
693?PC = 1
694endif
695ifidn <x>,<NEAR>
696?PC = 0
697endif
698ifidn <x>,<PUBLIC>
699?PU = 1
700endif
701endm
702if ?PC
703if ?WIN
704?IA = 2
705endif
706?adj = ?adj + 2
707endif
708ife ?PLM
709ife ?PC
710n label near
711else
712n label far
713endif
714?pg <_&n>,%?PU,%?PC,%?PAS
715else
716?pg <n>,%?PU,%?PC,%?PAS
717endif
718endm
719?pg macro n,p,c,a
720 .xcref
721 cBegin &macro g
722 .xcref
723 ?pg1 <n>,c,a,%?PO
724 ?CPD = 0
725 ?argc = 0
726 ?BA = 1
727 ??? = (???+1) AND 0FFFEH
728 if p
729 PUBLIC n
730 endif
731 ife c
732 n proc NEAR
733 else
734 n proc FAR
735 endif
736 ifidn <g>,<nogen>
737 if ???+?PO+a
738 %out <cBegin - possible invalid use of nogen>
739 endif
740 else
741 if ?IA
742 mov ax,ds
743 nop
744 inc bp
745 push bp
746 mov bp,sp
747 push ds
748 mov ds,ax
749 else
750 push bp
751 mov bp,sp
752 endif
753 if ???
754 sub sp,???
755 endif
756 mPush a,1
757 endif
758 .cref
759 purge cBegin
760 &endm
761 ?UTPE &macro
762 %out Unterminated Procedure Definition: "&n"
763 &endm
764endm
765
766?pg1 macro n,c,a,o
767 .xcref
768 cEnd &macro g
769 .xcref
770 ?BA = 0
771 ifidn <g>,<nogen>
772 if o+a
773 %out <cEnd - possible invalid use of nogen>
774 endif
775 else
776 mPop a,1
777 if ?IA
778 sub bp,2
779 mov sp,bp
780 pop ds
781 pop bp
782 dec bp
783 else
784 mov sp,bp
785 pop bp
786 endif
787 ife ?PLM
788 ret
789 else
790 ret o
791 endif
792 endif
793 n endp
794 .cref
795 purge cEnd
796 &endm
797 .cref
798endm
799
800assumes macro s,g
801local assumed
802assumed = 0
803ifidn <code>,<g>
804?cas <s>
805assumed = 1
806endif
807ifidn <CODE>,<g>
808?cas <s>
809assumed = 1
810endif
811ifidn <data>,<g>
812assume s&:dgroup
813assumed = 1
814endif
815ifidn <DATA>,<g>
816assume s&:dgroup
817assumed = 1
818endif
819ife assumed
820assume s&:&g
821endif
822endm
823if sizeC
824?cas macro s
825assume s&:_TEXT
826endm
827else
828?cas macro s
829assume s&:IGROUP
830endm
831endif
832createSeg macro n,ln,a,co,cl,grp
833ifnb <grp>
834ifidn <grp>,<IGROUP>
835ife sizeC
836addSeg IGROUP,n
837endif
838else
839addSeg grp,n
840endif
841endif
842ifnb <cl>
843n segment a co '&cl'
844else
845n segment a co
846endif
847n ends
848?cs1 <n>,<ln>
849endm
850if1
851ASMpass=1
852else
853ASMpass=2
854endif
855addSeg macro grp,seg
856ifndef def_&grp
857def_&grp= 0
858endif
859if def_&grp ne ASMpass
860add_&grp &macro s
861in_&grp <seg>,s
862&endm
863in_&grp &macro sl,s
864ifb <s>
865grp group sl
866else
867add_&grp &macro ns
868in_&grp <sl,s>,ns
869&endm
870endif
871&endm
872def_&grp=ASMpass
873else
874add_&grp seg
875endif
876endm
877defGrp macro nam
878addSeg nam
879endm
880?cs1 macro n,ln
881begin&ln &macro
882?cs2 <n>
883n segment
884&endm
885endm
886
887?cs2 macro n
888 sEnd &macro
889 n ends
890 &endm
891endm
892
893sBegin macro ln
894 begin&ln
895endm
896
897ife ?DF
898 createSeg _TEXT,code,byte,public,CODE,IGROUP
899 createSeg _DATA,data,word,public,DATA,DGROUP
900 if ?WIN
901 ife sizeC
902 createSeg _INITTEXT,initcode,byte,public,CODE,IGROUP
903 createSeg _INITDATA,initdata,word,public,DATA,DGROUP
904 endif
905 endif
906 ife sizeC
907 defGrp IGROUP
908 endif
909 defGrp DGROUP
910 if sizeC
911 codeOFFSET equ OFFSET _TEXT:
912 else
913 codeOFFSET equ OFFSET IGROUP:
914 endif
915 dataOFFSET equ OFFSET DGROUP:
916endif
917
918errnz macro x
919 if2
920 if x
921 errnz1 <x>,%(x)
922 endif
923 endif
924endm
925
926errnz1 macro x1,x2
927 = *ERRNZ* x1 = x2
928endm
929
930errn$ macro l,x
931 errnz <OFFSET $ - OFFSET l x>
932endm
diff --git a/v4.0/src/DEV/SMARTDRV/DEVSYM.ASM b/v4.0/src/DEV/SMARTDRV/DEVSYM.ASM
new file mode 100644
index 0000000..44a1ab8
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/DEVSYM.ASM
@@ -0,0 +1,128 @@
1BREAK <Device table and SRH definition>
2
3; The device table list has the form:
4SYSDEV STRUC
5SDEVNEXT DD ? ;Pointer to next device header
6SDEVATT DW ? ;Attributes of the device
7SDEVSTRAT DW ? ;Strategy entry point
8SDEVINT DW ? ;Interrupt entry point
9SDEVNAME DB 8 DUP (?) ;Name of device (only first byte used for block)
10SYSDEV ENDS
11
12;
13; Attribute bit masks
14;
15; Character devices:
16;
17; Bit 15 -> must be 1
18; 14 -> 1 if the device understands IOCTL control strings
19; 13 -> 1 if the device supports output-until-busy
20; 12 -> unused
21; 11 -> 1 if the device understands Open/Close
22; 10 -> must be 0
23; 9 -> must be 0
24; 8 -> unused
25; 7 -> unused
26; 6 -> unused
27; 5 -> unused
28; 4 -> 1 if device is recipient of INT 29h
29; 3 -> 1 if device is clock device
30; 2 -> 1 if device is null device
31; 1 -> 1 if device is console output
32; 0 -> 1 if device is console input
33;
34; Block devices:
35;
36; Bit 15 -> must be 0
37; 14 -> 1 if the device understands IOCTL control strings
38; 13 -> 1 if the device determines media by examining the FAT ID byte.
39; This requires the first sector of the fat to *always* reside in
40; the same place.
41; 12 -> unused
42; 11 -> 1 if the device understands Open/Close/removable media
43; 10 -> must be 0
44; 9 -> must be 0
45; 8 -> unused
46; 7 -> unused
47; 6 -> unused
48; 5 -> unused
49; 4 -> unused
50; 3 -> unused
51; 2 -> unused
52; 1 -> unused
53; 0 -> unused
54
55DevTyp EQU 8000H ; Bit 15 - 1 if Char, 0 if block
56CharDev EQU 8000H
57DevIOCtl EQU 4000H ; Bit 14 - CONTROL mode bit
58ISFATBYDEV EQU 2000H ; Bit 13 - Device uses FAT ID bytes,
59 ; comp media.
60OutTilBusy EQU 2000h ; Output until busy is enabled
61ISNET EQU 1000H ; Bit 12 - 1 if a NET device, 0 if
62 ; not. Currently block only.
63DEVOPCL EQU 0800H ; Bit 11 - 1 if this device has
64 ; OPEN,CLOSE and REMOVABLE MEDIA
65 ; entry points, 0 if not
66
67EXTENTBIT EQU 0400H ; Bit 10 - Currently 0 on all devs
68 ; This bit is reserved for future use
69 ; to extend the device header beyond
70 ; its current form.
71
72; NOTE Bit 9 is currently used on IBM systems to indicate "drive is shared".
73; See IOCTL function 9. THIS USE IS NOT DOCUMENTED, it is used by some
74; of the utilities which are supposed to FAIL on shared drives on server
75; machines (FORMAT,CHKDSK,RECOVER,..).
76
77ISSPEC EQU 0010H ;Bit 4 - This device is special
78ISCLOCK EQU 0008H ;Bit 3 - This device is the clock device.
79ISNULL EQU 0004H ;Bit 2 - This device is the null device.
80ISCOUT EQU 0002H ;Bit 1 - This device is the console output.
81ISCIN EQU 0001H ;Bit 0 - This device is the console input.
82
83;Static Request Header
84SRHEAD STRUC
85REQLEN DB ? ;Length in bytes of request block
86REQUNIT DB ? ;Device unit number
87REQFUNC DB ? ;Type of request
88REQSTAT DW ? ;Status Word
89 DB 8 DUP(?) ;Reserved for queue links
90SRHEAD ENDS
91
92;Status word masks
93STERR EQU 8000H ;Bit 15 - Error
94STBUI EQU 0200H ;Bit 9 - Buisy
95STDON EQU 0100H ;Bit 8 - Done
96STECODE EQU 00FFH ;Error code
97
98;Function codes
99DEVINIT EQU 0 ;Initialization
100DINITHL EQU 26 ;Size of init header
101DEVMDCH EQU 1 ;Media check
102DMEDHL EQU 15 ;Size of media check header
103DEVBPB EQU 2 ;Get BPB
104DEVRDIOCTL EQU 3 ;IOCTL read
105DBPBHL EQU 22 ;Size of Get BPB header
106DEVRD EQU 4 ;Read
107DRDWRHL EQU 22 ;Size of RD/WR header
108DEVRDND EQU 5 ;Non destructive read no wait (character devs)
109DRDNDHL EQU 14 ;Size of non destructive read header
110DEVIST EQU 6 ;Input status
111DSTATHL EQU 13 ;Size of status header
112DEVIFL EQU 7 ;Input flush
113DFLSHL EQU 15 ;Size of flush header
114DEVWRT EQU 8 ;Write
115DEVWRTV EQU 9 ;Write with verify
116DEVOST EQU 10 ;Output status
117DEVOFL EQU 11 ;Output flush
118DEVWRIOCTL EQU 12 ;IOCTL write
119DEVOPN EQU 13 ;Device open
120DEVCLS EQU 14 ;Device close
121DOPCLHL EQU 13 ;Size of OPEN/CLOSE header
122DEVRMD EQU 15 ;Removable media
123REMHL EQU 13 ;Size of Removable media header
124
125DevOUT EQU 16 ; output until busy.
126DevOutL EQU DevWrt ; length of output until busy
127
128SUBTTL
diff --git a/v4.0/src/DEV/SMARTDRV/DIRENT.ASM b/v4.0/src/DEV/SMARTDRV/DIRENT.ASM
new file mode 100644
index 0000000..e7150c8
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/DIRENT.ASM
@@ -0,0 +1,56 @@
1Break <Directory entry>
2
3;
4; +---------------------------+
5; | (12 BYTE) filename/ext | 0 0
6; +---------------------------+
7; | (BYTE) attributes | 11 B
8; +---------------------------+
9; | (10 BYTE) reserved | 12 C
10; +---------------------------+
11; | (WORD) time of last write | 22 16
12; +---------------------------+
13; | (WORD) date of last write | 24 18
14; +---------------------------+
15; | (WORD) First cluster | 26 1A
16; +---------------------------+
17; | (DWORD) file size | 28 1C
18; +---------------------------+
19;
20; First byte of filename = E5 -> free directory entry
21; = 00 -> end of allocated directory
22; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
23; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
24;
25
26dir_entry STRUC
27dir_name DB 11 DUP (?) ; file name
28dir_attr DB ? ; attribute bits
29dir_pad DB 10 DUP (?) ; reserved for expansion
30dir_time DW ? ; time of last write
31dir_date DW ? ; date of last write
32dir_first DW ? ; first allocation unit of file
33dir_size_l DW ? ; low 16 bits of file size
34dir_size_h DW ? ; high 16 bits of file size
35dir_entry ENDS
36
37attr_read_only EQU 1h
38attr_hidden EQU 2h
39attr_system EQU 4h
40attr_volume_id EQU 8h
41attr_directory EQU 10h
42attr_archive EQU 20h
43attr_device EQU 40h ; This is a VERY special bit.
44 ; NO directory entry on a disk EVER
45 ; has this bit set. It is set non-zero
46 ; when a device is found by GETPATH
47
48attr_all EQU attr_hidden+attr_system+attr_directory
49 ; OR of hard attributes for FINDENTRY
50
51attr_ignore EQU attr_read_only+attr_archive+attr_device
52 ; ignore this(ese) attribute(s) during
53 ; search first/next
54
55attr_changeable EQU attr_read_only+attr_hidden+attr_system+attr_archive
56 ; changeable via CHMOD
diff --git a/v4.0/src/DEV/SMARTDRV/EMM.ASM b/v4.0/src/DEV/SMARTDRV/EMM.ASM
new file mode 100644
index 0000000..ff61ab0
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/EMM.ASM
@@ -0,0 +1,223 @@
1BREAK <EMM control sector layout>
2
3;
4; The EMM control sector is a 1024 byte record which ALWAYS occupies the
5; very first 1024 bytes of "extra" memory that needs to be managed. Its
6; function is to provide a method to allocate available "extra" memory
7; to programs which desire to use it and avoid program conflicts that
8; would occur if two different programs attempted to use the same piece
9; of "extra" memory.
10;
11
12;
13; The EMM_CTRL structure defines the offsets into the 1024 byte control
14; sector of the various fields. The EMM_REC structure defines a sub-structure
15; contained within the EMM_CTRL structure which represents a particular
16; piece of allocated "extra" memory (an allocation record).
17;
18
19; Layout of each EMM record.
20
21EMM_REC STRUC
22EMM_FLAGS DW 0
23EMM_SYSTEM DW 0
24EMM_BASE DD ? ; 24 bit address of start of region
25EMM_KSIZE DW ? ; Size of region in kbytes
26EMM_REC ENDS
27
28; EMM_FLAGS Bits
29EMM_ALLOC EQU 0000000000000001B ; Zero -> record is free
30EMM_ISDRIVER EQU 0000000000000010B ; 1 -> driver is installed
31 ; for this region
32
33; EMM_SYSTEM Values
34EMM_EMM EQU 0 ; Allocated to EMM
35EMM_MSDOS EQU 1
36EMM_XENIX EQU 2
37EMM_APPLICATION EQU 3
38
39; Layout of EMM control 1024 byte record
40
41EMM_CTRL STRUC
42EMM_VER DB 50 DUP(?)
43EMM_TOTALK DW ? ; EXCLUDING the 1k of this record
44EMM_AVAILK DW ? ; Amount of above NOT allocated
45 DB SIZE EMM_REC DUP(?) ; NULL (0th) RECORD
46EMM_RECORD DB (1024 - 50 - 4 - 10 - (SIZE EMM_REC)) DUP(?)
47 ; EMM_REC structures
48EMM_TAIL_SIG DB 10 DUP(?)
49EMM_CTRL ENDS
50
51EMM_NUMREC EQU (1024 - 50 - 4 - 10 - (SIZE EMM_REC)) / (SIZE EMM_REC)
52
53
54;
55; The current initial (no "extra" memory allocated) EMM_CTRL sector is
56;
57; EMM_CONTROL LABEL BYTE
58; DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK "
59; DW EXTMEM_TOTALK - 1
60; DW EXTMEM_TOTALK - 1
61; ; NULL 0th record
62; DW EMM_ALLOC + EMM_ISDRIVER
63; DW EMM_EMM
64; DW EXTMEM_LOW + 1024
65; DW EXTMEM_HIGH
66; DW 0
67; ;**
68; DB 950 DUP(0)
69; DB "ARRARRARRA"
70;
71; Where EXTMEM_LOW:EXTMEM_HIGH is the 32 bit address of the first byte
72; of the EMM_CTRL sector (first byte of "extra" memory) and EXTMEM_TOTALK
73; is the size in K of the available "extra" memory. One is subtracted
74; from EXTMEM_TOTALK because the sizes in the EMM_CTRL record DO NOT
75; include the 1k taken up by the EMM_CTRL sector.
76;
77; The reason for the existance of the NULL 0th record is to facilitate
78; the computation of EMM_BASE for the first EMM_REC allocation record
79; created.
80;
81; The EMM_REC structures CANNOT be sparse. In other words if one sets
82; up a scan of the EMM_REC structures in the EMM_CTRL sector, as soon as
83; an EMM_REC structure WITHOUT the EMM_ALLOC bit set in its flag word
84; is encountered it is not necessary to scan further because it IS KNOWN
85; that all of the EMM_REC structures after the first one with EMM_ALLOC
86; clear also have EMM_ALLOC clear. What this means is that EMM_CTRL
87; memory CANNOT BE deallocated. Once an EMM_REC structure has its
88; EMM_ALLOC bit set, there is NO correct program operation which
89; can clear the bit UNLESS it IS KNOWN that the next EMM_REC structure
90; has its EMM_ALLOC bit clear or the EMM_REC structure is the last one.
91;
92;
93; USING THE EMM_CTRL SECTOR:
94;
95; A program which wishes to use the EMM_CTRL sector to access "extra"
96; memory should work as follows:
97;
98; Figure out how much memory you wish to allocate
99;
100; Figure out the location and size of the "extra" memory in the system
101;
102; IF (the first 1024 bytes of "extra" memory DO NOT contain a valid
103; EMM_CTRL record determined by checking for the existence of the
104; correct EMM_VER and EMM_TAIL_SIG strings)
105; Write a correct initial EMM_CTRL sector to the first 1024
106; bytes of extra memory. Be sure to fill in EMM_TOTALK,
107; EMM_AVAILK and EMM_BASE in the 0th record.
108;
109; Set up a scan of the EMM_REC structures in the EMM_CTRL sector.
110; NOTE: You can skip the NULL 0th record if you want since it has
111; known value.
112;
113; FOR (i=0;i<EMM_NUMREC;i++)
114; IF ( this EMM_REC has EMM_ALLOC clear)
115; IF ( EMM_AVAILK < amount I want to alloc)
116; ERROR insufficient memory
117; EMM_AVAILK = EMM_AVAILK - amount I want to alloc
118; EMM_FLAGS = EMM_ALLOC + EMM_ISDRIVER
119; EMM_KSIZE = amount I want to alloc
120; EMM_SYSTEM = appropriate value
121; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC +
122; (1024 * EMM_KSIZE of PREVIOUS EMM_REC)
123; break
124; ELSE
125; address next EMM_REC structure
126;
127; IF (i >= EMM_NUMREC)
128; ERROR no free EMM_REC structures
129;
130;
131; You can now see why we need that NUL 0th EMM_REC structure. In order to
132; perform this step
133;
134; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC +
135; (1024 * EMM_KSIZE of PREVIOUS EMM_REC)
136;
137; when the very first EMM_REC is allocated we must have a "previous EMM_REC"
138; structure to point at.
139;
140; The above code is rather simplistic in that all it does is do a simple
141; allocation. The EMM_ISDRIVER bit allows us to do some more sophisticated
142; things. In particular in the case of a RAMDrive type of program it is
143; desirable to "re-find" the same RAMDrive area in "extra" memory when the
144; system is re-booted. The EMM_ISDRIVER bit is used to help us do this.
145;
146; The EMM_ISDRIVER bit means "there is presently a piece of code in the
147; system which is using this memory". If we find an EMM_REC structure
148; which has its EMM_ALLOC bit set, but the EMM_ISDRIVER bit is clear
149; it means that the piece of code that originally allocated
150; the memory is gone and we may want to "re-find" this memory by
151; setting the EMM_ISDRIVER bit again. A RAMDrive program would have
152; slightly different code than the above:
153;
154; FOR (i=0;i<EMM_NUMREC;i++)
155; IF ( this EMM_REC has EMM_ALLOC clear)
156; IF ( EMM_AVAILK < amount I want to alloc)
157; ERROR insufficient memory
158; EMM_AVAILK = EMM_AVAILK - amount I want to alloc
159; EMM_FLAGS = EMM_ALLOC + EMM_ISDRIVER
160; EMM_KSIZE = amount I want to alloc
161; EMM_SYSTEM = appropriate value
162; EMM_BASE = EMM_BASE of PREVIOUS EMM_REC +
163; (1024 * EMM_KSIZE of PREVIOUS EMM_REC)
164; break
165; ELSE
166; IF ((EMM_SYSTEM == my value for EMM_SYSTEM) &&
167; (EMM_ISDRIVER is clear))
168; deal with differences between amount
169; I want to allocate and EMM_KSIZE
170; Set EMM_ISDRIVER
171; EMM_BASE is the base address of this piece
172; of memory and EMM_KSIZE is its size.
173; break
174; address next EMM_REC structure
175;
176; In this way we "re-find" memory that was previosly allocated (presumably
177; by us, or a related program).
178;
179; NOTE THAT THIS USE OF EMM_ISDRIVER REQUIRES SOME MECHANISM FOR CLEARING
180; EMM_ISDRIVER WHEN THE CODE OF INTEREST IS REMOVED FROM THE SYSTEM.
181; In the case of a RAMDrive program the code is removed whenever the system
182; is re-booted. For this reason a RAMDrive program will need code that is
183; invoked whenever a system re-boot is detected. What this code does is
184; scan the EMM_REC structures in the EMM_CTRL sector turning off the
185; EMM_ISDRIVER bits:
186;
187; FOR (i=0;i<EMM_NUMREC;i++)
188; IF ( this EMM_REC has EMM_ALLOC clear)
189; break
190; ELSE IF (EMM_SYSTEM == my value for EMM_SYSTEM)
191; clear EMM_ISDRIVER bit
192; address next EMM_REC
193;
194; Note that this code clears ALL of the ISDRIVER bits for EMM_SYSTEM
195; values of a certain value. This means there is a GLOBAL piece of
196; re-boot code for ALL of the programs using a particular EMM_SYSTEM
197; value. An alternative is to have each EMM_CTRL user clear the
198; EMM_ISDRIVER bits ONLY for those EMM_REC structures that it allocated.
199; This requires that the program keep a record of which EMM_REC structures
200; it is responsible for:
201;
202; FOR each of my EMM_REC structures
203; INDEX this EMM_REC structure in the EMM_CTRL sector
204; Clear EMM_ISDRIVER
205;
206; NOTE about this step:
207;
208; deal with differences between amount
209; I want to allocate and EMM_KSIZE
210;
211; in the above code. There are a lot of options here depending on the desired
212; behavior. If the NEXT EMM_REC structure has EMM_ALLOC clear, then it may
213; be possible for me to grow or shrink the block I found by adjusting
214; EMM_KSIZE and EMM_AVAILK. If the NEXT EMM_REC structure has EMM_ALLOC
215; set, then I am forced to either adjust the amount I want to allocate
216; to match EMM_KSIZE, or skip this EMM_REC without setting EMM_ISDRIVER.
217;
218;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
219; for rom 1nt15 extended memory interface
220emm_int equ 15h
221emm_size equ 88h
222emm_blkm equ 87h
223;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/v4.0/src/DEV/SMARTDRV/FL13.ASM b/v4.0/src/DEV/SMARTDRV/FL13.ASM
new file mode 100644
index 0000000..6ae1e44
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/FL13.ASM
@@ -0,0 +1,148 @@
1 TITLE Assembler helper routines for FLUSH13
2
3PAGE 58,132
4
5
6memS EQU 1 ; Small model
7?PLM = 0 ; Standard 'C'
8?WIN = 0 ; Not windows
9
10include cmacros.inc
11
12;extern int IOCTLOpen(char *);
13;extern int IOCTLWrite(int,char *,int);
14;extern int IOCTLRead(int,status *,int);
15;extern int IOCTLClose(int);
16
17sBegin CODE
18
19assumes CS, CODE
20assumes DS, DATA
21
22;** IOCTLOpen - Open the indicated device and make sure it's a device
23;
24; ENTRY:
25; Pointer to name of device
26; EXIT:
27; AX = -1 if error, device not opened
28; else AX = handle of open device
29; USES:
30; Standard 'C'
31;
32cProc IOCTLOpen, <PUBLIC>, <si,di,es>
33
34ParmW Nameptr
35
36cBegin
37 mov dx,Nameptr
38 MOV AX,3D02H
39 INT 21H ; Open the device
40 JC NO_DEV_ERR ; No device
41 MOV BX,AX
42 MOV AX,4400H
43 INT 21H ; Make sure it IS a device
44 JC CLOSE_NO_DEV
45 TEST DX,4080H
46 JZ CLOSE_NO_DEV
47 mov ax,bx ; Return the handle
48 jmp short PXDONE
49
50CLOSE_NO_DEV:
51 mov ax,3e00H ; Close
52 int 21H
53NO_DEV_ERR:
54 mov ax,-1
55PXDONE:
56cEnd
57
58;** IOCTLClose - Close the indicated handle
59;
60; ENTRY:
61; Handle
62; EXIT:
63; None
64; USES:
65; Standard 'C'
66;
67cProc IOCTLClose, <PUBLIC>, <si,di,es>
68
69ParmW Handle
70
71cBegin
72 mov bx,Handle
73 MOV AX,3E00H
74 INT 21H ; close the device
75cEnd
76
77;** IOCTLWrite - Perform IOCTLWrite to device handle
78;
79; ENTRY:
80; Handle to open device
81; Pointer to data to write
82; Count in bytes of data to write
83; EXIT:
84; AX = -1 error
85; else AX = input count
86; USES:
87; Standard 'C'
88;
89cProc IOCTLWrite, <PUBLIC>, <si,di,es>
90
91ParmW WHandle
92ParmW WDataPtr
93ParmW WCount
94
95cBegin
96 mov bx,WHandle
97 mov cx,WCount
98 mov dx,WDataPtr
99 MOV AX,4403H ; IOCTL Write
100 INT 21H
101 JC Werr
102 CMP AX,CX
103 JNZ Werr
104 jmp short WDONE
105
106WERR:
107 mov ax,-1
108WDONE:
109cEnd
110
111;** IOCTLRead - Perform IOCTLRead to device handle
112;
113; ENTRY:
114; Handle to open device
115; Pointer to data area to read into
116; Count in bytes of size of data area
117; EXIT:
118; AX = -1 error
119; else AX = input count
120; USES:
121; Standard 'C'
122;
123cProc IOCTLRead, <PUBLIC>, <si,di,es>
124
125ParmW RHandle
126ParmW RDataPtr
127ParmW RCount
128
129cBegin
130 mov bx,RHandle
131 mov cx,RCount
132 mov dx,RDataPtr
133 MOV AX,4402H ; IOCTL Read
134 INT 21H
135 JC Rerr
136 CMP AX,CX
137 JNZ Rerr
138 jmp short RDONE
139
140RERR:
141 mov ax,-1
142RDONE:
143cEnd
144
145
146sEnd CODE
147
148 end
diff --git a/v4.0/src/DEV/SMARTDRV/FLMES.ASM b/v4.0/src/DEV/SMARTDRV/FLMES.ASM
new file mode 100644
index 0000000..25177ba
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/FLMES.ASM
@@ -0,0 +1,86 @@
1 TITLE Message texts for FLUSH13
2
3PAGE 58,132
4
5CONST SEGMENT WORD PUBLIC 'DATA'
6CONST ENDS
7
8_BSS SEGMENT WORD PUBLIC 'DATA'
9_BSS ENDS
10
11_DATA SEGMENT WORD PUBLIC 'DATA'
12_DATA ENDS
13
14DGROUP GROUP CONST, _BSS, _DATA
15
16ASSUME DS:DGROUP
17
18_DATA SEGMENT
19
20 public _SWTCH_CONF
21 public _BAD_PARM
22 public _NO_DEV_MESS
23 public _IOCTL_BAD_MESS
24 public _STATUS_MES1
25 public _STATUS_MES2
26 public _DISSTRING
27 public _ENSTRING
28 public _OFFSTRING
29 public _ONSTRING
30 public _LOCKSTRING
31 public _UNLSTRING
32 public _REBOOT_MES
33 public _STATUS_3R
34 public _STATUS_3W
35 public _STATUS_3T
36 public _CACHE_MES
37 public _WT_MES
38 public _WB_MES
39 public _L_MES
40 public _C_MES
41 public _T_MES
42 public _STATUS_4
43 public _STATUS_5
44
45;
46; Messages
47;
48_SWTCH_CONF DB "Conflicting switch specified",13,10
49_BAD_PARM DB "Usage:",13,10," FLUSH13 [/s|/sx|/sr] [/d|/e] [/l|/u] [/i] [/f] [/wt:on|/wt:off]",13,10
50 DB " [/wc:on|/wc:off] [/t:nnnnn] [/c:on|/c:off]",0
51
52_NO_DEV_MESS DB "SMARTDRV device not found, or device error",0
53
54_IOCTL_BAD_MESS DB "SMARTDRV device function failed",0
55
56_STATUS_MES1 DB "SMARTDRV Device is NUL (instalation failed)",13,10,0
57
58_STATUS_MES2 DB "FLUSH13/SMARTDRV version 1.00",13,10,0
59_CACHE_MES DB " Caching is %-8s",0
60_L_MES DB " Cache is %-8s",13,10,0
61
62_WB_MES DB " Write Caching is %-3s",0
63_REBOOT_MES DB " Reboot flush is %-3s",13,10,0
64
65_C_MES DB " Caching of full track reads is %-3s",0
66_WT_MES DB " Write Through is %-3s",13,10,0
67
68_T_MES DB " Cache is auto flushed every %2u:%02u minutes (%u ticks)",13,10,0
69
70_DISSTRING DB "DISABLED",0
71_ENSTRING DB "ENABLED",0
72_OFFSTRING DB "OFF",0
73_ONSTRING DB "ON",0
74_LOCKSTRING DB "LOCKED",0
75_UNLSTRING DB "UNLOCKED",0
76
77
78_STATUS_3W DB " %10lu Write hits out of %10lu Total Writes. Hit rate %3u%%",13,10,0
79_STATUS_3R DB " %10lu Read hits out of %10lu Total Reads. Hit rate %3u%%",13,10,0
80_STATUS_3T DB " %10lu hits out of %10lu Total operations. Hit rate %3u%%",13,10,0
81_STATUS_4 DB " %3u Total tracks, %3u are used, %3u are locked, %3u are dirty",13,10,0
82
83_STATUS_5 DB " %4u - Current Size, %4u - Initial Size, %4u - Minimum Size",13,10,0
84
85_DATA ENDS
86 END
diff --git a/v4.0/src/DEV/SMARTDRV/FLUSH13.C b/v4.0/src/DEV/SMARTDRV/FLUSH13.C
new file mode 100644
index 0000000..cf01107
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/FLUSH13.C
@@ -0,0 +1,686 @@
1/*
2 * FLUSH13 -- Device mod utility for INT13 memory cache
3 *
4 * FLUSH13 [/s|/sx|/sr] [/d|/e] [/l|/u] [/i] [/f] [/wt:on|/wt:off]
5 * [/wc:on|/wc:off] [/t:nnnnn] [/r:on|/r:off] [/c:on|/c:off]
6 *
7 * No arguments - This causes FLUSH13 to flush out any "dirty"
8 * tracks in the INT13 cache. A "dirty" track is one
9 * which has been written into the cache, but not yet
10 * written to the disk. This invokation causes all dirty tracks
11 * to be written out to the disk so that the system can
12 * be re-booted or turned off. NOTE: FAILURE TO FLUSH
13 * THE CACHE BEFORE A RE-BOOT OR POWER OFF CAN CAUSE THE
14 * INFORMATION ON THE HARDFILE TO BE CORRUPTED.
15 *
16 * /f - Flush. Same as the no arguments case, but allows you to
17 * perform the flush and do something else (like /s).
18 *
19 * /i - Flush and invalidate. This is the same as the no argument
20 * case except that all of the information in the cache
21 * is also discarded. This makes the cache EMPTY.
22 *
23 * /d - Disable caching. This causes all dirty cache information
24 * to be flushed and all caching to stop.
25 *
26 * /e - Enable caching. This causes caching to be enabled after
27 * a previous /d disable. When INT13 is started it is enabled.
28 *
29 * /l - Lock the cache. This causes all dirty information to be
30 * flushed, and the cache contents to be locked in the cache.
31 * When in this mode the locked elements will not be discarded
32 * to make room for new tracks. This can be used
33 * to "load" the cache with desired things. For instance if
34 * you use the "foobar" program a lot, you can run foobar,
35 * causing it to be loaded into the cache, then lock the cache.
36 * This causes the foobar program to always be in the cache.
37 * You may lock the cache as many times as you want. Each lock
38 * causes the current information (including any previously
39 * locked information) to be locked.
40 * NOTE: Information in a locked cache is READ ONLY!! Any write
41 * operation on information in a locked cache causes the
42 * information to be unlocked.
43 *
44 * /u - Unlock the cache. This undoes a previous /l and returns
45 * the cache to normal operation.
46 *
47 * /s - Print status. This displays the settings of the setable
48 * device parameters.
49 * /sx - Print extended status. Same as /s, only additional
50 * Statistical information is also given.
51 * /sr - Reset statistics. Same as /sx, only the additional
52 * Statistical information is reset to 0.
53 *
54 * /wt:on off - Enable or Disable write through. When INT13 is caching
55 * write information, it is a good idea to imply a flush of
56 * the cache on some operations so that in case of a crash or
57 * power failure the information in the cache which is not on
58 * the disk will not be lost. /wt:on enables write through on full
59 * track INT 13s which are to tracks not currently in the cache.
60 * /wt:off disables it. INT13 is faster with write through
61 * off, at the expense of there being a bigger risk of
62 * loosing data. /wt:on IS NOT a substitute for flushing before
63 * a re-boot!!!! This write through mechanism is far from perfect,
64 * all it is is a risk REDUCER, not a risk eliminator. /wt:off
65 * is the setting when INT13 is started.
66 *
67 * /wc:on off - Enable or Disable write caching. There is risk when
68 * caching "dirty" information that the system will crash,
69 * or be re-booted, or be turned off before this information
70 * can be written to the disk. This may corrupt the disk.
71 * This risk can be ELIMINATED, at the expense of cache
72 * performance, by NOT caching any dirty information.
73 * /wc:off disables the caching of dirty information,
74 * eliminating the risk. /wc:on enables the caching of dirty
75 * information. /wc:on is the default when INT13 is started.
76 *
77 * WARNING: You must be careful to flush the cache before
78 * re-booting the system, or turning it off if /wc:on is selected.
79 * You should also be careful to disable the cache (/d), or do
80 * /wc:off before running any program under development which
81 * has a chance of crashing due to bugs.
82 *
83 * NOTE: When /wc:off is selected, write info CAN get into
84 * the cache (when the write is to a track which is currently
85 * in the cache). The difference is that this "dirty" information
86 * is IMMEDIATELY written out to the disk instead of being
87 * held in the cache in the "dirty" state. When the write is
88 * to a track that is not in the cache, it will be passed
89 * through to the disk without being cached.
90 *
91 * /t:nnnnn - Set the auto flush interval. INT13 listens on the system
92 * timer to note the passage of time and "age" the dirty
93 * information in the cache. Every nnnnn ticks, the cache is
94 * flushed. The timer ticks 18.2 times a second.
95 *
96 * nnnnn |
97 * ===========================================
98 * 18 | Flush every second
99 * 1092 | Flush every minute
100 * 5460 | Flush every 5 minutes
101 * 10920 | Flush every 10 minutes
102 * 21840 | Flush every 20 minutes
103 * 32760 | Flush every 30 minutes
104 * 65520 | Flush every hour
105 *
106 * The default setting of nnnnn is 1092 or every minute.
107 * NOTE: There is no way to "disable" this tick aging. Setting
108 * nnnnn = 0 causes a wait for 65536 ticks which is a
109 * little over an hour. The max value for nnnnn is 65535.
110 * Disabling the cache (/d), or turning write caching
111 * off (/wc:off) effectively prevents the aging from
112 * doing anything as there is never anything to flush
113 * in these cases. Setting very low values of nnnnn
114 * should be avoided as it places a lot of overhead into
115 * the timer interrupt service. Rather than set low values,
116 * it is better to just turn off write caching (/wc:off).
117 * NOTE: As stated above, the max value for nnnnn is 65535. It
118 * should be noted however that FLUSH13 DOES NOT object if
119 * you specify a number larger than this! It will simply
120 * use only the low 16 bits of the number.
121 *
122 * /r:on off - En/Disable reboot flush.
123 * INT13 has a provision for detecting Ctrl-Alt-Del user
124 * reboots. /r:on enables a flush of the cache at this time
125 * to prevent the disks from being corrupted. The default
126 * setting is /r:off. NOTE WARNING DANGER!!!!! Enabling
127 * this feature can prevent disks from being damaged BUT
128 * the mechanism has flaws. For one, you will have to hit
129 * Ctrl-Alt-Del a second time to get the system to reboot.
130 * YOU MUST NOT POUND ON THE KEY. You will crash the system if
131 * you do. Hit the key ONCE, if the system re-boots, fine. If
132 * there is info to flush out of the cache, the drive light
133 * will come on and the system will probably NOT reboot. WAIT
134 * until the drive light is OFF before hitting Ctrl-Alt-Del
135 * again. This feature of INT13 MAY NOT WORK with other
136 * software in the system. USER BEWARE!!!!!!!!!!!!!!!!!!!
137 *
138 * /c:on off - En/Disable all cache on reads.
139 * Normally INT13 does not cache EVERY I/O. Whenever
140 * it sees a full track I/O which is not currently in
141 * the cache, it DOES NOT cache that track. This is
142 * an optimization for "typical" operation, and actually
143 * increases performance. This is the default setting
144 * (/c:off). There may be some cases where it is desirable
145 * that ALL reads be cached. One example is that you are
146 * "loading" the cache prior to locking it with FLUSH13 /l.
147 * With /c:off, some pieces of what you're trying to load
148 * may not get into the cache. Another example is that
149 * you continually access in a sequential manner (like
150 * program load) some large file which happens to be
151 * contiguous on the disk. Again, there may be some "piece"
152 * of the file which does not get into the cache with
153 * /c:off. /c:on enables the caching of ALL reads.
154 * NOTE: The same "don't bother caching operations which
155 * are full track and not in the cache" applies
156 * to writes as well. /c has NO EFFECT on this
157 * behavior however. /c only effects read operations.
158 *
159 * MODIFICATION HISTORY
160 *
161 * 1.10 5/26/86 ARR First version in assembler
162 * 1.20 5/27/86 ARR Lock cache function added.
163 * 1.22 5/30/86 ARR /r reboot flush code added
164 * 1.23 6/03/86 ARR Cache statistics added
165 * 1.24 6/05/86 ARR Added /a "all cache" code
166 * 1.25 6/10/86 ARR Added total used, total locked to status
167 * RECODED in 'C'.
168 * /f switch added.
169 * 1.26 6/12/86 ARR /wb changed to /wc. Some status report wording
170 * changed. This was to align the behavior with the
171 * documentation a little better.
172 * 1.27 1/22/87 ARR Change to format of status information.
173 */
174
175#include <stdio.h>
176
177/*
178 * Messages in flmes.asm
179 */
180extern char NO_DEV_MESS[], IOCTL_BAD_MESS[], STATUS_MES2[], SWTCH_CONF[];
181extern char BAD_PARM[], STATUS_MES1[], DISSTRING[], ENSTRING[];
182extern char LOCKSTRING[], UNLSTRING[], REBOOT_MES[];
183extern char STATUS_3R[], STATUS_3W[], STATUS_3T[];
184extern char CACHE_MES[], WT_MES[], WB_MES[], L_MES[], C_MES[], T_MES[];
185extern char STATUS_4[], ONSTRING[], OFFSTRING[], STATUS_5[];
186
187/*
188 * Structure of the data returned by the status call to INT13
189 */
190typedef struct {
191 unsigned char write_through;
192 unsigned char write_buff;
193 unsigned char enable_13;
194 unsigned char nuldev;
195 unsigned int ticksetting;
196 unsigned char lock_cache;
197 unsigned char reboot_flush;
198 unsigned char all_cache;
199 unsigned char pad;
200 unsigned long total_writes;
201 unsigned long write_hits;
202 unsigned long total_reads;
203 unsigned long read_hits;
204 unsigned int ttracks;
205 unsigned int total_used;
206 unsigned int total_locked;
207 unsigned int total_dirty;
208 unsigned int current_size;
209 unsigned int initial_size;
210 unsigned int minimum_size;
211} status;
212
213/*
214 * Assembler routines in fl13.asm
215 */
216extern int IOCTLOpen(char *);
217extern int IOCTLWrite(int,char *,int);
218extern int IOCTLRead(int,status *,int);
219extern int IOCTLClose(int);
220
221/*
222 * GetNum - Read an unsigned 16 bit decimal number
223 *
224 * ENTRY: cptr points to string where decimal number is
225 * iptr points to unsigned int where number goes
226 *
227 * NOTES: Calls Fatal (which doesn't return) if no number is present.
228 * No error if number is > 16 bits, only low 16 bits are returned.
229 *
230 * EXIT: returns cptr advanced past number
231 * iptr contains number found
232 *
233 */
234char *GetNum(cptr,iptr)
235unsigned char *cptr;
236unsigned int *iptr;
237{
238 *iptr = 0;
239 if((*cptr < '0') || (*cptr > '9'))
240 Fatal(BAD_PARM);
241 while((*cptr >= '0') && (*cptr <= '9'))
242 *iptr = (*iptr * 10) + ((unsigned int) (*cptr++ - '0'));
243 return(cptr);
244}
245
246/*
247 * GetOnOff - Check for :on or :off string
248 *
249 * ENTRY: cptr points to string where :on or :off is supposed to be
250 * iptr points to unsigned int which is a boolean
251 *
252 * NOTES: Calls Fatal (which doesn't return) if :on or :off is not found.
253 * Case insensitive.
254 *
255 * EXIT: returns cptr advanced past :on or :off
256 * iptr contains 1 if :on was found
257 * iptr contains 0 if :off was found
258 *
259 */
260char *GetOnOff(cptr,iptr)
261char *cptr;
262int *iptr;
263{
264 if(*cptr++ != ':')
265 Fatal(BAD_PARM);
266 *cptr |= 0x20;
267 if(*cptr++ != 'o')
268 Fatal(BAD_PARM);
269 *cptr |= 0x20;
270 if(*cptr == 'n') {
271 cptr++;
272 *iptr = 1;
273 }
274 else if(*cptr == 'f'){
275 cptr++;
276 *cptr |= 0x20;
277 if(*cptr++ != 'f')
278 Fatal(BAD_PARM);
279 *iptr = 0;
280 }
281 else
282 Fatal(BAD_PARM);
283 return(cptr);
284}
285
286
287/*
288 * Flush13
289 *
290 * ENTRY: Std
291 *
292 * NOTES:
293 *
294 * EXIT: exit(0) if OK, exit(-1) if error.
295 *
296 */
297main(argc, argv, envp)
298int argc;
299char **argv;
300char **envp;
301
302{
303
304 int handle,boolval;
305 char *cptr;
306 unsigned long total_hits,total_ops;
307 unsigned int minutes,seconds;
308 struct {
309 unsigned SWITCH_S : 1;
310 unsigned SWITCH_I : 1;
311 unsigned SWITCH_D : 1;
312 unsigned SWITCH_E : 1;
313 unsigned SWITCH_L : 1;
314 unsigned SWITCH_U : 1;
315 unsigned SWITCH_T : 1;
316 unsigned SWITCH_WCON : 1;
317 unsigned SWITCH_WCOFF : 1;
318 unsigned SWITCH_WTON : 1;
319 unsigned SWITCH_WTOFF : 1;
320 unsigned SWITCH_ROFF : 1;
321 unsigned SWITCH_RON : 1;
322 unsigned SWITCH_SX : 1;
323 unsigned SWITCH_SR : 1;
324 unsigned SWITCH_CON : 1;
325 unsigned SWITCH_COFF : 1;
326 unsigned SWITCH_F : 1;
327 } switches;
328 struct {
329 unsigned char Tchar;
330 unsigned char tickvall; /* this is actually an unsigned int */
331 unsigned char tickvalh; /* but we have to declare it this way */
332 } tickpacket; /* so that the compiler doesn't word align */
333 status config;
334
335 /* Check for no arguments case and process if found */
336
337 handle = -1;
338 if (argc == 1) { /* no arguments */
339 if((handle = IOCTLOpen("SMARTAAR")) == -1)
340 Fatal(NO_DEV_MESS);
341 if(IOCTLWrite(handle,"\x00",1) == -1)
342 Fatal(IOCTL_BAD_MESS);
343 IOCTLClose(handle);
344 exit(0);
345 }
346
347 /* Initialize data associated with the argument parse */
348
349 switches.SWITCH_S = switches.SWITCH_I = switches.SWITCH_D = 0;
350 switches.SWITCH_E = switches.SWITCH_L = switches.SWITCH_U = 0;
351 switches.SWITCH_T = switches.SWITCH_WCON = switches.SWITCH_WCOFF = 0;
352 switches.SWITCH_WTON = switches.SWITCH_WTOFF = switches.SWITCH_ROFF = 0;
353 switches.SWITCH_RON = switches.SWITCH_SX = switches.SWITCH_SR = 0;
354 switches.SWITCH_CON = switches.SWITCH_COFF = switches.SWITCH_F = 0;
355
356 /* Parse the arguments */
357
358 ++argv; /* Skip argv[0] */
359 while(--argc) { /* While arguments */
360 cptr = *argv;
361 if(*cptr++ != '/') /* all arguments are switches */
362 Fatal(BAD_PARM);
363 if(*cptr == '\0') /* trailing / error? */
364 Fatal(BAD_PARM);
365 *cptr |= 0x20; /* lower case */
366 switch (*cptr++) {
367
368 /* Status */
369 case 's':
370 if(switches.SWITCH_S || switches.SWITCH_SX || switches.SWITCH_SR)
371 Fatal(SWTCH_CONF);
372 if(*cptr == '\0')
373 switches.SWITCH_S = 1;
374 else {
375 *cptr |= 0x20;
376 if(*cptr == 'r')
377 switches.SWITCH_SR = 1;
378 else if(*cptr == 'x')
379 switches.SWITCH_SX = 1;
380 else
381 Fatal(BAD_PARM);
382 cptr++;
383 }
384 break;
385
386 /* c on or off */
387 case 'c':
388 if(switches.SWITCH_CON || switches.SWITCH_COFF)
389 Fatal(SWTCH_CONF);
390 cptr = GetOnOff(cptr,&boolval);
391 if(boolval)
392 switches.SWITCH_CON = 1;
393 else
394 switches.SWITCH_COFF = 1;
395 break;
396
397 /* t set tick value */
398 case 't':
399 if(switches.SWITCH_T)
400 Fatal(SWTCH_CONF);
401 if(*cptr++ != ':')
402 Fatal(BAD_PARM);
403 cptr = GetNum(cptr,&tickpacket.tickvall);
404 tickpacket.Tchar = '\x0B'; /* set tick is call 5 */
405 switches.SWITCH_T = 1;
406 break;
407
408 /* wt or wb on or off */
409 case 'w':
410 *cptr |= 0x20;
411 if(*cptr == 'c') {
412 cptr++;
413 if(switches.SWITCH_WCOFF || switches.SWITCH_WCON)
414 Fatal(SWTCH_CONF);
415 cptr = GetOnOff(cptr,&boolval);
416 if(boolval)
417 switches.SWITCH_WCON = 1;
418 else
419 switches.SWITCH_WCOFF = 1;
420 }
421 else if(*cptr == 't') {
422 cptr++;
423 if(switches.SWITCH_WTOFF || switches.SWITCH_WTON)
424 Fatal(SWTCH_CONF);
425 cptr = GetOnOff(cptr,&boolval);
426 if(boolval)
427 switches.SWITCH_WTON = 1;
428 else
429 switches.SWITCH_WTOFF = 1;
430 }
431 else
432 Fatal(BAD_PARM);
433 break;
434
435 /* d disable */
436 case 'd':
437 if(switches.SWITCH_D || switches.SWITCH_E)
438 Fatal(SWTCH_CONF);
439 switches.SWITCH_D = 1;
440 break;
441
442 /* e enable */
443 case 'e':
444 if(switches.SWITCH_D || switches.SWITCH_E)
445 Fatal(SWTCH_CONF);
446 switches.SWITCH_E = 1;
447 break;
448
449 /* l lock */
450 case 'l':
451 if(switches.SWITCH_L || switches.SWITCH_U)
452 Fatal(SWTCH_CONF);
453 switches.SWITCH_L = 1;
454 break;
455
456 /* u unlock */
457 case 'u':
458 if(switches.SWITCH_L || switches.SWITCH_U)
459 Fatal(SWTCH_CONF);
460 switches.SWITCH_U = 1;
461 break;
462
463 /* i invalidate */
464 case 'i':
465 if(switches.SWITCH_I)
466 Fatal(SWTCH_CONF);
467 switches.SWITCH_I = 1;
468 break;
469
470 /* f flush */
471 case 'f':
472 if(switches.SWITCH_F)
473 Fatal(SWTCH_CONF);
474 switches.SWITCH_F = 1;
475 break;
476
477 /* r on or off */
478 case 'r':
479 if(switches.SWITCH_RON || switches.SWITCH_ROFF)
480 Fatal(SWTCH_CONF);
481 cptr = GetOnOff(cptr,&boolval);
482 if(boolval)
483 switches.SWITCH_RON = 1;
484 else
485 switches.SWITCH_ROFF = 1;
486 break;
487
488 default:
489 Fatal(BAD_PARM);
490
491 }
492 if(*cptr != '\0') /* must be at end of argument */
493 Fatal(BAD_PARM);
494 ++argv; /* next argument */
495 }
496
497 /* Open the device */
498
499 if((handle = IOCTLOpen("SMARTAAR")) == -1)
500 Fatal(NO_DEV_MESS);
501
502 /* Perform the actions indicated by the arguments */
503
504 if(switches.SWITCH_I) {
505 if(IOCTLWrite(handle,"\x01",1) == -1)
506 FatalC(handle,IOCTL_BAD_MESS);
507 }
508
509 if(switches.SWITCH_F) {
510 if(IOCTLWrite(handle,"\x00",1) == -1)
511 FatalC(handle,IOCTL_BAD_MESS);
512 }
513
514 if(switches.SWITCH_WTON) {
515 if(IOCTLWrite(handle,"\x04\x01",2) == -1)
516 FatalC(handle,IOCTL_BAD_MESS);
517 }
518 else if(switches.SWITCH_WTOFF) {
519 if(IOCTLWrite(handle,"\x04\x00",2) == -1)
520 FatalC(handle,IOCTL_BAD_MESS);
521 }
522
523 if(switches.SWITCH_WCON) {
524 if(IOCTLWrite(handle,"\x04\x03",2) == -1)
525 FatalC(handle,IOCTL_BAD_MESS);
526 }
527 else if(switches.SWITCH_WCOFF) {
528 if(IOCTLWrite(handle,"\x04\x02",2) == -1)
529 FatalC(handle,IOCTL_BAD_MESS);
530 }
531
532 if(switches.SWITCH_L) {
533 if(IOCTLWrite(handle,"\x06",1) == -1)
534 FatalC(handle,IOCTL_BAD_MESS);
535 }
536 else if(switches.SWITCH_U) {
537 if(IOCTLWrite(handle,"\x07",1) == -1)
538 FatalC(handle,IOCTL_BAD_MESS);
539 }
540
541 if(switches.SWITCH_T) {
542 if(IOCTLWrite(handle,&tickpacket.Tchar,3) == -1)
543 FatalC(handle,IOCTL_BAD_MESS);
544 }
545
546 if(switches.SWITCH_RON) {
547 if(IOCTLWrite(handle,"\x08\x01",2) == -1)
548 FatalC(handle,IOCTL_BAD_MESS);
549 }
550 else if(switches.SWITCH_ROFF) {
551 if(IOCTLWrite(handle,"\x08\x00",2) == -1)
552 FatalC(handle,IOCTL_BAD_MESS);
553 }
554
555 if(switches.SWITCH_CON) {
556 if(IOCTLWrite(handle,"\x0A\x01",2) == -1)
557 FatalC(handle,IOCTL_BAD_MESS);
558 }
559 else if(switches.SWITCH_COFF) {
560 if(IOCTLWrite(handle,"\x0A\x00",2) == -1)
561 FatalC(handle,IOCTL_BAD_MESS);
562 }
563
564 if(switches.SWITCH_E) {
565 if(IOCTLWrite(handle,"\x03",1) == -1)
566 FatalC(handle,IOCTL_BAD_MESS);
567 }
568 else if(switches.SWITCH_D) {
569 if(IOCTLWrite(handle,"\x02",1) == -1)
570 FatalC(handle,IOCTL_BAD_MESS);
571 }
572
573 if(switches.SWITCH_S || switches.SWITCH_SR || switches.SWITCH_SX) {
574 if(IOCTLRead(handle,&config,sizeof(config)) == -1)
575 FatalC(handle,IOCTL_BAD_MESS);
576 if(config.nuldev != 0)
577 printf(STATUS_MES1);
578 else {
579 printf(STATUS_MES2);
580 if(config.enable_13 != 0)
581 printf(CACHE_MES,ENSTRING);
582 else
583 printf(CACHE_MES,DISSTRING);
584 if(config.lock_cache != 0)
585 printf(L_MES,LOCKSTRING);
586 else
587 printf(L_MES,UNLSTRING);
588
589 if(config.write_buff != 0)
590 printf(WB_MES,ONSTRING);
591 else
592 printf(WB_MES,OFFSTRING);
593 if(config.reboot_flush != 0)
594 printf(REBOOT_MES,ONSTRING);
595 else
596 printf(REBOOT_MES,OFFSTRING);
597
598 if(config.all_cache != 0)
599 printf(C_MES,ONSTRING);
600 else
601 printf(C_MES,OFFSTRING);
602 if(config.write_through != 0)
603 printf(WT_MES,ONSTRING);
604 else
605 printf(WT_MES,OFFSTRING);
606
607 if(config.ticksetting == 0) {
608 minutes = 60;
609 seconds = 1;
610 }
611 else {
612 seconds = ((unsigned long)config.ticksetting * 10) / 182;
613 minutes = seconds / 60;
614 seconds = seconds % 60;
615 }
616 printf(T_MES,minutes,seconds,config.ticksetting);
617
618 if(switches.SWITCH_SR) {
619 if(IOCTLWrite(handle,"\x09",1) == -1)
620 FatalC(handle,IOCTL_BAD_MESS);
621 /* get the status again so that the extended status has the reset */
622 if(IOCTLRead(handle,&config,sizeof(config)) == -1)
623 FatalC(handle,IOCTL_BAD_MESS);
624 }
625 if(switches.SWITCH_SX || switches.SWITCH_SR) {
626 if(config.total_writes == 0)
627 printf(STATUS_3W,config.write_hits,config.total_writes,(unsigned int) 0);
628 else
629 printf(STATUS_3W,config.write_hits,config.total_writes,(unsigned int)(config.write_hits*100/config.total_writes));
630 if(config.total_reads == 0)
631 printf(STATUS_3R,config.read_hits,config.total_reads,(unsigned int) 0);
632 else
633 printf(STATUS_3R,config.read_hits,config.total_reads,(unsigned int)(config.read_hits*100/config.total_reads));
634 total_ops = config.total_reads + config.total_writes;
635 total_hits = config.read_hits + config.write_hits;
636 if(total_ops == 0)
637 printf(STATUS_3T,total_hits,total_ops,(unsigned int) 0);
638 else
639 printf(STATUS_3T,total_hits,total_ops,(unsigned int)(total_hits*100/total_ops));
640 printf(STATUS_4,config.ttracks,config.total_used,config.total_locked,config.total_dirty);
641 printf(STATUS_5,config.current_size,config.initial_size,config.minimum_size);
642 }
643 }
644 }
645
646 /* Close the device, and done */
647
648 IOCTLClose(handle);
649 exit(0);
650}
651
652/*
653 * Fatal -- Fatal (to flush13) error
654 *
655 * ENTRY: p is pointer to error message to print
656 *
657 * NOTES:
658 *
659 * EXIT: exit(-1)
660 *
661 */
662Fatal(p)
663char *p;
664{
665 fprintf(stderr,"\n%s\n",p);
666 exit(-1);
667}
668
669/*
670 * FatalC -- Fatal (to flush13) error, and close open handle
671 *
672 * ENTRY: p is pointer to error message to print
673 * hand is handle number of open device channel to close
674 *
675 * NOTES:
676 *
677 * EXIT: To Fatal
678 *
679 */
680FatalC(hand,p)
681int hand;
682char *p;
683{
684 IOCTLClose(hand);
685 Fatal(p);
686}
diff --git a/v4.0/src/DEV/SMARTDRV/FLUSH13.LNK b/v4.0/src/DEV/SMARTDRV/FLUSH13.LNK
new file mode 100644
index 0000000..16fb1dd
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/FLUSH13.LNK
@@ -0,0 +1,4 @@
1flush13.obj fl13.obj flmes.obj
2flush13.exe /m
3
4
diff --git a/v4.0/src/DEV/SMARTDRV/INT13.DOC b/v4.0/src/DEV/SMARTDRV/INT13.DOC
new file mode 100644
index 0000000..3e1917b
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/INT13.DOC
@@ -0,0 +1,369 @@
1mINT13.SYS is an MS-DOS device driver which implements a memory cache
2for data referenced on IBM-PC XT/AT Hard disks. It caches at the
3"INT 13H" level and caches tracks.
4
5NOTE WARNING: There is a "re-boot" bug in RAMDrive version 1.16. When
6 INT13 and RAMDrive are both installed, it is possible
7 that Ctrl-Alt-Del will not work. This problem is "fixed"
8 by updating your RAMDrive to version 1.17 or later.
9
10IN CONFIG.SYS:
11
12 device = [d:][path]int13.sys [bbbb] [/e | /a] [/d] [/wt:on] [/wc:off]
13 [/t:nnnnn] [/r:on] [/c:on]
14
15 bbbb First numeric argument, if present, is cache size
16 in K bytes. Default value is 256. Min is 128. Max
17 is 4096 (4 Meg).
18
19 /e Specifies that PC AT Extended Memory is to be used.
20 It is an error if /E is specified on a machine other
21 than an IBM PC AT. /E is the default.
22
23 NOTE: There is 1k of INT13 overhead. That is to say,
24 if there are 512k bytes of extended memory, there
25 will be 511k bytes available for assignment to INT13.
26
27 /a Specifies that Above Board memory is to be used. It
28 is an error if the above board device driver is not
29 present.
30
31 Neither /A or /E Specifies /E
32
33 NOTE: THESE ARE THE ONLY CONFIGURATIONS. You must either have an
34 Above Board (or compatible), or you must have extended memory
35 on an IBM PC-AT (or compatible).
36
37 /d Disable caching. Causes INT13 to come up with caching
38 disabled (default is enabled).
39
40 /wt:on Enable write through. When INT13 is
41 caching write information, it is a good idea to imply
42 a flush of the cache on some operations so that in
43 case of a crash or power failure the information in
44 the cache which is not on the disk will not be lost.
45 /wt:on enables write through on full track INT 13s which
46 are to tracks not currently in the cache. /wt:off
47 disables it. INT13 is faster with write through
48 disabled, at the expense of there being a bigger risk of
49 loosing data. /wt:on IS NOT a substitute for flushing
50 before a re-boot!!!! The write through mechanism is far
51 from perfect, all it is is a risk REDUCER, not a risk
52 eliminator. Write through is off by default.
53
54 /wc:off - Disable write caching. There is risk when
55 caching "dirty" information that the system will crash,
56 or be re-booted, or be turned off before this
57 information can be written to the disk. This may
58 corrupt the disk. This risk can be ELIMINATED, at the
59 expense of cache performance, by NOT caching any dirty
60 information. /wc:off disables the caching of dirty
61 information, eliminating the risk. Write caching is
62 on by default.
63
64 /t:nnnnn - Set the auto flush interval. INT13 listens on the
65 system timer to note the passage of time and "age" the
66 dirty information in the cache. Every nnnnn ticks,
67 the cache is flushed. The timer ticks 18.2 times a
68 second.
69
70 nnnnn |
71 ===========================================
72 18 | Flush every second
73 1092 | Flush every minute
74 5460 | Flush every 5 minutes
75 10920 | Flush every 10 minutes
76 21840 | Flush every 20 minutes
77 32760 | Flush every 30 minutes
78 65520 | Flush every hour
79
80 The default setting of nnnnn is 1092 or every minute.
81 nnnnn = 0 causes a wait for 65536 ticks which is a
82 little over an hour. The max value for nnnnn is 65535.
83
84 /r:on - Enable re-boot flush.
85 This enables the flush on re-boot logic. The default
86 is /r:off. This enables a flush in the Ctrl-Alt-Del
87 keyboard re-boot logic. NOTE WARNING DANGER!!!!!!!!
88 Enabling this feature can cause strange system behavior.
89 You will have to type Ctrl-Alt-Del twice at least. This
90 can adversly effect other software in the system.
91 The result of this can be very unpredictable.
92
93 /c:on - Enable all cache on reads.
94 Normally INT13 does not cache EVERY I/O. Whenever
95 it sees a full track I/O which is not currently in
96 the cache, it DOES NOT cache that track. This is
97 an optimization for "typical" operation, and actually
98 increases performance. This is the default setting
99 (/c:off). There may be some cases where it is desirable
100 that ALL reads be cached. One example is that you are
101 "loading" the cache prior to locking it with FLUSH13 /l.
102 With /c:off, some pieces of what you're trying to load
103 may not get into the cache. Another example is that
104 you continually access in a sequential manner (like
105 program load) some large file which happens to be
106 contiguous on the disk. Again, there may be some "piece"
107 of the file which does not get into the cache with
108 /c:off. /c:on enables the caching of ALL reads.
109 NOTE: The same "don't bother caching operations which
110 are full track and not in the cache" applies
111 to writes as well. /c has NO EFFECT on this
112 behavior however. /c only effects read operations.
113
114
115
116MESSAGES:
117
118
119 INT13: Above Board Memory Manager not present
120
121The /A switch was given but INT13 could not detect the presence of the
122Above Board memory manager. You need to have a
123
124 device = EMM.SYS
125
126line in your CONFIG.SYS file before you have any device = int13.sys
127lines. INT13 will install a driver, but it will be non-functional.
128
129
130 INT13: Above Board Memory Status shows error
131
132During the process of trying to set up the cache in Above Board memory
133an error was detected. Run the Above Board Confidence test to test
134your Above Board memory. INT13 will install a driver, but it will be
135non-functional.
136
137
138 INT13: Computer must be PC-AT, or PC-AT compatible
139
140The /E switch can only be given on an IBM PC AT or an IBM PC AT
141compatible computer that has the FCH model byte (byte at FFFF:000E).
142INT13 will install a driver, but it will be non-functional.
143
144
145 INT13: No extended memory available
146
147Your system has NO memory for RAMDrive drives.
148INT13 will install a driver, but it will be non-functional.
149
150
151 INT13: Insufficient memory
152
153Your system has some memory available for INT13 cache, but not enough
154to set up a driver. INT13 will install a driver, but it will be non-functional.
155
156
157 INT13: Invalid parameter
158
159You specified too many parameters, your numeric parameter is not
160valid, you specified conflicting or too many switches. Edit your CONFIG.SYS
161file and fix the INT13 line. INT13 will install a driver, but it will
162be non-functional.
163
164
165 INT13: Incorrect DOS version
166
167INT13 only runs on 2.X and 3.X versions of DOS.
168INT13 will install a driver, but it will be non-functional.
169
170
171 INT13: I/O error accessing cache memory
172
173During the set up of the INT13 cache, an error was detected trying to
174access the cache memory. Run any memory tests you have that will
175exercise your extended or expanded memory.
176INT13 will install a driver, but it will be non-functional.
177
178
179 INT13: No hardfiles on system
180
181INT13 could not find any hardfiles on your system. Only hardfiles
182which are compatible with IBM hardfiles at the ROM BIOS INT 13H
183level can be supported. INT13 will install a driver, but it will
184be non-functional.
185
186
187 INT13: Too many bytes per track on hardfile
188
189One of the hardfiles on your system defined a very large track.
190This track is too large for INT13 to be able to cache it.
191INT13 will install a driver, but it will be non-functional.
192
193
194 Microsoft INT13 Cache version Y.YY
195
196INT13 Header message, Y.YY is the version of INT13.
197
198
199 Cache size: nnnnk in UUUUUU Memory
200 Room for tttt tracks of ssss sectors each
201
202This is an informational message from INT13 telling you how many Kilo Bytes
203of memory were assigned to the cache and what type of memory it is, how many
204tracks this allows to be buffered and how many sectors there are per track.
205
206NOTE: There is nothing to "prevent" you from having two device = INT13.SYS
207 lines in your CONFIG.SYS file, but you should not do this. Very
208 unpredictable behavior will occur, and FLUSH13 will only "talk" to
209 one of them.
210
211INT13 has several behavior aspects that can be changed. This is done
212with the FLUSH13 utility.
213
214 FLUSH13 [/s|/sx|/sr] [/d|/e] [/l|/u] [/i] [/f] [/wt:on|/wt:off]
215 [/wc:on|/wc:off] [/t:nnnnn] [/r:on|/r:off] [/c:on|/c:off]
216
217 No arguments - This causes FLUSH13 to flush out any "dirty"
218 tracks in the INT13 cache. A "dirty" track is one
219 which has been written into the cache, but not yet
220 written to the disk. This invokation causes all dirty tracks
221 to be written out to the disk so that the system can
222 be re-booted or turned off. NOTE: FAILURE TO FLUSH
223 THE CACHE BEFORE A RE-BOOT OR POWER OFF CAN CAUSE THE
224 INFORMATION ON THE HARDFILE TO BE CORRUPTED.
225
226 /f - Flush. Same as the no arguments case, but allows you to
227 perform the flush and do something else (like /s).
228
229 /i - Flush and invalidate. This is the same as the no argument
230 case except that all of the information in the cache
231 is also discarded. This makes the cache EMPTY.
232
233 /d - Disable caching. This causes all dirty cache information
234 to be flushed and all caching to stop.
235
236 /e - Enable caching. This causes caching to be enabled after
237 a previous /d disable. When INT13 is started it is enabled.
238
239 /l - Lock the cache. This causes all dirty information to be
240 flushed, and the cache contents to be locked in the cache.
241 When in this mode the locked elements will not be discarded
242 to make room for new tracks. This can be used
243 to "load" the cache with desired things. For instance if
244 you use the "foobar" program a lot, you can run foobar,
245 causing it to be loaded into the cache, then lock the cache.
246 This causes the foobar program to always be in the cache.
247 You may lock the cache as many times as you want. Each lock
248 causes the current information (including any previously
249 locked information) to be locked.
250 NOTE: Information in a locked cache is READ ONLY!! Any write
251 operation on information in a locked cache causes the
252 information to be unlocked.
253
254 /u - Unlock the cache. This undoes a previous /l and returns
255 the cache to normal operation.
256
257 /s - Print status. This displays the settings of the setable
258 device parameters.
259 /sx - Print extended status. Same as /s, only additional
260 Statistical information is also given.
261 /sr - Reset statistics. Same as /sx, only the additional
262 Statistical information is reset to 0.
263
264 /wt:on off - Enable or Disable write through. When INT13 is caching
265 write information, it is a good idea to imply a flush of
266 the cache on some operations so that in case of a crash or
267 power failure the information in the cache which is not on
268 the disk will not be lost. /wt:on enables write through on full
269 track INT 13s which are to tracks not currently in the cache.
270 /wt:off disables it. INT13 is faster with write through
271 off, at the expense of there being a bigger risk of
272 loosing data. /wt:on IS NOT a substitute for flushing before
273 a re-boot!!!! This write through mechanism is far from perfect,
274 all it is is a risk REDUCER, not a risk eliminator. /wt:off
275 is the setting when INT13 is started.
276
277 /wc:on off - Enable or Disable write caching. There is risk when
278 caching "dirty" information that the system will crash,
279 or be re-booted, or be turned off before this information
280 can be written to the disk. This may corrupt the disk.
281 This risk can be ELIMINATED, at the expense of cache
282 performance, by NOT caching any dirty information.
283 /wc:off disables the caching of dirty information,
284 eliminating the risk. /wc:on enables the caching of dirty
285 information. /wc:on is the default when INT13 is started.
286
287 WARNING: You must be careful to flush the cache before
288 re-booting the system, or turning it off if /wc:on is selected.
289 You should also be careful to disable the cache (/d), or do
290 /wc:off before running any program under development which
291 has a chance of crashing due to bugs.
292
293 NOTE: When /wc:off is selected, write info CAN get into
294 the cache (when the write is to a track which is currently
295 in the cache). The difference is that this "dirty" information
296 is IMMEDIATELY written out to the disk instead of being
297 held in the cache in the "dirty" state. When the write is
298 to a track that is not in the cache, it will be passed
299 through to the disk without being cached.
300
301 /t:nnnnn - Set the auto flush interval. INT13 listens on the system
302 timer to note the passage of time and "age" the dirty
303 information in the cache. Every nnnnn ticks, the cache is
304 flushed. The timer ticks 18.2 times a second.
305
306 nnnnn |
307 ===========================================
308 18 | Flush every second
309 1092 | Flush every minute
310 5460 | Flush every 5 minutes
311 10920 | Flush every 10 minutes
312 21840 | Flush every 20 minutes
313 32760 | Flush every 30 minutes
314 65520 | Flush every hour
315
316 The default setting of nnnnn is 1092 or every minute.
317 NOTE: There is no way to "disable" this tick aging. Setting
318 nnnnn = 0 causes a wait for 65536 ticks which is a
319 little over an hour. The max value for nnnnn is 65535.
320 Disabling the cache (/d), or turning write caching
321 off (/wc:off) effectively prevents the aging from
322 doing anything as there is never anything to flush
323 in these cases. Setting very low values of nnnnn
324 should be avoided as it places a lot of overhead into
325 the timer interrupt service. Rather than set low values,
326 it is better to just turn off write caching (/wc:off).
327 NOTE: As stated above, the max value for nnnnn is 65535. It
328 should be noted however that FLUSH13 DOES NOT object if
329 you specify a number larger than this! It will simply
330 use only the low 16 bits of the number.
331
332 /r:on off - En/Disable reboot flush.
333 INT13 has a provision for detecting Ctrl-Alt-Del user
334 reboots. /r:on enables a flush of the cache at this time
335 to prevent the disks from being corrupted. The default
336 setting is /r:off. NOTE WARNING DANGER!!!!! Enabling
337 this feature can prevent disks from being damaged BUT
338 the mechanism has flaws. For one, you will have to hit
339 Ctrl-Alt-Del a second time to get the system to reboot.
340 YOU MUST NOT POUND ON THE KEY. You will crash the system if
341 you do. Hit the key ONCE, if the system re-boots, fine. If
342 there is info to flush out of the cache, the drive light
343 will come on and the system will probably NOT reboot. WAIT
344 until the drive light is OFF before hitting Ctrl-Alt-Del
345 again. This feature of INT13 MAY NOT WORK with other
346 software in the system. USER BEWARE!!!!!!!!!!!!!!!!!!!
347
348 /c:on off - En/Disable all cache on reads.
349 Normally INT13 does not cache EVERY I/O. Whenever
350 it sees a full track I/O which is not currently in
351 the cache, it DOES NOT cache that track. This is
352 an optimization for "typical" operation, and actually
353 increases performance. This is the default setting
354 (/c:off). There may be some cases where it is desirable
355 that ALL reads be cached. One example is that you are
356 "loading" the cache prior to locking it with FLUSH13 /l.
357 With /c:off, some pieces of what you're trying to load
358 may not get into the cache. Another example is that
359 you continually access in a sequential manner (like
360 program load) some large file which happens to be
361 contiguous on the disk. Again, there may be some "piece"
362 of the file which does not get into the cache with
363 /c:off. /c:on enables the caching of ALL reads.
364 NOTE: The same "don't bother caching operations which
365 are full track and not in the cache" applies
366 to writes as well. /c has NO EFFECT on this
367 behavior however. /c only effects read operations.
368
369If invalid or conflicting arguments are given, FLUSH13 prints a usage line.
diff --git a/v4.0/src/DEV/SMARTDRV/LOADALL.ASM b/v4.0/src/DEV/SMARTDRV/LOADALL.ASM
new file mode 100644
index 0000000..0476acd
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/LOADALL.ASM
@@ -0,0 +1,35 @@
1BREAK <LOADALL descriptor caches>
2
3DEF_ACCESS EQU 92H
4DEF_LIMIT EQU 0FFFFH
5
6SEGREG_DESCRIPTOR STRUC
7SEG_BASE DW ?
8 DB ?
9SEG_ACCESS DB DEF_ACCESS
10SEG_LIMIT DW DEF_LIMIT
11SEGREG_DESCRIPTOR ENDS
12
13DTR_DESCRIPTOR STRUC
14DTR_BASE DW ?
15 DB ?
16 DB 0
17DTR_LIMIT DW ?
18DTR_DESCRIPTOR ENDS
19;
20; 386 Descriptor template
21;
22desc struc
23lim_0_15 dw 0 ; limit bits (0..15)
24bas_0_15 dw 0 ; base bits (0..15)
25bas_16_23 db 0 ; base bits (16..23)
26access db 0 ; access byte
27gran db 0 ; granularity byte
28bas_24_31 db 0 ; base bits (24..31)
29desc ends
30
31gdt_descriptor struc
32gdt_limit dw ?
33gdt_base_0 dw ?
34gdt_base_2 dw ?
35gdt_descriptor ends
diff --git a/v4.0/src/DEV/SMARTDRV/MAKEFILE b/v4.0/src/DEV/SMARTDRV/MAKEFILE
new file mode 100644
index 0000000..80b7706
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/MAKEFILE
@@ -0,0 +1,19 @@
1# rules and dependencies follow
2#
3# use microsoft make to build
4#
5# set up build environment - include and library for c
6#
7
8all: smartdrv.sys
9
10smartdrv.obj: smartdrv.asm mi.asm loadall.asm \
11 syscall.asm emm.asm above.asm \
12 devsym.asm
13 masm smartdrv.asm;
14
15smartdrv.exe: smartdrv.obj
16 link smartdrv,,smartdrv/M;
17
18smartdrv.sys: smartdrv.exe
19 exe2bin smartdrv smartdrv.sys
diff --git a/v4.0/src/DEV/SMARTDRV/MI.ASM b/v4.0/src/DEV/SMARTDRV/MI.ASM
new file mode 100644
index 0000000..9d8efed
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/MI.ASM
@@ -0,0 +1,18 @@
1BREAK <Machine instruction, flag definitions and character types>
2
3mi_INT EQU 0CDh
4mi_Long_JMP EQU 0EAh
5mi_Long_CALL EQU 09Ah
6mi_Long_RET EQU 0CBh
7mi_Near_RET EQU 0C3h
8
9; xxxxoditszxaxpxc
10f_Overflow EQU 0000100000000000B
11f_Direction EQU 0000010000000000B
12f_Interrupt EQU 0000001000000000B
13f_Trace EQU 0000000100000000B
14f_Sign EQU 0000000010000000B
15f_Zero EQU 0000000001000000B
16f_Aux EQU 0000000000010000B
17f_Parity EQU 0000000000000100B
18f_Carry EQU 0000000000000001B
diff --git a/v4.0/src/DEV/SMARTDRV/OLI.CMP b/v4.0/src/DEV/SMARTDRV/OLI.CMP
new file mode 100644
index 0000000..8a9a767
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/OLI.CMP
@@ -0,0 +1,464 @@
1CMP V2.13 Copyright (C) 1984, 1985 by White Heron Corporation
2 All rights reserved
3
4 old: smartdrv.asm (on the left) Note: < marks old lines.
5 new: a:smartdrv.asm (on the right) > marks new lines.
6
7===============================================================================
8
96<; Will use IBM extended memory on PC-AT or
107<; use Above Board on PC, XT, or AT
118<;
129<;
1310<; device = SMARTDRV.sys [bbbb] [/a]
14
15 ----> changed to the following:
16
176>;; Will use IBM extended memory on PC-AT or
187>;; use Above Board on PC, XT, or AT, and
198>;; use extended, expanded, or upper extended memory on AT&T 6300 PLUS
209>;
2110>;
2211>;; device = SMARTDRV.sys [bbbb] [/a] [/u]
23
24===============================================================================
25
2640<;
27
28 ----> changed to the following:
29
3041>;; /u Specifies that upper extended memory will be used
3142>;; on the AT&T 6300 PLUS. Upper extended memory
3243>;; is the memory beginning at FA0000. It is used
3344>;; to hold the UNIX kernel when the machine is running
3445>;; Simul-Task. However, when operating as a pure
3546>;; MS-DOS machine, this 384K of memory is available
3647>;; for SMARTDRIVE.
3748>;; Note that it is an error to specify this switch
3849>;; if the machine is not a 6300 PLUS.
39
40===============================================================================
41
42102>;; ?.?? 7/24/87 WSH Added 6300 PLUS support. This code is marked by
43103>;; the use of double semi-colons to make it easy to
44104>;; find.
45
46 ----> inserted before the following old file line:
47
4893<
49
50===============================================================================
51
52125>
53126>;; In order to address memory above 1 MB on the AT&T 6300 PLUS, it is
54127>;; necessary to use the special OS-MERGE hardware to activate lines
55128>;; A20 to A23. However, these lines can be disabled only by resetting
56129>;; the processor. The return address offset and segment can be found
57130>;; at 40:a2, noted here as RealLoc1.
58131>;;
59132>BiosSeg segment at 40h ;; Used to locate 6300 PLUS reset address
60133> org 00a2h
61134>RealLoc1 dd 0
62135>BiosSeg ends
63
64 ----> inserted before the following old file line:
65
66113<
67
68===============================================================================
69
70147>;; The /U configuration using upper extended memory on the
71148>;; 6300 PLUS is a special case of the type 1 configuration.
72
73 ----> inserted before the following old file line:
74
75124<;
76
77===============================================================================
78
79327>;; The internal name of the device driver has been changed from SMARTDRV
80328>;; to SMARTAAR to avoid DOS name conflicts with files named SMARTDRV.*
81329>;;
82
83 ----> inserted before the following old file line:
84
85302<INT13DEV LABEL WORD
86
87===============================================================================
88
89307< DB "SMARTDRV" ;Name of device
90
91 ----> changed to the following:
92
93335> DB "SMARTAAR" ;Name of device
94
95===============================================================================
96
97387>;; Data peculiar to AT&T 6300 PLUS.
98388>
99389>S5_FLAG DB 0 ;; If set, computer is a 6300 PLUS
100
101 ----> inserted before the following old file line:
102
103359<
104
105===============================================================================
106
1073074>;; NOTE: The value at BASE_ADDR is patched during initialization when
1083075>;; loading a RAMDrive into upper extended memory on a PLUS
1093076>;;
110
111 ----> inserted before the following old file line:
112
1133043<BASE_ADDR LABEL DWORD ; 24 bit address of start of this RAMDRV
114
115===============================================================================
116
1173190< MOV AH,0DFH
118
119 ----> changed to the following:
120
1213224>
1223225>;;
1233226>;; Enable address line 20 on the PC AT or activate A20-A23 on the 6300 PLUS.
1243227>;; The former can be done by placing 0dfh in AH and activating the keyboard
1253228>;; processor. On the PLUS, 90h goes in AL and the port at 03f20h is written.
1263229>;; So the combined value of 0df90h can be used for both machines with
1273230>;; appropriate coding of the called routine A20.
1283231>;;
1293232>
1303233>;; MOV AH,0DFH
1313234> mov ax,0df90h ;; set up for PLUS or AT
132
133===============================================================================
134
1353248< MOV AH,0DDH
1363249< CALL A20 ; Disable address line 20
137
138 ----> changed to the following:
139
1403292>
1413293>;;
1423294>;; Reset of line A20 on the PC AT requires writing 0ddh to the keyboard
1433295>;; processor. On the PLUS, the appropriate value is 00.
1443296>;;
1453297>
1463298>;; MOV AH,0DDH
1473299> mov ax,0DD00h ;; setup for PLUS or AT. ah for IBM, al for PLUS
1483300> CALL A20 ; Disable address line 20
149
150===============================================================================
151
1523331>;; CS override needed on S5_FLAG to avoid phase errors on
1533332>;; forward declaration of this variable.
1543333> cmp cs:[S5_FLAG],0 ;; test for 6300 PLUS
1553334> jnz A20S5 ;; yes, do this code
156
157 ----> inserted before the following old file line:
158
1593280< CLI
160
161===============================================================================
162
1633376>
1643377>;;* A20S5 - Address enable/disable routine for the 6300 PLUS.
1653378>;;
1663379>;; This routine enables lines A20-A23 on the PLUS by writing
1673380>;; to port 03f20h. Bit 7 turns the lines on, and bit 4 sets
1683381>;; the power-up bit. To disable the lines, the processor
1693382>;; must be reset. This is done by saving the world and
1703383>;; jumping to the ROM 80286 reset code. Since the power-up bit
1713384>;; is set, the data segment is set to the BiosSeg at 40h
1723385>;; and a jump is then made to the address at RealLoc1.
1733386>;; At RealLoc1, one can find the CS:IP where the code
1743387>;; is to continue.
1753388>;;
1763389>;; Uses ax, flags.
1773390>;; Returns with zero flag set.
1783391>;;
1793392>A20S5:
1803393> cli
1813394> or al,al ;; if zero, then resetting processor
1823395> jnz A20S5Next
1833396> call RSet ;; must return with entry value of ax
1843397>A20S5Next:
1853398> push dx ;; set/reset port
1863399> mov dx,3f20h
1873400> out dx,al
1883401> pop dx
1893402> xor al,al
1903403> STI
1913404> RET
1923405>
1933406>;;* a20S5BOOT - This code bypasses the processor reset on a reboot
1943407>;; of the 6300 PLUS. Otherwise the machine hangs.
1953408>a20s5BOOT: ;; use this code before reboot
1963409> cli
1973410> jmp short a20s5next
1983411>
1993412>OldStackSeg dw 0 ;; used during PLUS processor reset
2003413> ;; to save the stack segment
2013414>
2023415>;;* Rset - Reset the 80286 in order to turn off the address lines
2033416>;; on the 6300 PLUS. Only way to do this on the
2043417>;; current hardware. The processor itself can be
2053418>;; reset by reading or writing prot 03f00h
2063419>;;
2073420>;; Uses flags.
2083421>;;
2093422>RSet:
2103423> pusha ;; save world
2113424> push ds ;; save segments
2123425> push es
2133426> mov ax,BiosSeg ;; point to the bios segment
2143427> mov ds,ax ;; ds -> 40h
2153428>assume ds:BiosSeg
2163429> push word ptr [RealLoc1] ;; save what might have been here
2173430> push word ptr [RealLoc1+2]
2183431> mov word ptr [RealLoc1],cs:[offset ReturnBack] ;; load our return address
2193432> mov word ptr [RealLoc1+2],cs
2203433>assume ds:nothing
2213434> mov [OldStackSeg],ss ;; save the stack segment, too
2223435> mov dx,03f00h ;; reset the processor
2233436> in ax,dx
2243437> nop
2253438> nop
2263439> nop
2273440> cli
2283441> hlt ;; should never get here
2293442>ReturnBack:
2303443> mov ss,[OldStackSeg] ;; start the recovery
2313444>assume ds:BiosSeg
2323445> pop word ptr [RealLoc1+2]
2333446> pop word ptr [RealLoc1]
2343447> pop es
2353448> pop ds
2363449> popa
2373450> ret
238
239 ----> inserted before the following old file line:
240
2413321<
242
243===============================================================================
244
2453530<; out any dirty tracks take a LONG time, so long that we loose
246
247 ----> changed to the following:
248
2493660>; out any dirty tracks take a LONG time, so long that we lose
250
251===============================================================================
252
2533652< ; Reset INT 1C vector to trun cache off
254
255 ----> changed to the following:
256
2573782> ; Reset INT 1C vector to turn cache off
258
259===============================================================================
260
2613732< MOV AH,0DFH
262
263 ----> changed to the following:
264
2653862>;; MOV AH,0DFH
2663863> mov ax,0df90h ;; set up for PLUS or AT
267
268===============================================================================
269
2703775< MOV AH,0DDH ; Disable adress line 20
2713776< CALL A20
272
273 ----> changed to the following:
274
2753906>;; MOV AH,0DDH ; Disable adress line 20
2763907> mov ax,0DD00h ;; setup for PLUS or AT. ah for IBM, al for PLUS
2773908> cmp [S5_FLAG],0
2783909> jz OFF20A
2793910> call a20s5boot ;; Don't reset the processor on PLUS, this time
2803911> jmp short off20b
2813912>off20a:
2823913> CALL A20
2833914>off20b:
284
285===============================================================================
286
2874078>
2884079>U_SWITCH db 0 ;; upper extended memory requested on 6300 PLUS
289
290 ----> inserted before the following old file line:
291
2923940<
293
294===============================================================================
295
2964274>
2974275>;;
2984276>;; 2.5 Check here for 6300 PLUS machine. First look for Olivetti copyright,
2994277>;; and if found, check id byte at f000:fffd.
3004278>;;
3014279>
3024280> push es ;; Olivetti Machine?
3034281> mov ax,0fc00h ;; Look for 'OL' at fc00:50
3044282> mov es,ax
3054283> cmp es:[0050h],'LO'
3064284> jnz notS5 ;; not found
3074285> mov ax,0f000h
3084286> mov es,ax
3094287> cmp word ptr es:[0fffdh],0fc00h ;; look for 6300 plus
3104288> jnz notS5
3114289> dec [S5_FLAG] ;; yep, set flag
3124290>notS5:
3134291> pop es
3144292>
315
316 ----> inserted before the following old file line:
317
3184134<;
319
320===============================================================================
321
3224411>;; Added for /u switch
3234412> cmp al,'u' ;; Look for U switch for PLUS
3244413> jnz A_TEST
3254414> cmp [S5_FLAG],0 ;; No good unless PLUS
3264415> jz bad_parm
3274416> TEST [GOTSWITCH],SWITCH_A ;; Already have switch A ?
3284417> JNZ BAD_PARM
3294418> cmp [U_SWITCH],0
3304419> jne bad_parm
3314420> dec [U_SWITCH]
3324421> jmp scan_loop
3334422>A_TEST:
3344423>;;
335
336 ----> inserted before the following old file line:
337
3384252< CMP AL,"a"
339
340===============================================================================
341
3424435>;; added for /u switch
3434436> cmp [U_SWITCH],0
3444437> jne bad_parm
3454438>;;
346
347 ----> inserted before the following old file line:
348
3494263< OR [GOTSWITCH],SWITCH_A
350
351===============================================================================
352
3534847>;; Note: When using upper extended memory on the PLUS, the value
3544848>;; at BASE_RESET + 2 is patched to FA during initialization.
3554849>;;
356
357 ----> inserted before the following old file line:
358
3594671<BASE_RESET LABEL DWORD ; RESMEM driver must patch this value
360
361===============================================================================
362
3635312> cmp U_SWITCH,0 ;; don't do this for at&t 6300 plus
3645313> jnz ret005
365
366 ----> inserted before the following old file line:
367
3685133< PUSH AX
369
370===============================================================================
371
3725394>
3735395>;; If upper extended memory is used on the PLUS, it is necessary to
3745396>;; patch the values of base_reset and base_addr to get the addressing right.
3755397>;;
3765398> cmp [U_SWITCH],0 ;; patch the code for /U option
3775399> jz AT001A
3785400> mov ax,00fah
3795401> mov word ptr [base_reset+2],ax ;; patching upper address
3805402> mov word ptr [base_addr+2],ax ;; to FA from 10
3815403>AT001A:
3825404>
383
384 ----> inserted before the following old file line:
385
3865213< MOV AX,8800H
387
388===============================================================================
389
3905214< INT 15H ; Get extended memory size
391
392 ----> changed to the following:
393
3945406> INT 15H ; Get extended memory size
395
396===============================================================================
397
3985410>
3995411>;; If running on a 6300 PLUS, it is necessary to subtract any upper extended
4005412>;; memory from the value obtained by int 15 to determine the correct memory
4015413>;; available for a type /E RAMDrive. If loading a /U RAMDrive, it is necessary
4025414>;; to find out if there IS any upper extended memory.
4035415>
4045416> cmp [U_SWITCH],0 ;; did we ask for upper extended memory
4055417> jz olstuff ;; no
4065418> call UpperMemCheck ;; yes, see if anything there
4075419> jc ERR_RET ;; no, quit
4085420> mov ax,384 ;; yes, but max allowed is 384K
4095421> jmp short at001b
4105422>olstuff:
4115423> cmp [S5_FLAG],0 ;; if not 6300 PLUS, go on
4125424> jz at001b
4135425> call UpperMemCheck ;; yes, see if 384K is there
4145426> jc at001b ;; no, so int 15h is right
4155427> sub ax,384 ;; yes, subtract 384K
4165428>AT001B:
4175429>
418
419 ----> inserted before the following old file line:
420
4215218< MOV DX,OFFSET ERRMSG2
422
423===============================================================================
424
4255466>
4265467>;;* UpperMemCheck - Called by 6300 PLUS to verify existence of
4275468>;; upper extended memory of 384K at FA0000h
4285469>;;
4295470>;; Returns carry set if no upper extended memory.
4305471>;;
4315472>;; This routine is called only by a 6300 PLUS, and
4325473>;; it reads the hardware switch DSW2 to do the job.
4335474>;;
4345475>UpperMemCheck:
4355476> push ax
4365477> in al,66h
4375478> and al,00001111b
4385479> cmp al,00001011b
4395480> pop ax
4405481> jnz nomem
4415482> clc
4425483> ret
4435484>nomem:
4445485> stc
4455486> ret
446
447 ----> inserted before the following old file line:
448
4495254<
450
451===============================================================================
452
4536301>s5flagmsg db " = S5 flag",13,10,"$"
4546302>U_msg db " = U Switch", 13,10,'$'
455
456 ----> inserted before the following old file line:
457
4586068<ENDIF
459
460===============================================================================
461
46228 discrepancies.
463 File smartdrv.asm has 6075 lines.
464 File a:smartdrv.asm has 6310 lines.
diff --git a/v4.0/src/DEV/SMARTDRV/SMARTDRV.ASM b/v4.0/src/DEV/SMARTDRV/SMARTDRV.ASM
new file mode 100644
index 0000000..3efe7c1
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/SMARTDRV.ASM
@@ -0,0 +1,7587 @@
1 TITLE EXTENDED/EXPANDED MEMORY DISK CACHE
2
3PAGE 58,132
4
5;
6;; Will use IBM extended memory on PC-AT or
7;; use Above Board on PC, XT, or AT, and
8;; use extended, expanded, or upper extended memory on AT&T 6300 PLUS
9;
10;
11;; device = SMARTDRV.sys [bbbb] [/a] [/u]
12;
13; bbbb First numeric argument, if present, is memory size
14; in K bytes. Default value is 256. Min is 128. Max
15; is 8192 (8 Meg).
16;
17; By default PC AT Extended Memory is to be used.
18; It is an error if /E is specified on a machine other
19; than an IBM PC AT. /E is the default.
20; NOTE: Information in cache in PC AT extended memory
21; will be lost at system re-boot (warm or cold). This is
22; due to the fact that the IBM PC AT ROM bootstrap code
23; zeroes all of memory.
24; NOTE: There is 1k of memory overhead. That is to say,
25; if there are 512k bytes of extended memory, there
26; will be 511k bytes available for assignment to int13.
27; This 1k overhead is fixed and makes int13 compatible
28; with RAMDRive.
29; NOTE: The same allocation strategy as is used in RAMDrive
30; is used. This allows RAMDrive and INT13 to coexist on
31; the same system. Mixing with IBM VDISK is NOT supported.
32;
33; /a Specifies that Above Board memory is to be used. It
34; is an error if the above board device driver is not
35; present.
36; NOTE: Information in cache in Above Board memory
37; will be lost at system re-boot (warm or cold). This is
38; due to the fact that the EMM device driver performs a
39; destructive test when it is installed which zeros all
40; of the Above Board memory.
41;; /u Specifies that upper extended memory will be used
42;; on the AT&T 6300 PLUS. Upper extended memory
43;; is the memory beginning at FA0000. It is used
44;; to hold the UNIX kernel when the machine is running
45;; Simul-Task. However, when operating as a pure
46;; MS-DOS machine, this 384K of memory is available
47;; for SMARTDRIVE.
48;; Note that it is an error to specify this switch
49;; if the machine is not a 6300 PLUS.
50;
51; NOTE WARNING: ALL OF THIS CODE ASSUMES THAT ALL HARDFILES ARE 512 BYTES
52; PER SECTOR!!! All other hardfile parameters are read via INT 13, but
53; Bytes/sector MUST be IBM standard 512.
54;
55; MODIFICATION HISTORY
56;
57; 1.00 5/10/86 ARR Initial version based on RAMDrive 1.16.
58; 1.01 5/20/86 ARR Slight re-organization of places where FLUSH_CACHE
59; is called to discard a track to make sure
60; TRACK_BUFFER is invalidated correctly.
61; 1.10 5/26/86 ARR Added Timer Int to flush cache after passage
62; of user setable time.
63; 1.20 5/27/86 ARR Additions at request of Neilk. /t:nnnnn /d /wb:on
64; /wb:off /wt:on /wt:off can be on device = line.
65; Lock cache function added.
66; 1.21 5/29/86 ARR Lock code made more intelligent.
67; 1.22 5/30/86 ARR /r reboot flush code added
68; 1.23 6/03/86 ARR Cache statistics added
69; 1.24 6/05/86 ARR Added /a "all cache" code
70; 1.25 6/10/86 ARR Added total used, total locked to status
71; 1.26 6/12/86 ARR /wb changed to /wc to align with docs. Discard
72; of track when write to locked track changed to
73; unlock. Discard of track when write with /wc:off
74; changed to immediate write through.
75; 1.27 6/17/86 ARR Bug regarding the INT 13 error which is not
76; an error (error 11H, ECC error corrected).
77; changed error handling logic to handle this
78; correctly (ignore it).
79; 1.28 7/31/86 ARR Default seg reg access byte changed from
80; 82H to 92H. This was needed for 80386 functionality.
81; Change to LOADALL.ASM, also RAMDrive problem.
82; 1.30 8/04/86 ARR Default cache size uped to 256K
83; Min cache size uped to 128K
84; 1.31 8/07/86 ARR Moved SMSW SIDT SGDT set into BLKMOV code for
85; problem with CEMM
86; 1.32 8/27/86 ARR Added code to A20 routine to provide approp
87; settle time for A20 switch to occur. This will
88; help us on Compaq machines and faster ATs and
89; 80386 machines. Thanks to CC of Compaq for fix.
90; 1.33 9/22/86 ARR Added more info to startup header, in particular,
91; tells you whether /A or /E cache.
92;
93; SMARTDRV
94; ------
95;
96; 1.00 5/13/87 SUNILP, GREGH, DAVIDW:
97; Modified INT13 to take care of multi track caching
98; Reduced functionality
99; Added two new IOCTL calls to increase/decrease
100; cache size, dynamically
101;
102;
103;; 7/24/87 WSH Added 6300 PLUS support. This code is marked by
104;; the use of double semi-colons to make it easy to
105;; find.
106;
107; 8/31/87 SUNILP
108; New extended memory allocation scheme. 386 support.
109; Support for new ps/2 systems. better 286 loadall
110; transfer. more complete expanded memory access.
111; several bug fixes.
112;
113; 1.01 9/17/87 SUNILP
114; Removed check that was limiting tracks to 32k bytes
115; Tracks can be upto 64k bytes now
116;
117; 1.02 10/22/87 SUNILP
118; Reduced statically allocated track buffer size to
119; minimum required
120;
121; 1.03 10/29/87 SUNILP
122; Changed name reported in messages to SMARTDrive
123;
124; 1/08/88 GREGH
125; Added support for OMTI controller. This code
126; is ifdef'd in with the OMTI keyword.
127;
128; 1.04 3/02/88 SUNILP
129; fix for recognition of 20MHz model 80.
130; fix for READ DASD int 13 dispatch.
131;
132; 1.05 5/13/88 SUNILP
133; fixed version checking to include dos 4.00
134;
135; 2.10 6/13/88 CHIPA Merged in these changes for HP Vectra
136; 11/20/87 RCP
137; Fixed a20 enabling/disabling problems on
138; Vectra machines.
139; 8/24/88 MRW Merged changes from Windows tree into DOS tree
140;
141
142BREAK MACRO subtitle
143 SUBTTL subtitle
144 PAGE
145ENDM
146
147.286p ; Use some 286 instructions in /E code
148
149DEBUG EQU 0
150S_OLIVETTI EQU 1 ; Flag for olivetti 6300 plus machine
151S_VECTRA EQU 2 ; Flag for HP Vectra machines
152WINDOWS_SWITCHES EQU 1 ; 1 = uses switches for windows, 0 = all switches
153;OMTI EQU 1 ; Used for code specific to the OMTI Controller
154
155MAX_HARD_FILES EQU 16 ; Max number of hardfiles our data structures support
156
157MIN_CACHE_SIZE_K EQU 128 ; Minimum size for cache in K (multiple of 16)
158
159IF1
160 IFDEF OMTI
161 %out OMTI Controller release
162 ENDIF
163ENDIF
164
165IF1
166 IF DEBUG
167 %out DEBUG VERSION!!!!!!
168 ENDIF
169ENDIF
170
171;; In order to address memory above 1 MB on the AT&T 6300 PLUS, it is
172;; necessary to use the special OS-MERGE hardware to activate lines
173;; A20 to A23. However, these lines can be disabled only by resetting
174;; the processor. The return address offset and segment can be found
175;; at 40:a2, noted here as RealLoc1.
176;;
177BiosSeg segment at 40h ;; Used to locate 6300 PLUS reset address
178 org 00a2h
179RealLoc1 dd 0
180BiosSeg ends
181;
182R_Mode_IDT segment at 0h
183R_mode_IDT ends
184;
185.xlist
186 include devsym.asm
187 include syscall.asm
188 include mi.asm
189.list
190
191; The INT13 device driver has 2 basic configurations.
192;
193; TYPE 1 - /E configuration using PC-AT extended memory and the LOADALL
194; instruction.
195;; The /U configuration using upper extended memory on the
196;; 6300 PLUS is a special case of the type 1 configuration.
197;
198; TYPE 2 - /A configuration using Above Board memory and EMM device
199; driver.
200;
201; The TYPE 2 driver uses the Above Board EMM device driver via INT 67H
202; to control access to, and to access the available memory.
203;
204; The TYPE 1 configuration uses the EMM control sector to
205; control access to the available memory
206;
207
208 include emm.asm
209
210 include loadall.asm
211
212 include above.asm
213
214 include ab_macro.asm
215
216BREAK <I/O Packet offset declarations>
217
218;
219; Define I/O packet offsets for useful values.
220;
221; SEE ALSO
222; MS-DOS Technical Reference manual section on Installable Device Drivers
223;
224
225; READ/WRITE PACKET OFFSETS
226RW_COUNT EQU WORD PTR (SIZE SRHEAD) + 5
227RW_TRANS EQU DWORD PTR (SIZE SRHEAD) + 1
228RW_START EQU WORD PTR (SIZE SRHEAD) + 7
229
230; MEDIA CHECK PACKET OFFSETS
231MCH_RETVAL EQU BYTE PTR (SIZE SRHEAD) + 1
232MCH_MEDIA EQU BYTE PTR (SIZE SRHEAD) + 0
233
234; BUILD BPB PACKET OFFSETS
235BPB_BUFFER EQU DWORD PTR (SIZE SRHEAD) + 1
236BPB_MEDIA EQU BYTE PTR (SIZE SRHEAD) + 0
237BPB_BPB EQU DWORD PTR (SIZE SRHEAD) + 5
238
239; INIT PACKET OFFSETS
240INIT_NUM EQU BYTE PTR (SIZE SRHEAD) + 0
241INIT_BREAK EQU DWORD PTR (SIZE SRHEAD) + 1
242INIT_BPB EQU DWORD PTR (SIZE SRHEAD) + 5
243INIT_DOSDEV EQU BYTE PTR (SIZE SRHEAD) + 9
244
245BREAK <Cache control structure>
246
247;
248; The cache control structure is the "management" data associated
249; with all of the data in the cache. The cache structures are
250; part of the device driver and they contain pointers to the
251; actual cache memory where the data is. This is more efficient
252; than putting the structures with the data as there is more overhead
253; to access stuff in the data area. The structures form a double
254; linked list in LRU order. The head points to the MRU element. The
255; tail points to the LRU element. Scans start at MRU as this is the
256; highest probability of a hit. Selection for bump is at LRU. All of
257; the links are short pointers. This limits the size of the cache
258; as the cache structures together with the device code must all
259; fit in 64K. This is more efficient than FAR links. Each cache element
260; contains one complete track of one of the INT 13 hard files (INT 13
261; floppy drives are NOT cached). Cache "read ahead" is obtained by
262; reading complete tracks into the cache even though the INT 13 user
263; may have only requested one sector. Write behind is accomplished
264; (if enabled) by holding tracks for a while allowing user writes
265; on that track to "accumulate".
266;
267; The original INT 13 caching algorithm (Aaronr) is sumarized as follows:
268;
269; If user read is in cache
270; Perform user read from cache
271; Else
272; If read is full track
273; Perform write through (if enabled)
274; Pass Read to old INT 13 handler (no cache operation)
275; Else
276; Read track into cache using old INT 13 handler
277; Perform user read out of cache
278;
279; If user write is in cache
280; If write buffering is enabled
281; Perform user write into cache
282; Else
283; Discard cache for this track
284; Pass write through to old INT 13 handler
285; Else
286; If write is full track
287; Perform write through (if enabled)
288; Pass Write to old INT 13 handler (no cache operation)
289; Else
290; If write buffering is enabled
291; Read track into cache using old INT 13 handler
292; Perform user write into cache
293; Else
294; Pass write through to old INT 13 handler
295;
296; SMARTDRV modifications:
297;
298; 1. Write through always.
299; 2. Multi track I/O capability support.
300; 3. Direct transfer between cache and user buffer address for
301; full tracks.
302;
303;
304;
305
306CACHE_CONTROL STRUC
307FWD_LRU_LNK DW ? ; Link to next CACHE_CONTROL, -1 if last
308BACK_LRU_LNK DW ? ; Link to previous CACHE_CONTROL, -1 if first
309BASE_OFFSET DD ? ; Offset releative to start of cache
310 ; memory of start of this track buffer
311TRACK_FLAGS DW ? ; Flags
312;
313; NOTE: The next two bytes are refed as a word.
314; MOV DX,WORD PTR STRC.TRACK_DRIVE
315; OR DH,80H
316; Puts the INT 13 drive in DL, and the head in DH which is correct
317; for an INT 13
318;
319TRACK_DRIVE DB ? ; INT 13 drive with high bit = 0
320TRACK_HEAD DB ? ; INT 13 head
321TRACK_CYLN DW ? ; INT 13 cylinder
322 ; High byte is low byte of cylinder #
323 ; High two bits of Low byte are high
324 ; two bits of cylinder #. Other bits
325 ; are 0. This makes it easy to load the
326 ; CX register for an INT 13 for this
327 ; track:
328 ; MOV CX,STRC.CACHE_CYLN
329 ; OR CL,1
330CACHE_CONTROL ENDS
331
332;
333; TRACK_FLAGS bits
334;
335TRACK_FREE EQU 0000000000000001B ; Track buffer is free
336TRACK_DIRTY EQU 0000000000000010B ; Track needs to be written
337TRACK_LOCKED EQU 0000000000000100B ; Track is locked
338
339BREAK <Device header>
340
341INT13CODE SEGMENT
342ASSUME CS:INT13CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
343
344 IF DEBUG
345 public strategy,int13$in,cmderr,err$cnt,err$exit,devexit
346 public INT13$IOCTL_Read,INT13$Read_St,INT13$Write_St,INT13$IOCTL_Write
347 public int_1C_handler,int_13_handler,POP_NO_PROC,INVALIDATE_CACHE
348 public CACHE_READ,CACHE_WRITE,FLUSH_PASS,FLUSH_INVALID_PASS
349 public FLUSH_WHOLE_CACHE_SAV,FLUSH_WHOLE_CACHE,FLUSH_CACHE
350 public WRITE_FROM_CACHE
351 public Cache_hit
352 public blkmov,INT_9,INT_19,RESET_SYSTEM,DO_INIT,SETBPB
353 public PRINT,ITOA,INT13$INIT,DRIVEPARMS,GETNUM,DISK_ABORT
354 public CTRL_IO,MM_SETDRIVE,FIND_VDRIVE,SET_RESET
355 public AT_EXT_INIT,FIX_DESCRIPTOR,ABOVE_INIT
356 public process_read_partial,process_block_read,pr_acc_trks
357 public pr_acc_trks,pr_cur_trk,process_write_partial,process_block_write
358 public check_parameters,process_regions,bytes_in_trk,sect_in_trk
359 public not_in_mem,read_disk
360 public not_in_memw,rd_partw,rd_part
361 public region
362 public SECTRKARRAY
363 ENDIF
364
365;**
366;
367; INT13 DEVICE HEADER
368;
369; COMMON TO TYPE 1, 2 drivers
370;
371; SEE ALSO
372; MS-DOS Technical Reference manual section on
373; Installable Device Drivers
374;
375
376;; The internal name of the device driver has been changed from SMARTDRV
377;; to SMARTAAR to avoid DOS name conflicts with files named SMARTDRV.*
378;;
379INT13DEV LABEL WORD
380 DW -1,-1
381DEVATS DW DEVOPCL + CharDev + DevIOCtl
382 DW STRATEGY
383 DW INT13$IN
384 DB "SMARTAAR" ;Name of device
385
386
387BREAK <Command dispatch table>
388
389;**
390;
391; This is the device driver command dispatch table.
392;
393; The first byte indicates the size of the table and therefore defines
394; which device function codes are valid.
395;
396; The entries in the table are NEAR word addresses of the appropriate
397; device routine. Thus the address of the routine to handle device function
398; 3 is:
399; WORD at ((INT13TBL + 1) + (2 * 3))
400;
401; COMMON TO TYPE 1, 2 drivers
402;
403;
404
405INT13TBL LABEL WORD
406 DB 15 ; Max allowed command code
407 DW INT13$INIT ; Init
408 DW CMDERR ; Media check
409 DW CMDERR ; Build BPB
410 DW INT13$IOCTL_Read ; IOCTL input
411 DW CMDERR ; Read
412 DW CMDERR ; Non-des read no-wait
413 DW INT13$Read_St ; Read status
414 DW CMDERR ; Read flush
415 DW CMDERR ; Write
416 DW CMDERR ; Write with verify
417 DW INT13$Write_St ; Output status
418 DW CMDERR ; Output flush
419 DW INT13$IOCTL_Write ; IOCTL output
420 DW DEVEXIT ; Open
421 DW DEVEXIT ; Close
422 DW CMDERR ; Rem media?
423
424BREAK <Device Control data>
425
426STATISTICS_SIZE EQU 40
427
428DRIVER_SEL DB 0 ; 0 if /E (TYPE 1), 1 if /A (TYPE 2),
429
430DEV_SIZE DW 256 ; Size in K of the cache
431
432SECTRACK DW ? ; Sectors per track
433
434current_dev_size dw ? ; Current size in K of cache
435
436;; Data peculiar to AT&T 6300 PLUS.
437
438S5_FLAG DB 0 ;; = S_OLIVETTI if 6300 plus machine
439 ;; = S_VECTRA if HP Vectra machine
440
441 db ? ; Spacer
442
443A20On dw 0DF90h
444A20Off dw 0DD00h
445
446special_mem dw 0
447;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
448; Unfortunately the code in smartdrv is very machine dependent
449; necessitating the use of a system flag to store the machine
450; configuration. The system flag is initialised during init time
451; and used when the caching services are requested. One bit which
452; is set and tested during caching is the state of the a20 line
453; when the cache code is entered. This is used because there are
454; applications which enable the a20 line and leave it enabled
455; throughout the duration of execution. Since smartdrv is a device
456; driver it shouldn't change the state of the environment.
457;
458; The system flag bit assignments are:
459;
460; -------------------------------------------------
461; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
462; -------------------------------------------------
463; |-----|-----| | | | | |
464; | | | | | -----286 (and AT)
465; | | | | -----------386 (later than B0)
466; not | | -----------------PS/2 machine
467; used | -----------------------Olivetti (not used)
468; -----------------------------A20 state (enabled ?)
469;
470; The Olivetti guys have defined a flag of their own. This should be removed
471; and the bit assigned out here for them should be used.
472;
473sys_flg db ?
474;
475; equates used for the system flag
476;
477M_286 equ 00000001B
478M_386 equ 00000010B
479M_PS2 equ 00000100B
480M_OLI equ 00001000B
481A20_ST equ 00010000B
482ifdef OMTI
483OMTI_EXT equ 00100000B
484endif
485
486;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
487; flag to indicate that reset code is being executed
488reboot_flg db 0
489;
490;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
491; emm ctrl address, needed for the reset code
492emm_ctrl_addr dw EXTMEM_LOW
493 dw EXTMEM_HIGH
494;
495;
496;
497;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
498; A20 address line state determination addresses
499;
500low_mem label dword
501 dw 20h*4
502 dw 0
503
504high_mem label dword
505 dw 20h*4 + 10h
506 dw 0ffffh
507
508;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
509; A20 PS2 equates
510;
511PS2_PORTA equ 0092h
512GATE_A20 equ 010b
513
514;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
515; 386 working areas
516start_gdt label byte
517nul_des desc <>
518cs_des desc <0FFFFh,0,0,09Fh,0,0>
519ss_des desc <0FFFFh,0,0,093h,0,0>
520ds_des desc <0FFFFh,0,0,093h,0,0>
521es_des desc <0FFFFh,0,0,093h,0,0>
522end_gdt label byte
523
524emm_gdt gdt_descriptor <end_gdt-start_gdt,0,0>
525;
526; int 15 gdt
527;
528int15_gdt label byte
529 desc <> ;dummy descriptor
530 desc <> ;descriptor for gdt itself
531src desc <0ffffh,,,93h,,>
532tgt desc <0ffffh,,,93h,,>
533 desc <> ;bios cs descriptor
534 desc <> ;stack segment descriptor
535
536;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537; 0 if device is valid
538; Non-0 if device install failed (device non-functional)
539;
540; We need this state because there is no way to "un-install"
541; a character device as there is with block devices
542;
543NULDEV DB 0
544
545;
546; 0 if caching is off
547; Non-0 if caching is on
548;
549ENABLE_13 DB 1 ; 0 for debug
550
551;
552; 0 if no write through
553; Non-0 if write through
554;
555WRITE_THROUGH DB 0
556
557;
558; 0 if no write buffering
559; Non-0 if write buffering enabled
560;
561WRITE_BUFF DB 0
562
563;
564; 0 if cache is unlocked
565; Non-0 if cache is locked
566;
567LOCK_CACHE DB 0
568
569;
570; 0 if full track I/O to tracks not in cache is not cached.
571; Non-0 if ALL I/O is to be cached
572;
573ALL_CACHE DB 1
574
575;
576; 0 if reboot flush is disabled
577; Non-0 if reboot flush is enabled
578;
579REBOOT_FLUSH DB 0
580
581;
582; An exclusion sem so that the INT 13 handler and the timer interact
583; without re-entrancy problems
584;
585INT_13_BUSY DB 0 ; Exclusion sem
586
587 EVEN ; Force word data to word align
588;
589; Statistics counters
590;
591; WARNING!!!! Do not disturb the order of these!!!! See IOCTL_READ code.
592;
593TOTAL_WRITES DD 0
594WRITE_HITS DD 0
595TOTAL_READS DD 0
596READ_HITS DD 0
597TTRACKS DW ? ; Total number of track buffers that fit
598 ; in DEV_SIZE K (number of cache elements)
599TOTAL_USED DW 0
600TOTAL_LOCKED DW 0
601TOTAL_DIRTY DW 0
602
603;
604; Tick counters
605;
606TICK_SETTING DW 1092 ; Approx 1 minute
607TICK_CNT DW 1092
608
609;
610; Non-zero if there are dirty buffers in the cache
611;
612DIRTY_CACHE DW 0 ; 0 if no dirty elements in cache
613
614BREAK <Common Device code>
615
616; INT13 DEVICE ENTRY POINTS - STRATEGY, INT13$IN
617;
618; This code is standard DOS device driver function dispatch
619; code. STRATEGY is the device driver strategy routine, INT13$IN
620; is the driver interrupt routine.
621;
622; INT13$IN uses INT13TBL to dispatch to the appropriate handler
623; for each device function. It also does standard packet
624; unpacking.
625;
626; SEE ALSO
627; MS-DOS Technical Reference manual section on
628; Installable Device Drivers
629;
630
631ASSUME CS:INT13CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
632
633PTRSAV DD 0 ; Storage location for packet addr
634
635;** STRATEGY - Device strategy routine
636;
637; Standard DOS 2.X 3.X device driver strategy routine. All it does
638; is save the packet address in PTRSAV.
639;
640; ENTRY ES:BX -> Device packet
641; EXIT NONE
642; USES NONE
643;
644; COMMON TO TYPE 1, 2 drivers
645;
646;
647
648STRATP PROC FAR
649
650STRATEGY:
651 MOV WORD PTR [PTRSAV],BX ; Save packet addr
652 MOV WORD PTR [PTRSAV+2],ES
653 RET
654
655STRATP ENDP
656
657;** INT13$IN - Device interrupt routine
658;
659; Standard DOS 2.X 3.X device driver interrupt routine.
660;
661;
662; ENTRY PTRSAV has packet address saved by previous STRATEGY call.
663; EXIT Dispatch to appropriate function handler
664; CX = Packet RW_COUNT
665; DX = Packet RW_START
666; ES:DI = Packet RW_TRANS
667; DS = INT13CODE
668; STACK has saved values of all regs but FLAGS
669; All function handlers must return through one of
670; the standard exit points
671; USES FLAGS
672;
673; COMMON TO TYPE 1, 2 drivers
674;
675;
676
677INT13$IN:
678 PUSH SI
679 PUSH AX
680 PUSH CX
681 PUSH DX
682 PUSH DI
683 PUSH BP
684 PUSH DS
685 PUSH ES
686 PUSH BX
687
688 LDS BX,[PTRSAV] ;GET POINTER TO I/O PACKET
689 ;
690 ; Set up registers for READ or WRITE since this is the most common case
691 ;
692 MOV CX,DS:[BX.RW_COUNT] ;CX = COUNT
693 MOV DX,DS:[BX.RW_START] ;DX = START SECTOR
694 MOV AL,DS:[BX.REQFUNC] ; Command code
695 MOV AH,BYTE PTR [INT13TBL] ; Valid range
696 CMP AL,AH
697 JA CMDERR ; Out of range command code
698 MOV SI,OFFSET INT13TBL + 1 ; Table of routines
699 CBW ; Make command code a word
700 ADD SI,AX ; Add it twice since one word in
701 ADD SI,AX ; table per command.
702
703 LES DI,DS:[BX.RW_TRANS] ; ES:DI transfer address
704
705 PUSH CS
706 POP DS
707
708ASSUME DS:INT13CODE
709
710 JMP WORD PTR [SI] ; GO DO COMMAND
711
712;** EXIT - ALL ROUTINES RETURN THROUGH ONE OF THESE PATHS
713;
714; Exit code entry points:
715;
716; SEE ALSO
717; MS-DOS Technical Reference manual section on
718; Installable Device Drivers
719;
720; GENERAL ENTRY for all entry points
721; All packet values appropriate to the specific device function
722; filled in except for the status word in the static request
723; header.
724;
725; CMDERR - Used when an invalid device command is detected
726;
727; ENTRY Stack has frame set up by INT13$IN
728; EXIT Standard Device driver with error 3
729; USES FLAGS
730;
731; ERR$CNT - Used when READ or WRITE wants to return with error code.
732; The packet RW_COUNT field is zeroed
733;
734; ENTRY AL is error code for low byte of packet status word
735; Stack has frame set up by INT13$IN
736; EXIT Standard Device driver with error AL
737; USES FLAGS
738;
739; ERR$EXIT - Used when a function other that READ or WRITE wants to
740; return an error
741;
742; ENTRY AL is error code for low byte of packet status word
743; Stack has frame set up by INT13$IN
744; EXIT Standard Device driver with error AL
745; USES FLAGS
746;
747; DEVEXIT - Used when a function wants to return with no error
748;
749; ENTRY AL is value for low byte of packet status word
750; NOTE: Typically there is no meaningful value
751; in the AL register when EXITing through here.
752; This is OK as the low 8 bits of the status word
753; have no meaning unless an error occured.
754; Stack has frame set up by INT13$IN
755; EXIT Standard Device driver with no error
756; USES FLAGS
757;
758; ERR1 - Used when a function wants to return with a value
759; for the whole status word
760;
761; ENTRY AX is value for packet status word
762; Stack has frame set up by INT13$IN
763; EXIT Standard Device driver with or without error
764; USES FLAGS
765;
766; COMMON TO TYPE 1, 2 drivers
767;
768;
769
770ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
771
772CMDERR:
773 MOV AL,3 ;UNKNOWN COMMAND ERROR
774 JMP SHORT ERR$EXIT
775
776ERR$CNT:
777 LDS BX,[PTRSAV]
778 MOV [BX.RW_COUNT],0 ; NO sectors transferred
779ERR$EXIT: ; Error in AL
780 MOV AH,(STERR + STDON) SHR 8 ;MARK ERROR RETURN
781 JMP SHORT ERR1
782
783EXITP PROC FAR
784
785DEVEXIT:
786 MOV AH,STDON SHR 8
787ERR1:
788 LDS BX,[PTRSAV]
789 MOV [BX.REQSTAT],AX ; Set return status
790
791 POP BX
792 POP ES
793 POP DS
794 POP BP
795 POP DI
796 POP DX
797 POP CX
798 POP AX
799 POP SI
800 RET ;RESTORE REGS AND RETURN
801EXITP ENDP
802
803;
804; The following functions are not supported at this time.
805;
806INT13$Read_St:
807ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
808INT13$Write_St:
809ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
810 JMP CMDERR
811
812BREAK <IOCTL Read function (get device control parms)>
813
814SET_ZRJ3:
815 JMP SET_ZR
816
817INT13$IOCTL_Read:
818ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
819 CLD
820 CMP CX,STATISTICS_SIZE ; Must have room to transfer data.
821 JB SET_ZRJ3 ; Not enough room from user
822 MOV [TOTAL_USED],0
823 MOV [TOTAL_LOCKED],0
824 MOV [TOTAL_DIRTY],0
825 ;
826 ; Count all occupied, dirty and locked elements
827 ;
828 MOV [INT_13_BUSY],1
829 MOV SI,[CACHE_HEAD]
830 INC SI
831NEXTCC:
832 DEC SI
833 TEST [SI.TRACK_FLAGS],TRACK_FREE
834 JNZ SKIPCC
835 INC [TOTAL_USED]
836 TEST [SI.TRACK_FLAGS],TRACK_LOCKED
837 JZ TEST_DIRTY
838 INC [TOTAL_LOCKED]
839TEST_DIRTY:
840 TEST [SI.TRACK_FLAGS],TRACK_DIRTY
841 JZ SKIPCC
842 INC [TOTAL_DIRTY]
843SKIPCC:
844 MOV SI,[SI.FWD_LRU_LNK]
845 INC SI
846 JNZ NEXTCC
847 MOV [INT_13_BUSY],0
848 MOV AL,[WRITE_THROUGH]
849 MOV AH,[WRITE_BUFF]
850 STOSW
851 MOV AL,[ENABLE_13]
852 MOV AH,[NULDEV]
853 STOSW
854 MOV AX,[TICK_SETTING]
855 STOSW
856 MOV AL,[LOCK_CACHE]
857 MOV AH,[REBOOT_FLUSH]
858 STOSW
859 MOV AL,[ALL_CACHE]
860 XOR AH,AH ; Unused currently
861 STOSW
862 MOV SI,OFFSET TOTAL_WRITES
863 MOV CX,12
864 REP MOVSW
865;
866; Transfer Above Board Information
867;
868 xor dx,dx
869 mov es:[di][0],dx
870 mov es:[di][2],dx
871 mov es:[di][4],dx
872 cmp [driver_sel],dl ; is it expanded memory?
873 jz no_ems ; no, info already set
874 mov cx,16
875 mov ax,[current_dev_size]
876 div cx
877 or dx,dx
878 jz no_remain
879 inc ax
880 xor dx,dx
881no_remain:
882 stosw
883 mov ax,[dev_size]
884 div cx
885 or dx,dx
886 jz no_remaind
887 inc ax
888no_remaind:
889 stosw
890 mov ax,MIN_CACHE_SIZE_K / 16
891 stosw
892no_ems:
893 LDS BX,[PTRSAV]
894ASSUME DS:NOTHING
895 MOV [BX.RW_COUNT],STATISTICS_SIZE ; transfer amount
896 JMP DEVEXIT
897
898BREAK <IOCTL Write functions (set device control parms and do flushes)>
899
900;
901; Command table for IOCTL Write functions. The first byte of the written
902; data contains the "function" code which is dispatched via this
903; table. The first byte is the maximum legal function code, then the word
904; addresses of the handlers for each function.
905;
906IOCTLTBL DB 0Ch
907 DW IOCTL_FLUSH ; Function 0h
908 DW IOCTL_FLUSH_INVALID ; Function 1h
909 DW IOCTL_DISABLE ; Function 2h
910 DW IOCTL_ENABLE ; Function 3h
911 DW IOCTL_WRITE_MOD ; Function 4h
912 DW IOCTL_SET_TICK ; Function 5h
913 DW IOCTL_LOCK ; Function 6h
914 DW IOCTL_UNLOCK ; Function 7h
915 DW IOCTL_REBOOT ; Function 8h
916 DW IOCTL_STAT_RESET ; Function 9h
917 DW IOCTL_ALL_CACHE ; Function Ah
918 dw ioctl_reduce_cache_size ; Function Bh
919 dw ioctl_increase_cache_size ; Function Ch
920
921SET_ZR:
922ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
923 LDS BX,[PTRSAV]
924ASSUME DS:NOTHING
925 MOV [BX.RW_COUNT],0 ; NO bytes transferred
926 JMP DEVEXIT
927
928SET_ERR_CNT:
929ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
930 MOV AL,3 ;UNKNOWN COMMAND ERROR
931 JMP ERR$CNT
932
933INT13$IOCTL_Write:
934ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
935 CMP [NULDEV],0 ; Is the device valid?
936 JNZ SET_ZR ; No, you get an error
937 MOV AL,ES:[DI] ; Get command byte
938 MOV AH,BYTE PTR [IOCTLTBL] ; Valid range
939 CMP AL,AH ; In range?
940 JA SET_ERR_CNT ; No
941 MOV SI,OFFSET IOCTLTBL + 1 ; Table of routines
942 CBW ; Make command code a word
943 ADD SI,AX ; Add it twice since one word in
944 ADD SI,AX ; table per command.
945 JMP WORD PTR [SI] ; GO DO COMMAND
946
947;** IOCTL_FLUSH -- Flush the cache, but keep the data
948;
949; ENTRY:
950; ES:DI is transfer address
951; CX is transfer count
952; EXIT:
953; Through one of the device exit paths
954; USES:
955; ALL
956;
957IOCTL_FLUSH:
958ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
959 MOV [INT_13_BUSY],1
960 CALL FLUSH_WHOLE_CACHE
961 MOV [INT_13_BUSY],0
962 JMP DEVEXIT
963
964;** IOCTL_FLUSH_INVALIDATE -- Flush the cache, and discard the data
965;
966; ENTRY:
967; ES:DI is transfer address
968; CX is transfer count
969; EXIT:
970; Through one of the device exit paths
971; USES:
972; ALL
973;
974IOCTL_FLUSH_INVALID:
975ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
976 MOV [INT_13_BUSY],1
977 CALL FLUSH_WHOLE_CACHE
978 CALL INVALIDATE_CACHE
979 MOV [INT_13_BUSY],0
980 JMP DEVEXIT
981
982;** IOCTL_DISABLE -- Disable the caching for both reads and writes
983;
984; Also flush and invalidate the cache
985;
986; ENTRY:
987; ES:DI is transfer address
988; CX is transfer count
989; EXIT:
990; Through one of the device exit paths
991; USES:
992; ALL
993;
994IOCTL_DISABLE:
995ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
996 MOV [INT_13_BUSY],1
997 CALL FLUSH_WHOLE_CACHE
998 CALL INVALIDATE_CACHE
999 MOV [ENABLE_13],0
1000 MOV [INT_13_BUSY],0
1001 JMP DEVEXIT
1002
1003;** IOCTL_ENABLE -- Enable the caching for reads (and possibly writes)
1004;
1005; ENTRY:
1006; ES:DI is transfer address
1007; CX is transfer count
1008; EXIT:
1009; Through one of the device exit paths
1010; USES:
1011; ALL
1012;
1013IOCTL_ENABLE:
1014ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1015 MOV [ENABLE_13],1
1016 JMP DEVEXIT
1017
1018;** IOCTL_WRITE_MOD -- En/Disable Write through and write caching
1019;
1020; ENTRY:
1021; ES:DI is transfer address
1022; CX is transfer count
1023; Second byte of data indicates what to set
1024; 0 Turn off Write through
1025; 1 Turn on Write through
1026; 2 Turn off Write buffering (also flush)
1027; 3 Turn on Write buffering (also flush)
1028; EXIT:
1029; Through one of the device exit paths
1030; USES:
1031; ALL
1032;
1033IOCTL_WRITE_MOD:
1034ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1035 CMP CX,2 ; Did user write enough?
1036 JB SET_ZR ; No, error
1037 MOV AL,ES:[DI.1] ; Get second byte
1038 CMP AL,3 ; In range?
1039 JA SET_ZR ; No, error
1040 CMP AL,2 ; WT or WB?
1041 JB SET_WRITE_TH ; WT
1042 DEC AL
1043 DEC AL ; 2 = 0, 3 = 1
1044 MOV [INT_13_BUSY],1
1045 MOV [WRITE_BUFF],AL
1046 CALL FLUSH_WHOLE_CACHE
1047 MOV [INT_13_BUSY],0
1048 JMP DEVEXIT
1049
1050SET_WRITE_TH:
1051 MOV [WRITE_THROUGH],AL
1052 JMP DEVEXIT
1053
1054;** IOCTL_SET_TICK -- Set tick count for auto flush
1055;
1056; ENTRY:
1057; ES:DI is transfer address
1058; CX is transfer count
1059; Second byte and third byte of data is value to set
1060; EXIT:
1061; Through one of the device exit paths
1062; USES:
1063; ALL
1064;
1065IOCTL_SET_TICK:
1066ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1067 CMP CX,3 ; Did user write enough?
1068 JB SET_ZRJ ; No, error
1069 MOV AX,ES:[DI.1] ; Get second byte and third byte as word
1070 MOV [TICK_SETTING],AX
1071 JMP DEVEXIT
1072
1073SET_ZRJ:
1074 JMP SET_ZR
1075
1076;** IOCTL_LOCK -- Lock the current cache
1077;
1078; Also flush the cache
1079;
1080; ENTRY:
1081; ES:DI is transfer address
1082; CX is transfer count
1083; EXIT:
1084; Through one of the device exit paths
1085; USES:
1086; ALL
1087;
1088IOCTL_LOCK:
1089ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1090 MOV [INT_13_BUSY],1
1091 CALL FLUSH_WHOLE_CACHE
1092 MOV [LOCK_CACHE],1
1093 ;
1094 ; Lock all cache elements that have something in them
1095 ;
1096 MOV SI,[CACHE_HEAD]
1097 INC SI
1098NEXTCS:
1099 DEC SI
1100 TEST [SI.TRACK_FLAGS],TRACK_FREE
1101 JNZ SKIPCS
1102 OR [SI.TRACK_FLAGS],TRACK_LOCKED
1103SKIPCS:
1104 MOV SI,[SI.FWD_LRU_LNK]
1105 INC SI
1106 JNZ NEXTCS
1107 MOV [INT_13_BUSY],0
1108 JMP DEVEXIT
1109
1110;** IOCTL_UNLOCK -- Unlock the cache
1111;
1112; ENTRY:
1113; ES:DI is transfer address
1114; CX is transfer count
1115; EXIT:
1116; Through one of the device exit paths
1117; USES:
1118; ALL
1119;
1120IOCTL_UNLOCK:
1121ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1122 MOV [INT_13_BUSY],1
1123 MOV [LOCK_CACHE],0
1124 ;
1125 ; UnLock all cache elements
1126 ;
1127 MOV SI,[CACHE_HEAD]
1128 INC SI
1129NEXTCX:
1130 DEC SI
1131 AND [SI.TRACK_FLAGS],NOT TRACK_LOCKED
1132 MOV SI,[SI.FWD_LRU_LNK]
1133 INC SI
1134 JNZ NEXTCX
1135 MOV [INT_13_BUSY],0
1136 JMP DEVEXIT
1137
1138;** IOCTL_REBOOT -- En/Disable Reboot flush
1139;
1140; ENTRY:
1141; ES:DI is transfer address
1142; CX is transfer count
1143; Second byte of data indicates what to set
1144; 0 Turn off reboot flush
1145; 1 Turn on reboot flush
1146; EXIT:
1147; Through one of the device exit paths
1148; USES:
1149; ALL
1150;
1151IOCTL_REBOOT:
1152ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1153 CMP CX,2 ; Did user write enough?
1154 JB SET_ZRJ ; No, error
1155 MOV AL,ES:[DI.1] ; Get second byte
1156 CMP AL,1 ; In range?
1157 JA SET_ZRJ ; No, error
1158 MOV [REBOOT_FLUSH],AL
1159 JMP DEVEXIT
1160
1161
1162;** IOCTL_STAT_RESET -- Reset the INT 13 statistics counters
1163;
1164; ENTRY:
1165; ES:DI is transfer address
1166; CX is transfer count
1167; EXIT:
1168; Through one of the device exit paths
1169; USES:
1170; ALL
1171;
1172IOCTL_STAT_RESET:
1173ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1174 XOR AX,AX
1175 MOV WORD PTR [TOTAL_WRITES],AX
1176 MOV WORD PTR [TOTAL_WRITES + 2],AX
1177 MOV WORD PTR [WRITE_HITS],AX
1178 MOV WORD PTR [WRITE_HITS + 2],AX
1179 MOV WORD PTR [TOTAL_READS],AX
1180 MOV WORD PTR [TOTAL_READS + 2],AX
1181 MOV WORD PTR [READ_HITS],AX
1182 MOV WORD PTR [READ_HITS + 2],AX
1183 JMP DEVEXIT
1184
1185;** IOCTL_ALL_CACHE -- En/Disable All cache
1186;
1187; ENTRY:
1188; ES:DI is transfer address
1189; CX is transfer count
1190; Second byte of data indicates what to set
1191; 0 Turn off all cache
1192; 1 Turn on all cache
1193; EXIT:
1194; Through one of the device exit paths
1195; USES:
1196; ALL
1197;
1198IOCTL_ALL_CACHE:
1199ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1200 CMP CX,2 ; Did user write enough?
1201 JB SET_ZRJ2 ; No, error
1202 MOV AL,ES:[DI.1] ; Get second byte
1203 CMP AL,1 ; In range?
1204 JA SET_ZRJ2 ; No, error
1205 MOV [ALL_CACHE],AL
1206 JMP DEVEXIT
1207
1208SET_ZRJ2:
1209 JMP SET_ZR
1210
1211;** ioctl_reduce_cache_size Dynamically reduce the size of the cache
1212;
1213; This routine dynamically reduces the size of an Above Board memory (/A)
1214; cache. The routine is passed the number of pages that the cache should
1215; be reduced by. The minimum size for a cache is 64K or 4 pages. In
1216; removing the tracks from the cache, the memory is returned to the EMM
1217; and then the cache control structures for that memory are taken off the
1218; LRU list, and set to free.
1219;
1220; NOTE: In this version of INT13, only reads are cached, so that when
1221; a cached track is "removed" from memory, it's contents are not
1222; updated to disk.
1223;
1224; ENTRY:
1225; ES:DI is transfer address
1226; EXIT:
1227; Through one of the device exit paths
1228; USES:
1229; ALL
1230;
1231error_reduce_exitj:
1232 jmp error_reduce_exit
1233
1234ioctl_reduce_cache_size:
1235 assume ds:Int13Code
1236 assume es:nothing
1237 assume ss:nothing
1238
1239 cmp byte ptr [driver_sel],1 ; Make sure using Above Board
1240 jnz error_reduce_exitj
1241 mov ax,es:[di.1] ; Get second byte
1242 or ax,ax ; Reduce by a non-0 amount?
1243 jnz do_it
1244 jmp devexit
1245do_it: mov cl,4 ; Multiply by 16 to get # of K bytes
1246 shl ax,cl ; AX has requested reduction in K
1247 mov bx,word ptr [current_dev_size]
1248 mov si,bx ; Save current_dev_size in SI for error
1249 sub bx,ax ; BX now has remaining cache memory in K
1250 cmp bx,MIN_CACHE_SIZE_K ; Compare BX with min cache in K bytes
1251 jl error_reduce_exitj
1252 mov word ptr [current_dev_size],bx
1253 shr bx,cl ; BX has new cache size in pages
1254 mov byte ptr [int_13_busy],1
1255;
1256; Request Reallocation of Pages from EMM
1257;
1258 push ax
1259 mov dx,word ptr [above_pid]
1260 mov ah,ABOVE_REALLOCATE_PID
1261 int 67h
1262 or ah,ah
1263 jnz real_fail
1264;
1265; Determine how many cache tracks will be lost
1266;
1267 mov bx,word ptr [sectrack] ; Init code checked for too large track
1268 mov cl,9
1269 shl bx,cl ; BX has bytes/track
1270 mov ax,word ptr [ttracks]
1271 mul bx ; AX:DX has bytes used by tracks
1272 xchg ax,si
1273 mov di,dx
1274 mov cx,1024
1275 mul cx ; AX:DX has total bytes allocated
1276 sub ax,si ; Find difference in allocated and used
1277 sbb dx,di
1278 xchg ax,si
1279 xchg dx,di
1280 pop ax ; AX still has requested reduction in K
1281 mul cx ; DX:AX has requested reduction in byte
1282
1283;
1284; Make sure the we have to free up tracks in order to satisfy the request
1285; HACK! HACK! HACK! Smartdrv should only allocate as many pages as it needs.
1286; ChipA 14-Mar-1988
1287;
1288 cmp dx,di
1289 ja free_tracks
1290 jb no_need_to_free_tracks
1291 cmp ax,si
1292 ja free_tracks
1293no_need_to_free_tracks:
1294 sub ax,ax
1295 mov dx,ax
1296 jmp all_freed
1297
1298free_tracks:
1299 sub ax,si ; Account for part not used
1300 sbb dx,di
1301 div bx ; AX has number of tracks being "lost"
1302 or dx,dx
1303 jz no_remainder
1304 inc ax ; Add one more track if remainder
1305;
1306; Determine which cache control structures we are to remove
1307;
1308no_remainder:
1309 mov si,ax
1310 mov cx,SIZE CACHE_CONTROL
1311 mul cx
1312 xchg ax,bx ; BX has backward offset into CCS's
1313 mov ax,word ptr [ttracks]
1314 sub word ptr [ttracks],si
1315 mul cx ; AX has end of Cache Control
1316 sub ax,bx ; AX has start offset of CCS's to remove
1317 mov cx,si ; CX has number of CCS's to remove
1318 mov si,word ptr [cache_control_ptr]
1319 add si,ax ; SI points to first CCS to modify
1320;
1321; Loop through each cache control structure, removing from LRU list
1322;
1323remove_cache_entries:
1324 mov word ptr [si].track_flags,TRACK_FREE
1325 call unlink_cache
1326 add si,SIZE CACHE_CONTROL
1327 loop remove_cache_entries
1328
1329all_freed:
1330 mov byte ptr [int_13_busy],0
1331 jmp devexit
1332
1333real_fail:
1334 pop ax
1335 mov [current_dev_size],si ; Restore former dev size
1336 mov byte ptr [int_13_busy],0
1337error_reduce_exit:
1338 mov al,0Ch ; General failure
1339 jmp err$cnt
1340
1341
1342;** ioctl_increase_cache_size Dynamically increase the size of the cache
1343;
1344; This routine dynamically increases the size of an Above Board memory (/A)
1345; cache. The routine is passed the number of pages that the cache should
1346; be increased by. The maximum size allowed is the size specified from the
1347; INT13.SYS command line. The cache control structures for the memory added
1348; to the cache are placed on the LRU list at the LRU position, so that they
1349; will be immediately available for incoming tracks.
1350;
1351; ENTRY:
1352; ES:DI is transfer address
1353; EXIT:
1354; Through one of the device exit paths
1355; USES:
1356; ALL
1357;
1358error_increase_exitj:
1359 jmp error_increase_exit
1360
1361ioctl_increase_cache_size:
1362 assume ds:Int13Code
1363 assume es:nothing
1364 assume ss:nothing
1365
1366 cmp [driver_sel],1 ; Make sure using Above Board
1367 jnz error_increase_exitj
1368 mov ax,es:[di.1] ; Get second byte
1369 mov cl,4 ; Multiply by 16 to get # of K bytes
1370 shl ax,cl ; AX has requested addition in K
1371 mov bx,word ptr [current_dev_size]
1372 mov si,bx ; Save current dev size for error
1373 add bx,ax ; BX now has new cache memory size in K
1374 cmp bx,[dev_size] ; Compare BX with largest size in K bytes
1375 jbe increase_size_ok
1376 mov bx, [dev_size] ; Go to MAX size
1377 mov ax, bx
1378 sub ax, si ; Correct increase
1379increase_size_ok:
1380 mov word ptr [current_dev_size],bx
1381 shr bx,cl ; BX has new cache size in pages
1382 mov [int_13_busy],1
1383;
1384; Request Reallocation of Pages from EMM
1385;
1386 push ax
1387 mov dx,[above_pid]
1388 mov ah,ABOVE_REALLOCATE_PID
1389 int 67h
1390 or ah,ah
1391 jnz realloc_fail
1392;
1393; Determine how many cache tracks will be gained
1394;
1395 mov bx,word ptr [sectrack] ; Init code checked for too large track
1396 mov cl,9
1397 shl bx,cl ; BX has bytes/track
1398 mov ax,word ptr [ttracks]
1399 mul bx ; AX:DX has bytes used by tracks
1400 xchg ax,si
1401 mov di,dx
1402 mov cx,1024
1403 mul cx ; AX:DX has total bytes allocated
1404 sub ax,si ; Find difference in allocated and used
1405 sbb dx,di
1406 xchg ax,si
1407 xchg dx,di
1408 pop ax ; AX still has requested reduction in K
1409 mul cx ; DX:AX has requested reduction in byte
1410 add ax,si ; Account for part not used
1411 adc dx,di
1412 div bx ; AX has number of tracks being "gained"
1413 or ax, ax ; DIV trashes flags
1414 jz nothing_to_gain
1415;
1416; Determine which cache control structures we are to add
1417;
1418 mov si,ax
1419 mov cx,SIZE CACHE_CONTROL
1420 mov ax,[ttracks]
1421 add [ttracks],si ; Update TTRACKS
1422 mul cx ; AX has end of Cache Control
1423 mov cx,si ; CX has number of CCS's to add
1424 mov si,[cache_control_ptr]
1425 add si,ax ; SI points to first CCS to modify
1426;
1427; Loop through each cache control structure, adding to LRU list
1428;
1429add_cache_entries:
1430 mov di,si ; Place element at LRU position
1431 xchg di,[cache_tail]
1432 mov [di].fwd_lru_lnk,si
1433 mov [si].back_lru_lnk,di
1434 mov [si].fwd_lru_lnk,-1
1435 mov [si].track_flags,TRACK_FREE
1436
1437 add si,SIZE CACHE_CONTROL
1438 loop add_cache_entries
1439nothing_to_gain:
1440 mov [int_13_busy],0
1441 jmp devexit
1442
1443realloc_fail:
1444 pop ax
1445 mov [current_dev_size],si ; Restore to original size
1446 mov [int_13_busy],0
1447error_increase_exit:
1448 mov al,0Ch ; General failure
1449 jmp err$cnt
1450
1451
1452;
1453; If the device errors out during install, we set the break address here.
1454;
1455ERROR_END LABEL BYTE
1456
1457BREAK <INT 1C (timer) handler>
1458
1459 EVEN ; Force word align
1460;
1461; Storage for the INT 1C vector BEFORE cache installed
1462;
1463OLD_1C DD ?
1464
1465;** INT_1C_HANDLER - Handler for INT 1C timer ticks
1466;
1467; ENTRY
1468; None
1469;
1470; EXIT
1471; To next 1C handler, EOI may be sent
1472;
1473; USES
1474; None
1475;
1476; SEE ALSO
1477; IBM PC TECH REF MANUAL section on INT 1C
1478; DOS PRINT utility (most of this is stolen from there)
1479;
1480INT_1C_HANDLER PROC FAR
1481ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1482 PUSH AX
1483 DEC [TICK_CNT]
1484 JNZ CHAIN_1C
1485 CMP [INT_13_BUSY],0
1486 JZ TRY_FLSH
1487RE_TRIGGER:
1488 INC [TICK_CNT] ; Set it back to 1 so next tick triggers
1489CHAIN_1C:
1490 POP AX
1491 JMP [OLD_1C]
1492
1493TRY_FLSH:
1494 mov al,00001011b ; Select ISR in 8259
1495 out 20H,al
1496 jmp short yyyy
1497yyyy:
1498 jmp short zzzz
1499zzzz:
1500 in al,20H ; Get ISR register
1501 and al,0FEH ; Mask timer int
1502 jnz RE_TRIGGER ; Another int is in progress
1503 INC [INT_13_BUSY] ; Exclude
1504 CMP [DIRTY_CACHE],0 ; Anything to do?
1505 JZ SKIP_FLSH ; No
1506 STI
1507 mov al,20H
1508 out 20H,al
1509 CALL FLUSH_WHOLE_CACHE_SAV
1510SKIP_FLSH:
1511 MOV AX,[TICK_SETTING]
1512 CLI
1513 MOV [TICK_CNT],AX
1514 MOV [INT_13_BUSY],0
1515 JMP CHAIN_1C
1516
1517INT_1C_HANDLER ENDP
1518
1519BREAK <INT 13 handler>
1520
1521
1522; INT 13 stack frame
1523;
1524STACK_FRAME STRUC
1525USER_OFF DW ? ; added for user transfer address
1526USER_ES DW ?
1527USER_DS DW ?
1528USER_DI DW ?
1529USER_SI DW ?
1530USER_BP DW ?
1531 DW ?
1532USER_BX DW ?
1533USER_DX DW ?
1534USER_CX DW ?
1535USER_AX DW ?
1536USER_IP DW ?
1537USER_CS DW ?
1538USER_FL DW ?
1539STACK_FRAME ENDS
1540
1541 EVEN ; Force word align
1542;
1543; Storage for the INT 13 vector BEFORE cache installed
1544;
1545OLD_13 DD ?
1546
1547;
1548; Array of sec/track for all hardfiles on system. First element cooresponds
1549; to first hard file.
1550; Value = 0 indicates no hardfile
1551;
1552SECTRKARRAY DB MAX_HARD_FILES DUP (0)
1553;
1554; ARRAY OF MAXIMUM USEABLE HEADS FOR ALL THE HARDFILES IN THE SYSTEM. FIRST
1555; ELEMENT CORRESPONDS TO FIRST HARDFILE.
1556; VALUE = FF INDICATES NO HARDFILE (SUNILP)
1557;
1558HDARRAY DB MAX_HARD_FILES DUP (0FFH)
1559
1560ifdef OMTI
1561OMTI_SET_CYL EQU 0EEh
1562OMTI_GET_CYL EQU 0FEh
1563OMTI_GET_REV EQU 0F9h
1564endif ;OMTI
1565;
1566; INT 13 function dispatch
1567; Addresses of routines for AH INT 13 functions
1568;
1569INT13DISPATCH LABEL WORD
1570 DW POP_NO_PROC ; 0, reset
1571 DW POP_NO_PROC ; 1, Read status
1572 DW CACHE_READ ; 2, read
1573 DW CACHE_WRITE ; 3, write
1574 DW POP_NO_PROC ; 4, verify
1575 DW INVALID_PASS ; 5, format
1576 DW INVALID_PASS ; 6, format
1577 DW INVALID_PASS ; 7, format
1578 DW POP_NO_PROC ; 8, drive parms
1579 DW INVALID_PASS ; 9, Init drive characteristic
1580 DW INVALID_PASS ; A, Read long
1581 DW INVALID_PASS ; B, Write long
1582 DW POP_NO_PROC ; C, Seek
1583 DW POP_NO_PROC ; D, Alt reset
1584 DW INVALID_PASS ; E, Read buffer
1585 DW INVALID_PASS ; F, Write buffer
1586 DW POP_NO_PROC ; 10, Test drive rdy
1587 DW POP_NO_PROC ; 11, Recalibrate
1588 DW POP_NO_PROC ; 12, Controller diag
1589 DW INVALID_PASS ; 13, Drive diag
1590 DW POP_NO_PROC ; 14, Controller diag internal
1591 DW POP_NO_PROC ; 15, READ DASD
1592;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1593;
1594; MODIFICATIONS TO DATA STRUCT TO SUPPORT MULTI-TRACK I/O
1595;
1596; sunilp
1597;
1598; extra declarations needed
1599;
1600max_hd db ? ;maximum useable head number for curr. drive
1601sect_in_trk db ? ;maximum sector number in trk for curr drive
1602bytes_in_trk dw ? ;numb of bytes in trk for current drive
1603int13err db ?
1604;
1605TRUE = 0ffH
1606FALSE = NOT TRUE
1607REG1_P = 001B
1608REG2_P = 010B
1609REG3_P = 100B
1610;
1611REG1t struc
1612START_H db ? ;start head
1613START_T dw ? ;start track
1614COUNT dw ? ;number of words
1615START_S dw ? ;start sector
1616REG1t ends
1617;
1618REG2t struc
1619 db ? ;start head
1620 dw ? ;start track
1621TRACKS db ? ;number of tracks
1622REG2t ends
1623;
1624REG3t struc
1625 db ? ;start head
1626 dw ? ;start track
1627 dw ? ;number of words
1628REG3t ends
1629;
1630REGIONt struc
1631FLAG db 0
1632REG1 db size REG1t dup(?)
1633REG2 db size REG2t dup(?)
1634REG3 db size REG3t dup(?)
1635REGIONt ends
1636;
1637;
1638REGION db size REGIONt dup(?)
1639;
1640;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1641;
1642; INT_13_HANDLER - Handler for INT 13 requests
1643;
1644; ENTRY
1645; All regs as for INT 13
1646;
1647; EXIT
1648; To old INT 13 handler with regs unchanged if cache not involved
1649; Else return in AH and flags as per INT 13.
1650;
1651; USES
1652; AH and carry bit of FLAGS
1653;
1654; SEE ALSO
1655; IBM PC TECH REF MANUAL section on INT 13
1656;
1657INT_13_HANDLER PROC FAR
1658ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1659 MOV [INT_13_BUSY],1 ; Exclude
1660 TEST DL,80H ; Hard file?
1661 JNZ IS_HARD ; Yes
1662NO_PROC:
1663 PUSHF
1664 CLI
1665 CALL [OLD_13] ; Let old handler do it
1666 MOV [INT_13_BUSY],0 ; Clear sem
1667 RET 2 ; "IRET" chucking flags
1668
1669;
1670; Pop off the stack frame and pass to old handler
1671;
1672POP_NO_PROC:
1673 POP BX
1674 POP ES
1675 POP DS
1676 ; Simulate POPA
1677 POP DI
1678 POP SI
1679 POP BP
1680 POP BX ; Dummy for pop sp
1681 POP BX
1682 POP DX
1683 POP CX
1684 POP AX
1685 ;
1686 JMP NO_PROC
1687
1688IS_HARD:
1689 STI ; INTs ok now
1690 ;
1691 ; Set up standard stack frame
1692 ;
1693 ; Simulate PUSHA
1694 PUSH AX
1695 PUSH CX
1696 PUSH DX
1697 PUSH BX
1698 PUSH BX ; dummy for push sp
1699 PUSH BP
1700 PUSH SI
1701 PUSH DI
1702 ;
1703 PUSH DS
1704 PUSH ES
1705 push bx
1706 ; Set frame pointer
1707 MOV BP,SP
1708 MOV BL,AH
1709 XOR BH,BH ; Command in BX
1710 PUSH CS
1711 POP DS
1712ASSUME DS:INT13CODE
1713 CMP [ENABLE_13],0 ; Are we enabled?
1714 JZ POP_NO_PROC ; No, ignore
1715
1716ifdef OMTI
1717;
1718; The following code is used to handle the extended cylinder access method
1719; used by the OMTI controller. This controller has a modified INT13 routine
1720; that uses a unique function number to tell the controller that the next
1721; access to INT13 is for an extended cylinder.
1722;
1723 test sys_flg,OMTI_EXT ; Are we in extended state?
1724 jnz in_extended_state
1725 cmp bx,OMTI_SET_CYL ; Is this the OMTI extended function?
1726 jnz check_command_range
1727 or sys_flg,OMTI_EXT
1728 jmp pop_no_proc
1729in_extended_state:
1730;
1731; If we are in the extended state, we want to make sure that this call
1732; does not go through into the cache. Therefore, we will check to see
1733; if this is a read or write function, and will return to the old INT13
1734; routine if so.
1735;
1736 and sys_flg,NOT OMTI_EXT ; Clear the extended flag
1737 cmp bx,2h ; READ
1738 jz pop_no_proc
1739 cmp bx,3h ; WRITE
1740 jz pop_no_proc
1741check_command_range:
1742;
1743; Allow the other OMTI functions to pass through
1744;
1745 cmp bx,OMTI_GET_CYL
1746 jz pop_no_proc
1747 cmp bx,OMTI_GET_REV
1748 jz pop_no_proc
1749endif ; OMTI
1750
1751 CMP BX,15H ; Command in range?
1752 JA INVALID_PASS ; No, throw out cache
1753 SHL BX,1 ; Times two bytes per table entry
1754 JMP [BX.INT13DISPATCH] ; Dispatch to handler
1755
1756;** FLUSH_INVALID_PASS -- Discard cache and pass through
1757;
1758; ENTRY:
1759; INT 13 regs except for BP,BX and DS
1760; EXIT:
1761; To old INT13 handler
1762;
1763FLUSH_INVALID_PASS:
1764ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1765 CALL FLUSH_WHOLE_CACHE
1766 CALL INVALIDATE_CACHE
1767 JMP POP_NO_PROC
1768
1769;** INVALID_PASS -- DISCARD CACHE, NO NEED TO FLUSH, PASS THROUGH
1770;
1771;** SUNIL PAI
1772;
1773; ENTRY:
1774; INT 13 regs except for BP,BX and DS
1775; EXIT:
1776; To old INT 13 handler
1777;
1778INVALID_PASS:
1779ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1780 CALL INVALIDATE_CACHE
1781 JMP POP_NO_PROC
1782
1783;** FLUSH_PASS -- Flush cache (but retain data) and pass through
1784;
1785; ENTRY:
1786; INT 13 regs except for BP,BX and DS
1787; EXIT:
1788; To old INT13 handler
1789;
1790FLUSH_PASS:
1791ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1792 CALL FLUSH_WHOLE_CACHE
1793 JMP POP_NO_PROC
1794
1795BREAK <CACHE_READ -- Read via cache>
1796
1797ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
1798;
1799cache_read:
1800;
1801; inputs: int13 regs except for bp - user stack frame
1802; bx - function (read,write)
1803; ds - int13code segment
1804;
1805; exits: to user success routine
1806; to user error routine
1807; to old int13 handler call
1808;
1809; uses: all but bp
1810;
1811; written by: sunil pai
1812;
1813 call check_parameters ; check user params
1814 jc pop_no_proc ; if error go to old int 13 handler
1815 ;
1816 call process_regions ; for multi-track business find the
1817 ; initial partial track, middle block
1818 ; and final partial track
1819 ; sets up REGION struct
1820;
1821; mov [int13err],FALSE ; clear int 13 error flag
1822;
1823 test [REGION.FLAG],REG1_P ; is region1 present
1824 je cr$2 ; if not present try region2
1825;
1826 mov dh,[REGION.REG1.START_H] ;start head
1827 mov cx,[REGION.REG1.START_T] ;get start track
1828 mov bx,[REGION.REG1.START_S] ;start sector
1829 mov ax,[REGION.REG1.COUNT] ;number of words
1830 call process_read_partial ;
1831 jc error ;go to process error
1832;
1833cr$2: test [REGION.FLAG],REG2_P ; is region2 present
1834 je cr$3 ; if not present try region3
1835;
1836 mov dh,[REGION.REG2.START_H] ; get start head
1837 mov cx,[REGION.REG2.START_T] ; get start track
1838 mov al,[REGION.REG2.TRACKS] ; get number of tracks
1839 call process_block_read ; multi track capability
1840 jc error ; fouled?
1841;
1842cr$3: test [REGION.FLAG],REG3_P ; is region3 present
1843 je suc ; if not we are done
1844;
1845 mov dh,[REGION.REG3.START_H] ; start head
1846 mov cx,[REGION.REG3.START_T] ; start track
1847 mov bx,1 ; start sector is 1
1848 mov ax,[REGION.REG3.COUNT] ; number of words
1849 call process_read_partial ;
1850 jc error ; just as we were about to fin!
1851;
1852; exit points - suc and error.
1853;
1854suc: and [bp.USER_FL],NOT f_Carry ;
1855 mov byte ptr [bp.USER_AX.1],0 ;
1856;
1857operation_done:
1858 mov cs:[int_13_busy],0 ;clear semaphore
1859 pop bx ;user offset
1860;
1861; simulate popa
1862;
1863 pop es
1864 pop ds
1865 pop di
1866 pop si
1867 pop bp
1868 pop bx
1869 pop bx
1870 pop dx
1871 pop cx
1872 pop ax
1873;
1874 iret
1875;
1876error:
1877;
1878; the next two instructions were removed because of the way Compaq
1879; handles bad sectors. they mark sectors bad not tracks. so in a
1880; track there may be good and bad sectors. However our int13 caching
1881; system does i/o from disk in tracks and will not get any track with
1882; bad sectors. to take care of this, we pass the read to the old int13
1883; handler even when there is an int 13 error
1884;
1885; test [int13err],TRUE
1886; jne er$1 ;if not int13 error go to call
1887 ;int13
1888 jmp pop_no_proc
1889;er$1: or [bp.USER_FL],f_Carry ;
1890; mov byte ptr [bp.USER_AX.1],AL ;int13 error code
1891; jmp operation_done
1892;
1893pop_no_procw:
1894 call invalidate_cache
1895 jmp pop_no_proc
1896;
1897cache_write:
1898;
1899; inputs: int13 regs except for bp - user stack frame
1900; bx - function (read,write)
1901; ds - int13code segment
1902;
1903; uses: all but bp
1904;
1905; written by: sunil pai
1906;
1907 call check_parameters ;check user params
1908 jc pop_no_procw ;error
1909 ;
1910 call process_regions ;for multi-track business find the
1911 ;initial partial track, middle block
1912 ;and final partial track
1913 ;sets up REGION struct
1914;
1915; writes always update disk, i.e., write through always operational
1916;
1917 mov ax,[bp.user_ax] ; restore int13 registers
1918 mov cx,[bp.user_cx] ;
1919 mov dx,[bp.user_dx] ;
1920 mov bx,[bp.user_bx] ;
1921 mov es,[bp.user_es] ;
1922 pushf ; since interrupt routine being called
1923 cli
1924 call [old_13] ; call old int 13 handler
1925 jnc cw$1 ; no error in writing to disk, continue
1926;
1927 or [bp.user_fl],f_Carry ; error then set carry
1928 mov byte ptr [bp.user_ax.1],ah ; and error code
1929 jmp short errorw ; and take error exit
1930;
1931; int 13 was successful, now we have to update cache as well
1932;
1933cw$1: and [bp.user_fl],not f_Carry ; int 13 success
1934 mov byte ptr [bp.user_ax.1],0 ;
1935;
1936 and dl,not 80h
1937;
1938 test [REGION.FLAG],REG1_P ; is region1 present
1939 je cw$2 ; if not present try region2
1940;
1941 mov dh,[REGION.REG1.START_H] ; get start head
1942 mov cx,[REGION.REG1.START_T] ; get start track
1943 mov bx,[REGION.REG1.START_S] ; start sector
1944 mov ax,[REGION.REG1.COUNT] ; number of words
1945 call process_write_partial ; partial write
1946 jc errorw ; go to process error
1947;
1948cw$2: test [REGION.FLAG],REG2_P ; is region2 present
1949 je cw$3 ; if not present try region3
1950;
1951 mov dh,[REGION.REG2.START_H] ; get start head
1952 mov cx,[REGION.REG2.START_T] ; get start track
1953 mov al,[REGION.REG2.TRACKS] ; get number of tracks
1954 call process_block_write ;
1955 jc errorw ; fouled?
1956;
1957cw$3: test [REGION.FLAG],REG3_P ; is region3 present
1958 je operation_donew ; if not we are done
1959;
1960 mov dh,[REGION.REG3.START_H] ; start head
1961 mov cx,[REGION.REG3.START_T] ; start track
1962 mov bx,1 ; start sector is 1
1963 mov ax,[REGION.REG3.COUNT] ; number of words
1964 call process_write_partial ;
1965 jnc operation_donew ; no error - finish
1966;
1967errorw: call invalidate_cache ; we are not sure of the
1968operation_donew:
1969 jmp operation_done
1970;
1971;
1972INT_13_HANDLER endp
1973;
1974process_read_partial proc near
1975;
1976; is used to read a partial track
1977;
1978; inputs: dx: head and drive (8th bit stripped)
1979; cx: track
1980; bx: start sector
1981; ax: number of words
1982;
1983; outputs:cy set if error
1984; clear if success
1985;
1986; strategy:
1987; if (track in cache) then {
1988; if (track in track_buffer) then
1989; perform user read from track buffer;
1990; else
1991; perform user read from cache;
1992; }
1993; else {
1994; read track into track buffer;
1995; read track buffer into cache;
1996; perform user read from track buffer;
1997; }
1998;
1999; cache transfers handled by freeing cache element if possible
2000; and making it lru
2001;
2002; uses: only dx assumed unchanged
2003;
2004 call track_in_cache ; is track in cache
2005 jc read_disk ; if not we have to read from disk
2006;
2007 cmp cx,[track_buffer_cyln] ; is it in the track buffer
2008 jnz not_in_mem ; no
2009 cmp dx,[track_buffer_hddr] ;
2010 jz read_bufferj ; yes
2011;
2012; read buffer from cache
2013;
2014not_in_mem:
2015 push dx
2016 xchg ax,bx ;get number of words in bx and start sect in ax
2017 dec ax ;0 based number
2018 mov cl,9 ;
2019 shl ax,cl ;byte offset
2020 xor dx,dx ;
2021;
2022 mov cx,bx ;number of words
2023 mov es,[bp.user_es] ;
2024 mov di,[bp.user_off];
2025 shl bx,1 ; number of bytes
2026 add [bp.user_off],bx ; update user offset
2027;
2028 add ax,word ptr [si.base_offset]
2029 adc dx,word ptr [si.base_offset.2]
2030 xor bh,bh
2031 push si
2032 push ds
2033 push bp
2034 call blkmov
2035 pop bp
2036 pop ds
2037 pop si
2038 pop dx
2039 jc err_cache
2040 call cache_is_mru
2041 clc
2042 ret
2043;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2044;
2045; track not in cache. see if free cache available to initiate transfer
2046;
2047read_disk:
2048 cmp di,-1 ;free cache
2049 jnz rd_part ;if present we can initiate read
2050 stc ; else error exit
2051 ret
2052;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2053;
2054read_bufferj:
2055 jmp short read_buffer
2056;
2057;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2058;
2059; cache element available. we can start by transferring track from disk
2060; to track buffer.
2061;
2062rd_part:
2063 mov si,di ;get element in si
2064 mov [track_buffer_cyln],-1 ;invalidate present track buffer
2065 mov [track_buffer_hddr],-1
2066 mov [si.track_flags],track_free ;if read fails
2067 push dx
2068 push cx
2069 push bx
2070 push ax
2071 or cl,1
2072 or dl,80h
2073 mov al,[sect_in_trk]
2074 mov ah,2 ; read
2075 push cs
2076 pop es
2077 mov bx,[track_buffer_ptr]
2078 pushf
2079 cli
2080 call [old_13]
2081 jnc rd$1
2082 cmp ah,11h ;the int13 error which is not an error
2083 je rd$1
2084 mov [int13err],TRUE
2085 add sp,8
2086 mov al,ah
2087 stc
2088 ret
2089;
2090; transfer track buffer to cache
2091;
2092rd$1:
2093 mov di,[track_buffer_ptr] ;es:di is transfer address
2094 mov cx,[bytes_in_trk]
2095 shr cx,1 ; cx is number words in track
2096 mov bh,1 ;write
2097 mov ax,word ptr [si.base_offset] ;address of cache
2098 mov dx,word ptr [si.base_offset.2] ;
2099 push ds
2100 push si
2101 push bp
2102 call blkmov
2103 pop bp
2104 pop si
2105 pop ds
2106 pop ax
2107 pop bx
2108 pop cx
2109 pop dx
2110 jnc rd$2
2111;
2112; error in transferring info to cache. invalidate cache element and
2113; make it lru
2114;
2115err_cache:
2116 mov [si.track_flags],track_free
2117 call cache_is_lru ; make cache element lru
2118 stc
2119 ret
2120;
2121; info transfer to cache successful. fill in track, head and drive
2122; info into cache control element and track buffer control element
2123;
2124if debug
2125rd_2:
2126endif
2127rd$2:
2128 mov word ptr [si.track_cyln],cx
2129 mov word ptr [si.track_drive],dx
2130 and [si.track_flags], not track_free
2131 mov word ptr [track_buffer_cyln],cx
2132 mov word ptr [track_buffer_hddr],dx
2133;
2134; perform user i/o from track buffer
2135;
2136read_buffer:
2137 call cache_is_mru
2138;
2139 mov si,bx ; start sector
2140 dec si ; 0 based number
2141 mov cl,9 ;
2142 shl si,cl ; byte offset in si
2143 add si,[track_buffer_ptr]
2144 mov cx,ax
2145 mov es,[bp.user_es]
2146 mov di,[bp.user_off]
2147 cld
2148rep movsw
2149 mov [bp.user_off],di
2150 clc
2151 ret
2152;
2153process_read_partial endp
2154;
2155process_block_read proc near
2156;
2157; inputs: ax = number of tracks
2158; dx = drive and head (8th bit stripped)
2159; cx = start track
2160; bp = user stack frame
2161;
2162; outputs: cy set if error
2163; cy clear if okay
2164;
2165; algorithm:
2166;
2167; repeat
2168; if (cur_trk in cache) then
2169; transfer track from cache to user buffer;
2170; no_of_trks = no_of_trks - 1
2171; else
2172; accumulate tracks which are not in cache
2173; read these in one disk operation
2174; transfer these from user buffer to cache
2175; no_of_trks = no_of_trks - accumulated_trks
2176; until no_of_trks == 0
2177;
2178pbr$1:
2179;
2180; since we are going to look ahead and see how many tracks can
2181; be dealt with together, we have to save start head and track
2182;
2183 push cx ; save start head
2184 push dx ; save start track
2185 xor ah,ah ;number of accumulated tracks
2186pbr$2: call track_in_cache ;
2187 jnc pbr$4 ; if current track in cache start processing
2188 inc dh ; go to next track
2189 call adj_hd_trk ;
2190 inc ah ;accumulate the tracks
2191 dec al ;are we done
2192 jne pbr$2 ;go to see next track
2193 pop dx ;restore start head and track
2194 pop cx ;
2195 call pr_acc_trks ;process the accumulated tracks
2196 ret ;we are done
2197pbr$4:
2198 pop dx ;restore start head and track
2199 pop cx
2200 or ah,ah ;are there any accumulated
2201 je pbr$5
2202 call pr_acc_trks ;process the accumulated tracks
2203 jc pbr$7 ;if carry set finish with error
2204 add dh,ah ;adjust track and head
2205 call adj_hd_trk
2206 jmp pbr$1
2207;
2208pbr$5: call pr_cur_trk ;process current track which is in cache
2209 jc pbr$7 ;if carry set finish with error
2210 inc dh
2211 call adj_hd_trk
2212pbr$6:
2213 dec al ;are we done?
2214 jne pbr$1 ;
2215 clc
2216pbr$7: ret
2217;
2218process_block_read endp
2219;
2220pr_acc_trks proc near
2221;
2222; inputs: cx = start track
2223; dh = start head
2224; ah = number of accumulated tracks
2225;
2226; outputs: if success :- cy clear, [bp.user_off] modified
2227; if failure :- cy set
2228;
2229; regs to be preserved: al,cx,si
2230;
2231; algorithm:
2232;
2233; read buffer from disk;
2234; for (cur_trk=start_trk,transfer_off=user_off; no_of_trks-- > 0;
2235; transfer_off=transfer_off+size_of_trk) do
2236; if ((cache=get_cache())!=-1) then
2237; transfer_trk_to_cache;
2238; else
2239; exit with error;
2240;
2241;
2242 push si
2243 push dx
2244 push cx
2245 push ax ; stack:- {ax,cx,dx,si}
2246;
2247; initialise int13 registers for reading the accumulated tracks into
2248; user memory.
2249;
2250 mov al,ah ;number of tracks
2251 xor ah,ah ;in ax
2252;
2253 mul [sect_in_trk] ;get number of sectors in ax
2254;
2255 mov ah,2
2256 or cx,1 ;start sector
2257;
2258 or dl,80h ;set hard disk bit
2259 mov bx,[bp.user_off];
2260 mov es,[bp.user_es] ;
2261;
2262 pushf
2263 cli
2264 call [old_13] ;perform multi track read
2265;
2266; check for int 13 error
2267;
2268 jnc pat$1 ;if okay proceed
2269;
2270 add sp,8 ;clear stack
2271 mov al,ah
2272 mov [int13err],TRUE ;
2273 stc
2274 ret ;error exit
2275;
2276; we have succesfully read al tracks into user memory. now these have
2277; to transfer these to cache.
2278;
2279pat$1: and dl,not 80h ;clear off 8th bit
2280 pop ax ;restore ax
2281 pop cx ;
2282 push cx ;
2283 push ax
2284;
2285 mov di,[bp.user_off];initialise transfer offset
2286;
2287; ah has number of tracks still left to be transferred
2288; di has transfer offset
2289; cx has current track number
2290; dx has current drive and head
2291;
2292pat$2:
2293 call get_cache ;get free cache element
2294;
2295; si = cache element
2296;
2297 cmp si,-1 ;was there an element
2298 je pat$5 ;cache saturated exit
2299;
2300; check if track is in track buffer
2301;
2302 cmp cx,[track_buffer_cyln]
2303 jne pat$21
2304 cmp dx,[track_buffer_hddr]
2305 jne pat$21
2306;
2307; track is in track buffer. to avoid two transfers invalidate
2308; track buffer
2309;
2310 mov [track_buffer_cyln],-1
2311 mov [track_buffer_hddr],-1
2312;
2313; transfer track from user buffer to cache
2314;
2315pat$21: mov [si.track_flags],track_free ;if write fails
2316 push cx
2317 push ax
2318 push ds
2319 push si
2320 push bp
2321 push di
2322 push dx
2323;
2324 mov es,[bp.user_es]
2325 mov cx,[bytes_in_trk]
2326 shr cx,1 ;words
2327 mov ax,word ptr [si.base_offset]
2328 mov dx,word ptr [si.base_offset.2]
2329 mov bh,1 ;write
2330 call blkmov
2331;
2332 pop dx
2333 pop di
2334 pop bp
2335 pop si
2336 pop ds
2337 pop ax
2338 pop cx
2339;
2340 jnc pat$3
2341;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2342; error in transferring information to cache. make it lru
2343;
2344;
2345 call cache_is_lru
2346pat$5:
2347 add sp,8
2348 stc
2349 ret ;cache error exit
2350;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2351;
2352; successfully transferred information to cache. fill in track and
2353; drive and head information into cache control element
2354;
2355pat$3: mov word ptr [si.track_cyln],cx
2356 mov word ptr [si.track_drive],dx
2357 and [si.track_flags],not track_free
2358 call cache_is_mru
2359
2360;
2361 add di,[bytes_in_trk] ;advance pointer in user transfer buffer to
2362 ;next track
2363;
2364 inc dh ;advance track
2365 call adj_hd_trk
2366;
2367pat$4: dec ah ;have we processed all the accumulated trks
2368 jne pat$2
2369 mov [bp.user_off],di ;update user transfer address to beyond
2370 ;this accumulated block
2371 pop ax
2372 pop cx
2373 pop dx
2374 pop si
2375 clc
2376 ret ;success exit
2377;
2378pr_acc_trks endp
2379;
2380pr_cur_trk proc near
2381;
2382; inputs:
2383; si = cache element
2384; cx = current track
2385; dx = drive and head
2386;
2387; outputs:
2388; cy = set if error
2389; = clear if success
2390;
2391; algorithm:
2392; transfer track from cache to user memory
2393;
2394 push ax
2395 push cx
2396 push dx
2397 push si
2398 push ds
2399 push bp
2400;
2401 mov cx,[bytes_in_trk]
2402 shr cx,1
2403 mov ax,word ptr [si.base_offset]
2404 mov dx,word ptr [si.base_offset.2]
2405 mov es,[bp.user_es]
2406 mov di,[bp.user_off]
2407 xor bh,bh ;read
2408 call blkmov
2409;
2410 pop bp
2411 pop ds
2412 pop si
2413 pop dx
2414 pop cx
2415 pop ax
2416;
2417 jnc pct$1
2418;
2419 mov [si.track_flags],track_free
2420 call cache_is_lru
2421 stc
2422 ret ;error exit
2423;
2424pct$1: call cache_is_mru
2425 mov di,[bytes_in_trk]
2426 add [bp.user_off],di
2427 clc
2428 ret
2429;
2430pr_cur_trk endp
2431;
2432process_write_partial proc near
2433;
2434; is used to write a partial track
2435;
2436; inputs: dx: int13 dx with high bit of dl set off
2437; cx: track
2438; bx: start sector
2439; ax: number of words
2440;
2441; outputs:cy set if error
2442; clear if success
2443;
2444; strategy:
2445; if (track in cache) then {
2446; if (track in track_buffer) then
2447; invalidate track buffer;
2448; perform user write into cache;
2449; }
2450; else {
2451; read track into track buffer;
2452; write track buffer into cache;
2453; }
2454;
2455;
2456 call track_in_cache ;is track in cache
2457 jc read_diskw ;if not we have to read from disk
2458;
2459 cmp cx,[track_buffer_cyln] ;is it in the track buffer
2460 jnz not_in_memw ;no
2461 cmp dx,[track_buffer_hddr] ;
2462 jnz not_in_memw ;no
2463 ;yes
2464;
2465 mov [track_buffer_cyln],-1 ;invalidate trk buf
2466 mov [track_buffer_hddr],-1 ;to avoid two transfers
2467;
2468; update cache element from user buffer
2469;
2470not_in_memw:
2471 push dx
2472 xchg ax,bx ;get number of words in bx and start sect in ax
2473 dec ax ;0 based number
2474 mov cl,9 ;
2475 shl ax,cl ;byte offset
2476 xor dx,dx ;
2477;
2478 mov cx,bx ;number of words
2479 mov es,[bp.user_es] ;
2480 mov di,[bp.user_off];
2481 shl bx,1
2482 add [bp.user_off],bx
2483;
2484 add ax,word ptr [si.base_offset]
2485 adc dx,word ptr [si.base_offset.2]
2486 mov bh,1 ;write
2487 push si
2488 push ds
2489 push bp
2490 call blkmov
2491 pop bp
2492 pop ds
2493 pop si
2494 pop dx
2495 jc err_cw
2496 call cache_is_mru
2497 clc
2498 ret
2499;
2500; cache error
2501;
2502err_cw: mov [si.track_flags],track_free
2503 call cache_is_lru
2504 stc
2505 ret
2506;
2507; track not in cache. see if free cache element available
2508;
2509read_diskw:
2510 cmp di,-1 ;free cache
2511 jnz rd_partw ;if present we can initiate read
2512 stc
2513 ret
2514;
2515; free cache element available. read track from disk into track buffer
2516;
2517rd_partw:
2518 mov si,di ;get element in si
2519 mov [track_buffer_cyln],-1
2520 mov [track_buffer_hddr],-1
2521 mov [si.track_flags],track_free
2522 push dx
2523 push cx
2524 push bx
2525 push ax
2526 or cl,1
2527 or dl,80h
2528 mov al,[sect_in_trk]
2529 mov ah,2
2530 push cs
2531 pop es
2532 mov bx,[track_buffer_ptr]
2533 pushf
2534 cli
2535 call [old_13]
2536 jnc wr$1
2537 cmp ah,11h ;the int13 error which is not an error
2538 je wr$1
2539 mov [int13err],TRUE
2540 add sp,8
2541 mov al,ah
2542 stc
2543 ret
2544;
2545; since we have already updated disk, the track read doesn't need
2546; to be updated from user buffer. transfer track from track buffer
2547; into cache
2548;
2549wr$1: mov di,[track_buffer_ptr] ;es:di is transfer address
2550 mov al,[sect_in_trk]
2551 xor ah,ah
2552 mov cl,8
2553 shl ax,cl
2554 mov cx,ax
2555 mov bh,1 ;write
2556 mov ax,word ptr [si.base_offset]
2557 mov dx,word ptr [si.base_offset.2]
2558 push ds
2559 push si
2560 push bp
2561 call blkmov
2562 pop bp
2563 pop si
2564 pop ds
2565 pop ax
2566 pop bx
2567 pop cx
2568 pop dx
2569 jnc wr$2
2570 ret
2571;
2572; information successfully transferred to cache. fill in cache
2573; control element with the info on head, drive and track
2574;
2575wr$2:
2576 mov word ptr [si.track_cyln],cx
2577 mov word ptr [si.track_drive],dx
2578 and [si.track_flags], not track_free
2579 mov word ptr [track_buffer_cyln],cx
2580 mov word ptr [track_buffer_hddr],dx
2581;
2582 call cache_is_mru
2583;
2584 shl ax,1
2585 add [bp.user_off],ax
2586 clc
2587 ret
2588;
2589process_write_partial endp
2590;
2591;
2592process_block_write proc near
2593;
2594; al = number of tracks
2595; cx = start track
2596; dx = drive and start head
2597; bp = user stack frame
2598;
2599; cy set if error
2600; cy clear if success
2601;
2602; algorithm: for (cur_trk=st_trk; trks-- > 0; )
2603; if (cur_trk in cache) then
2604; write cur_trk from user buffer into cache;
2605; else {
2606; get a free cache element;
2607; write cur_trk from user buffer into this cache elem
2608; }
2609;
2610 mov di,[bp.user_off]
2611;
2612pbw$1: push di ;save it because next call destroys di
2613 call track_in_cache ;is the track in cache
2614 jnc pbw$2
2615;
2616 cmp di,-1 ;no free cache
2617 je pbw$4 ;error exit
2618;
2619 mov si,di ;track was not in cache. now there will be one
2620 mov [si.track_flags],track_free
2621 mov word ptr [si.track_cyln],cx
2622 mov word ptr [si.track_drive],dx
2623;
2624pbw$2: pop di
2625;
2626; check if it is in track buffer also in which case invalidate trk buffer
2627;
2628 cmp cx,[track_buffer_cyln]
2629 jne pbw$21
2630 cmp dx,[track_buffer_hddr]
2631 jne pbw$21
2632;
2633; invalidate track buffer to avoid two transfers
2634;
2635 mov [track_buffer_cyln],-1
2636 mov [track_buffer_hddr],-1
2637;
2638; update cache from user buffer
2639pbw$21:
2640 push cx ;
2641 push ax
2642 push ds
2643 push si
2644 push bp
2645 push di
2646 push dx
2647;
2648 mov es,[bp.user_es]
2649 mov cx,[bytes_in_trk]
2650 shr cx,1
2651 mov ax,word ptr [si.base_offset]
2652 mov dx,word ptr [si.base_offset.2]
2653 mov bh,1
2654 call blkmov
2655;
2656 pop dx
2657 pop di
2658 pop bp
2659 pop si
2660 pop ds
2661 pop ax
2662 pop cx
2663;
2664 jnc pbw$22
2665 jmp err_cw
2666;
2667pbw$22: and [si.track_flags],not track_free
2668;
2669 inc dh ;go to next track
2670 call adj_hd_trk
2671pbw$3: add di,[bytes_in_trk]
2672 call cache_is_mru
2673;
2674 dec al ; are we done
2675 jne pbw$1
2676;
2677; success exit
2678 mov [bp.user_off],di
2679 clc
2680 ret
2681;
2682; error exit
2683;
2684pbw$4: pop di
2685 stc
2686 ret
2687;
2688process_block_write endp
2689;
2690check_parameters proc near
2691;
2692; inputs: same as int13 registers except for
2693; BP - user_stack_frame
2694; BX - function (either read or write)
2695; DS - int13code segment
2696;
2697; outputs: carry set if params invalid
2698; carry clear if params okay
2699;
2700; if parameters okay :
2701; dl - drive with high bit off
2702; bx - sector number
2703; cl - cleared of the sector number
2704;
2705;
2706; check for number of drives
2707;
2708 and dl, not 80H ; turn off high bit of drive
2709 cmp dl,MAX_HARD_FILES ; more than allowed drives?
2710 jae bad_parmx ; error.
2711;
2712; check for number of sectors
2713;
2714 or al,al ; zero sectors ?
2715 je bad_parmx ; error.
2716;
2717 cmp al,80h ; more than 80h sectors ?
2718 ja bad_parmx ; error.
2719;
2720; check for wrap in user transfer address
2721;
2722 mov di,[bp.user_bx] ; es:di is transfer address
2723 xor ah,ah ; ax has number of sectors
2724 mov si,ax ; get it into si
2725 push cx ;
2726 mov cl,9
2727 shl si,cl ; convert number of sectors into
2728 ; number of bytes
2729 dec si ; convert into zero based number
2730 pop cx ;
2731 add di,si ; add to transfer address offset
2732 jc bad_parmx ; if exceeds 64k offset then wrap
2733;
2734; get drive number into di to use as offset into sect / trk table
2735;
2736 mov di,dx ; drive number
2737 and di,0000000011111111B ; just get the relevant bits
2738;
2739; form sector number in bx and compare against allowed number of sectors
2740; in track on the drive indicated
2741;
2742 mov bx,cx ;
2743 and bx,0000000000111111B ; bl will then have sector number
2744 or bx,bx ; zero sector number
2745 je bad_parmx ; is bad
2746 cmp bl, [di.sectrkarray] ; is it more than number of sectors
2747 ; allowed
2748 ja bad_parmx ;
2749;
2750; check head parameter
2751;
2752 cmp dh,[di.hdarray] ; is it more than max useable val for drive
2753 ja bad_parmx ;
2754;
2755; do we need some code to check if read exceeds tracks in system ?
2756; should we also put a limit on the number of sectors that could
2757; be looked up in cache ?
2758;
2759;
2760; clear off sector number from cl to leave just trk number in cx
2761;
2762 and cl,11000000B ; clear off sector number
2763;
2764; store sectors in track for current drive and bytes in track for
2765; current drive in memory
2766;
2767 push bx
2768 push cx
2769 mov bl,[di.hdarray]
2770 mov [max_hd],bl ; maximum head number for cur. drive
2771 mov bl,[di.sectrkarray] ; number of sectors in trk
2772 mov [sect_in_trk],bl ; store this
2773 mov cl,9
2774 shl bx,cl ; bytes in track
2775 mov [bytes_in_trk],bx ; store this
2776 pop cx
2777 pop bx
2778 clc
2779 ret ;return with no error
2780;
2781bad_parmx:
2782 stc
2783 ret
2784;
2785check_parameters endp
2786;
2787process_regions proc near
2788;
2789; inputs: bx - start sector
2790; al - number of sectors
2791; cx - start track
2792;
2793; outputs: none
2794;
2795; action: initialise regions struct
2796;
2797 mov byte ptr [REGION.FLAG],0 ; clear regions flag
2798 cmp bx,1 ; if start sector is one
2799 je pr$2 ; might as well start with region2
2800;
2801; process region1
2802;
2803 or [REGION.FLAG],REG1_P ; mark region1 present
2804 mov ah,[sect_in_trk] ; get sectors in track
2805 sub ah,bl ; remaining number of sectors in track
2806 inc ah ; adjust 0 based numb to one based numb
2807 cmp ah,al
2808 jbe pr$1 ; if below or equal ah has number of sectors
2809 ; in region1
2810 mov ah,al ; else all the sectors are in region1
2811pr$1: sub al,ah ; adjust number of sectors
2812 mov [REGION.REG1.START_H],dh
2813 mov [REGION.REG1.START_T],cx
2814 mov [REGION.REG1.START_S],bx
2815 push cx ; save these registers
2816 push ax ;
2817 mov al,ah ;
2818 xor ah,ah ; ax has number of sectors now
2819 mov cl,8 ;
2820 shl ax,cl ; multiply by 256 to get number of words
2821 mov [REGION.REG1.COUNT],ax ; store this count
2822 pop ax ;
2823 pop cx
2824 inc dh
2825 call adj_hd_trk
2826;
2827; process region2
2828;
2829pr$2: or al,al ; are we done
2830 je pr$end ;
2831 xor ah,ah ; ax has number of sectors
2832 div [sect_in_trk] ; find number of tracks
2833 or al,al ; al will have number of full tracks
2834 ; ah will have number of sectors left
2835 je pr$3 ; if no full tracks no region2
2836;
2837 or [REGION.FLAG],REG2_P ; mark region2 present
2838 mov [REGION.REG2.START_H],dh
2839 mov [REGION.REG2.START_T],cx; store start track
2840 mov [REGION.REG2.TRACKS],al ; and number of tracks
2841 add dh,al ; adjust track number
2842 call adj_hd_trk
2843;
2844; process region3
2845;
2846pr$3: or ah,ah ; are we done (no sectors left)
2847 je pr$end ; if yes go to fin
2848 or [REGION.FLAG],REG3_P ; else mark region3 present
2849 mov [REGION.REG3.START_H],dh
2850 mov [REGION.REG3.START_T],cx ;store track number
2851 mov cl,8
2852 mov al,ah
2853 xor ah,ah ; convert number of sectors into number of
2854 shl ax,cl ; words
2855 mov [REGION.REG3.COUNT],ax ; store this
2856pr$end:
2857;
2858 ret
2859;
2860process_regions endp
2861;
2862; Support Routines:
2863;
2864;
2865track_in_cache proc near
2866;
2867; input: dl = drive number with bit 8 set off
2868; cx = cylinder number
2869;
2870 mov di,-1 ; di will return lru item nearest to matching
2871 ; element, -1 if none
2872 mov si,[cache_head] ; start with mru cache entry
2873 inc si ; to counter next instruction
2874nexte:
2875 dec si ; to counter last instruction in the loop
2876 test [si.track_flags],track_locked ; is the track locked?
2877 jnz no_set ;
2878 mov di,si ; if not locked update di to this element
2879no_set:
2880 test [si.track_flags],track_free ; is element free
2881 jnz skipe ; if free we need not check this one
2882 cmp dx,word ptr [si.track_drive] ; if not free check drive+head
2883 jnz skipe ;
2884 cmp cx,[si.track_cyln] ; and cylinder number
2885 jz tic$1 ; if found exit routine
2886skipe:
2887 mov si,[si.fwd_lru_lnk] ; else go to check next cache element
2888 inc si ; if last element was end then si = -1
2889 jnz nexte ; and incrementing it will set zero flag
2890 stc
2891 ret
2892tic$1: clc
2893 ret
2894;
2895track_in_cache endp
2896;
2897get_cache proc near
2898;
2899; inputs: none
2900; outputs: si = lru cache element not locked
2901; = -1 if all elems locked
2902;
2903 mov si,[cache_tail] ;start with lru element
2904 inc si ;to counter next instruction
2905gc$1:
2906 dec si ; to counter last instruction in loop
2907 test [si.track_flags],track_locked ; is the element locked
2908 jz gc$2 ; if not locked this is the lucky(?) guy
2909;
2910 mov si,[si.back_lru_lnk] ; else go back in chain to check the
2911 ; next recently used cache element
2912 inc si ; as before -1 is the end of chain
2913 jnz gc$1 ; incrementing it will set zero flag
2914;
2915 dec si ; no element found, si = -1
2916;
2917gc$2: ret
2918;
2919get_cache endp
2920;
2921adj_hd_trk proc near
2922;
2923; inputs: ch,cl track number
2924; dh changed head number to be checked and adjusted
2925;
2926; outputs: cx and dh updated
2927;
2928 pushf
2929aht$1: cmp dh,[max_hd] ;is the head number > heads on drive
2930 jbe aht$2
2931 sub dh,[max_hd] ;if so decrease head number by number of
2932 ;heads on drive
2933 dec dh ;by one more
2934 add ch,1 ;and step to next track
2935 jnc aht$1
2936 add cl,40h
2937 jmp aht$1
2938aht$2: popf
2939 ret
2940;
2941adj_hd_trk endp
2942
2943CACHE_HIT PROC NEAR
2944ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
2945CACHE_HIT ENDP
2946
2947
2948;** INVALIDATE_CACHE -- Discard all cache info
2949;
2950; ENTRY
2951; Cache is flushed (If it is not, all dirty info will simply be chucked)
2952; EXIT
2953; All elements of cache are marked free
2954; USES
2955; BX,FLAGS
2956;
2957INVALIDATE_CACHE PROC NEAR
2958ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
2959 MOV BX,[CACHE_HEAD]
2960 INC BX ; Counter next instruction
2961NEXTC:
2962 DEC BX
2963 MOV [BX.TRACK_FLAGS],TRACK_FREE
2964 MOV BX,[BX.FWD_LRU_LNK]
2965 INC BX
2966 JNZ NEXTC
2967 ;
2968 ; Track buffer invalid too
2969 ;
2970 MOV [TRACK_BUFFER_CYLN],-1
2971 MOV [TRACK_BUFFER_HDDR],-1
2972 MOV [DIRTY_CACHE],0
2973 ret
2974
2975INVALIDATE_CACHE ENDP
2976
2977;** CACHE_IS_MRU -- Put cache element in LRU chain at MRU position
2978;
2979; ENTRY
2980; SI points cache element to place at MRU position
2981; EXIT
2982; SI is at MRU position (head)
2983; USES
2984; DI,FLAGS
2985;
2986CACHE_IS_MRU PROC NEAR
2987ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
2988 push di
2989 CMP SI,[CACHE_HEAD]
2990 JZ RET444
2991 CALL UNLINK_CACHE
2992 MOV DI,SI
2993 XCHG DI,[CACHE_HEAD]
2994 MOV [DI.BACK_LRU_LNK],SI
2995 MOV [SI.FWD_LRU_LNK],DI
2996 MOV [SI.BACK_LRU_LNK],-1
2997RET444: pop di
2998 RET
2999
3000CACHE_IS_MRU ENDP
3001
3002;** CACHE_IS_LRU -- Put cache element in LRU chain at LRU position
3003;
3004; ENTRY
3005; SI points to cache element to place at LRU position
3006; EXIT
3007; SI is at LRU position (tail)
3008; USES
3009; DI,FLAGS
3010;
3011CACHE_IS_LRU PROC NEAR
3012ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3013 push di
3014 CMP SI,[CACHE_TAIL]
3015 JZ RET555
3016 CALL UNLINK_CACHE
3017 MOV DI,SI
3018 XCHG DI,[CACHE_TAIL]
3019 MOV [DI.FWD_LRU_LNK],SI
3020 MOV [SI.BACK_LRU_LNK],DI
3021 MOV [SI.FWD_LRU_LNK],-1
3022RET555: pop di
3023 RET
3024
3025CACHE_IS_LRU ENDP
3026
3027;** UNLINK_CACHE -- Unlink cache element from LRU chain
3028;
3029; ENTRY
3030; SI points to element to unlink
3031; EXIT
3032; SI is unlinked
3033; USES
3034; DI,FLAGS
3035;
3036UNLINK_CACHE PROC NEAR
3037ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3038 PUSH BX
3039 MOV DI,[SI.BACK_LRU_LNK] ; Get prev guy
3040 INC DI ; Guy First?
3041 JZ NEW_HEAD ; Yes
3042 DEC DI
3043 MOV BX,[SI.FWD_LRU_LNK] ; Get next guy
3044 MOV [DI.FWD_LRU_LNK],BX ; Prev fwd is my fwd
3045 INC BX ; Is that guy last?
3046 JZ NEW_TAIL ; Yes
3047 DEC BX
3048 MOV [BX.BACK_LRU_LNK],DI ; Next back is my back
3049NULL_CACHE:
3050 POP BX
3051 RET
3052
3053NEW_HEAD:
3054 MOV DI,[SI.FWD_LRU_LNK] ; Is head also tail?
3055 INC DI
3056 JZ NULL_CACHE ; Yes
3057 DEC DI
3058 MOV [CACHE_HEAD],DI ; New head
3059 MOV [DI.BACK_LRU_LNK],-1 ; New head has no back link
3060 POP BX
3061 RET
3062
3063NEW_TAIL:
3064 MOV [CACHE_TAIL],DI ; New tail
3065 POP BX
3066 RET
3067UNLINK_CACHE ENDP
3068
3069RETRY_CNT DB ?
3070
3071;** WRITE_FROM_CACHE -- Write out cache element to disk
3072;
3073; ENTRY
3074; SI -> cache element to write
3075; EXIT
3076; Carry Clear
3077; Written OK
3078; Track buffer is set to this track
3079; Carry Set
3080; Error, AL is error code
3081; Track buffer is set to empty
3082; USES
3083; AX,BX,CX,DX,ES,DI,FLAGS
3084;
3085WRITE_FROM_CACHE PROC NEAR
3086ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3087 ;
3088 ; First transfer track down to track buffer because we can't write
3089 ; direct to extended or expanded mem with INT 13
3090 ;
3091 PUSH CS
3092 POP ES
3093 MOV DI,[TRACK_BUFFER_PTR] ; ES:DI is transfer addr for BLKMOV
3094 MOV BX,WORD PTR [SI.TRACK_DRIVE]
3095 XOR BH,BH
3096 MOV AL,[BX.SECTRKARRAY]
3097 XOR AH,AH
3098 PUSH AX
3099 MOV CL,8
3100 SHL AX,CL ; AX is words in track
3101 MOV CX,AX
3102 XOR BH,BH ; Read
3103 MOV AX,WORD PTR [SI.BASE_OFFSET]
3104 MOV DX,WORD PTR [SI.BASE_OFFSET.2] ; DX:AX is address in mem
3105 PUSH DS
3106 PUSH SI
3107 PUSH BP
3108 CALL BLKMOV ; Track buffer contents to track buffer
3109 POP BP
3110 POP SI
3111 POP DS
3112 JC ERR_FLP
3113 POP AX ; AL is sec/trk
3114 ;
3115 ; Now write it out to drive from the track buffer
3116 ;
3117 MOV CX,[SI.TRACK_CYLN]
3118 MOV DX,WORD PTR [SI.TRACK_DRIVE]
3119 MOV [TRACK_BUFFER_CYLN],CX ; Set track buffer currency
3120 MOV [TRACK_BUFFER_HDDR],DX
3121 OR CL,1
3122 OR DL,80H
3123 MOV AH,3
3124 PUSH CS
3125 POP ES
3126 MOV BX,[TRACK_BUFFER_PTR]
3127 PUSH AX
3128 MOV [RETRY_CNT],5
3129RETRY_WRITE:
3130 PUSHF
3131 CALL [OLD_13] ; Write it out
3132 JC ERR_RETRY
3133NO_ERR1:
3134 POP AX
3135ERR_FL:
3136 ret
3137
3138ERR_RETRY:
3139 CMP AH,11H ; The error that is not an error?
3140 JZ NO_ERR1 ; Yes, cmp cleared carry
3141 PUSH AX ; Save error in AH
3142 MOV AH,0 ; Reset
3143 INT 13H
3144 POP AX ; Get error back
3145 DEC [RETRY_CNT]
3146 JZ SET_ERR ; Return error
3147 POP AX ; Recover correct AX for INT 13
3148 PUSH AX
3149 JMP RETRY_WRITE
3150
3151SET_ERR:
3152 MOV AL,AH ; INT 13 error to AL
3153ERR_FLP:
3154 ADD SP,2
3155 STC
3156 MOV [TRACK_BUFFER_CYLN],-1 ; Zap the track buffer
3157 MOV [TRACK_BUFFER_HDDR],-1
3158 JMP ERR_FL
3159
3160WRITE_FROM_CACHE ENDP
3161
3162;** FLUSH_CACHE -- Flush specific cache element if it's dirty
3163;
3164; ENTRY
3165; SI points to element to flush
3166; EXIT
3167; Carry Clear
3168; SI is flushed if it was dirty
3169; SI.TRACK_FLAGS dirty bit clear
3170; Track buffer set to this track
3171; Carry Set
3172; SI could not be flushed
3173; SI.TRACK_FLAGS = free
3174; AL is error code
3175; Track buffer set to empty
3176; USES
3177; AX,BX,CX,DX,ES,DI,FLAGS
3178;
3179FLUSH_CACHE PROC NEAR
3180ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3181 TEST [SI.TRACK_FLAGS],TRACK_FREE ; Clears carry
3182 JNZ IGNORE_TRK
3183 TEST [SI.TRACK_FLAGS],TRACK_DIRTY ; Clears carry
3184 JZ IGNORE_TRK
3185 CALL WRITE_FROM_CACHE
3186 DEC [DIRTY_CACHE] ; Doesn't effect carry
3187 JC FLUSH_ERRX
3188 AND [SI.TRACK_FLAGS],NOT TRACK_DIRTY ; Clears carry
3189IGNORE_TRK:
3190 ret
3191
3192FLUSH_ERRX:
3193 MOV [SI.TRACK_FLAGS],TRACK_FREE ; Track gone, unlocked
3194 RET
3195
3196FLUSH_CACHE ENDP
3197
3198;** FLUSH_WHOLE_CACHE_SAV -- Flush all dirty cache elements saving regs
3199;
3200; ENTRY
3201; None
3202; EXIT
3203; Cache flushed
3204; USES
3205; FLAGS
3206;
3207FLUSH_WHOLE_CACHE_SAV PROC NEAR
3208ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
3209 ; Simulate PUSHA
3210 PUSH AX
3211 PUSH CX
3212 PUSH DX
3213 PUSH BX
3214 PUSH BX ; dummy for push sp
3215 PUSH BP
3216 PUSH SI
3217 PUSH DI
3218 ;
3219 PUSH DS
3220 PUSH ES
3221 PUSH CS
3222 POP DS
3223ASSUME DS:INT13CODE
3224 CALL FLUSH_WHOLE_CACHE
3225 POP ES
3226 POP DS
3227 ; Simulate POPA
3228 POP DI
3229 POP SI
3230 POP BP
3231 POP BX ; Dummy for pop sp
3232 POP BX
3233 POP DX
3234 POP CX
3235 POP AX
3236 ;
3237 ret
3238FLUSH_WHOLE_CACHE_SAV ENDP
3239
3240;** FLUSH_WHOLE_CACHE -- Flush all dirty cache elements
3241;
3242; ENTRY
3243; None
3244; EXIT
3245; Cache flushed
3246; USES
3247; AX,BX,CX,DX,ES,SI,DI,FLAGS
3248;
3249FLUSH_WHOLE_CACHE PROC NEAR
3250ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3251 MOV SI,[CACHE_HEAD]
3252 INC SI ; Counter next instruction
3253FLSH_LP:
3254 DEC SI
3255 CALL FLUSH_CACHE
3256 MOV SI,[SI.FWD_LRU_LNK]
3257 INC SI
3258 JNZ FLSH_LP
3259FLUSH_DONE:
3260 MOV [DIRTY_CACHE],0 ; No dirty guys in cache
3261 ret
3262
3263FLUSH_WHOLE_CACHE ENDP
3264
3265BREAK <Drive code for /E driver>
3266
3267;
3268; The following label defines the start of the I/O code which is driver type
3269; specific.
3270;
3271; THE TYPE 2 driver must REPLACE this code with code appropriate
3272; to the driver type.
3273;
3274 EVEN ; Force start of drive code to word boundary
3275
3276DRIVE_CODE LABEL WORD
3277
3278EXTMEM_LOW EQU 0000H ; 24 bit addr of start of extended memory
3279EXTMEM_HIGH EQU 0010H
3280
3281;** BASE_ADDR data element
3282;
3283; The next value defines the 24 bit address of the start of the memory for
3284; the cache. It is equal to the EMM_BASE value in the
3285; EMM_REC structure for the cache.
3286;
3287; NOTE THAT IT IS INITIALIZED TO THE START OF EXTENDED MEMORY. This is
3288; because BLKMOV is used to read the EMM_CTRL sector during initialization
3289; of a TYPE 1 driver.
3290;
3291; NOTE: This data element is shared by TYPE 1, 2 drivers, but
3292; its meaning and correct initial value are driver type specific.
3293;
3294
3295;; NOTE: The value at BASE_ADDR is patched during initialization when
3296;; loading a RAMDrive into upper extended memory on a PLUS
3297;;
3298BASE_ADDR LABEL DWORD ; 24 bit address of start of this RAMDRV
3299 DW EXTMEM_LOW
3300 DW EXTMEM_HIGH
3301;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3302;** BLKMOV - Perform transfer for TYPE 1 driver
3303;
3304; This routine is the transfer routine for moving bytes
3305; to and from the AT extended memory in real mode using
3306; the LOADALL instruction. The LOADALL instruction is used
3307; to set up a segment descriptor which has a 24 bit address.
3308; During the time the LOADALL 24 bit segment descriptor is
3309; in effect we must have interrupts disabled. If a real mode
3310; 8086 interrupt handler was given control it might perform
3311; a segment register operation which would destroy the special
3312; segment descriptor set up by LOADALL. This is prevented by
3313; doing a CLI during the "LOADALL time".
3314;
3315; WARNING NUMBER ONE:
3316; THIS CODE WILL NOT WORK ON ANY 80286 MACHINE WHERE THE NMI
3317; INTERRUPT IS ANYTHING BUT A FATAL, SYSTEM HALTING ERROR.
3318;
3319; Since it is bad to leave interrupts disabled for a long
3320; time, the I/O is performed 256 words at a time enabling
3321; interrupts between each 256 word piece. This keeps the time
3322; interrupts are disabled down to a reasonable figure in the 100mSec
3323; range.
3324;
3325; To use the LOADALL instruction 102 bytes at location 80:0 must
3326; be used. INT13 copies the contents of 80:0 into its own buffer,
3327; copies in the LOADALL info, performs the LOADALL, and then copies
3328; back the previous contents of 80:0. These operations are all
3329; performed during the time interrupts are disabled for each 256 word
3330; block. This must be done with interrupts disabled because this area
3331; on DOS 2.X and 3.X contains variable BIOS data.
3332;
3333; In order to gain full 24 bit addressing it is also required
3334; that address line 20 be enabled. This effects 8086 compatibility
3335; on 80286 systems. This code leaves address line 20 enabled
3336; for the ENTIRE duration of the I/O because it is too time
3337; expensive to disable/enable it for each 256 word block.
3338;
3339; WARNING NUMBER TWO:
3340; IF A MULTITASKING PRE-EMPTIVE SYSTEM SCHEDULES AND RUNS
3341; AN APPLICATION WHICH RELIES ON THE 1 MEG ADDRESS WRAP
3342; PROPERTY OF THE 8086 AND 8088 DURING THE TIME INT13
3343; IS IN THE MIDDLE OF DOING AN I/O WITH ADDRESS LINE 20 ENABLED,
3344; THE APPLICATION WILL NOT RUN PROPERLY AND MAY DESTRUCT THE
3345; INT13 MEMORY.
3346;
3347; METHOD:
3348; Perform various LOADALL setup operations
3349; Enable address line 20
3350; While there is I/O to perform
3351; Do "per 256 word block" LOADALL setup operations
3352; Set up copy of 80:0 to INT13 buffer
3353; CLI
3354; copy 80:0 to INT13 buffer
3355; copy LOADALL info to 80:0
3356; LOADALL
3357; do 256 word transfer
3358; copy INT13 80:0 buffer back to 80:0
3359; STI
3360; Disable address line 20
3361;
3362; SEE ALSO
3363; INTEL special documentation of LOADALL instruction
3364;
3365; ENTRY:
3366; ES:DI is packet transfer address.
3367; CX is number of words to transfer.
3368; DX:AX is 32 bit start byte offset (0 = start of cache)
3369; BH is 1 for WRITE, 0 for READ
3370;
3371; BASE_ADDR set to point to start of cache memory
3372; This "input" is not the responsibility of the caller. It
3373; is up to the initialization code to set it up when the
3374; device is installed
3375;
3376; EXIT:
3377; Carry Clear
3378; OK, operation performed successfully
3379; Carry Set
3380; Error during operation, AL is error number (INT 13 error)
3381;
3382; USES:
3383; ALL
3384;
3385; This routine is specific to TYPE 1 driver
3386;
3387; sunilp - incorporated blkmov_386 (thanks to gregh)
3388; incorporated loadall_286 trick (thanks to scottra)
3389; added new a20 functionality
3390; ideally the code should be all relocatable abd the 386
3391; blkmov should be relocated on the 286 blkmov for the
3392; 386 case. Also the A20 routines for the Olivetti or PS/2
3393; should also ideally be relocated on top of the normal A20
3394
3395BLKMOV:
3396ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
3397 test [sys_flg],M_386
3398 je blkmov_286
3399 jmp blkmov_386
3400 ;
3401 ; Compute 32 bit address of start of I/O
3402 ;
3403blkmov_286:
3404 ADD AX,WORD PTR [BASE_ADDR]
3405 ADC DX,WORD PTR [BASE_ADDR + 2]
3406 ;
3407 ; Dispatch on function
3408 ;
3409 OR BH,BH
3410 JZ READ_IT
3411 ;
3412 ; Write
3413 ;
3414 MOV WORD PTR [ESDES.SEG_BASE],AX
3415 MOV BYTE PTR [ESDES.SEG_BASE + 2],DL
3416; MOV [LSI],DI
3417 mov [lbx],di ;sp
3418 MOV [LDI],0
3419 MOV SI,OFFSET DSDES
3420 JMP SHORT SET_TRANS
3421
3422READ_IT:
3423 MOV WORD PTR [DSDES.SEG_BASE],AX
3424 MOV BYTE PTR [DSDES.SEG_BASE + 2],DL
3425 MOV [LDI],DI
3426; MOV [LSI],0 ;sp
3427 mov [lbx],0
3428 MOV SI,OFFSET ESDES
3429SET_TRANS:
3430 MOV AX,ES
3431 CALL SEG_SET ; Set ES or DS segreg
3432 ;
3433 ; Set stack descriptor
3434 ;
3435 MOV AX,SS
3436 MOV [LSSS],AX
3437 MOV SI,OFFSET SSDES
3438 CALL SEG_SET
3439 MOV [LSP],SP
3440; SUB [LSP],2 ; CX is on stack at LOADALL
3441;
3442; the loadall kludge
3443;
3444 mov ax,cs ;sp
3445 inc ax ;sp
3446 mov [lcss],ax ;sp
3447 mov si,offset CSDES ;sp
3448 mov ax,cs ;sp
3449 call seg_set ;sp
3450 ;
3451 ; Set Other LOADALL stuff
3452 ;
3453 SMSW [LDSW]
3454 SIDT FWORD PTR [IDTDES]
3455 SGDT FWORD PTR [GDTDES]
3456 ;
3457 ; NOW The damn SXXX instructions store the desriptors in a
3458 ; different order than LOADALL wants
3459 ;
3460 MOV SI,OFFSET IDTDES
3461 CALL FIX_DESCRIPTOR
3462 MOV SI,OFFSET GDTDES
3463 CALL FIX_DESCRIPTOR
3464 ;
3465 ; Enable address line 20
3466 ;
3467
3468;;
3469;; Enable address line 20 on the PC AT or activate A20-A23 on the 6300 PLUS.
3470;; The former can be done by placing 0dfh in AH and activating the keyboard
3471;; processor. On the PLUS, 90h goes in AL and the port at 03f20h is written.
3472;; So the combined value of 0df90h can be used for both machines with
3473;; appropriate coding of the called routine A20.
3474;;
3475
3476;; MOV AH,0DFH
3477 mov ax,cs:[A20On] ;; set up for PLUS or AT
3478 CALL A20
3479 Jc NR_ERR
3480; JMP SHORT IO_START ;sp
3481 jmp short move_main_loop ;sp
3482
3483NR_ERR:
3484 MOV AL,0AAH ; Drive not ready error
3485 STC
3486 RET
3487
3488;IOLOOP: ;sp
3489; PUSH CX ;sp
3490
3491move_main_loop: ;sp
3492assume ds:nothing ;sp
3493 jcxz io_done ;sp
3494 mov cs:[ldx],cx ;sp
3495 MOV AX,80H
3496 MOV DS,AX
3497 PUSH CS
3498 POP ES
3499 XOR SI,SI
3500 MOV DI,OFFSET cs:[SWAP_80]
3501 MOV CX,102/2
3502 mov cs:[ssSave],ss
3503 CLD
3504 CLI ; Un interruptable
3505 REP MOVSW ; Save contents of 80:0
3506 PUSH DS
3507 PUSH ES
3508 POP DS
3509 POP ES
3510 XOR DI,DI
3511 MOV SI,OFFSET cs:LOADALL_TBL
3512 MOV CX,102/2
3513 REP MOVSW ; Transfer in LOADALL info
3514 DW 050FH ; LOADALL INSTRUCTION
3515AFTER_LOADALL:
3516; set up stack for moving 80:0 information back again
3517;
3518 xor bp,bp
3519 mov ss,ax
3520 mov si,offset cs:[swap_80]
3521 mov cx,102/2
3522move_loop:
3523 lods word ptr cs:[si]
3524 mov ss:[bp],ax
3525 inc bp
3526 inc bp
3527 loop move_loop
3528 mov ss,cs:[ssSave]
3529 mov cx,dx
3530 mov si,bx
3531;critical code
3532 sti
3533 rep movsw
3534 cli ; bugfix sunilp
3535 mov ax,cs
3536 dec ax
3537 push ax
3538 mov ax,offset io_done
3539 push ax
3540 db 0cbh
3541;
3542 db 16 dup (0fah) ; bugfix sunilp
3543 mov ax,cs
3544 dec ax
3545 push ax
3546 mov ax,offset resume_int
3547 push ax
3548 db 0cbh
3549;
3550resume_int:
3551 mov cs:[ldi],di
3552 mov cs:[lbx],si
3553 jmp move_main_loop
3554
3555; REP MOVSW ; Move data
3556;IO_START:
3557; JCXZ IODN
3558; MOV WORD PTR [LCX],256 ; ASSUME full block
3559; SUB CX,256
3560; JNC IOLOOP ; OK
3561; ADD [LCX],CX ; OOPs, partial block
3562; XOR CX,CX ; This is the last block
3563; JMP IOLOOP
3564
3565;IODN:
3566io_done:
3567 sti ; bugfix sunilp
3568 MOV CX,800H ; Retry this many times
3569OFFLP:
3570
3571;;
3572;; Reset of line A20 on the PC AT requires writing 0ddh to the keyboard
3573;; processor. On the PLUS, the appropriate value is 00.
3574;;
3575
3576;; MOV AH,0DDH
3577 mov ax,cs:[A20Off] ;; setup for PLUS or AT. ah for IBM, al for PLUS
3578 CALL A20 ; Disable address line 20
3579 jnc dis_done
3580 LOOP OFFLP
3581dis_done:
3582 CLC
3583 RET
3584
3585;** A20 - ENABLE/DISABLE ADDRESS LINE 20 ON IBM PC-AT
3586;
3587; This routine enables/disables address line 20 by twiddling bits
3588; in one of the keyboard controller registers.
3589;
3590; SEE ALSO
3591; IBM Technical Reference Personal Computer AT Manual #1502243
3592; Page 5-155
3593;
3594; ENTRY
3595; AH = 0DDH to disable A20
3596; AH = 0DFH to enable A20
3597; EXIT
3598; CY Failed
3599; NC Succeeded
3600; USES
3601; AL, FLAGS
3602;
3603; WARNING If this routine is called in a CLI state this routine has
3604; the side effect of enabling interrupts.
3605;
3606; This routine is specific to TYPE 1 driver
3607;
3608
3609A20:
3610ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
3611;; CS override needed on S5_FLAG to avoid phase errors on
3612;; forward declaration of this variable.
3613 cmp cs:[S5_FLAG],S_OLIVETTI ;; test for 6300 PLUS
3614 jne test_vec ;; yes, do this code
3615 jmp a20s5
3616test_vec:
3617 cmp cs:[S5_FLAG],S_VECTRA
3618 jne test_ps2
3619 jmp VecA20
3620test_ps2:
3621 test cs:[sys_flg],M_PS2 ; is it a ps2 machine
3622 jne a20ps2 ; if yes it has separate a20 routine
3623old_a20:
3624 CLI
3625 call check_a20 ; check to see if it can be enb /disb
3626 jc a20suc ; no it may not be toggled
3627 CALL E_8042
3628 JNZ a20err
3629 MOV AL,0D1H
3630 OUT 64H,AL
3631 CALL E_8042
3632 JNZ a20err
3633 MOV AL,AH
3634 OUT 60H,AL
3635 CALL E_8042
3636 JNZ a20err
3637 ;
3638 ; We must wait for the a20 line to settle down, which (on an AT)
3639 ; may not happen until up to 20 usec after the 8042 has accepted
3640 ; the command. We make use of the fact that the 8042 will not
3641 ; accept another command until it is finished with the last one.
3642 ; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
3643 ; time is on the order of 30 usec, easily satisfying the IBM 8042
3644 ; settling requirement. (Thanks, CW!)
3645 ;
3646 mov al,0FFh ;* Pulse Output Port (pulse no lines)
3647 out 64H,al ;* send cmd to 8042
3648 CALL E_8042 ;* wait for 8042 to accept cmd
3649 jnz A20Err
3650
3651A20Suc: sti
3652 clc
3653 RET
3654A20Err: sti
3655 stc
3656 ret
3657;
3658; Helper routine for A20. It waits for the keyboard controller to be "ready".
3659;
3660E_8042:
3661ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
3662 PUSH CX
3663 XOR CX,CX
3664E_LOOP:
3665 IN AL,64H
3666 AND AL,2
3667 LOOPNZ E_LOOP
3668 POP CX
3669 RET
3670;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3671; A20 status checking. If request is to enable a20 we must check to
3672; see if it is already enabled. If so we just set the sys_flg to
3673; indicate this. On disabling the routine checks to see if disabling
3674; is allowed
3675;
3676check_a20:
3677assume ds:nothing,es:nothing,ss:nothing
3678 cmp ah,0ddh ; is it a disable operation
3679 jne check_a20_enable
3680;
3681; check if a20 disabling allowed
3682;
3683 test cs:[sys_flg],a20_st
3684 jne no_toggle
3685toggle: clc
3686 ret
3687;
3688; a20 enabling, check if allowed
3689;
3690check_a20_enable:
3691 and cs:[sys_flg], not A20_ST
3692 push cx
3693 push ds
3694 push si
3695 push es
3696 push di
3697 lds si,cs:low_mem
3698 les di,cs:high_mem
3699 mov cx,3
3700 cld
3701repe cmpsw
3702 pop di
3703 pop es
3704 pop si
3705 pop ds
3706 jcxz not_enabled
3707 pop cx
3708 or cs:[sys_flg],A20_ST
3709no_toggle:
3710 stc
3711 ret
3712not_enabled:
3713 pop cx
3714 clc
3715 ret
3716
3717;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3718; A20 routine for PS2s. The PS2 A20 hardware has shifted and toggling
3719; a bit in the system port is all that is required.
3720A20PS2:
3721assume ds:nothing,es:nothing,ss:nothing
3722 cli
3723;
3724; first separate disable operation from enable operation
3725;
3726 cmp ah,0ddh
3727 je disbl_PS2
3728;
3729; enabling the a20
3730;
3731 and cs:[sys_flg],not A20_ST
3732 in al,PS2_PORTA ; input a20 status
3733 test al,GATE_A20 ; is the a20 line set
3734 je set_it ;
3735 or cs:[sys_flg],A20_ST ; indicate that it was already set
3736ps2a20suc:
3737 clc
3738 sti
3739 ret
3740
3741set_it: push cx
3742 xor cx,cx
3743 or al,GATE_A20
3744 out PS2_PORTA,al ; set it
3745see_agn:
3746 in al,PS2_PORTA ; read status again
3747 test al,GATE_A20
3748 loopz see_agn
3749 pop cx
3750 jz ps2err
3751 clc
3752 sti
3753 ret
3754;
3755; disabling the ps2
3756;
3757disbl_PS2:
3758 test cs:[sys_flg],A20_ST
3759 jne ps2a20suc
3760;
3761 push cx
3762 xor cx,cx
3763 in al,PS2_PORTA
3764 and al,not GATE_A20
3765 out PS2_PORTA,al
3766see_agn1:
3767 in al,PS2_PORTA
3768 test al,GATE_A20
3769 loopnz see_agn1
3770 pop cx
3771 jnz ps2err
3772 clc
3773 sti
3774 ret
3775;
3776ps2err:
3777 stc
3778 sti
3779 ret
3780
3781
3782;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3783;;* VECA20 - Address enable/disable routine for Vectra family computers
3784;;
3785;; This routine does the same function as A20 for Vectra machines.
3786;; Vectra machines require writing single byte as opposed to
3787;; double byte commands to the 8041. This is due to a bug
3788;; in older versions in the Vectra 8041 controllers. IBM
3789;; machines must use double byte commands due to lack of
3790;; implementation of single byte commands in some of their machines.
3791;;
3792;; Uses al, flags
3793;; Has same results as A20
3794;;
3795VecA20:
3796 CLI
3797 call check_a20
3798 jc VecA20Suc
3799 call E_8042
3800 jnz VecA20Err
3801 mov al,ah ;sigle byte command is code passed
3802 out 64H,al
3803 call E_8042
3804 jnz VecA20Err
3805; See A20 for a description of the following code. It simply makes
3806; sure that the previous command has been completed. We cannot
3807; pulse the command reg since there is a bug in some Vectra 8041s
3808; instead we write the byte again knowing that when this one is
3809; accepted the previous one has been processed.
3810 mov al,ah
3811 out 64H,al
3812 call E_8042
3813 jnz VecA20Err
3814VecA20Suc:
3815 sti
3816 clc
3817 ret
3818VecA20Err:
3819 sti
3820 stc
3821 ret
3822
3823
3824;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3825;;* A20S5 - Address enable/disable routine for the 6300 PLUS.
3826;;
3827;; This routine enables lines A20-A23 on the PLUS by writing
3828;; to port 03f20h. Bit 7 turns the lines on, and bit 4 sets
3829;; the power-up bit. To disable the lines, the processor
3830;; must be reset. This is done by saving the world and
3831;; jumping to the ROM 80286 reset code. Since the power-up bit
3832;; is set, the data segment is set to the BiosSeg at 40h
3833;; and a jump is then made to the address at RealLoc1.
3834;; At RealLoc1, one can find the CS:IP where the code
3835;; is to continue.
3836;;
3837;; Uses ax, flags.
3838;; Returns with zero flag set.
3839;;
3840A20S5: test [reboot_flg],0ffh ;; sunilp
3841 jne a20s5boot ;; sunilp
3842 cli
3843 or al,al ;; if zero, then resetting processor
3844 jnz A20S5Next
3845 call RSet ;; must return with entry value of ax
3846A20S5Next:
3847 push dx ;; set/reset port
3848 mov dx,3f20h
3849 out dx,al
3850 pop dx
3851 clc ;; sunilp modification cy flag now important
3852 STI
3853 RET
3854
3855;;* a20S5BOOT - This code bypasses the processor reset on a reboot
3856;; of the 6300 PLUS. Otherwise the machine hangs.
3857a20s5BOOT: ;; use this code before reboot
3858 cli
3859 jmp short a20s5next
3860
3861OldStackSeg dw 0 ;; used during PLUS processor reset
3862 ;; to save the stack segment
3863
3864;;* Rset - Reset the 80286 in order to turn off the address lines
3865;; on the 6300 PLUS. Only way to do this on the
3866;; current hardware. The processor itself can be
3867;; reset by reading or writing prot 03f00h
3868;;
3869;; Uses flags.
3870;;
3871RSet:
3872 pusha ;; save world
3873 push ds ;; save segments
3874 push es
3875 mov ax,BiosSeg ;; point to the bios segment
3876 mov ds,ax ;; ds -> 40h
3877assume ds:BiosSeg
3878 push word ptr [RealLoc1] ;; save what might have been here
3879 push word ptr [RealLoc1+2]
3880 mov word ptr [RealLoc1],cs:[offset ReturnBack] ;; load our return address
3881 mov word ptr [RealLoc1+2],cs
3882assume ds:nothing
3883 mov [OldStackSeg],ss ;; save the stack segment, too
3884 mov dx,03f00h ;; reset the processor
3885 in ax,dx
3886 nop
3887 nop
3888 nop
3889 cli
3890 hlt ;; should never get here
3891ReturnBack:
3892 mov ss,[OldStackSeg] ;; start the recovery
3893assume ds:BiosSeg
3894 pop word ptr [RealLoc1+2]
3895 pop word ptr [RealLoc1]
3896 pop es
3897 pop ds
3898 popa
3899 ret
3900;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3901blkmov_386: ;_protect:
3902assume ds:int13code,es:nothing,ss:nothing
3903;
3904; Compute 32 bit address of start of I/O
3905;
3906 add ax,word ptr [base_addr]
3907 adc dx,word ptr [base_addr + 2]
3908;
3909 push cx
3910;
3911; Are we in virtual mode
3912;
3913 smsw cx
3914 test cx,01B ; is the pe bit set
3915 je pr_mode_tran
3916
3917 jmp int_15_tran
3918;
3919; Dispatch on function
3920;
3921pr_mode_tran:
3922 or bh,bh
3923 jz read_it_1
3924;
3925; Write
3926;
3927; Update ES descriptor with address of track in cache
3928;
3929 mov si,offset es_des
3930 mov [si].bas_0_15,ax
3931 mov [si].bas_16_23,dl
3932 mov [si].bas_24_31,dh
3933;
3934; Update DS descriptor with transfer address
3935;
3936 mov ax,es
3937 mov cx,16
3938 mul cx
3939 mov si,offset ds_des
3940 mov [si].bas_0_15,ax
3941 mov [si].bas_16_23,dl
3942 mov [si].bas_24_31,dh
3943
3944
3945; Switch SI and DI for write transfer
3946
3947 mov si,di
3948 xor di,di
3949
3950 jmp short set_trans_1
3951
3952read_it_1:
3953;
3954; Update DS descriptor with address of track in cache
3955;
3956 mov si,offset ds_des
3957 mov [si].bas_0_15,ax
3958 mov [si].bas_16_23,dl
3959 mov [si].bas_24_31,dh
3960;
3961; Update ES descriptor with transfer address
3962;
3963 mov ax,es
3964 mov cx,16
3965 mul cx
3966 mov si,offset es_des
3967 mov [si].bas_0_15,ax
3968 mov [si].bas_16_23,dl
3969 mov [si].bas_24_31,dh
3970;
3971; Keep SI and DI the same for read transfer
3972;
3973 xor si,si
3974
3975set_trans_1:
3976;
3977; Restore Transfer Count
3978;
3979 pop cx
3980
3981;
3982 mov ax,cs:[A20On]
3983 call A20
3984 jc nr_err_1
3985;
3986; we shall do the transfer 1024 words at a time
3987;
3988 db 66h
3989 push ax
3990 mov bx,cx
3991assume ds:nothing
3992pr_io_agn_1:
3993 mov cx,1024
3994 cmp bx,cx
3995 ja pr_strt_1
3996 mov cx,bx
3997pr_strt_1:
3998 sub bx,cx
3999 cli ; Un interruptable
4000 cld
4001 lgdt fword ptr emm_gdt
4002
4003
4004;
4005; Switch to protected mode
4006;
4007 db 66h,0Fh, 20h, 0 ;mov eax,cr0
4008 or ax,1
4009 db 66h,0Fh,22h, 0 ;mov cr0,eax
4010;
4011; Clear prefetch queue
4012;
4013 db 0eah ; far jump
4014 dw offset flush_prefetch
4015 dw cs_des - start_gdt
4016;
4017flush_prefetch:
4018 assume cs:nothing
4019;
4020; Initialize segment registers
4021;
4022 mov ax,ds_des - start_gdt
4023 mov ds,ax
4024 assume ds:nothing
4025 mov ax,es_des - start_gdt
4026 mov es,ax
4027 assume es:nothing
4028 shr cx,1 ; convert word count to dword count
4029 db 0f3h,066h,0a5h ; rep movsd
4030; rep movsw ; Move data
4031;
4032;
4033; Return to Real Mode
4034;
4035;
4036 db 66h,0Fh, 20h, 0 ; mov eax,cr0
4037 and ax,0FFFEh
4038 db 66h,0Fh, 22h, 0 ; mov cr0,eax
4039;
4040; Flush Prefetch Queue
4041;
4042 db 0EAh ; Far jump
4043 dw offset flushcs
4044cod_seg dw ? ; Fixed up at initialization time
4045 assume cs:Int13Code
4046flushcs:
4047;
4048 sti
4049; see if transfer done else go to do next block
4050;
4051 or bx,bx
4052 jne pr_io_agn_1
4053;
4054 db 66h
4055 pop ax
4056 mov ax,cs
4057 mov es,ax
4058 assume es:nothing
4059 mov ds,ax
4060 assume ds:Int13Code
4061
4062 mov cx,800h ; Retry this many times
4063offlp_1:
4064 mov ax,cs:[A20Off]
4065 call A20 ; Disable address line 20
4066 jnc offlp1_out
4067 loop offlp_1
4068offlp1_out:
4069 clc
4070 ret
4071
4072nr_err_1:
4073
4074 mov al,0AAh ; Drive not ready error
4075 stc
4076 ret
4077;
4078int_15_tran:
4079assume ds:int13code,es:nothing,ss:nothing
4080 or bh,bh
4081 jz read_it_2
4082;
4083; Write
4084;
4085; Update tgt descriptor with address of track in cache
4086;
4087 mov si,offset tgt
4088 mov [si].bas_0_15,ax
4089 mov [si].bas_16_23,dl
4090 mov [si].bas_24_31,dh
4091;
4092; Update src descriptor with transfer address
4093;
4094 mov ax,es
4095 mov cx,16
4096 mul cx
4097 add ax,di
4098 adc dx,0
4099 mov si,offset src
4100 mov [si].bas_0_15,ax
4101 mov [si].bas_16_23,dl
4102 mov [si].bas_24_31,dh
4103;
4104 jmp short set_trans_2
4105
4106read_it_2:
4107;
4108; Update src descriptor with address of track in cache
4109;
4110 mov si,offset src
4111 mov [si].bas_0_15,ax
4112 mov [si].bas_16_23,dl
4113 mov [si].bas_24_31,dh
4114;
4115; Update tgt descriptor with transfer address
4116;
4117 mov ax,es
4118 mov cx,16
4119 mul cx
4120 add ax,di
4121 adc dx,0
4122 mov si,offset tgt
4123 mov [si].bas_0_15,ax
4124 mov [si].bas_16_23,dl
4125 mov [si].bas_24_31,dh
4126;
4127set_trans_2:
4128;
4129; Restore Transfer Count
4130;
4131 pop bx
4132
4133;
4134; we shall do the transfer 1024 words at a time
4135;
4136pr_io_agn_2:
4137 mov cx,1024
4138 cmp bx,cx
4139 ja pr_strt_2
4140 mov cx,bx
4141pr_strt_2:
4142 sub bx,cx
4143 push cs
4144 pop es
4145 mov si,offset int15_gdt
4146 mov ax,emm_blkm shl 8
4147 int emm_int
4148 jc nr_err_1
4149;
4150;
4151; see if transfer done else fo to do next block
4152;
4153 or bx,bx
4154 je io_exit
4155;
4156 add [src.bas_0_15],2048
4157 adc [src.bas_16_23],0
4158 adc [src.bas_24_31],0
4159;
4160 add [tgt.bas_0_15],2048
4161 adc [tgt.bas_16_23],0
4162 adc [tgt.bas_24_31],0
4163;
4164 jmp pr_io_agn_2
4165io_exit:
4166 clc
4167 ret
4168;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4169;** SEG_SET - Set up a LOADALL segment descriptor as in REAL mode
4170;
4171; This routine sets the BASE value in the segment descriptor
4172; pointed to by DS:SI with the segment value in AX as the 80286
4173; does in REAL mode. This routine is used to set a descriptor
4174; which DOES NOT have an extended 24 bit address.
4175;
4176; SEE ALSO
4177; INTEL special documentation of LOADALL instruction
4178;
4179; ENTRY:
4180; DS:SI -> Seg register descriptor
4181; AX is seg register value
4182; EXIT:
4183; NONE
4184; USES:
4185; AX
4186;
4187; This routine is specific to TYPE 1 driver
4188;
4189
4190SEG_SET:
4191ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
4192 PUSH DX
4193 PUSH CX
4194 MOV CX,16
4195 MUL CX ; Believe or not, this is faster than a 32 bit SHIFT
4196 MOV WORD PTR [SI.SEG_BASE],AX
4197 MOV BYTE PTR [SI.SEG_BASE + 2],DL
4198 POP CX
4199 POP DX
4200 RET
4201
4202;** FIX_DESCRIPTOR - Shuffle GTD IDT descriptors
4203;
4204; The segment descriptors for the IDT and GDT are stored
4205; by the SIDT instruction in a slightly different format
4206; than the LOADALL instruction wants them. This routine
4207; performs the transformation by PUSHing the contents
4208; of the descriptor, and then POPing them in a different
4209; order.
4210;
4211; SEE ALSO
4212; INTEL special documentation of LOADALL instruction
4213; INTEL 80286 processor handbook description of SIDT instruction
4214;
4215; ENTRY:
4216; DS:SI points to IDT or GDT descriptor in SIDT form
4217; EXIT:
4218; DS:SI points to IDT or GDT descriptor in LOADALL form
4219; USES:
4220; 6 words of stack
4221;
4222; NOTE: The transformation is reversable, so this routine
4223; will also work to transform a descriptor in LOADALL
4224; format to one in SIDT format.
4225;
4226; Specific to TYPE 1 driver
4227;
4228
4229FIX_DESCRIPTOR:
4230ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
4231 PUSH WORD PTR [SI + 4]
4232 PUSH WORD PTR [SI + 2]
4233 PUSH WORD PTR [SI]
4234 POP WORD PTR [SI + 4]
4235 POP WORD PTR [SI]
4236 POP WORD PTR [SI + 2]
4237 RET
4238
4239;** DATA SPECIFIC TO THE LOADALL INSTRUCTION USAGE
4240;
4241; SWAP_80 and LOADALL_TBL are data elements specific to the use
4242; of the LOADALL instruction by TYPE 1 drivers.
4243;
4244
4245;
4246; Swap buffer for contents of 80:0
4247;
4248 EVEN ; Force word alignment of SWAP_80 and LOADALL_TBL
4249
4250SWAP_80 DB 102 DUP(?)
4251ssSave dw ?
4252
4253;
4254; LOADALL data buffer placed at 80:0
4255;
4256LOADALL_TBL LABEL BYTE
4257 DB 6 DUP(0)
4258LDSW DW ?
4259 DB 14 DUP (0)
4260TR DW 0
4261FLAGS DW 0 ; High 4 bits 0, Int off, Direction clear
4262 ; Trace clear. Rest don't care.
4263LIP DW OFFSET AFTER_LOADALL
4264LDT DW 0
4265LDSS DW 8000h
4266LSSS DW ?
4267LCSS DW ?
4268LESS DW ?
4269LDI DW ?
4270LSI DW ?
4271LBP DW ?
4272LSP DW ?
4273LBX DW ?
4274LDX DW ?
4275LCX DW ?
4276LAX DW 80H
4277ESDES SEGREG_DESCRIPTOR <>
4278CSDES SEGREG_DESCRIPTOR <>
4279SSDES SEGREG_DESCRIPTOR <>
4280DSDES SEGREG_DESCRIPTOR <>
4281GDTDES DTR_DESCRIPTOR <>
4282LDTDES DTR_DESCRIPTOR <0D000H,0,0FFH,0088H>
4283IDTDES DTR_DESCRIPTOR <>
4284TSSDES DTR_DESCRIPTOR <0C000H,0,0FFH,0800H>
4285
4286;** TRUE LOCATION OF ABOVE_PID
4287;
4288; Define the TRUE (runtime TYPE 2 driver) location of ABOVE_PID.
4289; This is the only piece of TYPE 2 specific data that we need
4290; in the resident image. We must define it HERE rather than down
4291; at ABOVE_BLKMOV so that we have its TRUE location after the
4292; TYPE 2 code is swapped in at initialization. If we defined
4293; it down at ABOVE_BLKMOV any instruction like:
4294;
4295; MOV DX,[ABOVE_PID]
4296;
4297; Would have to be "fixed up" when we moved the ABOVE_BLKMOV
4298; code into its final location.
4299;
4300
4301ABOVE_PID EQU WORD PTR $ - 2 ; TRUE location of ABOVE_PID
4302
4303;
4304; The following label defines the end of the region where BLKMOV code
4305; may be swapped in. BLKMOV code to be swapped in MUST fit
4306; between DRIVE_CODE and DRIVE_END
4307;
4308DRIVE_END LABEL WORD
4309
4310
4311BREAK <INT 19/9 Handlers>
4312
4313;
4314; As discussed above in the documentation of the EMM_CTRL sector it
4315; is necessary to hear about system re-boots so that the EMM_ISDRIVER
4316; bits in the EMM_REC structure can be manipulated correctly.
4317;
4318; On the IBM PC family of machines there are two events which cause a
4319; "soft" system re-boot which we might expect the EMM_CTRL sector to
4320; survive through. One is software INT 19H, the other is the Ctrl-Alt-Del
4321; character sequence which can be detected by "listening" on INT 9 for
4322; it. The code below consists of a handler for INT 19H, a handler
4323; for INT 9, and a drive TYPE dependant piece of code.
4324;
4325; The drive TYPE dependant piece of code works as follows:
4326;
4327; TYPE 1 uses EMM_CTRL sector so it turnd off the
4328; EMM_ISDRIVER bit in the record indicated by MY_EMM_REC.
4329; EACH TYPE 1 driver in the system includes the INT 19/9
4330; code.
4331;
4332; TYPE 2 DOES NOT use the EMM_CTRL sector but it still has
4333; a handler. What this handler does is issue an
4334; ABOVE_DEALLOC call to deallocate the Above Board
4335; memory allocated to INT13. In current versions
4336; of the EMM device driver this step is unnecessary
4337; as the EMM device driver is thrown away together
4338; with all of the allocation information when the system
4339; is re-booted. We do it anyway because some future version
4340; of the EMM device driver may be smarter and retain
4341; allocation information through a warm-boot. Currently,
4342; doing this doesn't hurt anything. Since this code cannot
4343; do a global ABOVE_DEALLOC for all TYPE 2 drivers in the
4344; system, it does an ABOVE_DEALLOC only for its memory
4345; and EACH TYPE 2 driver in the system includes the INT 19/9
4346; code.
4347;
4348
4349;
4350; Storage locations for the "next" INT 19 and INT 9 vectors, the ones
4351; that were in the interrupt table when the device driver was loaded.
4352; They are initialized to -1 to indicate they contain no useful information.
4353;
4354OLD_19 LABEL DWORD
4355 DW -1
4356 DW -1
4357
4358OLD_9 LABEL DWORD
4359 DW -1
4360 DW -1
4361;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4362; modification to meet new memory allocation standard
4363OLD_15 LABEL DWORD
4364 DW -1
4365 DW -1
4366int15_size dw 0
4367;
4368;
4369INT_15:
4370ASSUME DS:NOTHING,SS:NOTHING,ES:NOTHING
4371;
4372; This piece of code determines the size of extended memory
4373; which was allocated before this driver and then subtracts
4374; the amount it has allocated for itself
4375;
4376; inputs: ah = 88h is of interest
4377; outputs: ax = size of extended memory allocated by all before and
4378; including us
4379; regs used: flags
4380;
4381 pushf
4382 cmp ah,88h
4383 je mem_det
4384 popf
4385 jmp [old_15]
4386mem_det:
4387 mov ax,[int15_size]
4388 popf
4389 clc
4390 sti
4391 iret
4392;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4393;** INT 9 Keyboard handler
4394;
4395; All this piece of code does is look for the Ctrl-Alt-Del event.
4396; If key is not Ctrl-Alt-Del, it jumps to OLD_9 without doing
4397; anything. If the Ctrl-Alt-Del key is detected it calls
4398; RESET_SYSTEM to perform driver TYPE specific re-boot code.
4399; It then resets INT 13H to disable the cache and then jumps to
4400; OLD_9 to pass on the event.
4401;
4402; NOTE THAT UNLIKE INT 19 THIS HANDLER DOES NOT NEED TO RESET
4403; THE INT 9 AND INT 19 VECTORS. This is because the Ctrl-Alt-Del
4404; IBM ROM re-boot code resets these vectors.
4405;
4406; We would LIKE to ALSO flush the cache, but we can't. For one the
4407; keyboard is at a higher IRQ than the disk. We could EOI the keyboard,
4408; but this doesn't fix the second problem. INT 13s to write
4409; out any dirty tracks take a LONG time, so long that we lose
4410; the key. In other words we see Ctrl-Alt-Del, but none of the
4411; INT 9 handlers after us will.
4412;
4413;
4414; SEE ALSO
4415; INT 9 IBM ROM code in ROM BIOS listing of
4416; IBM PC Technical Reference manual for any PC family member
4417;
4418; ENTRY
4419; NONE
4420; EXIT
4421; NONE, via OLD_9
4422; USES
4423; FLAGS
4424;
4425; THIS CODE IS USED BY TYPE 1,2 drivers.
4426;
4427
4428INT_9:
4429ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
4430 PUSH AX
4431 PUSH DS
4432 IN AL,60H
4433 CMP AL,83 ; DEL key?
4434 JNZ CHAIN ; No
4435 XOR AX,AX
4436 MOV DS,AX
4437 MOV AL,BYTE PTR DS:[417H] ; Get KB flag
4438 NOT AL
4439 TEST AL,0CH ; Ctrl Alt?
4440 JNZ CHAIN ; No
4441 MOV [INT_13_BUSY],1 ; Exclude
4442;
4443; We would LIKE to do this, always but we can't. For one the keyboard
4444; is at a higher IRQ than the disk. We can EOI the keyboard,
4445; but this doesn't fix the second problem. INT 13s to write
4446; out any dirty tracks take a LONG time, so long that we loose
4447; the key. In other words we see Ctrl-Alt-Del, but none of the
4448; INT 9 handlers after us will.
4449;
4450 CMP [REBOOT_FLUSH],0 ; Reboot flush enabled?
4451 JZ NO_REBOOT_FLUSH ; No
4452 CMP [DIRTY_CACHE],0 ; Anything to do?
4453 JZ NO_REBOOT_FLUSH ; No
4454 MOV AL,20H
4455 OUT 20H,AL ; EOI the keyboard int
4456 CALL FLUSH_WHOLE_CACHE_SAV ; Flush cache
4457NO_REBOOT_FLUSH:
4458;
4459 CALL RESET_SYSTEM ; Ctrl Alt DEL
4460 ;
4461 ; Reset INT 13 vector to turn cache off
4462 ;
4463 MOV AX,WORD PTR [OLD_13]
4464 CLI
4465 MOV WORD PTR DS:[13H * 4],AX
4466 MOV AX,WORD PTR [OLD_13 + 2]
4467 MOV WORD PTR DS:[(13H * 4) + 2],AX
4468 ;
4469 ; Reset INT 1C vector to turn cache off
4470 ;
4471; MOV AX,WORD PTR [OLD_1C]
4472; MOV WORD PTR DS:[1CH * 4],AX
4473; MOV AX,WORD PTR [OLD_1C + 2]
4474; MOV WORD PTR DS:[(1CH * 4) + 2],AX
4475 MOV [INT_13_BUSY],0
4476CHAIN:
4477 POP DS
4478 POP AX
4479 JMP [OLD_9]
4480
4481;** INT 19 Software re-boot handler
4482;
4483; All this piece of code does is sit on INT 19 waiting for
4484; a re-boot to be signaled by being called. It calls
4485; FLUSH_WHOLE_CACHE_SAV to flush out any dirty cache info then
4486; RESET_SYSTEM to perform driver TYPE specific re-boot code,
4487; resets the INT 19, INT 13 and INT 9 vectors,
4488; and then jumps to OLD_19 to pass on the event.
4489;
4490; NOTE THAT UNLIKE INT 9 THIS HANDLER NEEDS TO RESET
4491; THE INT 9 AND INT 19 VECTORS. This is because the INT 19
4492; IBM ROM re-boot code DOES NOT reset these vectors, and we
4493; don't want to leave them pointing to routines that are not
4494; protected from getting stomped on by the re-boot.
4495;
4496; SEE ALSO
4497; INT 19 IBM ROM code in ROM BIOS listing of
4498; IBM PC Technical Reference manual for any PC family member
4499;
4500; ENTRY
4501; NONE
4502; EXIT
4503; NONE, via OLD_19
4504; USES
4505; FLAGS
4506;
4507; THIS CODE IS USED BY TYPE 1,2 drivers.
4508;
4509
4510INT_19:
4511ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
4512 MOV [INT_13_BUSY],1 ; Exclude
4513 cmp [reboot_flush],0 ;
4514 je no_flush
4515 CALL FLUSH_WHOLE_CACHE_SAV ; Flush out the cache
4516no_flush:
4517 CALL RESET_SYSTEM
4518 PUSH AX
4519 PUSH DS
4520 XOR AX,AX
4521 MOV DS,AX
4522 MOV AX,WORD PTR [OLD_13]
4523 CLI
4524 ;
4525 ; Reset INT 13 vector to trun cache off
4526 ;
4527 MOV WORD PTR DS:[13H * 4],AX
4528 MOV AX,WORD PTR [OLD_13 + 2]
4529 MOV WORD PTR DS:[(13H * 4) + 2],AX
4530 ;
4531 ; Reset INT 1C vector to turn cache off
4532 ;
4533; MOV AX,WORD PTR [OLD_1C]
4534; MOV WORD PTR DS:[1CH * 4],AX
4535; MOV AX,WORD PTR [OLD_1C + 2]
4536; MOV WORD PTR DS:[(1CH * 4) + 2],AX
4537 ;
4538 ; Since INT 19 DOES NOT reset any vectors (like INT 9 Ctrl Alt DEL does),
4539 ; we must replace those vectors we have mucked with.
4540 ;
4541 ; NOTE THAT WE RESET VECTORS DIRECTLY!!!!!!!!!!!!!!!!!!
4542 ; We are not sure that DOS is reliable enough to call.
4543 ;
4544 MOV AX,WORD PTR [OLD_19]
4545 MOV WORD PTR DS:[19H * 4],AX
4546 MOV AX,WORD PTR [OLD_19 + 2]
4547 MOV WORD PTR DS:[(19H * 4) + 2],AX
4548;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4549; removed from smartdrv
4550; MOV AX,WORD PTR [OLD_9]
4551; MOV WORD PTR DS:[9H * 4],AX
4552; MOV AX,WORD PTR [OLD_9 + 2]
4553; MOV WORD PTR DS:[(9H * 4) + 2],AX
4554;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4555 mov ax,word ptr [old_15]
4556 cmp ax,word ptr [old_15+2]
4557 jne res_15
4558 cmp ax,-1
4559 je skip_res
4560res_15:
4561 mov word ptr ds:[15h*4],ax
4562 mov ax,word ptr [old_15+2]
4563 mov word ptr ds:[(15h*4) +2],ax
4564;
4565skip_res:
4566 POP DS
4567 POP AX
4568 MOV [INT_13_BUSY],0
4569 JMP [OLD_19]
4570
4571;** RESET_SYSTEM perform TYPE 1 (/E) driver specific reboot code
4572;
4573; This code performs the EMM_ISDRIVER reset function as described
4574; in EMM.ASM for all EMM_REC structure for this device (offset
4575; stored in MY_EMM_REC). We use the same LOADALL
4576; method described at BLKMOV to address the EMM_CTRL sector
4577; at the start of extended memory and perform our changes in
4578; place.
4579;
4580; NOTE: RESET_SYSTEM ALSO defines the start of ANOTHER piece of
4581; driver TYPE specific code that TYPE 2 drivers
4582; will have to swap in a different piece of code for.
4583;
4584; ENTRY
4585; NONE
4586; EXIT
4587; NONE
4588; USES
4589; NONE
4590;
4591; This code is specific to TYPE 1 drivers
4592;
4593
4594RESET_SYSTEM:
4595ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
4596 JMP SHORT TRUE_START
4597
4598MY_EMM_REC DW 0 ; Offset into 1K EMM_CTRL of my record
4599
4600TRUE_START:
4601 PUSHA
4602 mov cs:[reboot_flg],0ffh ; set the reboot flag
4603 cmp cs:[my_emm_rec],0 ; was an emm record allocated?
4604 je reset_skip
4605 PUSH DS
4606 PUSH ES
4607;
4608; reset base_addr to be address of emm ctrl sector
4609;
4610 mov ax,cs:[emm_ctrl_addr]
4611 mov dx,cs:[emm_ctrl_addr+2]
4612 mov word ptr cs:[base_addr],ax
4613 mov word ptr cs:[base_addr+2],dx
4614 ;
4615 ; read 1k emm control sector into track buffer, I want to keep memory
4616 ; access methods separate from driver code. We end up wasting a lot of
4617 ; time here but is reboot code anyway so thats okay
4618 ;
4619 mov bx,cs
4620 mov es,bx ;
4621 mov di,cs:[track_buffer_ptr]
4622 mov cx,512
4623 xor ax,ax
4624 xor dx,dx
4625 mov bh,0 ; read
4626 push es
4627 push di
4628 call blkmov
4629 pop di
4630 pop es
4631 jc finish_reset
4632;
4633; fix the flags for my emm record so that it is no longer in use
4634;
4635 mov bx,cs:[my_emm_rec]
4636 add bx,di
4637 and es:[bx.emm_flags],not emm_isdriver
4638;
4639; write out the modified emm record out to memory
4640;
4641 xor ax,ax
4642 xor dx,dx
4643 mov bh,1 ; write
4644 call blkmov
4645finish_reset:
4646 POP ES
4647 POP DS
4648reset_skip:
4649 POPA
4650 RET
4651
4652;
4653; The following label defines the end of the
4654; Driver TYPE specific RESET_SYSTEM code which will have to be replaced
4655; for different driver TYPEs as the code between RESET_SYSTEM and
4656; RESET_INCLUDE. Swapped in code MUST FIT between RESET_SYSTEM and
4657; RESET_INCLUDE.
4658;
4659RESET_INCLUDE LABEL BYTE
4660
4661;
4662; This data is only used at INIT, but it must be protected from overwrite
4663; by the DO_INIT code.
4664;
4665TERM_ADDR LABEL DWORD ; Address to return as break address in INIT packet
4666 DW ? ; Computed at INIT time
4667 DW ? ; INT13 CS filled in at INIT
4668
4669;
4670; THIS CODE MUST BE IN RESIDENT PORTION BECAUSE IT WRITES IN THE AREA
4671; OCCUPIED BY THE DISPOSABLE INIT CODE.
4672;
4673
4674;** DO_INIT - Initialize cache structures to "empty"
4675;
4676DO_INIT:
4677ASSUME DS:INT13CODE
4678 MOV AX,[SECTRACK]
4679 MOV CL,9
4680 SHL AX,CL ; AX is bytes per track buffer
4681 MOV BX,[CACHE_CONTROL_PTR]
4682 MOV CX,[TTRACKS]
4683 MOV [CACHE_HEAD],BX
4684 MOV [BX.BACK_LRU_LNK],-1
4685 MOV WORD PTR [BX.BASE_OFFSET],0
4686 MOV WORD PTR [BX.BASE_OFFSET+2],0
4687 MOV [BX.TRACK_FLAGS],TRACK_FREE
4688 MOV DI,BX
4689 ADD BX,SIZE CACHE_CONTROL ; Next structure
4690 DEC CX ; One less to do
4691 JCXZ SETDONE ; one buffer in cache
4692SETLOOP:
4693 MOV [DI.FWD_LRU_LNK],BX
4694 MOV [BX.BACK_LRU_LNK],DI
4695 MOV [BX.TRACK_FLAGS],TRACK_FREE
4696 MOV DX,WORD PTR [DI.BASE_OFFSET]
4697 ADD DX,AX
4698 MOV WORD PTR [BX.BASE_OFFSET],DX
4699 MOV DX,WORD PTR [DI.BASE_OFFSET+2]
4700 ADC DX,0
4701 MOV WORD PTR [BX.BASE_OFFSET+2],DX
4702 MOV DI,BX
4703 ADD BX,SIZE CACHE_CONTROL ; Next structure
4704 LOOP SETLOOP
4705SETDONE:
4706 MOV [DI.FWD_LRU_LNK],-1
4707 MOV [CACHE_TAIL],DI ; That is the tail
4708;
4709; NOTE FALL THROUGH!!!!!!!
4710;
4711
4712;** SETBPB - Set INIT packet I/O return values
4713;
4714; This entry is used to set the INIT packet Break address
4715;
4716; ENTRY
4717; TERM_ADDR set to device end
4718; EXIT
4719; through DEVEXIT
4720; USES
4721; DS, BX, CX
4722;
4723; COMMON TO TYPE 1, 2 drivers
4724;
4725
4726SETBPB:
4727ASSUME DS:NOTHING
4728 ;
4729 ; 7. Set the return INIT I/O packet values
4730 ;
4731 LDS BX,[PTRSAV]
4732 MOV CX,WORD PTR [TERM_ADDR]
4733 MOV WORD PTR [BX.INIT_BREAK],CX ;SET BREAK ADDRESS
4734 MOV CX,WORD PTR [TERM_ADDR + 2]
4735 MOV WORD PTR [BX.INIT_BREAK + 2],CX
4736 JMP DEVEXIT
4737
4738
4739 EVEN ; Make sure we get word alignment of the track
4740 ; buffer.
4741
4742;
4743; The following items define the "track buffer". When we want to I/O a track
4744; this is where we do it. We cannot I/O the track directly into extended
4745; memory because we have no way to specify a 24 bit address to INT 13. We
4746; Cannot I/O direct to expanded memory because DMA into the expanded memory
4747; window is not supported. This buffer also "holds" one track, so we keep
4748; track of the last track that was in here because it is faster to access
4749; it here than through extended/expanded memory. A value of -1 in the
4750; "currency" fields indicates that there is currently nothing interesting
4751; in the track buffer. NOTE: It is ASSUMED that the track buffer always
4752; represents a track that is IN the cache, therefore one must be sure to
4753; invalidate the track buffer when the cache element it represents is
4754; discarded. The offset of the track buffer is dynamic. Never talk about
4755; OFFSET TRACK_BUFFER. Always get the track buffer address out of
4756; TRACK_BUFFER_PTR. The initialization code "moves" the track buffer so
4757; that it does not cause a DMA Boundary error which would slow things
4758; down quite a bit.
4759;
4760
4761;
4762; Cylinder and hd/drv of track in track buffer
4763;
4764TRACK_BUFFER_CYLN DW -1
4765TRACK_BUFFER_HDDR DW -1
4766
4767;
4768; Pointer to track buffer. May be adjusted for DMA boundary error prevention.
4769;
4770TRACK_BUFFER_PTR DW OFFSET TRACK_BUFFER
4771
4772;
4773; Cache structure pointers
4774;
4775
4776;
4777; Pointer to cache structures. This ends up being right after TRACK_BUFFER.
4778;
4779CACHE_CONTROL_PTR DW ?
4780
4781;
4782; Cache head and tail pointers
4783;
4784CACHE_HEAD DW ?
4785CACHE_TAIL DW ?
4786
4787;
4788; This is the "in the 1Meg address space" track buffer. Its TRUE start
4789; may be adjusted for DMA boundary violation error prevention, and its
4790; Size may be adjusted depending on how many sectors per track there
4791; are. WARNING! This buffer must be AT LEAST 1024 bytes for /E driver
4792; init code (buffer for 1K EMM control sector).
4793;
4794TRACK_BUFFER DB (512 * 2 + 16) DUP(0)
4795 ; we really don't need those 16 bytes, i
4796 ; am just paranoid
4797;
4798; The TERM_ADDR for the device will be set somewhere "around" here
4799; by the init code
4800;
4801
4802BREAK <COMMON INIT CODE>
4803
4804;** DISPOSABLE INIT DATA
4805;
4806; INIT data which need not be part of resident image
4807;
4808
4809U_SWITCH db 0 ;; upper extended memory requested on 6300 PLUS
4810
4811EXT_K DW ? ; Size in K of Extended memory.
4812
4813NUM_ARG DB 1 ; Counter for numeric
4814 ; arguments bbbb.
4815
4816GOTSWITCH DB 0 ; Bit map of switches seen
4817
4818 SWITCH_E EQU 00000001B
4819 SWITCH_A EQU 00000010B ; Only switch allowed
4820 SWITCH_T EQU 00000100B
4821 SWITCH_D EQU 00001000B
4822 SWITCH_WT EQU 00010000B
4823 SWITCH_WC EQU 00100000B
4824 SWITCH_R EQU 01000000B
4825 SWITCH_C EQU 10000000B
4826;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4827sys_det proc near
4828;
4829; author: sunilp, august 1, 1987. thanks to rickha for most of this
4830; routine.
4831;
4832; purpose: to determine whether extended memory cache can be installed
4833; on this system. also to determine and store in the system
4834; flag the machine identification.
4835;
4836; inputs: none
4837;
4838; outputs: CY set if this machine doesn't allow extended memory cache.
4839; CY clear if this machine allows extended memory cache and
4840; the system flag is set according to the machine type.
4841;
4842; registers used: ax,es,flags
4843;----------------------------------
4844; Clear the state of the system flag
4845;
4846assume ds:int13code,es:nothing,ss:nothing
4847 xor ax,ax ; 0000 into AX
4848 mov [sys_flg],al ; clear system flag
4849;----------------------------------
4850; Determine if 8086/8088 system. If so we should abort immediately.
4851;
4852 push ax ; ax has 0
4853 popf ; try to put that in the flags
4854 pushf
4855 pop ax ; look at what really went into flags
4856 and ax,0F000h ; mask off high flag bits
4857 cmp ax,0F000h ; Q: was high nibble all ones ?
4858 je cpu_err ; Y: it's an 8086 (or 8088)
4859;----------------------------------
4860; Determine if 80286/80386 machine.
4861;
4862 mov ax,0F000h ; N: try to set the high bits
4863 push ax
4864 popf ; ... in the flags
4865 pushf
4866 pop ax ; look at actual flags
4867 and ax,0F000h ; Q: any high bits set ?
4868 je cpu_286 ; N: it's an 80286
4869;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4870; It is a 386 cpu. We should next try to determine if the ROM is
4871; B0 or earlier. We don't want these guys.
4872;
4873cpu_386:
4874 pushf ; clear
4875 pop ax ; NT
4876 and ax,not 0F000h ; and
4877 push ax ; IOPL
4878 popf ; bits
4879;----------------------------------
4880; the next three instructions were removed because we are loaded
4881; in real mode. So there is no need to check for virtual mode.
4882;
4883; smsw ax ;check for Virtual Mode
4884; test ax,0001 ; Q: Currently in Virtual Mode ?
4885; jnz cpu_exit ; Y: quit with error message
4886;----------------------------------
4887 ; N: check 386 stepping for B0
4888 call is_b0 ; Q: B0 ?
4889 jc cpu_err ; Y: abort
4890;----------------------------------
4891; We have a valid 386 guy. Set the flag to indicate this.
4892;
4893 or [sys_flg],M_386 ; set 386 bit
4894 jmp short PS2Test
4895
4896;----------------------------------
4897; This is a 286 guy. Check for AT model byte. We don't want non-ATs.
4898; Set 286 bit if AT type. Then check for PS/2
4899;
4900cpu_286:
4901 mov ax,0ffffh
4902 mov es,ax
4903 cmp byte ptr es:[0eh],0fch ; AT model byte
4904 jne cpu_err ; if not abort
4905;
4906 or [sys_flg],M_286 ; set 286 flag bit
4907;
4908;
4909; Determine if this is a PS/2 system
4910;
4911PS2Test:
4912 call IsPS2Machine
4913 or ax,ax
4914 jz NCRTest
4915 or [sys_flg],M_PS2
4916
4917NCRTest:
4918 call IsNCRMachine
4919 or ax,ax
4920 jz cpu_suc
4921
4922 ; We're on an NCR machine, send D7 and D5 to the 8042 in order
4923 ; to toggle A20 instead of the DF and DD we usually send.
4924 ; ChipA 06-16-88
4925 mov cs:[A20On],0D790h
4926 mov cs:[A20Off],0D500h
4927
4928;----------------------------------
4929; success exit:--
4930cpu_suc:
4931 clc
4932 ret
4933
4934;----------------------------------
4935; error exit:--
4936cpu_err:
4937 stc
4938 ret
4939;
4940sys_det endp
4941
4942
4943;*--------------------------------------------------------------------------*
4944;* *
4945;* IsPS2Machine HARDWARE DEP. *
4946;* *
4947;* Check for PS/2 machine *
4948;* *
4949;* ARGS: None *
4950;* RETS: AX = 1 if we're on a valid PS/2 machine, 0 otherwise *
4951;* REGS: AX and Flags clobbered *
4952;* *
4953;*--------------------------------------------------------------------------*
4954
4955IsPS2Machine proc near
4956
4957 mov ah,0C0h ; Get System Description Vector
4958 stc
4959 int 15h
4960 jc short IPMNoPS2 ; Error? Not a PS/2.
4961
4962 ; Are we on a PS/2 Model 35?
4963 cmp es:[bx+2],09FCh
4964 je short IPMFoundIt ; Yup, use the PS/2 method
4965
4966 ; Do we have a "Micro Channel" computer?
4967 mov al,byte ptr es:[bx+5] ; Get "Feature Information Byte 1"
4968 test al,00000010b ; Test the "Micro Channel Implemented" bit
4969 jz short IPMNoPS2
4970
4971IPMFoundIt: mov ax,1
4972 ret
4973
4974IPMNoPS2: xor ax,ax
4975 ret
4976
4977IsPS2Machine endp
4978
4979
4980;*--------------------------------------------------------------------------*
4981;* *
4982;* IsNCRMachine HARDWARE DEP. *
4983;* *
4984;* Check for NCR machine *
4985;* *
4986;* ARGS: None *
4987;* RETS: AX = 1 if we're on a valid NCR machine, 0 otherwise *
4988;* REGS: AX and Flags clobbered *
4989;* *
4990;*--------------------------------------------------------------------------*
4991
4992; Look for 'NC' at F000:FFEA
4993
4994IsNCRMachine proc near
4995
4996 mov ax,0F000h
4997 mov es,ax
4998 mov ax,word ptr es:[0FFEAh]
4999 cmp ax,'CN'
5000 je INMFoundIt
5001 xor ax,ax
5002 ret
5003
5004INMFoundIt: mov ax,1
5005 ret
5006
5007IsNCRMachine endp
5008
5009
5010;******************************************************************************
5011; IS_B0 - check for 386-B0
5012;
5013; This routine takes advantage of the fact that the bit INSERT and
5014; EXTRACT instructions that existed in B0 and earlier versions of the
5015; 386 were removed in the B1 stepping. When executed on the B1, INSERT
5016; and EXTRACT cause an INT 6 (invalid opcode) exception. This routine
5017; can therefore discriminate between B1/later 386s and B0/earlier 386s.
5018; It is intended to be used in sequence with other checks to determine
5019; processor stepping by exercising specific bugs found in specific
5020; steppings of the 386.
5021;
5022; ENTRY: REAL MODE on 386 processor (CPU ID already performed)
5023; EXIT: CF = 0 if B1 or later
5024; CF = 1 if B0 or prior
5025;
5026; ENTRY:
5027; EXIT:
5028; USED: AX, flags
5029; STACK:
5030;------------------------------------------------------------------------------
5031is_b0 proc near
5032 push bx
5033 push cx
5034 push dx
5035 push ds
5036
5037 xor bx,bx
5038 mov ds,bx ; DS = 0000 (real mode IDT)
5039assume ds:R_Mode_IDT
5040 push [bx+(6*4)]
5041 pop cs:[int6_save] ; save old INT 6 offset
5042 push [bx+(6*4)+2]
5043 pop cs:[int6_save+2] ; save old INT 6 segment
5044
5045 mov word ptr [bx+(6*4)],offset int6
5046 mov [bx+(6*4)+2],cs ; set vector to new INT 6 handler
5047;
5048; Attempt execution of Extract Bit String instruction. Execution on
5049; B0 or earlier with length (CL) = 0 will return 0 into the destination
5050; (CX in this case). Execution on B1 or later will fail and dummy INT 6
5051; handler will return execution to the instruction following the XBTS.
5052; CX will remain unchanged in this case.
5053;
5054 xor ax,ax
5055 mov dx,ax
5056 mov cx,0FF00h ; Extract length (CL)=0, CX=non-zero
5057 db 0Fh,0A6h,0CAh ; XBTS CX,DX,AX,CL
5058
5059 xor bx,bx
5060 mov ds,bx ; DS = 0000 (real mode IDT)
5061 push cs:[int6_save] ; restore original INT 6 offset
5062 pop [bx+(6*4)] ;
5063 push cs:[int6_save+2] ; restore original INT 6 segment
5064 pop [bx+(6*4)+2]
5065
5066 or cx,cx ; Q: CX = 0 (meaning <=B0) ?
5067 jz ib_exit ; Y: exit (carry clear)
5068 stc ; N: set carry to indicate >=B1
5069ib_exit:
5070 cmc ; flip carry tense
5071 pop ds
5072 pop dx
5073 pop cx
5074 pop bx
5075 ret ; *** RETURN ***
5076is_b0 endp
5077;
5078; Temporary INT 6 handler - assumes the cause of the exception was the
5079; attempted execution of an XTBS instruction.
5080;
5081int6 proc near
5082 push bp
5083 mov bp,sp
5084 add word ptr [bp+2],3 ; bump IP past faulting instruction
5085 pop bp
5086 iret ; *** RETURN ***
5087int6_save dw 0000,0000
5088int6 endp
5089;***************************************************************************
5090
5091;** PRINT - Print a "$" terminated message on stdout
5092;
5093; This routine prints "$" terminated messages on stdout.
5094; It may be called with only the DX part of the DS:DX message
5095; pointer set, the routine puts the correct value in DS to point
5096; at the INT13 messages.
5097;
5098; ENTRY:
5099; DX pointer to "$" terminated message (INT13CODE relative)
5100; EXIT:
5101; NONE
5102; USES:
5103; AX
5104;
5105; COMMON TO TYPE 1, 2, 3, 4 drivers
5106;
5107
5108PRINT:
5109ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5110 PUSH DS
5111 PUSH CS
5112 POP DS
5113 MOV AH,Std_Con_String_Output
5114 INT 21H
5115 POP DS
5116 RET
5117
5118;** ITOA - Print Decimal Integer on stdout
5119;
5120; Print an unsigned 16 bit value as a decimal integer on stdout
5121; with leading zero supression. Prints from 1 to 5 digits. Value
5122; 0 prints as "0".
5123;
5124; Routine uses divide instruction and a recursive call. Maximum
5125; recursion is four (five digit number) plus one word on stack
5126; for each level.
5127;
5128; ENTRY AX has binary value to be printed
5129; EXIT NONE
5130; USES AX,CX,DX,FLAGS
5131;
5132; COMMON TO TYPE 1, 2, 3, 4 drivers
5133;
5134
5135ITOA:
5136ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5137
5138 MOV CX,10
5139 XOR DX,DX
5140 DIV CX ; DX is low digit, AX is higher digits
5141 OR AX,AX
5142 JZ PRINT_THIS_DIGIT ; No more higher digits
5143 PUSH DX ; Save this digit
5144 CALL ITOA ; Print higher digits first
5145 POP DX ; Recover this digit
5146PRINT_THIS_DIGIT:
5147 ADD DL,"0" ; Convert to ASCII
5148 MOV AH,Std_CON_Output
5149 INT 21H
5150 RET
5151
5152
5153;** INT13$INIT - Device Driver Initialization routine
5154;
5155; INT13 Initialization routine. This is the COMMON initialization
5156; code used by ALL driver TYPEs. Its jobs are to:
5157;
5158; 1. Initialize various global values
5159; 2. Check for correct DOS version and do changes to the device
5160; based on the DOS version if needed.
5161; 3. Set OLD_13, OLD_1C and Parse the command line and set values accordingly
5162; 4. Set up the cache parameters and
5163; Call a TYPE specific INIT routine based on the Parse
5164; to set up a specific driver TYPE.
5165; 5. Print out report of INT13 parameters
5166; 6. Set the return INIT I/O packet values
5167;
5168; The first two lines perform step 1. Step two starts after and
5169; goes through VER_OK. Step 3 starts at VER_OK and goes through
5170; ARGS_DONE. Step 4 starts at ARGS_DONE and goes through I001.
5171; Step 5 starts at I001 and goes through DRIVE_SET. Step 6 starts
5172; at DRIVE_SET and goes through SETBPB. Step 7 starts at SETBPB
5173; and ends at the JMP DEVEXIT 10 lines later.
5174;
5175; At any time during the above steps an error may be detected. When
5176; this happens one of the error messages is printed and INT13
5177; de-installs itself. It does this at DEVABORT_NOMES by changing
5178; the Device attributes to a BLOCK DEVICE and setting its size to NULL.
5179; All INT13 needs to do is make sure any INT vectors it changed
5180; (INT 9 and INT 19 and INT 13) get restored to what they were
5181; when INT13 first started. If an EMM_CTRL sector is being
5182; used (TYPE 1) and one of the EMM_REC structures has been
5183; marked EMM_ISDRIVER by this driver, it must turn that bit back off
5184; since the driver did not install. A TYPE 2 driver must make sure it
5185; ABOVE_DEALLOCs any memory it allocated from the EMM device. The duty
5186; of reclaiming EMM_CTRL or Above Board memory and re-setting vectors
5187; is done by the DISK_ABORT routine which may be called by either
5188; this COMMON INIT code, or the TYPE specific INIT code.
5189;
5190; Step 1 initializes the segment part of TERM_ADDR to the correct
5191; value for type 1, 2 drivers.
5192;
5193; Step 2 checks to make sure that we are running on a DOS in the
5194; 2.X or 3.X series which this driver is restricted to. If running
5195; on a 2.X series the device header attribute word and device command
5196; table are patched to exclude those device calls that don't exist
5197; on DOS 2.X.
5198;
5199; Step 3 uses the "DEVICE = xxxxxxxxx" line pointer provided by
5200; DOS to look for the various device parameters. NOTE: This pointer
5201; IS NOT DOCUMENTED in the DOS 2.X tech ref material, but it does
5202; exist in the same way as 3.X. This code is simple even though
5203; it looks rather long. First it skips over the device name field
5204; to get to the arguments. In then parses the arguments as they are
5205; encountered. All parameter errors are detected here. NOTE THAT
5206; THIS ROUTINE IS NOT RESPONSIBLE FOR SETTING DEFAULT VALUES OF
5207; PARAMETER VARIABLES. This is accomplished by static initialization
5208; of the parameter variables.
5209;
5210; Step 4 calls a device TYPE specific initialization routine based
5211; on the parse in step 3 (presence or absense of /E and /A switches).
5212; NOTE that one of the prime jobs of these device TYPE specific
5213; routines is to set all of the variables that are needed by Step
5214; 5 and 6 that haven't been set by the COMMON init code:
5215;
5216; DEV_SIZE set to TRUE size of device
5217; BASE_ADDR set to TRUE start of device so BLKMOV
5218; can be called
5219; BASE_RESET set so DISK_ABORT can be called
5220; TERM_ADDR set to correct end of device
5221;
5222; Step 5 makes the status report display of DEVICE SIZE and other info.
5223;
5224; Step 6 sets the INIT I/O packet return values for Break address.
5225;
5226;
5227; SEE ALSO
5228; MS-DOS Technical Reference manual section on
5229; Installable Device Drivers
5230;
5231; ENTRY from INT13$IN
5232; EXIT Through DEVEXIT
5233; USES ALL
5234;
5235; COMMON TO TYPE 1, 2 drivers
5236;
5237
5238INT13$INIT:
5239ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
5240 ;
5241 ; 1. Initialize various global values
5242 ;
5243 MOV WORD PTR [TERM_ADDR + 2],CS
5244 ;
5245 ; 2. Check for correct DOS version and do changes to the device
5246 ; based on the DOS version if needed.
5247 ;
5248 CLD
5249 MOV AH,GET_VERSION
5250 INT 21H
5251 XCHG AH,AL
5252 CMP AX,(2 SHL 8) + 00
5253 JB BADVER ; Below 2.00, BAD
5254 CMP AX,(3 SHL 8) + 00
5255 JB VER2X ; 2.X requires some patches
5256 CMP AX,(4 SHL 8) + 00
5257 JBE VER_OK ; 3.X or 4.0 OK
5258BADVER:
5259 MOV DX,OFFSET BADVERMES
5260 JMP DEVABORT
5261
5262VER2X:
5263 AND [DEVATS],NOT DEVOPCL ; No such bit in 2.X
5264 MOV BYTE PTR [INT13TBL],11 ; Fewer functions too
5265VER_OK:
5266
5267;;
5268;; 2.5 Check here for 6300 PLUS machine. First look for Olivetti copyright,
5269;; and if found, check id byte at f000:fffd.
5270;;
5271
5272 push es ;; Olivetti Machine?
5273 mov ax,0fc00h ;; Look for 'OL' at fc00:50
5274 mov es,ax
5275 cmp es:[0050h],'LO'
5276 jnz notS5 ;; not found
5277 mov ax,0f000h
5278 mov es,ax
5279 cmp word ptr es:[0fffdh],0fc00h ;; look for 6300 plus
5280 jnz notS5
5281 mov [S5_FLAG],S_OLIVETTI ;; yep, set flag
5282notS5:
5283
5284;; Check here for an HP Vectra machine. Look for HP id byte.
5285;;
5286 mov ax,0f000H
5287 mov es,ax
5288 cmp es:[0f8H],'PH'
5289 jnz notHP
5290 mov [S5_FLAG],S_VECTRA
5291notHP:
5292 pop es
5293
5294;
5295; 3. Set OLD_13, OLD_1C and Parse the command line and set values accordingly
5296;
5297 MOV AX,(Get_Interrupt_Vector SHL 8) OR 13H
5298 INT 21H
5299 MOV WORD PTR [OLD_13],BX
5300 MOV WORD PTR [OLD_13 + 2],ES
5301 MOV AX,(Get_Interrupt_Vector SHL 8) OR 1CH
5302 INT 21H
5303 MOV WORD PTR [OLD_1C],BX
5304 MOV WORD PTR [OLD_1C + 2],ES
5305 LDS SI,[PTRSAV]
5306ASSUME DS:NOTHING
5307 MOV DX,OFFSET HEADERMES
5308 CALL PRINT
5309 LDS SI,[SI.INIT_BPB] ; DS:SI points to config.sys
5310SKIPLP1: ; Skip leading delims to start of name
5311 LODSB
5312 CMP AL," "
5313 JZ SKIPLP1
5314 CMP AL,9
5315 JZ SKIPLP1
5316 CMP AL,","
5317 JZ SKIPLP1
5318 JMP SHORT SKIPNM
5319
5320ARGS_DONEJ:
5321 JMP ARGS_DONE
5322
5323SWITCHJ:
5324 JMP SWITCH
5325
5326SKIPLP2: ; Skip over device name
5327 LODSB
5328SKIPNM:
5329 CMP AL,13
5330 JZ ARGS_DONEJ
5331 CMP AL,10
5332 JZ ARGS_DONEJ
5333 CMP AL," "
5334 JZ FIRST_ARG
5335 CMP AL,9
5336 JZ FIRST_ARG
5337 CMP AL,","
5338 JZ FIRST_ARG
5339 CMP AL,0 ; Need this for 2.0 2.1
5340 JNZ SKIPLP2
5341SCAN_LOOP: ; PROCESS arguments
5342 LODSB
5343FIRST_ARG:
5344 OR AL,AL ; Need this for 2.0 2.1
5345 JZ ARGS_DONEJ
5346 CMP AL,13
5347 JZ ARGS_DONEJ
5348 CMP AL,10
5349 JZ ARGS_DONEJ
5350 CMP AL," "
5351 JZ SCAN_LOOP
5352 CMP AL,9
5353 JZ SCAN_LOOP
5354 CMP AL,","
5355 JZ SCAN_LOOP
5356 CMP AL,"/"
5357 JZ SWITCHJ
5358 CMP AL,"0"
5359 JB BAD_PARMJ
5360 CMP AL,"9"
5361 JA BAD_PARMJ
5362 DEC SI
5363 CALL GETNUM
5364 CMP [NUM_ARG],1
5365 JA BAD_PARMJ ; Only 1 numeric argument
5366SET_SIZE:
5367 CMP BX,128
5368 JB BAD_PARMJ
5369 CMP BX,8192
5370 JA BAD_PARMJ
5371 MOV [DEV_SIZE],BX
5372;A
5373 mov [current_dev_size],bx
5374;A
5375 JMP SHORT NUM_DONE
5376
5377BAD_PARMJ:
5378 JMP SHORT BAD_PARM
5379
5380NUM_DONE:
5381 INC [NUM_ARG] ; Next numeric argument
5382SCAN_LOOPJ:
5383 JMP SCAN_LOOP
5384
5385BAD_PARM:
5386 MOV DX,OFFSET ERRMSG1
5387DEVABORT:
5388 CALL PRINT
5389DEVABORT_NOMES:
5390; INC [NULDEV] ;Indicate NUL device
5391; MOV WORD PTR [TERM_ADDR],OFFSET ERROR_END ;Minimul null device
5392; JMP SETBPB ;and return
5393 LDS BX,[PTRSAV]
5394 MOV WORD PTR [BX].INIT_NUM,0
5395 MOV WORD PTR [BX].INIT_BREAK[0],0
5396 MOV WORD PTR [BX].INIT_BREAK[2],CS
5397 MOV [DEVATS],0
5398 JMP DEVEXIT
5399
5400SWITCH:
5401 LODSB
5402 OR AL,20H
5403
5404if WINDOWS_SWITCHES eq 0
5405 CMP AL,"e"
5406 JNZ ABOVE_TEST
5407EXT_SET:
5408 TEST [GOTSWITCH],SWITCH_E + SWITCH_A
5409 JNZ BAD_PARM
5410 OR [GOTSWITCH],SWITCH_E
5411 MOV [DRIVER_SEL],0
5412 JMP SCAN_LOOP
5413
5414ABOVE_TEST:
5415
5416endif ; WINDOWS_SWITCHES eq 0
5417
5418;; Added for /u switch
5419 cmp al,'u' ;; Look for U switch for PLUS
5420 jnz A_TEST
5421 cmp [S5_FLAG],S_OLIVETTI ;; No good unless PLUS
5422 jne bad_parm
5423 TEST [GOTSWITCH],SWITCH_A ;; Already have switch A ?
5424 JNZ BAD_PARM
5425 cmp [U_SWITCH],0
5426 jne bad_parm
5427 dec [U_SWITCH]
5428 jmp scan_loop
5429A_TEST:
5430;;
5431 CMP AL,"a"
5432
5433if WINDOWS_SWITCHES
5434 jnz bad_parm
5435else
5436 JNZ DIS_TEST
5437endif ;WINDOWS_SWITCHES
5438
5439ABOVE_SET:
5440 TEST [GOTSWITCH],SWITCH_A ; Was SWITCH_E + SWITCH_A
5441 JNZ BAD_PARM
5442;; added for /u switch
5443 cmp [U_SWITCH],0
5444 jne bad_parm
5445;;
5446 OR [GOTSWITCH],SWITCH_A
5447 MOV [DRIVER_SEL],1
5448 JMP SCAN_LOOP
5449
5450if WINDOWS_SWITCHES eq 0
5451
5452DIS_TEST:
5453 CMP AL,"d"
5454 JNZ W_TEST
5455DIS_SET:
5456 TEST [GOTSWITCH],SWITCH_D
5457 JNZ BAD_PARM
5458 OR [GOTSWITCH],SWITCH_D
5459 MOV [ENABLE_13],0
5460 JMP SCAN_LOOP
5461
5462W_TEST:
5463 CMP AL,"w"
5464 JNZ T_TEST
5465 LODSW
5466 OR AL,20H
5467 CMP AX,":c"
5468 JNZ WT_TEST
5469 LODSW
5470 OR AX,2020H
5471 CMP AX,"fo"
5472 JNZ BAD_PARM
5473 LODSB
5474 OR AL,20H
5475 CMP AL,"f"
5476 JNZ BAD_PARMJX
5477WC_SET:
5478 TEST [GOTSWITCH],SWITCH_WC
5479 JNZ BAD_PARMJX
5480 OR [GOTSWITCH],SWITCH_WC
5481 MOV [WRITE_BUFF],0
5482 JMP SCAN_LOOP
5483
5484WT_TEST:
5485 CMP AX,":t"
5486 JNZ BAD_PARMJX
5487 LODSW
5488 OR AX,2020H
5489 CMP AX,"no"
5490 JNZ BAD_PARMJX
5491WT_SET:
5492 TEST [GOTSWITCH],SWITCH_WT
5493 JNZ BAD_PARMJX
5494 OR [GOTSWITCH],SWITCH_WT
5495 MOV [WRITE_THROUGH],1
5496 JMP SCAN_LOOP
5497
5498BAD_PARMJX:
5499 JMP BAD_PARM
5500
5501T_TEST:
5502 CMP AL,"t"
5503 JNZ R_TEST
5504 LODSW
5505 CMP AL,":"
5506 JNZ BAD_PARMJX
5507 CMP AH,"0"
5508 JB BAD_PARMJX
5509 CMP AH,"9"
5510 JA BAD_PARMJX
5511 DEC SI
5512 CALL GETNUM
5513T_SET:
5514 TEST [GOTSWITCH],SWITCH_T
5515 JNZ BAD_PARMJX
5516 OR [GOTSWITCH],SWITCH_T
5517 MOV [TICK_SETTING],BX
5518 JMP SCAN_LOOP
5519
5520R_TEST:
5521 CMP AL,"r"
5522 JNZ C_TEST
5523 LODSW
5524 OR AH,20H
5525 CMP AX,"o:"
5526 JNZ BAD_PARMJX
5527 LODSB
5528 OR AL,20H
5529 CMP AL,"n"
5530 JNZ BAD_PARMJX
5531 TEST [GOTSWITCH],SWITCH_R
5532 JNZ BAD_PARMJX
5533 OR [GOTSWITCH],SWITCH_R
5534 MOV [REBOOT_FLUSH],1
5535 JMP SCAN_LOOP
5536
5537C_TEST:
5538 CMP AL,"c"
5539 JNZ BAD_PARMJX
5540 LODSW
5541 OR AH,20H
5542 CMP AX,"o:"
5543 JNZ BAD_PARMJX
5544 LODSB
5545 OR AL,20H
5546 CMP AL,"n"
5547 JNZ BAD_PARMJX
5548 TEST [GOTSWITCH],SWITCH_C
5549 JNZ BAD_PARMJX
5550 OR [GOTSWITCH],SWITCH_C
5551 MOV [ALL_CACHE],1
5552 JMP SCAN_LOOP
5553endif ;WINDOWS_SWITCHES eq 0
5554
5555ARGS_DONE:
5556;
5557; 4. Call a TYPE specific INIT routine based on the Parse
5558; to set up a specific driver TYPE.
5559;
5560 PUSH CS
5561 POP DS
5562ASSUME DS:INT13CODE
5563 MOV AL,[DRIVER_SEL] ; Find out which init to call
5564 OR AL,AL
5565 JNZ NEXTV
5566 CALL AT_EXT_INIT
5567 JMP SHORT INI_RET
5568
5569NEXTV:
5570 CALL ABOVE_INIT
5571INI_RET:
5572 JNC I001
5573 JMP DEVABORT_NOMES
5574
5575I001:
5576DRIVE_SET:
5577 ;
5578 ; update the current device size
5579 ;
5580 mov ax,[dev_size]
5581 mov [current_dev_size],ax
5582 ;
5583 ; 6. Print out report of INT13 parameters
5584 ;
5585 MOV DX,OFFSET STATMES1
5586 CALL PRINT
5587 MOV AX,[DEV_SIZE]
5588 CALL ITOA
5589 MOV DX,OFFSET STATMES1E
5590 CMP [DRIVER_SEL],0
5591 JZ PTYPX
5592 MOV DX,OFFSET STATMES1A
5593PTYPX:
5594 CALL PRINT
5595 MOV DX,OFFSET STATMES2
5596 CALL PRINT
5597 MOV AX,[TTRACKS]
5598 CALL ITOA
5599 MOV DX,OFFSET STATMES3
5600 CALL PRINT
5601 MOV AX,[SECTRACK]
5602 CALL ITOA
5603 MOV DX,OFFSET STATMES4
5604 CALL PRINT
5605
5606ifdef OMTI
5607 mov dx,offset omti_msg
5608 call print
5609endif
5610IF DEBUG
5611 MOV DX,OFFSET STATMES5
5612 CALL PRINT
5613 MOV AX,CS
5614 CALL ITOA
5615 MOV DX,OFFSET STATMES6
5616 CALL PRINT
5617ENDIF
5618 ;
5619 ; Turn on the cache by chaining INT 13, and INT 1C
5620 ;
5621 MOV DX,OFFSET INT_13_HANDLER
5622 MOV AX,(Set_Interrupt_Vector SHL 8) OR 13H
5623 INT 21H
5624; MOV DX,OFFSET INT_1C_HANDLER
5625; MOV AX,(Set_Interrupt_Vector SHL 8) OR 1CH
5626; INT 21H
5627 JMP DO_INIT
5628
5629;** DRIVEPARMS Initialize drive related cache parameters
5630;
5631; ENTRY
5632; Stuff set so that BLKMOV can be used to access cache memory
5633; DEV_SIZE set to TRUE cache size in K
5634; EXIT
5635; Carry Set
5636; Error, message already printed
5637; Carry clear
5638; TRACK_BUFFER_PTR adjusted for DMA error prevention
5639; CACHE_CONTROL_PTR set
5640; TERM_ADDR set
5641; TTRACKS set
5642; SECTRACK set
5643; SECTRKARRAY set
5644; HDARRAY set (SUNILP)
5645; USES
5646; ALL but DS
5647;
5648; COMMON TO TYPE 1, 2 drivers
5649;
5650;
5651NO_HARDFILES:
5652ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
5653 MOV DX,OFFSET NOHARD
5654PEER:
5655 CALL PRINT
5656 STC
5657 RET
5658
5659TRACK_TOO_BIG:
5660 MOV DX,OFFSET BIGTRACK
5661 JMP PEER
5662
5663DRIVEPARMS:
5664ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
5665 ;
5666 ; First figure out sec/track of any hardfiles
5667 ;
5668 MOV DL,80H
5669 MOV AH,8
5670 INT 13H
5671 JC NO_HARDFILES
5672 OR DL,DL
5673 JZ NO_HARDFILES
5674 AND CL,00111111B
5675 MOV [SECTRKARRAY],CL
5676 mov [hdarray],dh
5677 XOR CH,CH
5678 MOV [SECTRACK],CX
5679 MOV CL,DL
5680 DEC CX
5681 JCXZ FINISHED
5682 CMP CX,MAX_HARD_FILES - 1
5683 JBE DNUM_OK
5684 MOV CX,MAX_HARD_FILES - 1
5685DNUM_OK:
5686 MOV DL,81H
5687PARMLOOP:
5688 PUSH CX
5689 PUSH DX
5690 MOV AH,8
5691 INT 13H
5692 JC IGNORE_DRIVE
5693 AND CL,00111111B
5694 POP BX
5695 PUSH BX
5696 AND BX,0000000001111111B
5697 MOV [BX.SECTRKARRAY],CL
5698 mov [bx.hdarray],dh
5699 XOR CH,CH
5700 CMP CX,[SECTRACK]
5701 JBE IGNORE_DRIVE
5702 MOV [SECTRACK],CX
5703IGNORE_DRIVE:
5704 POP DX
5705 INC DL
5706 POP CX
5707 LOOP PARMLOOP
5708FINISHED:
5709 ;
5710 ; Figure out number of full tracks that fit in cache
5711 ;
5712 MOV AX,[SECTRACK]
5713 MOV CX,512
5714 MUL CX ; DX:AX = Bytes per track
5715 OR DX,DX
5716 JNZ TRACK_TOO_BIG
5717 MOV BX,AX ; BX is bytes per track
5718 MOV AX,[DEV_SIZE]
5719 MOV CX,1024
5720 MUL CX ; DX:AX = size of cache in bytes
5721 DIV BX ; AX is full tracks in cache
5722 MOV [TTRACKS],AX
5723 ;
5724 ; Figure out if we have a DMA boundary problem
5725 ;
5726 mov DX,DS ; Check for 64k boundary error
5727 shl DX,1
5728 shl DX,1
5729 shl DX,1
5730 shl DX,1 ; Segment converted to absolute address
5731 add DX,[TRACK_BUFFER_PTR] ; Combine with offset
5732 add DX,511 ; simulate a one sector transfer
5733 ; And set next divide for round up
5734;
5735; If carry is set, then we are within 512 bytes of the end of the DMA segment.
5736; Adjust TRACK_BUFFER_PTR UP by 512 bytes.
5737;
5738 jnc NotWithin512
5739 add [TRACK_BUFFER_PTR],512 ; adjust
5740 jmp short SetCachest
5741
5742NotWithin512:
5743;
5744; DX is the physical low 16 bits of the proposed track buffer plus 511.
5745; See how many sectors fit up to boundary.
5746;
5747 shr DH,1 ; DH = number of sectors in DMA segment
5748 ; till start of buffer rounded up
5749 mov AH,128 ; AH = max number of sectors in DMA segment
5750 sub AH,DH
5751;
5752; AH is now the number of sectors that we can successfully transfer using this
5753; address without a DMA boundary problem. If this number is above or equal to
5754; the track buffer size, then buffer is OK. Otherwise, we adjust buffer UP
5755; till it is after the boundary by adding ((AH+1)*512) to the buffer address.
5756;
5757 mov al,ah
5758 xor ah,ah
5759 cmp AX,[SECTRACK] ; can we fit it in?
5760 jae SetCachest ; yes, buffer is OK
5761 inc ax ; Add 1
5762 mov cl,9 ; Mult by 512
5763 shl ax,cl
5764 add [TRACK_BUFFER_PTR],ax ; Adjust
5765SetCachest:
5766 ;
5767 ; Set pointer to cache control structures
5768 ;
5769 mov bx,[SECTRACK]
5770 mov cl,9 ; Mult by 512
5771 shl bx,cl ; AX is bytes in Track buffer
5772 add bx,[TRACK_BUFFER_PTR] ; First byte after track buffer
5773 mov [CACHE_CONTROL_PTR],bx
5774 mov cx,SIZE CACHE_CONTROL
5775 mov ax,[TTRACKS]
5776 MUL cx
5777 add bx,ax
5778 ;
5779 ; Set TERM_ADDR
5780 ;
5781 mov word ptr [TERM_ADDR],bx
5782 CLC
5783 RET
5784
5785;** GETNUM - Read an unsigned integer
5786;
5787; This routine looks at DS:SI for a decimal unsigned integer.
5788; It is up to the caller to make sure DS:SI points to the start
5789; of a number. If it is called without DS:SI pointing to a valid
5790; decimal digit the routine will return 0. Any non decimal digit
5791; defines the end of the number and SI is advanced over the
5792; digits which composed the number. Leading "0"s are OK.
5793;
5794; THIS ROUTINE DOES NOT CHECK FOR NUMBERS LARGER THAN WILL FIT
5795; IN 16 BITS. If it is passed a pointer to a number larger than
5796; 16 bits it will return the low 16 bits of the number.
5797;
5798; This routine uses the MUL instruction to multiply the running
5799; number by 10 (initial value is 0) and add the numeric value
5800; of the current digit. Any overflow on the MUL or ADD is ignored.
5801;
5802; ENTRY:
5803; DS:SI -> ASCII text of number
5804; EXIT:
5805; BX is binary for number
5806; SI advanced to point to char after number
5807; USES:
5808; AX,BX,DX,SI
5809;
5810; COMMON TO TYPE 1, 2, 3, 4 drivers
5811;
5812
5813GETNUM:
5814ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5815
5816 XOR BX,BX
5817GETNUM1:
5818 LODSB
5819 SUB AL,"0"
5820 JB NUMRET
5821 CMP AL,9
5822 JA NUMRET
5823 CBW
5824 XCHG AX,BX
5825 MOV DX,10
5826 MUL DX
5827 ADD BX,AX
5828 JMP GETNUM1
5829
5830NUMRET:
5831 DEC SI
5832 RET
5833
5834BREAK <INITIAL EMM control sector>
5835
5836;** flag to signify valid emm control record
5837;
5838valid_emm db 0
5839
5840;** INITIAL EMM_CTRL sector
5841;
5842; This is a datum which represents a correct initial EMM_CTRL
5843; sector as discussed in the EMM_CTRL documentation. It is used
5844; to check for the presense of a valid EMM_CTRL by comparing
5845; the signature strings, and for correctly initializing the
5846; EMM_CTRL sector if needed.
5847;
5848; The DWORD at BASE_RESET, which is the EMM_BASE of the NULL
5849; 0th EMM_REC structure, is used as a storage location of
5850; the address of the EMM_CTRL sector (PLUS 1024!!!!!!).
5851; This value can be used if it is necessary to re-address the
5852; EMM_CTRL sector during initialization. See the DISK_ABORT routine.
5853; NOTE THAT BASE_RESET CAN NOT BE USED AT RUNTIME AS THIS DATUM
5854; IS NOT PART OF THE RESIDENT IMAGE.
5855;
5856; This data is appropriate to TYPE 1 drivers
5857;
5858
5859EMM_CONTROL LABEL BYTE
5860 DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK "
5861 DW 0
5862 DW 0
5863 ; NULL 0th record
5864 DW EMM_ALLOC + EMM_ISDRIVER
5865 DW EMM_EMM
5866;; Note: When using upper extended memory on the PLUS, the value
5867;; at BASE_RESET + 2 is patched to FA during initialization.
5868;;
5869BASE_RESET LABEL DWORD ; RESMEM driver must patch this value
5870 DW EXTMEM_LOW + 1024
5871 DW EXTMEM_HIGH
5872 DW 0
5873
5874 DB 950 DUP(0)
5875 DB "ARRARRARRA"
5876
5877
5878BREAK <INT13 COMMON INIT ROUTINES>
5879
5880;** DISK_ABORT - De-install INT13 after init
5881;
5882; This routine MUST BE CALLED to de-install a INT13 cache
5883; if the de-installation takes place:
5884;
5885; AFTER INT 19/INT 9 vectors are replaced
5886; AFTER ABOVE_PID is valid for TYPE 2
5887; AFTER an EMM_REC structure in the EMM_CTRL sector
5888; has been marked EMM_ISDRIVER for TYPE 1.
5889;
5890; In all cases the INT 9 and INT 19 vectors are replaced if the
5891; value of both words of OLD_19 is NOT -1. This is why the initial value
5892; of this datum is -1. In the event that the INT 9 and INT 19
5893; vectors are replaced, this datum takes on some value other than -1.
5894;
5895; If this is a TYPE 1 driver the EMM_ISDRIVER bit is
5896; turned off in the EMM_REC pointed to by MY_EMM_REC.
5897; NOTE THAT A TYPE 1 DRIVER MAY USE THIS ROUTINE
5898; IF IT HAS NOT "TURNED ON" AN EMM_ISDRIVER BIT IN ONE OF THE EMM_REC
5899; STRUCTURES. This is OK because the initial 0 value of MY_EMM_REC
5900; is checked, and nothing is done if it is still 0.
5901;
5902; If this is a TYPE 2 driver, an ABOVE_DEALLOC call is made on
5903; ABOVE_PID.
5904;
5905; ENTRY:
5906; BASE_RESET valid if TYPE 1
5907; ABOVE_PID valid if TYPE 2
5908; EXIT:
5909; NONE
5910; USES:
5911; ALL but DS
5912;
5913; COMMON TO TYPE 1, 2 drivers
5914;
5915
5916DISK_ABORT:
5917ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
5918
5919 CMP [DRIVER_SEL],1
5920 JNZ NOT_ABOVE
5921AGAIN:
5922 ;
5923 ; TYPE 2, De-alloc the Above Board memory
5924 ;
5925 MOV DX,[ABOVE_PID]
5926 MOV AH,ABOVE_DEALLOC
5927 INT 67H
5928 CMP AH,ABOVE_ERROR_BUSY
5929 JZ AGAIN
5930 JMP SHORT RET002
5931
5932NOT_ABOVE:
5933 CMP [MY_EMM_REC],0 ; Need to turn off bit?
5934 JZ RET002 ; No
5935 ;
5936 ; TYPE 1, turn off EMM_ISDRIVER at MY_EMM_REC
5937 ;
5938 MOV AX,WORD PTR [BASE_RESET]
5939 MOV DX,WORD PTR [BASE_RESET + 2]
5940 SUB AX,1024 ; Backup to EMM_CTRL
5941 SBB DX,0
5942 MOV WORD PTR [BASE_ADDR],AX
5943 MOV WORD PTR [BASE_ADDR + 2],DX
5944 XOR BH,BH ; READ
5945 CALL CTRL_IO ; Get EMM_CTRL
5946 JC RET002
5947 MOV DI,OFFSET TRACK_BUFFER
5948 ADD DI,[MY_EMM_REC]
5949 AND [DI.EMM_FLAGS],NOT EMM_ISDRIVER ; Undo install
5950 MOV BH,1 ; WRITE
5951 CALL CTRL_IO ; EMM_CTRL back out
5952RET002:
5953 ;
5954 ; Reset INT 9, and/or INT 19 if OLD_19 is not -1
5955 ;
5956 PUSH DS
5957 LDS DX,[OLD_19]
5958ASSUME DS:NOTHING
5959 MOV AX,DS
5960 CMP AX,-1
5961 JNZ RESET_VECS
5962 CMP AX,DX
5963 JZ NO_VECS
5964RESET_VECS:
5965 MOV AX,(Set_Interrupt_Vector SHL 8) OR 19H
5966 INT 21H
5967;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5968; removed from smartdrv
5969; LDS DX,[OLD_9]
5970; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
5971; INT 21H
5972;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5973 lds dx,[old_15]
5974 cmp ax,-1
5975 jne reset_15
5976 cmp ax,dx
5977 je no_vecs
5978reset_15:
5979 mov ax,(set_interrupt_vector shl 8) or 15h
5980 int 21h
5981NO_VECS:
5982 POP DS
5983 RET
5984
5985;** CTRL_IO - Read/Write the first 1024 bytes at BASE_ADDR
5986;
5987; This routine is used at INIT time to read the first 1024
5988; bytes at BASE_ADDR. If TYPE 1 and BASE_ADDR points
5989; to the EMM_CTRL address (initial value), the EMM_CTRL sector
5990; is read/written. If TYPE 1 and BASE_ADDR has been set
5991; to the start of the cache, the first 1024 bytes of the cache
5992; are read/written. If TYPE 2, the first 1024 bytes of
5993; the cache are read/written. All this routine does is
5994; set inputs to BLKMOV to transfer 1024 bytes at offset 0 to/from
5995; TRACK_BUFFER.
5996;
5997; ENTRY:
5998; BH = 0 for READ, 1 for WRITE
5999; EXIT:
6000; TRACK_BUFFER filled in with 1024 bytes at BASE_ADDR
6001; USES:
6002; ALL but DS
6003;
6004; COMMON TO TYPE 1, 2 drivers
6005;
6006
6007CTRL_IO:
6008ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6009 XOR DX,DX
6010 MOV AX,DX ; Offset 0
6011 MOV CX,512 ; 1024 bytes
6012 PUSH CS
6013 POP ES
6014 MOV DI,OFFSET TRACK_BUFFER
6015 PUSH DS
6016 CALL BLKMOV ; Read in EMM_CTRL
6017 POP DS
6018 RET
6019
6020;** MM_SETDRIVE - Look for/Init EMM_CTRL and DOS volume
6021;
6022; This routine is used by TYPE 1 drivers to check for/initialize
6023; the EMM_CTRL sector.
6024;
6025; This routine reads the EMM_CTRL sector in to TRACK_BUFFER
6026; CALLS FIND_VDRIVE to check out and alloc or find an EMM_REC
6027; Sets BASE_ADDR to point to the start of the INT13 cache memory
6028; Writes the updated EMM_CTRL back out from TRACK_BUFFER
6029;
6030; ENTRY:
6031; BASE_ADDR initialized to point at START of extended memory
6032; so that the EMM_CTRL sector can be accessed by
6033; doing I/O at offset 0.
6034; EXT_K is set to size of extended memory
6035; DEV_SIZE is set to user requested device size
6036; EXIT:
6037; CARRY SET - error, message already printed
6038; CARRY CLEAR
6039; BASE_ADDR set for this drive
6040; DEV_SIZE set to TRUE size
6041;
6042; USES
6043; ALL but DS
6044;
6045; Used by TYPE 1 drivers
6046;
6047
6048MM_SETDRIVE:
6049ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6050 XOR BH,BH ; READ
6051 CALL CTRL_IO ; Get EMM_CTRL
6052 MOV DX,OFFSET INIT_IO_ERR
6053 JC ERR_RET2
6054 CALL FIND_VDRIVE ; Snoop
6055 JC RET001
6056 PUSH ES ; Save EMM_BASE from EMM_REC
6057 PUSH DI
6058; modification sunilp
6059 cmp [u_switch],0 ; we shall use ol' microsoft standard for this
6060 je mm_s$1 ; if we are using int15 scheme no need to write
6061 ; out emm control record
6062; end modification sp
6063 MOV BH,1 ; WRITE
6064 CALL CTRL_IO ; Write EMM_CTRL back out
6065 MOV DX,OFFSET INIT_IO_ERR
6066 JC ERR_RET2P
6067mm_s$1:
6068 POP WORD PTR [BASE_ADDR] ; Set final correct BASE_ADDR
6069 POP WORD PTR [BASE_ADDR + 2]
6070 CLC
6071RET001:
6072 RET
6073
6074ERR_RET2P:
6075 ADD SP,4
6076ERR_RET2:
6077 CALL PRINT
6078 STC
6079 RET
6080
6081;** FIND_VDRIVE - Check out EMM_CTRL and alloc
6082;
6083; This code checks for a valid EMM_CTRL and sets up
6084; an initial one if there isn't. It then performs the
6085; algorithm described in the EMM_CTRL documentation
6086; to either allocate a NEW EMM_REC of type EMM_APPLICATION,
6087; or find an existing EMM_REC which is EMM_APPLICATION and has
6088; its EMM_ISDRIVER bit clear. In the later case it
6089; checks to see if DEV_SIZE is consistent with EMM_KSIZE
6090; and tries to make adjustments to EMM_KSIZE or DEV_SIZE
6091; if they are not consistent.
6092;
6093; First the EMM_CTRL signature strings are checked.
6094; If they are not valid we go to SETCTRL to set up a new
6095; empty EMM_CTRL in SECTOR_BUFFER.
6096; If the signatures are valid, EMM_TOTALK is checked
6097; against EXT_K. If they are the same, the EMM_CTRL sector is
6098; valid and we skip to SCAN_DEV. Otherwise we initialize the
6099; EMM_CTRL sector at SETCTRL. All we need to do to set up the initial
6100; EMM_CTRL sector is transfer the record at EMM_CONTROL into
6101; TRACK_BUFFER and set EMM_TOTALK and EMM_AVAILK to EXT_K - 1.
6102;
6103; In either case, finding a valid EMM_CTRL or setting up a correct
6104; initial one, we end up at SCAN_DEV. This code performs the
6105; scan of the EMM_REC structures looking for a "free" one
6106; or an allocated one which is EMM_APPLICATION and has its EMM_ISDRIVER
6107; bit clear as described in the EMM_CTRL sector documentation.
6108;
6109; If we find a "free" EMM_REC structure we go to GOT_FREE_REC
6110; and try to allocate some memory. This attempt will fail if
6111; EMM_AVAILK is less than 16K. We then call SET_RESET to do
6112; the INT 9/INT 19 setup. We adjust DEV_SIZE to equal the
6113; available memory if DEV_SIZE is > EMM_AVAILK. Then all we do
6114; is set EMM_AVAILK and all of the fields in the EMM_REC structure
6115; as described in the EMM_CTRL sector documentation.
6116;
6117; Call SET_RESET to do INT 9/INT 19 setup.
6118; IF the EMM_REC structure we found is the LAST EMM_REC structure
6119; we cannot edit any sizes and whatever the EMM_KSIZE
6120; is we stuff it into DEV_SIZE and set the EMM_ISDRIVER
6121; bit, and we're done.
6122; NOTE: We DO NOT check that EMM_KSIZE is at least
6123; 16K as we know this EMM_REC was created
6124; by some PREVIOUS INT13 program who
6125; DID make sure it was at least 16K
6126; ELSE
6127; IF EMM_KSIZE == DEV_SIZE
6128; set EMM_ISDRIVER and we're done
6129; IF EMM_KSIZE < DEV_SIZE
6130; either the user has edited his DEVICE = line since
6131; the last time the system was re-booted, or at the
6132; time we initially allocated this region EMM_AVAILK
6133; was less than DEV_SIZE and we had to trim the device
6134; size back.
6135; This case is handled at INSUFF_MEM.
6136; IF the next EMM_REC structure is not allocated
6137; IF EMM_AVAILK == 0
6138; We can't do anything, so set DEV_SIZE
6139; to EMM_KSIZE and we're done.
6140; ELSE
6141; allocate appropriate amount off of EMM_AVAILK
6142; and add it to EMM_KSIZE and we're done.
6143; ELSE
6144; We can't do anything, so set DEV_SIZE
6145; to EMM_KSIZE and we're done.
6146; ELSE
6147; This is the EMM_KSIZE > DEV_SIZE case, it means the
6148; user MUST have edited his DEVICE = line.
6149; IF next EMM_REC is NOT free
6150; We can't shrink the allocation block,
6151; but we'll leave DEV_SIZE set to the user
6152; specification and let him waste memory.
6153; ELSE
6154; SHRINK the allocation block by adding
6155; the extra memory back onto EMM_AVAILK
6156; and subtracting it from EMM_KSIZE and
6157; we're done
6158;
6159; ENTRY:
6160; SECTOR_BUFFER containes POSSIBLE EMM_CTRL sector
6161; MUST BE CHECKED
6162; EXT_K is set to size of extended memory
6163; DEV_SIZE is set to user requested device size
6164; EXIT:
6165; CARRY SET
6166; Error, message already printed
6167; CARRY CLEAR
6168; ES:DI = BASE_ADDR for this drive from EMM_BASE of EMM_REC
6169; EMM_REC is marked EMM_ISDRIVER
6170; TRACK_BUFFER must be written out, it contains an updated
6171; EMM_CTRL sector
6172; DEV_SIZE set to TRUE size
6173; MY_EMM_REC is the offset in the 1k EMM_CTRL sector of the
6174; record we allocated.
6175;
6176; USES:
6177; ALL but DS
6178;
6179; Specific to TYPE 1 drivers
6180;
6181; substancial modification to this routine, would have totally changed
6182; if it weren't for the olivetti memory
6183;
6184; we are going to be int15 guys from now except for the olivetti memory
6185;
6186FIND_VDRIVE:
6187ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6188 PUSH CS
6189 POP ES
6190 MOV DI,OFFSET TRACK_BUFFER
6191 MOV SI,OFFSET EMM_CONTROL
6192 MOV CX,50
6193 CLD
6194 REPE CMPSB
6195 jnz no_emm_rec
6196; JNZ SETCTRL ; No EMM_CTRL
6197 ADD SI,EMM_TAIL_SIG - 50
6198 ADD DI,EMM_TAIL_SIG - 50
6199 MOV CX,10
6200 REPE CMPSB
6201 jnz no_emm_rec
6202; JNZ SETCTRL ; No EMM_CTRL
6203;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6204; with int15 guys around this is not feasible
6205; MOV DI,OFFSET TRACK_BUFFER
6206; MOV AX,[EXT_K]
6207; DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
6208; CMP AX,[DI.EMM_TOTALK]
6209; JZ SCAN_DEV ; EMM_CTRL is valid
6210;SETCTRL:
6211;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6212;
6213; modification sunilp
6214;
6215 dec [valid_emm] ; signal prescence of emm record
6216no_emm_rec:
6217 cmp [u_switch],0h ; is it a u driver
6218 jne old_st ; if not go to install acc to new int15
6219 jmp new_st ; standard
6220;
6221; for olivetti u memory we still have to install according to ol' microsoft st
6222;
6223old_st:
6224 cmp [valid_emm],0h ; do we have a valid emm
6225 jne scan_dev ; if yes go to scan structures
6226set_ctrl: ; else we have to install a new one
6227 MOV DI,OFFSET TRACK_BUFFER
6228 PUSH DI
6229 MOV SI,OFFSET EMM_CONTROL
6230 MOV CX,1024/2
6231 REP MOVSW ; Move in initial EMM_CTRL
6232 POP DI
6233 MOV AX,[EXT_K]
6234 DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
6235 MOV [DI.EMM_TOTALK],AX
6236 MOV [DI.EMM_AVAILK],AX
6237SCAN_DEV:
6238 MOV SI,OFFSET TRACK_BUFFER ; DS:SI points to EMM_CTRL
6239 MOV DI,SI
6240 ADD DI,EMM_RECORD ; DS:DI points to EMM records
6241 MOV CX,EMM_NUMREC
6242LOOK_REC:
6243 TEST [DI.EMM_FLAGS],EMM_ALLOC
6244 JNZ CHECK_SYS
6245 JMP GOT_FREE_REC ; Must alloc new region
6246
6247CHECK_SYS:
6248 CMP [DI.EMM_SYSTEM],EMM_APPLICATION
6249 JNZ NEXTREC ; Not correct type
6250 TEST [DI.EMM_FLAGS],EMM_ISDRIVER
6251 JNZ NEXTRECI ; Driver already in
6252 CALL SET_RESET ; Set up INT 19,9
6253 MOV AX,[DI.EMM_KSIZE]
6254 CMP CX,1
6255 JBE OK_SET_DEV ; If this is last record, must
6256 ; select this size
6257 CMP AX,[DEV_SIZE]
6258 JZ OK_SET_DEV ; Exact match, Okay
6259 JB INSUFF_MEM ; User asked for more
6260 ; Size of found block is bigger than requested size.
6261 ; User MUST have edited CONFIG.SYS.
6262 PUSH DI
6263 ADD DI,SIZE EMM_REC
6264 TEST [DI.EMM_FLAGS],EMM_ALLOC
6265 POP DI
6266 JZ SHRINK_BLOCK ; Next block is free, shrink
6267 MOV AX,[DEV_SIZE]
6268 JMP SHORT SET_2
6269
6270SHRINK_BLOCK:
6271 SUB AX,[DEV_SIZE] ; AX is amount to shrink
6272 ADD [SI.EMM_AVAILK],AX
6273 MOV AX,[DEV_SIZE]
6274 MOV [DI.EMM_KSIZE],AX
6275 JMP SHORT SET_2
6276
6277INSUFF_MEM: ; Size of found block is smaller
6278 ; than requested size.
6279 PUSH DI
6280 ADD DI,SIZE EMM_REC
6281 TEST [DI.EMM_FLAGS],EMM_ALLOC
6282 POP DI
6283 JNZ OK_SET_DEV ; Next block is NOT free, can't grow
6284TRY_TO_GROW_BLOCK:
6285 CMP [SI.EMM_AVAILK],0
6286 JZ OK_SET_DEV ; Need SPECIAL check for this case
6287 SUB AX,[DEV_SIZE]
6288 NEG AX ; AX is amount we would like to grow
6289 SUB [SI.EMM_AVAILK],AX
6290 JNC GOT_THE_MEM
6291 ADD AX,[SI.EMM_AVAILK] ; AX is MAX we can grow
6292 MOV [SI.EMM_AVAILK],0 ; We take all that's left
6293GOT_THE_MEM:
6294 ADD [DI.EMM_KSIZE],AX
6295 MOV AX,[DI.EMM_KSIZE]
6296SET_2:
6297OK_SET_DEV:
6298 MOV [DEV_SIZE],AX
6299 OR [DI.EMM_FLAGS],EMM_ISDRIVER
6300 MOV [MY_EMM_REC],DI
6301 SUB [MY_EMM_REC],OFFSET TRACK_BUFFER ; Make start of EMM_CTRL relative
6302 LES DI,[DI.EMM_BASE]
6303 XOR AX,AX ; Set zero, clear carry
6304 RET
6305
6306NEXTRECI:
6307NEXTREC:
6308 ADD DI,SIZE EMM_REC ; Next record
6309 LOOP LOOK_RECJ
6310VERROR:
6311 MOV DX,OFFSET ERRMSG2
6312 CALL PRINT
6313 STC
6314 RET
6315
6316LOOK_RECJ:
6317 JMP LOOK_REC
6318
6319GOT_FREE_REC:
6320 MOV AX,[SI.EMM_AVAILK]
6321 CMP AX,16
6322 JB VERROR ; 16K is smallest device
6323 CALL SET_RESET ; Set INT 19,9
6324 CMP AX,[DEV_SIZE]
6325 JBE GOTSIZE ; Not enough for user spec
6326 MOV AX,[DEV_SIZE] ; User size is OK
6327GOTSIZE:
6328 MOV [DEV_SIZE],AX
6329 SUB [SI.EMM_AVAILK],AX
6330 MOV [DI.EMM_KSIZE],AX
6331 MOV [DI.EMM_SYSTEM],EMM_APPLICATION
6332 MOV [DI.EMM_FLAGS],EMM_ALLOC + EMM_ISDRIVER
6333 MOV [MY_EMM_REC],DI
6334 SUB [MY_EMM_REC],OFFSET TRACK_BUFFER ; Make start of EMM_CTRL relative
6335 PUSH DI
6336 SUB DI,SIZE EMM_REC ; Look at prev record to compute base
6337 MOV AX,[DI.EMM_KSIZE]
6338 LES BX,[DI.EMM_BASE]
6339 MOV DI,ES ; DI:BX is prev base
6340 MOV CX,1024
6341 MUL CX ; Mult size by 1024 to get # bytes
6342 ADD AX,BX ; Add size onto base to get next base
6343 ADC DX,DI
6344 POP DI
6345 MOV WORD PTR [DI.EMM_BASE],AX
6346 MOV WORD PTR [DI.EMM_BASE + 2],DX
6347 LES DI,[DI.EMM_BASE]
6348 XOR AX,AX ; Set zero, clear carry
6349 INC AX ; RESET zero
6350 RET
6351
6352;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6353; the new int15 standard
6354;
6355new_st:
6356 mov bx,[ext_k] ; contiguous memory reported by int15
6357 cmp [valid_emm],0 ; is there a valid emm record
6358 je no_adjust ; if not there no need to adjust
6359 ; the memory available
6360; else we have to find how much memory is already allocated by the microsoft
6361; emm control block and subtract this from the amount that is available. the
6362; memory allocated is totalk - availk + 1
6363;
6364 sub bx,1 ; subtract the emm ctrl record size
6365 mov di,offset track_buffer ; set up to address the ctrl record
6366 ; read in
6367 mov ax,[di.emm_totalk] ; ax <- totalk
6368 sub ax,[di.emm_availk] ; ax <- totalk - availk
6369 sub bx,ax ; adjust memory available
6370 jc verror ; if no memory go to abort
6371;
6372 cmp bx,128 ; is it the minimum required
6373 jb verror ; if less go to abort
6374;
6375; the memory available has been found and is in bx. now compare it with
6376; requested device size and take the minimum of the two
6377;
6378no_adjust:
6379 cmp [dev_size],bx ;
6380 jb skip_adj_dev_size ; if enough space we don't need to adj
6381 ; dev_size
6382 mov [dev_size],bx ; else we have compromise on dev size
6383skip_adj_dev_size:
6384;
6385; now that we have the correct dev size we should proceed with the installation
6386; of a new int 15 handler which will account for the memory grabbed by this guy
6387;
6388 mov bx,[ext_k] ; get memory which was reported by int15
6389 add bx,[special_mem] ; account for olivetti guys
6390 sub bx,[dev_size] ;
6391 mov [int15_size],bx ; this is the size thaat will be reported
6392 ; by the int 15 handler
6393; now install the int15 handler
6394;
6395 push ax
6396 push dx
6397 push bx
6398 push es
6399 mov ax,(get_interrupt_vector shl 8) or 15h
6400 int 21h
6401 mov word ptr [old_15],bx
6402 mov word ptr [old_15+2],es
6403 mov dx,offset int_15
6404 mov ax,(set_interrupt_vector shl 8) or 15h
6405 int 21h
6406 pop es
6407 pop bx
6408 pop dx
6409 pop ax
6410;
6411; set up int19 vector
6412;
6413 call set_reset
6414;
6415; now fill device base address in es:di
6416;
6417 mov ax,[ext_k]
6418 sub ax,[dev_size] ; this now has memory left
6419 mov cx,1024 ; we are going to find size in bytes
6420 mul cx ; dx:ax = ax * 1024
6421 add ax,word ptr [base_addr] ;
6422 adc dx,word ptr [base_addr+2] ;
6423 mov es,dx ;
6424 mov di,ax ;
6425 ret
6426
6427;** SET_RESET - Set up INT 19/INT 9 vectors
6428;
6429; This routine will install the INT 9 and INT 19
6430; code by saving the current INT 9 and INT 19
6431; vectors in OLD_9 and OLD_19 (NOTE: the change in the value of OLD_19
6432; to something other than -1 indicates that the vectors have been
6433; replaced), setting the vectors to point to INT_9 and INT_19.
6434;
6435; ENTRY:
6436; NONE
6437; EXIT:
6438; NONE
6439; USES:
6440; None
6441;
6442; COMMON TO TYPE 1, 2 drivers
6443;
6444
6445SET_RESET:
6446ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6447 cmp U_SWITCH,0 ;; don't do this for at&t 6300 plus
6448 jnz ret005
6449 PUSH AX
6450 PUSH DX
6451 PUSH BX
6452 PUSH ES
6453 MOV AX,(Get_Interrupt_Vector SHL 8) OR 19H
6454 INT 21H
6455 MOV WORD PTR [OLD_19],BX
6456 MOV WORD PTR [OLD_19 + 2],ES
6457 MOV DX,OFFSET INT_19
6458 MOV AX,(Set_Interrupt_Vector SHL 8) OR 19H
6459 INT 21H
6460 MOV AX,(Get_Interrupt_Vector SHL 8) OR 9H
6461 INT 21H
6462 MOV WORD PTR [OLD_9],BX
6463 MOV WORD PTR [OLD_9 + 2],ES
6464; MOV DX,OFFSET INT_9
6465; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
6466; INT 21H
6467 POP ES
6468 POP BX
6469 POP DX
6470 POP AX
6471RET005:
6472 RET
6473
6474BREAK </E INIT Code>
6475
6476;** AT_EXT_INIT - Perform /E (TYPE 1) specific initialization
6477;
6478; This code does the drive TYPE specific initialization for TYPE 1
6479; drivers.
6480;
6481; Make sure running on 80286 IBM PC-AT compatible system by
6482; making sure the model byte at FFFF:000E is FC.
6483; Get the size of extended memory by using 8800H call to INT 15.
6484; and make sure it is big enough to accomodate thr driver.
6485; Limit DEV_SIZE to the available memory found in the previous step
6486; by making DEV_SIZE smaller if necessary.
6487; Initialize the GLOBAL parts of the LOADALL information which
6488; are not set by each call to BLKMOV.
6489; CALL MM_SETDRIVE to look for EMM_CTRL and perform all the
6490; other initialization tasks.
6491; Call DRIVEPARMS to set TERM_ADDR and other drive specific cache parms
6492;
6493; ENTRY:
6494; Invokation line parameter values set.
6495; EXIT:
6496; CARRY SET
6497; Error, message already printed. Driver not installed.
6498; EMM_CTRL not marked (but MAY be initialized if
6499; a valid one was not found).
6500; CARRY CLEAR
6501; BASE_ADDR set for this drive from EMM_BASE of EMM_REC
6502; BASE_RESET set from BASE_ADDR
6503; TERM_ADDR set
6504; EMM_REC is marked EMM_ISDRIVER
6505; MY_EMM_REC set
6506; DEV_SIZE set to TRUE size
6507; RESET_SYSTEM code and INT 9/INT 19 code included,
6508; INT 19 and 9 vector patched.
6509;
6510; USES:
6511; ALL but DS
6512;
6513; Code is specific to TYPE 1 driver
6514;
6515
6516AT_EXT_INIT:
6517ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6518 push ds
6519 call sys_det ; new routine to do more comprehensive
6520 pop ds
6521 jnc at001 ; checks than before
6522 MOV DX,OFFSET BAD_AT
6523ERR_RET:
6524 CALL PRINT
6525 STC
6526 RET
6527
6528AT001:
6529
6530;; If upper extended memory is used on the PLUS, it is necessary to
6531;; patch the values of base_reset and base_addr to get the addressing right.
6532;;
6533 cmp [U_SWITCH],0 ;; patch the code for /U option
6534 jz AT001A
6535 mov ax,00fah
6536 mov word ptr [emm_ctrl_addr+2],ax ;; in resident part for reset code
6537 mov word ptr [base_reset+2],ax ;; patching upper address
6538 mov word ptr [base_addr+2],ax ;; to FA from 10
6539AT001A:
6540 MOV AX,8800H
6541 INT 15H ; Get extended memory size
6542 MOV DX,OFFSET NO_MEM
6543 OR AX,AX
6544 JZ ERR_RET
6545
6546;; If running on a 6300 PLUS, it is necessary to subtract any upper extended
6547;; memory from the value obtained by int 15 to determine the correct memory
6548;; available for a type /E RAMDrive. If loading a /U RAMDrive, it is necessary
6549;; to find out if there IS any upper extended memory.
6550
6551 cmp [U_SWITCH],0 ;; did we ask for upper extended memory
6552 jz olstuff ;; no
6553 call UpperMemCheck ;; yes, see if anything there
6554 jc ERR_RET ;; no, quit
6555 mov ax,384 ;; yes, but max allowed is 384K
6556 jmp short at001b
6557olstuff:
6558 cmp [S5_FLAG],S_OLIVETTI ;; if not 6300 PLUS, go on
6559 jne at001b
6560 call UpperMemCheck ;; yes, see if 384K is there
6561 jc at001b ;; no, so int 15h is right
6562 sub ax,384 ;; yes, subtract 384K
6563 mov [special_mem],384 ;; store special memory size
6564AT001B:
6565
6566 MOV DX,OFFSET ERRMSG2
6567 CMP AX,128 ; 128k min cache
6568 JB ERR_RET
6569 MOV [EXT_K],AX
6570 MOV BX,AX
6571; DEC BX ; BX is MAX possible cache size
6572 CMP [DEV_SIZE],BX
6573 JBE AT002 ; DEV_SIZE OK
6574 MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available
6575AT002:
6576;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6577; 386 modification
6578 test [sys_flg],M_386
6579 je loadall_setup
6580 mov ax,cs
6581 mov word ptr [cod_seg],ax
6582; set cs descriptor
6583 mov cx,16
6584 mul cx
6585 mov si,offset cs_des
6586 mov [si].bas_0_15,ax
6587 mov [si].bas_16_23,dl
6588 mov [si].bas_24_31,dh
6589; set gdt base
6590 mov si,offset emm_gdt
6591 add ax,offset start_gdt
6592 adc dx,0
6593 mov [si].gdt_base_0,ax
6594 mov [si].gdt_base_2,dx
6595 jmp short common_setup
6596 ;
6597 ; Init various pieces of LOADALL info
6598 ;
6599;;;; SMSW [LDSW]
6600;;;; SIDT QWORD PTR [IDTDES]
6601;;;; SGDT QWORD PTR [GDTDES]
6602;;;; ;
6603;;;; ; NOW The damn SXXX instructions store the desriptors in a
6604;;;; ; different order than LOADALL wants
6605;;;; ;
6606;;;; MOV SI,OFFSET IDTDES
6607;;;; CALL FIX_DESCRIPTOR
6608;;;; MOV SI,OFFSET GDTDES
6609;;;; CALL FIX_DESCRIPTOR
6610loadall_setup:
6611 MOV [LCSS],CS
6612 MOV SI,OFFSET CSDES
6613 MOV AX,CS
6614 CALL SEG_SET
6615common_setup:
6616 CALL MM_SETDRIVE
6617 JC RETXXX
6618 CALL DRIVEPARMS
6619 JNC RETXXX
6620 CALL DISK_ABORT
6621 STC
6622RETXXX:
6623 RET
6624
6625;;* UpperMemCheck - Called by 6300 PLUS to verify existence of
6626;; upper extended memory of 384K at FA0000h
6627;;
6628;; Returns carry set if no upper extended memory.
6629;;
6630;; This routine is called only by a 6300 PLUS, and
6631;; it reads the hardware switch DSW2 to do the job.
6632;;
6633UpperMemCheck:
6634 push ax
6635 in al,66h
6636 and al,00001111b
6637 cmp al,00001011b
6638 pop ax
6639 jnz nomem
6640 clc
6641 ret
6642nomem:
6643 stc
6644 ret
6645
6646BREAK </A INIT Code>
6647
6648;** EMM device driver name
6649;
6650; The following datum defines the Above Board EMM 8 character
6651; device driver name that is looked for as part of TYPE 2
6652; specific initialization.
6653;
6654; This datum is specific to TYPE 2 drivers
6655;
6656
6657ABOVE_DEV_NAME DB "EMMXXXX0"
6658
6659;** ABOVE_INIT - Perform /A (TYPE 2) specific initialization
6660;
6661; This code performes the driver specific initialization for
6662; type 2 drivers.
6663;
6664; Swap ABOVE_BLKMOV code in for TYPE 1 code at BLKMOV
6665; Swap ABOVE_RESET code in for TYPE 1 code at RESET_SYSTEM
6666; Check to make sure EMM Above Board device driver is installed
6667; by looking for device name relative to INT 67H segment
6668; address. This is method 2 described on page 36 and 37
6669; of the Expanded Memory Manager Programming Specification.
6670;
6671; WARNING! If run on a version of DOS where all INT vectors
6672; are managed by the kernel, or on a system where some
6673; foreign program (not EMM.SYS) is also using INT 67H, this
6674; method will fail to find the EMM device driver.
6675; The reason this method was used rather than the more portable
6676; method 1 described on pages 33 and 34 of the EMM Programming
6677; Specification is that the DOS Installable Device Driver
6678; document makes a statement about which DOS system calls
6679; may be made in a device initialization routine, and
6680; OPEN, IOCTL, and CLOSE are not included in the allowed
6681; set. Adherance to the Installable Device Driver document,
6682; therefore, excludes the use of method 1.
6683;
6684; Check the EMM device status
6685; Get the EMM map window address and set BASE_ADDR
6686; Get the available Above Board memory
6687; Adjust DEV_SIZE to be consistent with the available memory if needed,
6688; and also round DEV_SIZE up so that it is a multiple of the 16K
6689; granularity of the Above Board memory.
6690; Allocate DEV_SIZE worth of Above Board memory and set ABOVE_PID.
6691; After this point we can use CTRL_IO and/or BLKMOV to
6692; read/write the memory we have allocated.
6693; Install the INT 9 and INT 19 code by calling SET_RESET.
6694; Call DRIVEPARMS to set TERM_ADDR and other drive specific cache parms
6695;
6696; SEE ALSO
6697; INTEL Expanded Memory Manager Programming Specification
6698;
6699; ENTRY:
6700; Invokation line parameter values set.
6701; EXIT:
6702; ABOVE_BLKMOV code swapped in at BLKMOV
6703; ABOVE_RESET code swapped in at RESET_SYSTEM
6704; CARRY SET
6705; Error, message already printed. Driver not installed.
6706; No Above Board memory allocated.
6707; CARRY CLEAR
6708; BASE_ADDR set to segment address of Above Board map window
6709; ABOVE_PID contains PID of allocated above board memory
6710; DEV_SIZE set to TRUE size
6711; TERM_ADDR set
6712;
6713; USES:
6714; ALL but DS
6715;
6716; Code is specific to TYPE 2 driver
6717;
6718
6719ABOVE_INIT:
6720ASSUME DS:INT13CODE,ES:NOTHING,SS:NOTHING
6721 ;
6722 ; Swap above code into place
6723 ;
6724 PUSH CS
6725 POP ES
6726 MOV SI,OFFSET ABOVE_CODE
6727 MOV DI,OFFSET DRIVE_CODE
6728 MOV CX,OFFSET DRIVE_END - OFFSET DRIVE_CODE
6729 REP MOVSB
6730 MOV SI,OFFSET ABOVE_RESET
6731 MOV DI,OFFSET RESET_SYSTEM
6732 MOV CX,OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM
6733 REP MOVSB
6734 ;
6735 ; Check for presence of Above board memory manager
6736 ;
6737 MOV AX,(Get_Interrupt_Vector SHL 8) OR 67H
6738 INT 21H
6739 MOV DI,SDEVNAME
6740 MOV SI,OFFSET ABOVE_DEV_NAME
6741 MOV CX,8
6742 REPE CMPSB
6743 JZ GOT_MANAGER
6744 MOV DX,OFFSET NO_ABOVE
6745ABOVE_ERR:
6746 CALL PRINT
6747 STC
6748 RET
6749
6750GOT_MANAGER:
6751 ;
6752 ; Check memory status
6753 ;
6754 MOV CX,8000H
6755STLOOP:
6756 MOV AH,ABOVE_STATUS
6757 INT 67H
6758 CMP AH,ABOVE_SUCCESSFUL
6759 JZ MEM_OK
6760 CMP AH,ABOVE_ERROR_BUSY
6761 LOOPZ STLOOP
6762ST_ERR:
6763 MOV DX,OFFSET BAD_ABOVE
6764 JMP ABOVE_ERR
6765
6766MEM_OK:
6767 ;
6768 ; Get base address of map region and set BASE_ADDR
6769 ;
6770 MOV AH,ABOVE_GET_SEG
6771 INT 67H
6772 CMP AH,ABOVE_ERROR_BUSY
6773 JZ MEM_OK
6774 CMP AH,ABOVE_SUCCESSFUL
6775 JNZ ST_ERR
6776 MOV WORD PTR [BASE_ADDR],0
6777 MOV WORD PTR [BASE_ADDR + 2],BX
6778 ;
6779 ; Allocate drive memory
6780 ;
6781GET_AVAIL:
6782 MOV AH,ABOVE_GET_FREE
6783 INT 67H
6784 CMP AH,ABOVE_ERROR_BUSY
6785 JZ GET_AVAIL
6786 CMP AH,ABOVE_SUCCESSFUL
6787 JNZ ST_ERR
6788 MOV AX,DX ; AX is total 16K pages
6789 ; BX is un-allocated 16K pages
6790 MOV DX,OFFSET NO_MEM
6791 OR AX,AX
6792 JZ ABOVE_ERR
6793 MOV DX,OFFSET ERRMSG2
6794;
6795; change in allocation strategy new default is all of available pages
6796; < 8192K.
6797;
6798; algorithm: if (free_pages < 8) then error();
6799; else {
6800; if (free_pages > 200h) then free_pages = 200h;
6801; if (num_arg == 1) then dev_size = free_pages;
6802; else dev_size = min (dev_size,free_pages)
6803
6804
6805
6806 CMP BX,8 ; 128K = 16K * 8 = Min cache size
6807 JB ABOVE_ERR
6808 cmp bx,0200h ; 8192K = Max cache size
6809 jbe ab0$1 ; if less or equal fine
6810 mov bx,0200h ; else limit it to 8192K
6811ab0$1:
6812 mov cx,4 ; to convert number of pages into no of k
6813 shl bx,cl
6814 cmp [num_arg],1 ; is numeric argument 1 ( means none )
6815 jne ab0$2 ; cache size has been requested
6816 mov [dev_size],bx ; else use all of available cache
6817 jmp short ab001 ;
6818ab0$2:
6819 cmp [dev_size],bx ; minimum of dev size and bx
6820 jb ab001
6821 mov [dev_size],bx ;
6822
6823
6824ab001:
6825 mov bx,[dev_size]
6826 mov [current_dev_size],bx ; Initialize current device size
6827 ;
6828 ; BX is K we want to allocate (limited by available K)
6829 ; BX is at least 16
6830 ;
6831 MOV AX,BX
6832 MOV CX,4 ; Convert back to # of 16K pages
6833 SHR BX,CL
6834 TEST AX,0FH ; Even????
6835 JZ OKAYU ; Yes
6836 INC BX ; Gotta round up
6837 PUSH BX
6838 MOV CX,4
6839 SHL BX,CL
6840 MOV [DEV_SIZE],BX ; Correct dev size too by rounding it up to
6841 ; next multiple of 16K, no sense wasting
6842 ; part of a page.
6843;A
6844 mov [current_dev_size],bx ; Correct current device size also
6845;A
6846 POP BX
6847OKAYU:
6848 MOV AH,ABOVE_ALLOC
6849 INT 67H
6850 CMP AH,ABOVE_ERROR_BUSY
6851 JZ OKAYU
6852 CMP AH,ABOVE_SUCCESSFUL
6853 JZ GOT_ID
6854 CMP AH,ABOVE_ERROR_MAP_CNTXT
6855 JZ ST_ERRJ
6856 CMP AH,ABOVE_ERROR_OUT_OF_PIDS
6857 JB ST_ERRJ
6858 MOV DX,OFFSET ERRMSG2
6859 JMP ABOVE_ERR
6860
6861ST_ERRJ:
6862 JMP ST_ERR
6863
6864GOT_ID:
6865 MOV [ABOVE_PID],DX
6866 ;
6867 ; INSTALL ABOVE RESET handler
6868 ;
6869 CALL SET_RESET
6870 ;
6871 ; We are now in good shape.
6872 ;
6873 CALL DRIVEPARMS
6874 JNC RETYYY
6875 CALL DISK_ABORT
6876 STC
6877RETYYY:
6878 RET
6879
6880BREAK <Drive code for /A driver. Swapped in at BLKMOV>
6881
6882;
6883; This label defines the start of the code swapped in at DRIVE_CODE
6884;
6885ABOVE_CODE LABEL WORD
6886
6887;
6888; WARNING DANGER!!!!!!!
6889;
6890; This code is tranfered over the /E driver code at DRIVE_CODE
6891;
6892; ALL jmps etc. must be IP relative.
6893; ALL data references must be to cells at the FINAL, TRUE location
6894; (no data cells may be named HERE, must be named up at BLKMOV).
6895; OFFSET of ABOVE_BLKMOV relative to ABOVE_CODE MUST be the same as
6896; the OFFSET of BLKMOV relative to DRIVE_CODE.
6897; SIZE of stuff between ABOVE_CODE and ABOVE_END MUST be less than
6898; or equal to size of stuff between DRIVE_CODE and DRIVE_END.
6899
6900IF2
6901 IF((OFFSET ABOVE_BLKMOV - OFFSET ABOVE_CODE) NE (OFFSET BLKMOV - OFFSET DRIVE_CODE))
6902 %out ERROR BLKMOV, ABOVE_BLKMOV NOT ALIGNED
6903 ENDIF
6904 IF((OFFSET ABOVE_END - OFFSET ABOVE_CODE) GT (OFFSET DRIVE_END - OFFSET DRIVE_CODE))
6905 %out ERROR ABOVE CODE TOO BIG
6906 ENDIF
6907ENDIF
6908
6909 DD ? ; 24 bit address of start of this RAMDRV
6910;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6911;** ABOVE_BLKMOV - Perform transfer for TYPE 2 driver
6912;
6913; This routine is the transfer routine for moving bytes
6914; to and from the Above Board memory containing the cache.
6915;
6916; The Above Board is implemented as 4 16K windows into the Above
6917; Board memory, giving a total window of 64K wich starts on some
6918; 16K boundary of the Above Board memory. Given that a DOS I/O
6919; request is up to 64K bytes starting on some sector boundary,
6920; the most general I/O picture is:
6921;
6922; |------------|------------|------------|------------|------------|
6923; | Above Brd | Above Brd | Above Brd | Above Brd | Above Brd |
6924; |Log page n |Log page n+1|Log page n+2|log page n+3|Log page n+4|
6925; |------------|------------|------------|------------|------------|
6926; |---|---| | |
6927; | | |---------------- 64K bytes of sectors -------------|
6928; Byte | | |
6929; offset|------------------|------------------------| |
6930; of first| Number of words in | |
6931; byte of | first part of I/O that |---|---|
6932; I/O in | can be performed once Number
6933; first | logical pages n - n+3 of words
6934; Log page| are mapped into physical in tail
6935; | pages 0 - 3 part of I/O
6936; Location of that have
6937; first byte to be done
6938; of sector M, once logical
6939; the start sector page n+4 is
6940; of the I/O mapped into
6941; physical page
6942; 0
6943;
6944; One or both of "Byte offset of first byte of I/O in first page" and
6945; "Number of words in tail part of I/O" may be zero depending on the
6946; size of the I/O and its start offset in the first logical page it is
6947; possible to map.
6948;
6949; WARNING: IF A PRE-EMPTIVE MULTITASKING SYSTEM SCHEDULES A TASK WHICH
6950; IS USING THE ABOVE BOARD DURING THE TIME THIS DRIVER IS IN THE
6951; MIDDLE OF PERFORMING AN I/O, THE SYSTEM HAD BETTER MANAGE THE A
6952; BOARD MAPPING CONTEXT CORRECTLY OR ALL SORTS OF STRANGE UNPLEASANT
6953; THINGS WILL OCCUR.
6954;
6955; SEE ALSO
6956; INTEL Expanded Memory Manager Programming Specification
6957;
6958; ENTRY:
6959; ES:DI is packet transfer address.
6960; CX is number of words to transfer.
6961; DX:AX is 32 bit start byte offset (0 = start of cache)
6962; BH is 1 for WRITE, 0 for READ
6963;
6964; BASE_ADDR set to point to Above Board mapping window in main memory
6965; This "input" is not the responsibility of the caller. It
6966; is up to the initialization code to set it up when the
6967; device is installed
6968;
6969; EXIT:
6970; Carry Clear
6971; OK, operation performed successfully
6972; Carry Set
6973; Error during operation, AL is error number
6974;
6975; USES:
6976; ALL
6977;
6978; This routine is specific to TYPE 2 driver
6979;
6980above_blkmov:
6981assume ds:int13code,es:nothing,ss:nothing
6982;
6983; save mapping context and return with error if save fails
6984;
6985 save_mapping_context
6986 jnc ab_blk$1
6987 ret
6988;
6989; find logical page number, offset of i/o in first page
6990;
6991ab_blk$1:
6992 push cx
6993 mov cx,1024*16 ; 16k bytes / page
6994 div cx ; dx:ax / 16k --> log page numb in ax
6995 ; --> offset of i/o in dx
6996 mov si,dx ; transfer offset to si
6997 mov dx,ax ; store the page number in dx
6998 pop cx
6999;
7000; find case and dispatch accordingly
7001;
7002; case 0 : user buffer below page map, can use aaron's code
7003; case 1 : user buffer above page map, can use aaron's code
7004; case 2 : user buffer totally within page map, use pai's code
7005; case 3 : user buffer partly in page map partly below, error
7006; case 4 : user buffer partly in page map partly above, error
7007;
7008 push bx
7009 push cx
7010;
7011; if( final_user_off < pm_base_addr ) then case 0
7012;
7013 mov ax,di ; get user buffer initial offset into ax
7014 shr ax,1 ; convert to word offset
7015 dec cx ; convert word count to 0 based number
7016 add ax,cx ; user buffer final word offset
7017 shr ax,1 ; convert to segment
7018 shr ax,1 ;
7019 shr ax,1 ;
7020 mov bx,es ; get segment of buffer
7021 add ax,bx ; now we have the segment of the user buffer
7022 ; with offset < 16
7023 sub ax,word ptr [base_addr+2] ; compare against page map
7024 jc aar_cd ; if below page map then execute old code
7025;
7026; if( initial_user_off < pm_base_addr ) then error
7027;
7028 mov cx,4
7029 mov bp,di ; get initial offset in bp
7030 shr bp,cl ;
7031 add bp,bx ;
7032 sub bp,word ptr [base_addr +2]
7033 jc ab_error ;
7034;
7035; if ( initial_user_off >= pm_end_addr ) then case1
7036;
7037 cmp bp,4*1024 ;
7038 jae aar_cd ;
7039;
7040; if ( final_addr >= pm_end_addr ) then error
7041;
7042 cmp ax,4*1024
7043 jae ab_error
7044;
7045; case 2
7046;
7047within_pm: jmp new_code ; user buffer in page map
7048 ; so we need to execute new code
7049ab_error:
7050 add sp,4
7051 mov al,0bbh ; general failure
7052 stc
7053 jmp short REST_CONT ; RESTORE CONTEXT!!!
7054aar_cd:
7055 pop cx
7056 pop bx
7057;
7058; Referring back to the diagram given above the following routine is
7059; to take care of transfer of the most general case.
7060; What this routine does is break every I/O down into the above parts.
7061; The first or main part of the I/O is performed by mapping 1 to 4
7062; sequential logical pages into the 4 physical pages and executing one
7063; REP MOVSW. If the tail word count is non-zero then the fith sequential
7064; logical page is mapped into physical page 0 and another REP MOVSW is
7065; executed.
7066;
7067; METHOD:
7068; Break I/O down as described above into main piece and tail piece
7069; Map the appropriate number of sequential pages (up to 4)
7070; into the page window at BASE_ADDR to set up the main piece
7071; of the I/O.
7072; Set appropriate seg and index registers and CX to perform the
7073; main piece of the I/O into the page window
7074; REP MOVSW
7075; IF there is a tail piece
7076; Map the next logical page into physical page 0
7077; Reset the appropriate index register to point at phsical page 0
7078; Move tail piece word count into CX
7079; REP MOVSW
7080; Restore Above Board page mapping context
7081;
7082 XOR BP,BP ; No tail page
7083 PUSH BX
7084 ;
7085 ; DX is first page #, SI is byte offset of start of I/O in first page
7086 ;
7087 MOV AX,DX
7088 MOV BX,SI
7089 SHR BX,1 ; # Words in first 16k page which are not part
7090 ; of I/O
7091 PUSH CX
7092 ADD BX,CX ; # of words we need to map to perform I/O
7093 MOV DX,BX
7094 AND DX,1FFFH ; DX is number of words to transfer last page
7095 ; remainder of div by words in 16K bytes
7096 MOV CL,13 ; Div by # words in 16K
7097 SHR BX,CL ; BX is number of pages to map (may need round up)
7098 OR DX,DX ; Remainder?
7099 JZ NO_REM
7100 INC BX ; Need one more page
7101NO_REM:
7102 MOV CX,BX ; CX is total pages we need to map
7103 MOV BX,AX ; BX is first logical page
7104 CMP CX,4 ; We can map up to 4 pages
7105 JBE NO_TAIL
7106 MOV BP,DX ; Words to move in tail page saved in BP
7107 DEC CX ; Need second map for the 5th page
7108 POP AX
7109 SUB AX,DX ; Words to move in first 4 pages is input
7110 ; word count minus words in tail page
7111 PUSH AX ; Count for first mapping back on stack
7112NO_TAIL:
7113 ; Map CX pages
7114 MOV DX,[ABOVE_PID]
7115 MOV AX,ABOVE_MAP SHL 8 ; Physical page 0
7116 PUSH AX
7117MAP_NEXT:
7118 POP AX ; Recover correct AX register
7119 PUSH AX
7120 PUSH BX
7121 PUSH DX
7122 INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX
7123 POP DX
7124 POP BX
7125 OR AH,AH
7126 JNZ MAP_ERR1 ; error
7127IF2
7128 IF (ABOVE_SUCCESSFUL)
7129 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
7130 ENDIF
7131ENDIF
7132NEXT_PAGE:
7133 INC BX ; Next logical page
7134 POP AX
7135 INC AL ; Next physical page
7136 PUSH AX
7137 LOOP MAP_NEXT
7138 POP AX ; Clean stack
7139 POP CX ; Word count for first page mapping
7140 POP AX ; Operation in AH
7141 ;
7142 ; BX has # of next logical page (Tail page if BP is non-zero)
7143 ; BP has # of words to move in tail page (0 if no tail)
7144 ; CX has # of words to move in current mapping
7145 ; SI is offset into current mapping of start of I/O
7146 ; AH indicates READ or WRITE
7147 ;
7148 PUSH AX ; Save op for possible second I/O
7149 OR AH,AH
7150 JZ READ_A
7151 ;
7152 ; WRITE
7153 ;
7154 PUSH ES
7155 PUSH DI
7156 MOV DI,SI ; Start page offset to DI
7157 POP SI ; DS:SI is transfer addr
7158 POP DS
7159ASSUME DS:NOTHING
7160 MOV ES,WORD PTR [BASE_ADDR + 2] ; ES:DI -> start
7161 JMP SHORT FIRST_MOVE
7162
7163READ_A:
7164ASSUME DS:INT13CODE
7165 MOV DS,WORD PTR [BASE_ADDR + 2] ; DS:SI -> start
7166ASSUME DS:NOTHING
7167FIRST_MOVE:
7168 REP MOVSW
7169 OR BP,BP ; Tail?
7170 JNZ TAIL_IO ; Yup
7171ALL_DONE:
7172 POP AX
7173 CLC
7174REST_CONT:
7175 ; Restore page mapping context
7176 PUSH AX ; Save possible error code
7177 PUSHF ; And carry state
7178REST_AGN:
7179 MOV DX,[ABOVE_PID]
7180 MOV AH,ABOVE_RESTORE_MAP_PID
7181 INT 67H
7182 OR AH,AH
7183 JZ ROK
7184IF2
7185 IF (ABOVE_SUCCESSFUL)
7186 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
7187 ENDIF
7188ENDIF
7189 CMP AH,ABOVE_ERROR_BUSY
7190 JZ REST_AGN
7191 CMP AH,ABOVE_ERROR_NO_CNTXT
7192 JZ ROK ; Ignore the invalid PID error
7193 POP DX
7194 POP DX ; Clean stack
7195 MOV AL,0BBH ; General failure
7196 STC
7197 RET
7198
7199ROK:
7200 POPF ; Recover carry state
7201 POP AX ; and possible error code
7202 RET
7203
7204TAIL_IO:
7205 MOV DX,[ABOVE_PID]
7206MAP_AGN:
7207 MOV AX,ABOVE_MAP SHL 8 ; map logical page BX to phys page 0
7208 PUSH BX
7209 PUSH DX
7210 INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX
7211 POP DX
7212 POP BX
7213 OR AH,AH
7214 JNZ MAP_ERR2 ; Error
7215IF2
7216 IF (ABOVE_SUCCESSFUL)
7217 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
7218 ENDIF
7219ENDIF
7220SECOND_MOVE:
7221 POP AX ; Recover Op type
7222 PUSH AX
7223 OR AH,AH
7224 JZ READ_SEC
7225 ;
7226 ; WRITE
7227 ;
7228 XOR DI,DI ; ES:DI -> start of tail
7229 JMP SHORT SMOVE
7230
7231READ_SEC:
7232 XOR SI,SI ; DS:SI -> start of tail
7233SMOVE:
7234 MOV CX,BP
7235 REP MOVSW
7236 JMP ALL_DONE
7237
7238MAP_ERR1:
7239 CMP AH,ABOVE_ERROR_BUSY ; Busy?
7240 JZ MAP_NEXT ; Yes, wait till not busy (INTs are ON)
7241 ADD SP,6 ; Clean stack
7242 JMP SHORT DNR_ERR
7243
7244MAP_ERR2:
7245 CMP AH,ABOVE_ERROR_BUSY
7246 JZ MAP_AGN
7247 ADD SP,2
7248DNR_ERR:
7249 MOV AL,0AAH ; Drive not ready
7250 STC
7251 JMP REST_CONT
7252;
7253;
7254; this code has been written to handle te cases of overlapping usage
7255; of the above board page frame segment by the cache and user buffer
7256; assumption: in dos tracks cannot be more than 64 sectors long so
7257; in the worst case we shall have the user buffer occupying three
7258; pages is the page frame. we attempt to find the page that is
7259; available for the cache and use it repeatedly to access the cache
7260;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7261; the algorithm is:
7262; ******************************************************
7263; [STEP1: determine the page we can use for the cache]
7264;
7265; if (initial_para_offset_user in page 1 or above ) then {
7266; physical_cache_page = 0;
7267; cache_segment = above board segment;
7268; }
7269; else {
7270; physical_cache_page = 3;
7271; cache_segment = above_board_segment + 3*1024;
7272; }
7273;
7274; ******************************************************
7275; [STEP2: initial setup]
7276;
7277; count = user_count_requested;
7278; number_to_be_transferred = min ( count, (16K - si) >> 2 );
7279; exchange source and destination if necessary;
7280;
7281; *******************************************************
7282; [STEP3: set up transfer and do it]
7283;
7284; count = count - number_to_be_transferred;
7285; map_page cache_handle,physical_cache_page,logical_cache_page
7286; mov data
7287;
7288; *******************************************************
7289; [STEP4: determine if another transfer needed and setup if so]
7290;
7291; if ( count == 0 ) then exit;
7292; if ( operation == read ) then source_offset = 0;
7293; else dest_offset = 0;
7294; number_to_be_transferred = min ( count, 8*1024 );
7295; logical_page_number++ ;
7296;
7297; *******************************************************
7298; [STEP5: go to do next block]
7299;
7300; goto [STEP3]
7301;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7302;
7303new_code:
7304 assume ds:int13code,es:nothing,ss:nothing
7305;
7306; input parameters:
7307;
7308; bp : start para offset of user buffer in physical page frame
7309; ax : end para offset of user buffer in physical page frame
7310; di : transfer offset of user buffer
7311; es : transfer segment of user buffer
7312; dx : logical page number in cache
7313; si : offset from start in logical page number
7314;
7315; on stack { cx,bx } where cx = number of words, bx = read / write status
7316;
7317; [STEP1: finding physical cache page and page frame]
7318;
7319 ;
7320 ; assume is physical page 0
7321 ;
7322 xor al,al ; use page 0 for cache
7323 mov bx,word ptr [base_addr+2]
7324 ;
7325 ; see if this assumption valid
7326 ;
7327 cmp bp,1024 ; is initial in page 1 or above
7328 jae ab$30 ; if so or assumption is valid
7329 ;
7330 ; else we have to correct our assumption
7331 ;
7332 mov al,3 ; use page 3 for cache
7333 add bx,3*1024 ;
7334 ;
7335 ; initialise page frame segment
7336 ;
7337ab$30:
7338 mov ds,bx
7339 ;
7340assume ds:nothing
7341;
7342; [STEP2: initialising transfer parameters]
7343;
7344 ;
7345 pop bp ; bp will have count of words left to be transferred
7346 pop bx ; read / write status
7347 push bx ; save it back again
7348 push dx ; save this too
7349 ;
7350 ; initially si offset into logical page, so we can only do 16*1024 - si
7351 ; byte transfer
7352 ;
7353 mov cx,16*1024
7354 sub cx,si
7355 shr cx,1 ; convert to word count
7356 ;
7357 ; number to be transferred is the minimum of this and the user requested
7358 ; count
7359 ;
7360 cmp cx,bp
7361 jb ab$31
7362 mov cx,bp
7363 ;
7364ab$31:
7365 ;
7366 ; see if write, then we have to switch source with destination
7367 ;
7368 or bh,bh
7369 je ab$32 ; if read we don't have to do anything
7370 ; else we have to switch
7371 src_dest_switch
7372ab$32:
7373 ;
7374 ; set direction flag so that we don't have to do it repeatedly
7375 ;
7376 cld
7377;
7378; [STEP3: set up transfer and do it]
7379;
7380ab$33:
7381 ;
7382 ; update count of words still left to be transferred after this
7383 ;
7384 sub bp,cx
7385 ;
7386 ; map the logical page in cache to the physical page selected
7387 ;
7388 mov bx,dx ; get logical page into bx
7389 ; al already holds the physical page #
7390 map_page
7391 jnc ab$34 ; suceeded ?
7392 ;
7393 ; else report error
7394 ;
7395 add sp,4
7396 stc
7397 jmp short restore_mp ; and go to restore page map
7398ab$34:
7399 ;
7400 ; succeeded, do the transfer
7401 ;
7402rep movsw
7403 ;
7404;
7405; [STEP4: check if transfer done, if not set up for next block]
7406; [STEP5: go back to STEP3]
7407 ;
7408 ; check if done
7409 ;
7410 or bp,bp ; count 0
7411 je ab$40 ; yes, go to finish up
7412 ;
7413 ; recover original dx and bx, increment dx and then save both again
7414 ;
7415 pop dx
7416 pop bx
7417 inc dx
7418 push bx
7419 push dx
7420 ;
7421 ; words to be transferred minimum of count and 8*1024 words
7422 ;
7423 mov cx,8*1024 ; 8k words in a page
7424 cmp cx,bp ;
7425 jbe ab$35 ; if below or equal this is what we want
7426 ;
7427 mov cx,bp ; else we can transfer the whole count
7428ab$35:
7429 ;
7430 ; see whether cache src or dest and accordingly reset either si or di
7431 ;
7432 or bh,bh ; read?
7433 jne ab$36 ; if write go to modify
7434 ;
7435 ; read, zero si and go back to step3
7436 ;
7437 xor si,si
7438 jmp short ab$33 ; to step 3
7439ab$36:
7440 ;
7441 ; write, zero di and go back to step3
7442 ;
7443 xor di,di
7444 jmp short ab$33 ; to step 3
7445;
7446; finishing up we have to restore the page map
7447;
7448ab$40:
7449 add sp,4
7450 clc
7451restore_mp:
7452 restore_mapping_context
7453 ret
7454
7455 DW ? ; SPACE for ABOVE_PID
7456
7457;
7458; This label defines the end of the code swapped in at DRIVE_CODE
7459;
7460ABOVE_END LABEL WORD
7461
7462BREAK <Drive code for /A driver. Swapped in at RESET_SYSTEM>
7463
7464
7465;
7466; WARNING DANGER!!!!!!!
7467;
7468; This code is tranfered over the /E driver code at RESET_SYSTEM
7469;
7470; ALL jmps etc. must be IP relative.
7471; ALL data references must be to cells at the FINAL, TRUE location
7472; (no data cells may be named HERE, must be named up at RESET_SYSTEM).
7473; SIZE of stuff between ABOVE_RESET and ABOVE_RESET_END MUST be less than
7474; or equal to size of stuff between RESET_SYSTEM and RESET_INCLUDE.
7475;
7476; NOTE: EACH ABOVE BOARD driver has an INT 19 and 9 handler. This is
7477; different from /E and RESMEM in which only the first
7478; driver has an INT 19 and 9 handler.
7479;
7480
7481IF2
7482 IF((OFFSET ABOVE_RESET_END - OFFSET ABOVE_RESET) GT (OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM))
7483 %out ERROR ABOVE_RESET CODE TOO BIG
7484 ENDIF
7485ENDIF
7486
7487;** ABOVE_RESET perform TYPE 2 (/A) driver specific reboot code
7488;
7489; This code issues an ABOVE_DEALLOC call for the memory
7490; associated with this particular TYPE 2 cache since the
7491; system is being re-booted and the driver is "gone".
7492;
7493; ENTRY
7494; NONE
7495; EXIT
7496; NONE
7497; USES
7498; NONE
7499;
7500; This code is specific to TYPE 2 drivers
7501;
7502
7503ABOVE_RESET:
7504ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
7505 PUSH AX
7506 PUSH DX
7507AGAIN_RESET:
7508 MOV DX,[ABOVE_PID]
7509 MOV AH,ABOVE_DEALLOC ; Close PID
7510 INT 67H
7511 CMP AH,ABOVE_ERROR_BUSY
7512 JZ AGAIN_RESET
7513 POP DX
7514 POP AX
7515 RET
7516
7517;
7518; This label defines the end of the code swapped in at RESET_SYSTEM
7519;
7520ABOVE_RESET_END LABEL BYTE
7521
7522BREAK <messages and common data>
7523
7524;** Message texts and common data
7525;
7526; Init data. This data is disposed of after initialization.
7527; it is mostly texts of all of the messages
7528;
7529; COMMON to TYPE 1 and 2 drivers
7530;
7531; THIS IS THE START OF DATA SUBJECT TO TRANSLATION
7532
7533NO_ABOVE db "SMARTDrive : Expanded Memory Manager not present",13,10,"$"
7534BAD_ABOVE db "SMARTDrive : Expanded Memory Status shows error",13,10,"$"
7535BAD_AT db "SMARTDrive : Cannot run on this computer",13,10,"$"
7536NO_MEM db "SMARTDrive : No extended memory available",13,10,"$"
7537ERRMSG1 db "SMARTDrive : Invalid parameter",13,10,"$"
7538ERRMSG2 db "SMARTDrive : Insufficient memory",13,10,"$"
7539INIT_IO_ERR db "SMARTDrive : I/O error accessing cache memory",13,10,"$"
7540NOHARD db "SMARTDrive : No hard drives on system",13,10,"$"
7541BIGTRACK db "SMARTDrive : Too many bytes per track on hard drive",13,10,"$"
7542BADVERMES db 13,10,"SMARTDrive : Incorrect DOS version",13,10,"$"
7543
7544;
7545; This is the Int13 header message.
7546;
7547HEADERMES db 13,10,"Microsoft SMARTDrive Disk Cache v2.10",13,10,"$"
7548
7549;
7550; This is the status message used to display INT13 configuration
7551; it is:
7552;
7553; STATMES1<size in K><STATMES1A|STATMES1E>STATMES2<# tracks in cache>STATMES3
7554; <sectors per track>STATMES4
7555;
7556; It is up to translator to move the message text around the numbers
7557; so that the message is printed correctly when translated
7558;
7559STATMES1 db " Cache size: $"
7560STATMES1A db "K in Expanded Memory$"
7561STATMES1E db "K in Extended Memory$"
7562STATMES2 db 13,10," Room for $"
7563STATMES3 db " tracks of $"
7564STATMES4 db " sectors each",13,10,13,10,"$"
7565ifdef OMTI
7566omti_msg db " OMTI controller release",13,10,"$"
7567endif
7568
7569;-----------------------------------------------------------------------
7570;
7571; END OF DATA SUBJECT TO TRANSLATION
7572;
7573
7574IF DEBUG
7575STATMES5 db "Device CS = $"
7576STATMES6 db " decimal",13,10,"$"
7577s5flagmsg db " = S5 flag",13,10,"$"
7578U_msg db " = U Switch", 13,10,'$'
7579ENDIF
7580
7581 db "This program is the property of Microsoft Corporation."
7582
7583INT13_END LABEL BYTE
7584
7585INT13CODE ENDS
7586 END
7587 \ No newline at end of file
diff --git a/v4.0/src/DEV/SMARTDRV/SMARTDRV.LNK b/v4.0/src/DEV/SMARTDRV/SMARTDRV.LNK
new file mode 100644
index 0000000..be9d1c2
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/SMARTDRV.LNK
@@ -0,0 +1,3 @@
1int13
2int13.exe
3int13.map -map;
diff --git a/v4.0/src/DEV/SMARTDRV/SYSCALL.ASM b/v4.0/src/DEV/SMARTDRV/SYSCALL.ASM
new file mode 100644
index 0000000..3f6d712
--- /dev/null
+++ b/v4.0/src/DEV/SMARTDRV/SYSCALL.ASM
@@ -0,0 +1,147 @@
1BREAK <system call definitions>
2
3Abort EQU 0 ; 0 0
4Std_Con_Input EQU 1 ; 1 1
5Std_Con_Output EQU 2 ; 2 2
6Std_Aux_Input EQU 3 ; 3 3
7Std_Aux_Output EQU 4 ; 4 4
8Std_Printer_Output EQU 5 ; 5 5
9Raw_Con_IO EQU 6 ; 6 6
10Raw_Con_Input EQU 7 ; 7 7
11Std_Con_Input_No_Echo EQU 8 ; 8 8
12Std_Con_String_Output EQU 9 ; 9 9
13Std_Con_String_Input EQU 10 ; 10 A
14Std_Con_Input_Status EQU 11 ; 11 B
15Std_Con_Input_Flush EQU 12 ; 12 C
16Disk_Reset EQU 13 ; 13 D
17Set_Default_Drive EQU 14 ; 14 E
18FCB_Open EQU 15 ; 15 F
19FCB_Close EQU 16 ; 16 10
20Dir_Search_First EQU 17 ; 17 11
21Dir_Search_Next EQU 18 ; 18 12
22FCB_Delete EQU 19 ; 19 13
23FCB_Seq_Read EQU 20 ; 20 14
24FCB_Seq_Write EQU 21 ; 21 15
25FCB_Create EQU 22 ; 22 16
26FCB_Rename EQU 23 ; 23 17
27Get_Default_Drive EQU 25 ; 25 19
28Set_DMA EQU 26 ; 26 1A
29;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
30; C A V E A T P R O G R A M M E R ;
31; ;
32Get_Default_DPB EQU 31 ; 31 1F
33; ;
34; C A V E A T P R O G R A M M E R ;
35;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
36FCB_Random_Read EQU 33 ; 33 21
37FCB_Random_Write EQU 34 ; 34 22
38Get_FCB_File_Length EQU 35 ; 35 23
39Get_FCB_Position EQU 36 ; 36 24
40Set_Interrupt_Vector EQU 37 ; 37 25
41Create_Process_Data_Block EQU 38 ; 38 26
42FCB_Random_Read_Block EQU 39 ; 39 27
43FCB_Random_Write_Block EQU 40 ; 40 28
44Parse_File_Descriptor EQU 41 ; 41 29
45Get_Date EQU 42 ; 42 2A
46Set_Date EQU 43 ; 43 2B
47Get_Time EQU 44 ; 44 2C
48Set_Time EQU 45 ; 45 2D
49Set_Verify_On_Write EQU 46 ; 46 2E
50; Extended functionality group
51Get_DMA EQU 47 ; 47 2F
52Get_Version EQU 48 ; 48 30
53Keep_Process EQU 49 ; 49 31
54;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
55; C A V E A T P R O G R A M M E R ;
56; ;
57Get_DPB EQU 50 ; 50 32
58; ;
59; C A V E A T P R O G R A M M E R ;
60;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
61Set_CTRL_C_Trapping EQU 51 ; 51 33
62Get_InDOS_Flag EQU 52 ; 52 34
63Get_Interrupt_Vector EQU 53 ; 53 35
64Get_Drive_Freespace EQU 54 ; 54 36
65Char_Oper EQU 55 ; 55 37
66International EQU 56 ; 56 38
67; Directory Group
68MKDir EQU 57 ; 57 39
69RMDir EQU 58 ; 58 3A
70CHDir EQU 59 ; 59 3B
71; File Group
72Creat EQU 60 ; 60 3C
73Open EQU 61 ; 61 3D
74Close EQU 62 ; 62 3E
75Read EQU 63 ; 63 3F
76Write EQU 64 ; 64 40
77Unlink EQU 65 ; 65 41
78LSeek EQU 66 ; 66 42
79CHMod EQU 67 ; 67 43
80IOCtl EQU 68 ; 68 44
81XDup EQU 69 ; 69 45
82XDup2 EQU 70 ; 70 46
83Current_Dir EQU 71 ; 71 47
84; Memory Group
85Alloc EQU 72 ; 72 48
86Dealloc EQU 73 ; 73 49
87Setblock EQU 74 ; 74 4A
88; Process Group
89Exec EQU 75 ; 75 4B
90Exit EQU 76 ; 76 4C
91Get_Return_Code EQU 77 ; 77 4D
92Find_First EQU 78 ; 78 4E
93; Special Group
94Find_Next EQU 79 ; 79 4F
95; SPECIAL SYSTEM GROUP
96;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
97; C A V E A T P R O G R A M M E R ;
98; ;
99Set_Current_PDB EQU 80 ; 80 50
100Get_Current_PDB EQU 81 ; 81 51
101Get_In_Vars EQU 82 ; 82 52
102SetDPB EQU 83 ; 83 53
103; ;
104; C A V E A T P R O G R A M M E R ;
105;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
106Get_Verify_On_Write EQU 84 ; 84 54
107;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
108; C A V E A T P R O G R A M M E R ;
109; ;
110Dup_PDB EQU 85 ; 85 55
111; ;
112; C A V E A T P R O G R A M M E R ;
113;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
114Rename EQU 86 ; 86 56
115File_Times EQU 87 ; 87 57
116AllocOper EQU 88 ; 88 58
117; Network extention system calls
118GetExtendedError EQU 89 ; 89 59
119CreateTempFile EQU 90 ; 90 5A
120CreateNewFile EQU 91 ; 91 5B
121LockOper EQU 92 ; 92 5C Lock and Unlock
122;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
123; C A V E A T P R O G R A M M E R ;
124; ;
125ServerCall EQU 93 ; 93 5D CommitAll, ServerDOSCall,
126 ; CloseByName, CloseUser,
127 ; CloseUserProcess,
128 ; GetOpenFileList
129; ;
130; C A V E A T P R O G R A M M E R ;
131;----+----+----+----+----+----+----+----+----+----+----+----+----+----+----;
132UserOper EQU 94 ; 94 5E Get and Set
133AssignOper EQU 95 ; 95 5F On, Off, Get, Set, Cancel
134xNameTrans EQU 96 ; 96 60
135PathParse EQU 97 ; 97 61
136GetCurrentPSP EQU 98 ; 98 62
137Hongeul EQU 99 ; 99 63
138
139Set_Oem_Handler EQU 248 ; 248 F8
140OEM_C1 EQU 249 ; 249 F9
141OEM_C2 EQU 250 ; 250 FA
142OEM_C3 EQU 251 ; 251 FB
143OEM_C4 EQU 252 ; 252 FC
144OEM_C5 EQU 253 ; 253 FD
145OEM_C6 EQU 254 ; 254 FE
146OEM_C7 EQU 255 ; 255 FF
147 \ No newline at end of file