summaryrefslogtreecommitdiff
path: root/v4.0/src/DEV/RAMDRIVE
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/RAMDRIVE
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 '')
-rw-r--r--v4.0/src/DEV/RAMDRIVE/ABOVE.INC61
-rw-r--r--v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC180
-rw-r--r--v4.0/src/DEV/RAMDRIVE/DEVSYM.INC128
-rw-r--r--v4.0/src/DEV/RAMDRIVE/DIRENT.INC56
-rw-r--r--v4.0/src/DEV/RAMDRIVE/EMM.INC223
-rw-r--r--v4.0/src/DEV/RAMDRIVE/LOADALL.INC35
-rw-r--r--v4.0/src/DEV/RAMDRIVE/MAKEFILE36
-rw-r--r--v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM82
-rw-r--r--v4.0/src/DEV/RAMDRIVE/MI.INC18
-rw-r--r--v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM6218
-rw-r--r--v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK3
-rw-r--r--v4.0/src/DEV/RAMDRIVE/SYSCALL.INC146
12 files changed, 7186 insertions, 0 deletions
diff --git a/v4.0/src/DEV/RAMDRIVE/ABOVE.INC b/v4.0/src/DEV/RAMDRIVE/ABOVE.INC
new file mode 100644
index 0000000..52878c8
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/ABOVE.INC
@@ -0,0 +1,61 @@
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
40
41
42;
43; EMM INT 67H AH return values
44;
45ABOVE_SUCCESSFUL EQU 0
46ABOVE_ERROR_SOFTWARE EQU 80H
47ABOVE_ERROR_HARDWARE EQU 81H
48ABOVE_ERROR_BUSY EQU 82H
49ABOVE_ERROR_BAD_PID EQU 83H
50ABOVE_ERROR_BAD_FUNC EQU 84H
51ABOVE_ERROR_OUT_OF_PIDS EQU 85H
52ABOVE_ERROR_MAP_CNTXT EQU 86H
53ABOVE_ERROR_INSUFF_MEM EQU 87H
54ABOVE_ERROR_INSUFF_FREE EQU 88H
55ABOVE_ERROR_ALLOC_ZERO EQU 89H
56ABOVE_ERROR_LOG_INVALID EQU 8AH
57ABOVE_ERROR_PHYS_INVALID EQU 8BH
58ABOVE_ERROR_CNTXT_NO_STACK EQU 8CH
59ABOVE_ERROR_SECOND_SAVE EQU 8DH
60ABOVE_ERROR_NO_CNTXT EQU 8EH
61ABOVE_ERROR_BAD_PARM EQU 8FH
diff --git a/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC b/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC
new file mode 100644
index 0000000..10fb733
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/AB_MACRO.INC
@@ -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,02h ; 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,0ch ; 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,0ch ; 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,02h ; 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/RAMDRIVE/DEVSYM.INC b/v4.0/src/DEV/RAMDRIVE/DEVSYM.INC
new file mode 100644
index 0000000..44a1ab8
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/DEVSYM.INC
@@ -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/RAMDRIVE/DIRENT.INC b/v4.0/src/DEV/RAMDRIVE/DIRENT.INC
new file mode 100644
index 0000000..e7150c8
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/DIRENT.INC
@@ -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/RAMDRIVE/EMM.INC b/v4.0/src/DEV/RAMDRIVE/EMM.INC
new file mode 100644
index 0000000..ff61ab0
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/EMM.INC
@@ -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/RAMDRIVE/LOADALL.INC b/v4.0/src/DEV/RAMDRIVE/LOADALL.INC
new file mode 100644
index 0000000..0476acd
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/LOADALL.INC
@@ -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/RAMDRIVE/MAKEFILE b/v4.0/src/DEV/RAMDRIVE/MAKEFILE
new file mode 100644
index 0000000..c61e83e
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/MAKEFILE
@@ -0,0 +1,36 @@
1#** makefile for Ramdrive
2
3DEST = ramdrive
4MSG = messages
5
6# Definitions for assembler
7
8ASM = masm
9AFLAGS = -Mx -t
10AINC = -I../../inc
11
12# Definitions for C compiler
13
14CC = cl
15CFLAGS = -Ox -X -Zlp
16CINC = -I../../h
17
18# Definitions for linker
19
20LINK = link
21
22# Dependencies follow
23
24all: ramdrive.sys
25
26ramdrive.obj: ramdrive.asm above.inc loadall.inc emm.inc mi.inc \
27 dirent.inc syscall.inc devsym.inc
28 masm $(AFLAGS) $(AINC) ramdrive;
29
30messages.obj: messages.asm
31 masm $(AFLAGS) $(AINC) messages;
32
33ramdrive.sys: ramdrive.obj messages.obj
34 link @ramdrive.lnk
35 exe2bin ramdrive ramdrive.sys
36 del ramdrive.exe
diff --git a/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM b/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM
new file mode 100644
index 0000000..66c528b
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/MESSAGES.ASM
@@ -0,0 +1,82 @@
1 TITLE MESSAGE MODULE FOR RAMDRIVE.ASM
2;
3; WRITTEN BY S. P. 3/3/87
4;
5PAGE 58,132
6
7BREAK MACRO subtitle
8 SUBTTL subtitle
9 PAGE
10ENDM
11
12BREAK <messages and common data>
13
14RAMCODE SEGMENT
15ASSUME CS:RAMCODE,DS:RAMCODE,ES:NOTHING,SS:NOTHING
16
17;** Message texts and common data
18;
19; Init data. This data is disposed of after initialization.
20; it is mostly texts of all of the messages
21;
22; COMMON to TYPE 1,2,3 and 4 drivers
23;
24; THIS IS THE START OF DATA SUBJECT TO TRANSLATION
25
26 PUBLIC NO_ABOVE,BAD_ABOVE,BAD_AT,NO_MEM,ERRMSG1,ERRMSG2
27 PUBLIC ERRMSG2,INIT_IO_ERR,BADVERMES
28 PUBLIC HEADERMES,PATCH2X,DOS_DRV
29 PUBLIC STATMES1,STATMES2,STATMES3,STATMES4,STATMES4,STATMES5
30
31NO_ABOVE db "RAMDrive: Expanded Memory Manager not present",13,10,"$"
32BAD_ABOVE db "RAMDrive: Expanded Memory Status shows error",13,10,"$"
33BAD_AT db "RAMDrive: Computer must be PC-AT, or PC-AT compatible",13,10,"$"
34NO_MEM db "RAMDrive: No extended memory available",13,10,"$"
35ERRMSG1 db "RAMDrive: Invalid parameter",13,10,"$"
36ERRMSG2 db "RAMDrive: Insufficient memory",13,10,"$"
37INIT_IO_ERR db "RAMDrive: I/O error accessing drive memory",13,10,"$"
38BADVERMES db 13,10,"RAMDrive: Incorrect DOS version",13,10,"$"
39
40;
41; This is the Ramdrive header message. THE MESSAGE IS DYNAMICALLY
42; PATCHED AT RUNTIME. The DOS drive letter of the RAMDRIVE
43; is patched in at DOS_DRV for DOS versions >= 3.00. For
44; DOS versions < 3.00 the three bytes 13,10,"$" are placed
45; at the label PATCH2X eliminating the drive specifier since
46; this information cannot be determined on 2.X DOS.
47; NO PART OF THIS MESSAGE WHICH MUST BE PRINTED ON ALL VERSIONS
48; OF DOS CAN BE PLACED AFTER THE LABEL PATCH2X. This may cause
49; translation problems for some languages, if this is so
50; the only solution is to eliminate the drive letter part of
51; the message totally for ALL DOS versions:
52;
53; HEADERMES db 13,10,"Microsoft RAMDrive version 1.17 "
54; PATCH2X db 13,10,"$"
55; DOS_DRV db "A"
56;
57;
58HEADERMES db 13,10,"Microsoft RAMDrive version 2.12 "
59PATCH2X db "virtual disk "
60DOS_DRV db "A"
61 db ":",13,10,"$"
62
63;
64; This is the status message used to display RAMDRIVE configuration
65; it is:
66;
67; STATMES1<size in K>STATMES2<Sector size in bytes>STATMES3
68; <sectors per alloc unit>STATMES4<Number of root dir entries>
69; STATMES5
70;
71; It is up to translator to move the message text around the numbers
72; so that the message is printed correctly when translated
73;
74STATMES1 db " Disk size: $"
75STATMES2 db "k",13,10," Sector size: $"
76STATMES3 db " bytes",13,10," Allocation unit: $"
77STATMES4 db " sectors",13,10," Directory entries: $"
78STATMES5 db 13,10,"$"
79
80
81RAMCODE ENDS
82 END
diff --git a/v4.0/src/DEV/RAMDRIVE/MI.INC b/v4.0/src/DEV/RAMDRIVE/MI.INC
new file mode 100644
index 0000000..9d8efed
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/MI.INC
@@ -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/RAMDRIVE/RAMDRIVE.ASM b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM
new file mode 100644
index 0000000..7874042
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.ASM
@@ -0,0 +1,6218 @@
1 TITLE EXTENDED MEMORY RAMDRIVE
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 or
8; use main memory on PC, XT, or AT
9;
10;
11; device = ramdrive.sys [bbbb] [ssss] [dddd] [/E | /A]
12;
13; bbbb First numeric argument, if present, is disk size
14; in K bytes. Default value is 64. Min is 16. Max
15; is 4096 (4 Meg).
16;
17; ssss Second numeric argument, if present, is sector size
18; in bytes. Default value is 512. Allowed values are
19; 128, 256, 512, 1024.
20; NOTE: In the case of IBM PC DOS the MAX value is 512.
21; If 1024 is specified the device will not be installed.
22; This "error" is detected by DOS and is not due to
23; the code in RAMDrive.
24; The 1024 byte size is included for those MS-DOS systems
25; where it might be allowed.
26;
27; dddd Third numeric argument, if present, is the number of
28; root directory entries. Default is 64. Min is 2
29; max is 1024. The value is rounded up to the nearest
30; sector size boundary.
31; NOTE: In the event that there is not enough memory
32; to create the RAMDrive volume, RAMDrive will try to make
33; a DOS volume with 16 directory entries. This may
34; result in a volume with a different number of directory
35; entries than the dddd parameter specifies.
36;
37; /E Specifies that PC AT Extended Memory is to be used.
38; It is an error if /E is specified on a machine other
39; than an IBM PC AT.
40; NOTE: Information on RAMDrive drives in PC AT extended memory
41; will be lost at system re-boot (warm or cold). This is
42; due to the fact that the IBM PC AT ROM bootstrap code
43; zeroes all of memory.
44; NOTE: There is 1k of RAMDrive overhead. That is to say,
45; if there are 512k bytes of extended memory, there
46; will be 511k bytes available for assignment to RAMDrive
47; drives. This 1k overhead is fixed and does not depend
48; on the number of RAMDrive drives installed.
49;
50; /A Specifies that Above Board memory is to be used. It
51; is an error if the above board device driver is not
52; present.
53; NOTE: Information on RAMDrive drives in Above Board memory
54; will be lost at system re-boot (warm or cold). This is
55; due to the fact that the EMM device driver performs a
56; destructive test when it is installed which zeros all
57; of the Above Board memory.
58;
59; Neither /A or /E Specifies drive is to be set up below the
60; 640K boundary in main memory.
61; The RAMDRIVE.SYS program looks for memory to assign to the RAMDrive
62; drives by looking for functioning system RAM between the
63; "end of memory" as determined by the INT 12H ROM BIOS
64; function, and the start of the video RAM (0A000:0H).
65; If RAM is found by the above scan, it is assigned to
66; RAMDrive and managed in the same way as extended memory
67; is when the /E switch is used. As with /E there is
68; 1k of RAMDrive overhead. That is to say, if there are 256k
69; bytes of memory above the INT 12 memory size, there
70; will be 255k bytes available for assignment to RAMDrive
71; drives. This 1k overhead is fixed and does not depend
72; on the number of RAMDrive drives installed.
73; Information on such RAMDrive drives will NOT be lost on
74; a "warm boot" (INT 19H or Ctrl-Alt-DEL).
75; If RAM is NOT found by the above scan, RAMDrive will attempt
76; to allocate memory for the device AS PART OF THE DEVICE.
77; In other words the device starts immediately after the
78; RAMDrive resident code.
79; Information on such RAMDrive drives WILL BE lost on
80; a "warm boot" (INT 19H or Ctrl-Alt-DEL).
81;
82;
83;
84; MODIFICATION HISTORY
85;
86; 1.00 5/30/85 ARR Initial version.
87;
88; 1.01 6/03/85 ARR Added CSIZE home code in INIDRV. Does a better
89; job of computing good CSIZE value.
90;
91; 1.10 6/05/85 ARR Changed name of program from VDISK to RAMDRIVE
92;
93; 1.11 6/06/85 ARR Changed BAD_AT message
94;
95; 1.12 6/06/85 ARR Fixed bug in /A BLKMOV code. Was forgetting
96; to save and restore page mapping context
97;
98; 1.13 6/14/85 ARR Was using 32 bit shifts to do div/mul by
99; powers of two. As it turns out, using the
100; DIV or MUL instruction is faster. This is
101; so even for small numbers like 16. This is
102; due to the fact that the LOOP involved in
103; doing a 32 bit shift is expensive.
104;
105; 1.14 6/14/85 ARR dddd param minimum changed from 4 to 2
106; to be IBM compatible. Code added to round
107; up to sector size boundaries.
108;
109; 1.15 6/24/85 ARR Assorted clean up, mostly in Above Board
110; code.
111;
112; 1.16 7/09/85 ARR Align code more closely to the G.L.
113; coding standard.
114;
115; Changed ITOA routine. Smaller and will print any
116; 16 bit value.
117;
118; DISK_ABORT would run through EMM_CTRL reset code
119; on a RESMEM_SPECIAL driver. Added code
120; to skip if this type of driver.
121;
122; Added check in CHECK_DOS_VOL in event valid BPB
123; is found to make sure SSIZE and DIRNUM values
124; match. If you edit DEVICE = to change these
125; values on an existing drive and re-boot
126; RAMDrive would ignore you and suck up old
127; values.
128;
129; 11/12/85 ARR DEBUG EQU added and some RESMEM debug code
130; stuck in to discover that the HP Vectra is
131; not as AT compatible as HP thinks.
132;
133; 02/11/86 ARR Message area identified by "TRANSLATION"
134; and translation notes added to several
135; messages
136;
137; 04/03/86 ARR Changed use of SIDT to set GDT descriptor
138; in /E init code to SGDT. Previous masm wouldn't
139; assemble SGDT, new one works OK.
140;
141; 1.17 5/26/86 ARR New version for "above" insignificgant changes. And
142; fixed major oops in /e RESET_SYSTEM code which would
143; hang the system if an interrupt occured at the wrong
144; time.
145;
146; 1.19 3/4/87 SP Fixed CSIZ homing oscillation bug. Shifted Ramdriv
147; configuration display code before relocation code
148; to facilitate creation of message module. Shifted
149; translatable messages to message module.
150;
151; 2.00 8/23/87 sp 386 support ( both prot mode transfer and int15 )
152; 286 loadall kludge
153; new int15 allocation
154; new above_blkmov routine (to handle overlapping
155; transfers in above board memory
156; olivetti support
157; removed int 9 trapping
158; reset code different for extended memory
159;
160; 2.01 9/28/87 sp Fixed bug in parsing for /u option
161;
162; 2.02 3/02/88 sp Extended PS2 model 80 recognition to more than
163; one sub-model
164; 2.03 5/13/88 SP extended version check to include dos 4.00
165;
166; 2.04 5/23/88 SP reworked messages to mention expanded memory
167;
168; 2.10 6/13/88 CHIPA Merged in HP Vectra stuff
169; 11/20/87 RCP Fixed a20 enabling/disabling problems on
170; Vectra machines.
171;
172; 2.12 7/26/88 SP Ramdrives installed between int12 and A000 are
173; no longer attempted.
174
175BREAK MACRO subtitle
176 SUBTTL subtitle
177 PAGE
178ENDM
179
180.286p ; Use some 286 instructions in /E code
181
182DEBUG EQU 0
183
184IF1
185 IF DEBUG
186 %out DEBUG VERSION!!!!!!
187 ENDIF
188ENDIF
189
190.xlist
191 include devsym.inc
192 include syscall.inc
193 include dirent.inc
194 include mi.inc
195.list
196
197; The RAMDrive device driver has 4 basic configurations.
198;
199; TYPE 1 - /E configuration using PC-AT extended memory and the LOADALL
200; instruction.
201;
202; TYPE 2 - /A configuration using Above Board memory and EMM device
203; driver.
204;
205; TYPE 3 - Neither /A or /E (RESMEM) configuration using main memory
206; and normal 8086 addressing, RAMDrive memory is located
207; somewhere AFTER the "end of memory" as indicated by the
208; INT 12H memory size.
209;
210; TYPE 4 - RESMEM configuration as TYPE 3 EXCEPT that the RAMDrive
211; memory is part of the RAMDrive device driver.
212;
213; The TYPE 2 driver uses the Above Board EMM device driver via INT 67H
214; to control access to, and to access the available memory.
215;
216; The TYPE 4 driver needs no external help to control access to the available
217; memory since the RAMDrive memory is part of the device driver and
218; immediately follows the RAMDrive code in memory.
219;
220; The TYPE 1 and TYPE 3 configurations use the EMM control sector to
221; control access to the available memory
222
223 include emm.inc
224
225 include loadall.inc
226
227 include above.inc
228
229 include ab_macro.inc
230
231BREAK <I/O Packet offset declarations>
232
233;
234; Define I/O packet offsets for useful values.
235;
236; SEE ALSO
237; MS-DOS Technical Reference manual section on Installable Device Drivers
238;
239; MACHINE ID EQUATES
240S_OLIVETTI EQU 01H ; Olivetti 6300 PLUS machine
241S_VECTRA EQU 02H ; Vectra PC machine
242
243; READ/WRITE PACKET OFFSETS
244RW_COUNT EQU WORD PTR (SIZE SRHEAD) + 5
245RW_TRANS EQU DWORD PTR (SIZE SRHEAD) + 1
246RW_START EQU WORD PTR (SIZE SRHEAD) + 7
247
248; MEDIA CHECK PACKET OFFSETS
249MCH_RETVAL EQU BYTE PTR (SIZE SRHEAD) + 1
250MCH_MEDIA EQU BYTE PTR (SIZE SRHEAD) + 0
251
252; BUILD BPB PACKET OFFSETS
253BPB_BUFFER EQU DWORD PTR (SIZE SRHEAD) + 1
254BPB_MEDIA EQU BYTE PTR (SIZE SRHEAD) + 0
255BPB_BPB EQU DWORD PTR (SIZE SRHEAD) + 5
256
257; INIT PACKET OFFSETS
258INIT_NUM EQU BYTE PTR (SIZE SRHEAD) + 0
259INIT_BREAK EQU DWORD PTR (SIZE SRHEAD) + 1
260INIT_BPB EQU DWORD PTR (SIZE SRHEAD) + 5
261INIT_DOSDEV EQU BYTE PTR (SIZE SRHEAD) + 9
262
263BREAK <some segment definitions>
264
265;; In order to address memory above 1 MB on the AT&T 6300 PLUS, it is
266;; necessary to use the special OS-MERGE hardware to activate lines
267;; A20 to A23. However, these lines can be disabled only by resetting
268;; the processor. The return address offset and segment can be found
269;; at 40:a2, noted here as RealLoc1.
270;;
271BiosSeg segment at 40h ;; Used to locate 6300 PLUS reset address
272 org 00a2h
273RealLoc1 dd 0
274BiosSeg ends
275;
276R_Mode_IDT segment at 0h
277R_mode_IDT ends
278;
279
280BREAK <Device header>
281
282RAMCODE SEGMENT
283ASSUME CS:RAMCODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
284
285;**
286;
287; RAMDRIVE DEVICE HEADER
288;
289; COMMON TO TYPE 1, 2, 3, 4 drivers
290;
291; SEE ALSO
292; MS-DOS Technical Reference manual section on
293; Installable Device Drivers
294;
295
296RAMDEV LABEL WORD
297 DW -1,-1
298DEVATS DW DEVOPCL
299 DW STRATEGY
300 DW RAM$IN
301 DB 1 ;1 RAMDRIVE
302
303
304BREAK <Command dispatch table>
305
306;**
307;
308; This is the device driver command dispatch table.
309;
310; The first byte indicates the size of the table and therefore defines
311; which device function codes are valid.
312;
313; The entries in the table are NEAR word addresses of the appropriate
314; device routine. Thus the address of the routine to handle device function
315; 3 is:
316; WORD at ((RAMTBL + 1) + (2 * 3))
317;
318; COMMON TO TYPE 1, 2, 3, 4 drivers
319;
320;
321
322RAMTBL LABEL WORD
323 DB 15 ; Max allowed command code
324 DW RAM$INIT
325 DW MEDIA$CHK
326 DW GET$BPB
327 DW CMDERR
328 DW RAM$READ
329 DW DEVEXIT
330 DW DEVEXIT
331 DW DEVEXIT
332 DW RAM$WRIT
333 DW RAM$WRIT
334 DW DEVEXIT
335 DW DEVEXIT
336 DW DEVEXIT
337 DW DEVEXIT
338 DW DEVEXIT
339 DW RAM$REM
340
341
342BREAK <BPB and boot sector for installed device>
343
344;** RAMDRIVE BIOS PARAMETER BLOCK AND BOGUS BOOT SECTOR
345;
346; This region is a valid DOS 2.X 3.X "boot sector" which contains
347; the BPB. This is used for signiture verification of a valid
348; RAMDrive as well as for storage of the relevant BPB parameters.
349;
350; The BOOT_START code is a very simple stub which does nothing
351; except go into an infinite loop. THIS "CODE" SHOULD NEVER
352; BE EXECUTED BY ANYONE.
353;
354; COMMON TO TYPE 1, 2, 3, 4 drivers
355;
356;
357
358BOOT_SECTOR LABEL BYTE
359 JMP BOOT_START
360 DB "RDV 1.20"
361
362RDRIVEBPB:
363SSIZE DW 512 ; Physical sector size in bytes
364CSIZE DB 0 ; Sectors/allocation unit
365RESSEC DW 1 ; Reserved sectors for DOS
366FATNUM DB 1 ; No. allocation tables
367DIRNUM DW 64 ; Number directory entries
368SECLIM DW 0 ; Number sectors
369 DB 0F8H ; Media descriptor
370FATSEC DW 1 ; Number of FAT sectors
371 DW 1 ; Number of sectors per track
372 DW 1 ; Number of heads
373 DW 0 ; Number of hidden sectors
374
375SEC_SHFT DB 8 ; Shifting number of
376 ; sectors LEFT by this
377 ; many bits yields #words
378 ; in that many sectors.
379 ; 128 6
380 ; 256 7
381 ; 512 8
382 ; 1024 9
383
384BOOT_START:
385 JMP BOOT_START
386
387BOOT_SIG LABEL BYTE
388 DB (128 - (OFFSET BOOT_SIG - OFFSET BOOT_SECTOR)) DUP ("A")
389
390;
391; The following label is used to determine the size of the boot record
392; OFFSET BOOT_END - OFFSET BOOT_SECTOR
393;
394BOOT_END LABEL BYTE
395
396BREAK <Common Device code>
397
398; RAMDRIVE DEVICE ENTRY POINTS - STRATEGY, RAM$IN
399;
400; This code is standard DOS device driver function dispatch
401; code. STRATEGY is the device driver strategy routine, RAM$IN
402; is the driver interrupt routine.
403;
404; RAM$IN uses RAMTBL to dispatch to the appropriate handler
405; for each device function. It also does standard packet
406; unpacking.
407;
408; SEE ALSO
409; MS-DOS Technical Reference manual section on
410; Installable Device Drivers
411;
412
413ASSUME CS:RAMCODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
414
415PTRSAV DD 0 ; Storage location for packet addr
416
417;** STRATEGY - Device strategy routine
418;
419; Standard DOS 2.X 3.X device driver strategy routine. All it does
420; is save the packet address in PTRSAV.
421;
422; ENTRY ES:BX -> Device packet
423; EXIT NONE
424; USES NONE
425;
426; COMMON TO TYPE 1, 2, 3, 4 drivers
427;
428;
429
430STRATP PROC FAR
431
432STRATEGY:
433 MOV WORD PTR [PTRSAV],BX ; Save packet addr
434 MOV WORD PTR [PTRSAV+2],ES
435 RET
436
437STRATP ENDP
438
439;** RAM$IN - Device interrupt routine
440;
441; Standard DOS 2.X 3.X device driver interrupt routine.
442;
443;
444; ENTRY PTRSAV has packet address saved by previous STRATEGY call.
445; EXIT Dispatch to appropriate function handler
446; CX = Packet RW_COUNT
447; DX = Packet RW_START
448; ES:DI = Packet RW_TRANS
449; DS = RAMCODE
450; STACK has saved values of all regs but FLAGS
451; All function handlers must return through one of
452; the standard exit points
453; USES FLAGS
454;
455; COMMON TO TYPE 1, 2, 3, 4 drivers
456;
457;
458
459RAM$IN:
460 PUSH SI
461 PUSH AX
462 PUSH CX
463 PUSH DX
464 PUSH DI
465 PUSH BP
466 PUSH DS
467 PUSH ES
468 PUSH BX
469
470 LDS BX,[PTRSAV] ;GET POINTER TO I/O PACKET
471 ;
472 ; Set up registers for READ or WRITE since this is the most common case
473 ;
474 MOV CX,DS:[BX.RW_COUNT] ;CX = COUNT
475 MOV DX,DS:[BX.RW_START] ;DX = START SECTOR
476 MOV AL,DS:[BX.REQFUNC] ; Command code
477 MOV AH,BYTE PTR [RAMTBL] ; Valid range
478 CMP AL,AH
479 JA CMDERR ; Out of range command code
480 MOV SI,OFFSET RAMTBL + 1 ; Table of routines
481 CBW ; Make command code a word
482 ADD SI,AX ; Add it twice since one word in
483 ADD SI,AX ; table per command.
484
485 LES DI,DS:[BX.RW_TRANS] ; ES:DI transfer address
486
487 PUSH CS
488 POP DS
489
490ASSUME DS:RAMCODE
491
492 JMP WORD PTR [SI] ; GO DO COMMAND
493
494;** EXIT - ALL ROUTINES RETURN THROUGH ONE OF THESE PATHS
495;
496; Exit code entry points:
497;
498; SEE ALSO
499; MS-DOS Technical Reference manual section on
500; Installable Device Drivers
501;
502; GENERAL ENTRY for all entry points
503; All packet values appropriate to the specific device function
504; filled in except for the status word in the static request
505; header.
506;
507; CMDERR - Used when an invalid device command is detected
508;
509; ENTRY Stack has frame set up by RAM$IN
510; EXIT Standard Device driver with error 3
511; USES FLAGS
512;
513; ERR$CNT - Used when READ or WRITE wants to return with error code.
514; The packet RW_COUNT field is zeroed
515;
516; ENTRY AL is error code for low byte of packet status word
517; Stack has frame set up by RAM$IN
518; EXIT Standard Device driver with error AL
519; USES FLAGS
520;
521; ERR$EXIT - Used when a function other that READ or WRITE wants to
522; return an error
523;
524; ENTRY AL is error code for low byte of packet status word
525; Stack has frame set up by RAM$IN
526; EXIT Standard Device driver with error AL
527; USES FLAGS
528;
529; DEVEXIT - Used when a function wants to return with no error
530;
531; ENTRY AL is value for low byte of packet status word
532; NOTE: Typically there is no meaningful value
533; in the AL register when EXITing through here.
534; This is OK as the low 8 bits of the status word
535; have no meaning unless an error occured.
536; Stack has frame set up by RAM$IN
537; EXIT Standard Device driver with no error
538; USES FLAGS
539;
540; ERR1 - Used when a function wants to return with a value
541; for the whole status word
542;
543; ENTRY AX is value for packet status word
544; Stack has frame set up by RAM$IN
545; EXIT Standard Device driver with or without error
546; USES FLAGS
547;
548; COMMON TO TYPE 1, 2, 3, 4 drivers
549;
550;
551
552ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
553
554CMDERR:
555 MOV AL,3 ;UNKNOWN COMMAND ERROR
556 JMP SHORT ERR$EXIT
557
558ERR$CNT:
559 LDS BX,[PTRSAV]
560 MOV [BX.RW_COUNT],0 ; NO sectors transferred
561ERR$EXIT: ; Error in AL
562 MOV AH,(STERR + STDON) SHR 8 ;MARK ERROR RETURN
563 JMP SHORT ERR1
564
565EXITP PROC FAR
566
567DEVEXIT:
568 MOV AH,STDON SHR 8
569ERR1:
570 LDS BX,[PTRSAV]
571 MOV [BX.REQSTAT],AX ; Set return status
572
573 POP BX
574 POP ES
575 POP DS
576 POP BP
577 POP DI
578 POP DX
579 POP CX
580 POP AX
581 POP SI
582 RET ;RESTORE REGS AND RETURN
583EXITP ENDP
584
585
586;** MEDIA$CHK - Device Driver Media check routine
587;
588; RAMDRIVE Media check routine. ALWAYS returns media not changed
589;
590; SEE ALSO
591; MS-DOS Technical Reference manual section on
592; Installable Device Drivers
593;
594; ENTRY from RAM$IN
595; EXIT through DEVEXIT
596; USES DS,BX
597;
598; COMMON TO TYPE 1, 2, 3, 4 drivers
599;
600
601MEDIA$CHK:
602ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
603 LDS BX,[PTRSAV]
604ASSUME DS:NOTHING
605 MOV [BX.MCH_RETVAL],1 ; ALWAYS NOT CHANGED
606 JMP DEVEXIT
607
608;** GET$BPB - Device Driver Build BPB routine
609;
610; RAMDRIVE Build BPB routine. Returns pointer to BPB at RDRIVEBPB
611;
612; SEE ALSO
613; MS-DOS Technical Reference manual section on
614; Installable Device Drivers
615;
616; ENTRY from RAM$IN
617; EXIT through DEVEXIT
618; USES DS,BX
619;
620; COMMON TO TYPE 1, 2, 3, 4 drivers
621;
622
623GET$BPB:
624ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
625 LDS BX,[PTRSAV]
626ASSUME DS:NOTHING
627 MOV WORD PTR [BX.BPB_BPB],OFFSET RDRIVEBPB
628 MOV WORD PTR [BX.BPB_BPB + 2],CS
629 JMP DEVEXIT
630
631;** RAM$REM - Device Driver Removable Media routine
632;
633; RAMDRIVE Removable Media routine. ALWAYS returns media not removable
634; NOTE: This routine is never called if running on DOS 2.X
635;
636; SEE ALSO
637; MS-DOS Technical Reference manual section on
638; Installable Device Drivers
639;
640; ENTRY from RAM$IN
641; EXIT through ERR1
642; USES AX
643;
644; COMMON TO TYPE 1, 2, 3, 4 drivers
645;
646
647RAM$REM:
648ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
649 MOV AX,STBUI + STDON ; Media NOT removable
650 JMP ERR1
651
652;** RAM$READ - Device Driver READ routine
653;
654; RAMDRIVE READ routine. Perform device READ by calling MEMIO
655;
656; SEE ALSO
657; MS-DOS Technical Reference manual section on
658; Installable Device Drivers
659;
660; DO_OP entry point used by RAM$WRITE
661;
662; ENTRY from RAM$IN
663; ES:DI is transfer address
664; CX is sector transfer count
665; DX is start sector number
666; EXIT through DEVEXIT or ERR$CNT
667; USES ALL
668;
669; COMMON TO TYPE 1, 2, 3, 4 drivers
670;
671
672RAM$READ:
673ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
674 XOR BH,BH
675DO_OP:
676 CALL MEMIO
677 JC T_ERR
678 JMP DEVEXIT
679
680T_ERR: ; AL has error number
681 JMP ERR$CNT
682
683;** RAM$WRITE - Device Driver WRITE routine
684;
685; RAMDRIVE WRITE routine. Perform device WRITE by calling MEMIO
686;
687; SEE ALSO
688; MS-DOS Technical Reference manual section on
689; Installable Device Drivers
690;
691; ENTRY from RAM$IN
692; ES:DI is transfer address
693; CX is sector transfer count
694; DX is start sector number
695; EXIT Jump to DO_OP to call MEMIO with BH = 1 (WRITE)
696; USES BH
697;
698; COMMON TO TYPE 1, 2, 3, 4 drivers
699;
700
701RAM$WRIT:
702ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
703 MOV BH,1
704 JMP DO_OP
705
706;** MEMIO - Perform READ or WRITE to RAMDrive
707;
708; This routine performs common pre-amble code for the BLKMOV
709; routine which is the one which does the real work. It checks
710; the I/O parameters for validity and sets up the inputs to
711; BLKMOV. What it does is convert the sector count in CX to
712; the number of words in that many sectors or 8000H which ever
713; is less. It also converts the start sector number in DX into
714; a 32 bit byte offset equal to that many sectors.
715;
716; NOTE that we convert the number of sectors to transfer
717; to a number of words to transfer.
718; Sector size is always a power of two, therefore a multiple
719; of two so there are no "half word" problems.
720; DOS NEVER asks for a transfer larger than 64K bytes except
721; in one case where we can ignore the extra anyway.
722;
723; ENTRY:
724; ES:DI is packet transfer address.
725; CX is number of sectors to transfer.
726; DX is starting sector number
727; BH is 1 for WRITE, 0 for READ
728; EXIT:
729; If error detected
730; Carry Set
731; Error on operation, AL is error number
732; else
733; through BLKMOV
734; ES:DI is packet transfer address.
735; CX is number of words to transfer.
736; DX:AX is 32 bit start byte offset (0 = sector 0 of RAMDrive drive)
737; BH is 1 for WRITE, 0 for READ
738; USES:
739; AX, DX, CX, FLAGS
740;
741; COMMON TO TYPE 1, 2, 3, 4 drivers
742;
743
744SEC_NOT_FOUND:
745 MOV AL,8 ; Sector not found error
746 STC
747 RET
748
749MEMIO:
750ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
751 CMP DX,[SECLIM] ; Check for valid I/O
752 JAE SEC_NOT_FOUND ; Start is beyond end
753 MOV AX,DX
754 ADD AX,CX
755 CMP AX,[SECLIM]
756 JA SEC_NOT_FOUND ; End is beyond end
757 ;
758 ; Convert sector count to word count
759 ;
760 MOV AX,CX
761 MOV CL,[SEC_SHFT]
762 SHL AX,CL ; AX is # words to move
763 JNC CNT_SET ; Overflow???
764 MOV AX,8000H ; Limit to 64K bytes
765CNT_SET:
766 MOV CX,AX
767 ;
768 ; Now compute start offset of I/O
769 ;
770 MOV AX,DX
771 MUL [SSIZE] ; DX:AX is byte offset of start
772 JMP BLKMOV ; Perform I/O
773
774BREAK <Work Area for Ramdrive>
775
776S5_FLAG DB 0 ;; S_OLIVETTI means 6300 PLUS machine
777 ;; S_VECTRA means Vectra machine
778
779A20On dw 0DF90h
780A20Off dw 0DD00h
781
782;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
783; Unfortunately the code in ramdrive is very machine dependent
784; necessitating the use of a system flag to store the machine
785; configuration. The system flag is initialised during init time
786; and used when the caching services are requested. One bit which
787; is set and tested during caching is the state of the a20 line
788; when the cache code is entered. This is used because there are
789; applications which enable the a20 line and leave it enabled
790; throughout the duration of execution. Since ramdrive is a device
791; driver it shouldn't change the state of the environment.
792;
793; The system flag bit assignments are:
794;
795; -------------------------------------------------
796; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
797; -------------------------------------------------
798; |-----| | | | | | |
799; | | | | | | -----286 (and AT)
800; | | | | | -----------386 (later than B0)
801; not | | | -----------------PS/2 machine
802; used | | -----------------------Olivetti (not used)
803; | -----------------------------A20 state (enabled ?)
804; -----------------------------------DOS 3.x >= 3.3
805
806; The Olivetti guys have defined a flag of their own. This should be removed
807; and the bit assigned out here for them should be used.
808;
809sys_flg db ?
810;
811; equates used for the system flag
812;
813M_286 equ 00000001B
814M_386 equ 00000010B
815M_PS2 equ 00000100B
816M_OLI equ 00001000B
817A20_ST equ 00010000B
818DOS_33 equ 00100000B
819;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
820; A20 address line state determination addresses
821;
822low_mem label dword
823 dw 20h*4
824 dw 0
825
826high_mem label dword
827 dw 20h*4 + 10h
828 dw 0ffffh
829
830;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
831; A20 PS2 equates
832;
833PS2_PORTA equ 0092h
834GATE_A20 equ 010b
835
836;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
837; 386 working areas
838start_gdt label byte
839nul_des desc <>
840cs_des desc <0FFFFh,0,0,09Fh,0,0>
841ss_des desc <0FFFFh,0,0,093h,0,0>
842ds_des desc <0FFFFh,0,0,093h,0,0>
843es_des desc <0FFFFh,0,0,093h,0,0>
844end_gdt label byte
845
846emm_gdt gdt_descriptor <end_gdt-start_gdt,0,0>
847;
848; int 15 gdt
849;
850int15_gdt label byte
851 desc <> ;dummy descriptor
852 desc <> ;descriptor for gdt itself
853src desc <0ffffh,,,93h,,>
854tgt desc <0ffffh,,,93h,,>
855 desc <> ;bios cs descriptor
856 desc <> ;stack segment descriptor
857
858;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
859
860BREAK <Drive code for /E driver>
861
862;
863; The following label defines the start of the I/O code which is driver type
864; specific.
865;
866; THE TYPE 2 driver must REPLACE this code with code appropriate
867; to the driver type.
868;
869 EVEN ; Force start of drive code to word boundary
870
871DRIVE_CODE LABEL WORD
872
873EXTMEM_LOW EQU 0000H ; 24 bit addr of start of extended memory
874EXTMEM_HIGH EQU 0010H
875
876;** BASE_ADDR data element
877;
878; The next value defines the 24 bit address of the start of the memory for
879; the cache. It is equal to the EMM_BASE value in the
880; EMM_REC structure for the cache.
881;
882; NOTE THAT IT IS INITIALIZED TO THE START OF EXTENDED MEMORY. This is
883; because BLKMOV is used to read the EMM_CTRL sector during initialization
884; of a TYPE 1 driver.
885;
886; NOTE: This data element is shared by TYPE 1, 2 drivers, but
887; its meaning and correct initial value are driver type specific.
888;
889
890;; NOTE: The value at BASE_ADDR is patched during initialization when
891;; loading a RAMDrive into upper extended memory on a PLUS
892;;
893BASE_ADDR LABEL DWORD ; 24 bit address of start of this RAMDRV
894 DW EXTMEM_LOW
895 DW EXTMEM_HIGH
896;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
897;** BLKMOV - Perform transfer for TYPE 1 driver
898;
899; This routine is the transfer routine for moving bytes
900; to and from the AT extended memory in real mode using
901; the LOADALL instruction. The LOADALL instruction is used
902; to set up a segment descriptor which has a 24 bit address.
903; During the time the LOADALL 24 bit segment descriptor is
904; in effect we must have interrupts disabled. If a real mode
905; 8086 interrupt handler was given control it might perform
906; a segment register operation which would destroy the special
907; segment descriptor set up by LOADALL. This is prevented by
908; doing a CLI during the "LOADALL time".
909;
910; WARNING NUMBER ONE:
911; THIS CODE WILL NOT WORK ON ANY 80286 MACHINE WHERE THE NMI
912; INTERRUPT IS ANYTHING BUT A FATAL, SYSTEM HALTING ERROR.
913;
914; Since it is bad to leave interrupts disabled for a long
915; time, the I/O is performed 256 words at a time enabling
916; interrupts between each 256 word piece. This keeps the time
917; interrupts are disabled down to a reasonable figure in the 100mSec
918; range.
919;
920; To use the LOADALL instruction 102 bytes at location 80:0 must
921; be used. INT13 copies the contents of 80:0 into its own buffer,
922; copies in the LOADALL info, performs the LOADALL, and then copies
923; back the previous contents of 80:0. These operations are all
924; performed during the time interrupts are disabled for each 256 word
925; block. This must be done with interrupts disabled because this area
926; on DOS 2.X and 3.X contains variable BIOS data.
927;
928; In order to gain full 24 bit addressing it is also required
929; that address line 20 be enabled. This effects 8086 compatibility
930; on 80286 systems. This code leaves address line 20 enabled
931; for the ENTIRE duration of the I/O because it is too time
932; expensive to disable/enable it for each 256 word block.
933;
934; WARNING NUMBER TWO:
935; IF A MULTITASKING PRE-EMPTIVE SYSTEM SCHEDULES AND RUNS
936; AN APPLICATION WHICH RELIES ON THE 1 MEG ADDRESS WRAP
937; PROPERTY OF THE 8086 AND 8088 DURING THE TIME INT13
938; IS IN THE MIDDLE OF DOING AN I/O WITH ADDRESS LINE 20 ENABLED,
939; THE APPLICATION WILL NOT RUN PROPERLY AND MAY DESTRUCT THE
940; INT13 MEMORY.
941;
942; METHOD:
943; Perform various LOADALL setup operations
944; Enable address line 20
945; While there is I/O to perform
946; Do "per 256 word block" LOADALL setup operations
947; Set up copy of 80:0 to INT13 buffer
948; CLI
949; copy 80:0 to INT13 buffer
950; copy LOADALL info to 80:0
951; LOADALL
952; do 256 word transfer
953; copy INT13 80:0 buffer back to 80:0
954; STI
955; Disable address line 20
956;
957; SEE ALSO
958; INTEL special documentation of LOADALL instruction
959;
960; ENTRY:
961; ES:DI is packet transfer address.
962; CX is number of words to transfer.
963; DX:AX is 32 bit start byte offset (0 = start of cache)
964; BH is 1 for WRITE, 0 for READ
965;
966; BASE_ADDR set to point to start of cache memory
967; This "input" is not the responsibility of the caller. It
968; is up to the initialization code to set it up when the
969; device is installed
970;
971; EXIT:
972; Carry Clear
973; OK, operation performed successfully
974; Carry Set
975; Error during operation, AL is error number (INT 13 error)
976;
977; USES:
978; ALL
979;
980; This routine is specific to TYPE 1 driver
981;
982; sunilp - incorporated blkmov_386 (thanks to gregh)
983; incorporated loadall_286 trick (thanks to scottra)
984; added new a20 functionality
985; ideally the code should be all relocatable abd the 386
986; blkmov should be relocated on the 286 blkmov for the
987; 386 case. Also the A20 routines for the Olivetti or PS/2
988; should also ideally be relocated on top of the normal A20
989
990BLKMOV:
991ASSUME DS:ramcode,ES:NOTHING,SS:NOTHING
992 test [sys_flg],M_386
993 je blkmov_286
994 jmp blkmov_386
995 ;
996 ; Compute 32 bit address of start of I/O
997 ;
998blkmov_286:
999 ADD AX,WORD PTR [BASE_ADDR]
1000 ADC DX,WORD PTR [BASE_ADDR + 2]
1001 ;
1002 ; Dispatch on function
1003 ;
1004 OR BH,BH
1005 JZ READ_IT
1006 ;
1007 ; Write
1008 ;
1009 MOV WORD PTR [ESDES.SEG_BASE],AX
1010 MOV BYTE PTR [ESDES.SEG_BASE + 2],DL
1011; MOV [LSI],DI
1012 mov [lbx],di ;sp
1013 MOV [LDI],0
1014 MOV SI,OFFSET DSDES
1015 JMP SHORT SET_TRANS
1016
1017READ_IT:
1018 MOV WORD PTR [DSDES.SEG_BASE],AX
1019 MOV BYTE PTR [DSDES.SEG_BASE + 2],DL
1020 MOV [LDI],DI
1021; MOV [LSI],0 ;sp
1022 mov [lbx],0
1023 MOV SI,OFFSET ESDES
1024SET_TRANS:
1025 MOV AX,ES
1026 CALL SEG_SET ; Set ES or DS segreg
1027 ;
1028 ; Set stack descriptor
1029 ;
1030 MOV AX,SS
1031 MOV [LSSS],AX
1032 MOV SI,OFFSET SSDES
1033 CALL SEG_SET
1034 MOV [LSP],SP
1035; SUB [LSP],2 ; CX is on stack at LOADALL
1036;
1037; the loadall kludge
1038;
1039 mov ax,cs ;sp
1040 inc ax ;sp
1041 mov [lcss],ax ;sp
1042 mov si,offset CSDES ;sp
1043 mov ax,cs ;sp
1044 call seg_set ;sp
1045 ;
1046 ; Set Other LOADALL stuff
1047 ;
1048 SMSW [LDSW]
1049 SIDT FWORD PTR [IDTDES]
1050 SGDT FWORD PTR [GDTDES]
1051 ;
1052 ; NOW The damn SXXX instructions store the desriptors in a
1053 ; different order than LOADALL wants
1054 ;
1055 MOV SI,OFFSET IDTDES
1056 CALL FIX_DESCRIPTOR
1057 MOV SI,OFFSET GDTDES
1058 CALL FIX_DESCRIPTOR
1059 ;
1060 ; Enable address line 20
1061 ;
1062
1063;;
1064;; Enable address line 20 on the PC AT or activate A20-A23 on the 6300 PLUS.
1065;; The former can be done by placing 0dfh in AH and activating the keyboard
1066;; processor. On the PLUS, 90h goes in AL and the port at 03f20h is written.
1067;; So the combined value of 0df90h can be used for both machines with
1068;; appropriate coding of the called routine A20.
1069;;
1070
1071;; MOV AH,0DFH
1072 mov ax,cs:[A20On] ;; set up for PLUS or AT
1073 CALL A20
1074 Jc NR_ERR
1075; JMP SHORT IO_START ;sp
1076 jmp short move_main_loop ;sp
1077
1078NR_ERR:
1079 MOV AL,02 ; Drive not ready error
1080 STC
1081 RET
1082io_donej: jmp io_done
1083;IOLOOP: ;sp
1084; PUSH CX ;sp
1085
1086move_main_loop: ;sp
1087assume ds:nothing ;sp
1088 jcxz io_donej ;sp
1089 mov cs:[ldx],cx ;sp
1090 MOV AX,80H
1091 MOV DS,AX
1092 PUSH CS
1093 POP ES
1094 XOR SI,SI
1095 MOV DI,OFFSET cs:[SWAP_80]
1096 MOV CX,102/2
1097 mov cs:[ssSave],ss
1098 CLD
1099 CLI ; Un interruptable
1100 test [sys_flg],dos_33 ; is it dos 3.3 or above
1101 jne mml$1 ; if so we don't need to store contents
1102 ; of 80:0
1103 REP MOVSW ; Save contents of 80:0
1104mml$1:
1105 PUSH DS
1106 PUSH ES
1107 POP DS
1108 POP ES
1109 XOR DI,DI
1110 MOV SI,OFFSET cs:LOADALL_TBL
1111 MOV CX,102/2
1112 REP MOVSW ; Transfer in LOADALL info
1113 DW 050FH ; LOADALL INSTRUCTION
1114AFTER_LOADALL:
1115; set up stack for moving 80:0 information back again
1116;
1117 xor bp,bp
1118 mov ss,ax
1119 mov si,offset cs:[swap_80]
1120 mov cx,102/2
1121 test [sys_flg],dos_33
1122 jne mml$2
1123move_loop:
1124 lods word ptr cs:[si]
1125 mov ss:[bp],ax
1126 inc bp
1127 inc bp
1128 loop move_loop
1129mml$2:
1130 mov ss,cs:[ssSave]
1131 mov cx,dx
1132 mov si,bx
1133;critical code
1134 sti
1135 rep movsw
1136 cli ; bugfix sunilp
1137 mov ax,cs
1138 dec ax
1139 push ax
1140 mov ax,offset io_done
1141 push ax
1142 db 0cbh
1143;
1144 db 16 dup (0fah) ; bugfix sunilp
1145 mov ax,cs
1146 dec ax
1147 push ax
1148 mov ax,offset resume_int
1149 push ax
1150 db 0cbh
1151;
1152resume_int:
1153 mov cs:[ldi],di
1154 mov cs:[lbx],si
1155 jmp move_main_loop
1156
1157; REP MOVSW ; Move data
1158;IO_START:
1159; JCXZ IODN
1160; MOV WORD PTR [LCX],256 ; ASSUME full block
1161; SUB CX,256
1162; JNC IOLOOP ; OK
1163; ADD [LCX],CX ; OOPs, partial block
1164; XOR CX,CX ; This is the last block
1165; JMP IOLOOP
1166
1167;IODN:
1168io_done:
1169 sti ; bugfix sunilp
1170 MOV CX,800H ; Retry this many times
1171OFFLP:
1172
1173;;
1174;; Reset of line A20 on the PC AT requires writing 0ddh to the keyboard
1175;; processor. On the PLUS, the appropriate value is 00.
1176;;
1177
1178;; MOV AH,0DDH
1179 mov ax,cs:[A20Off] ;; setup for PLUS or AT. ah for IBM, al for PLUS
1180 CALL A20 ; Disable address line 20
1181 jnc dis_done
1182 LOOP OFFLP
1183dis_done:
1184 CLC
1185 RET
1186
1187;** A20 - ENABLE/DISABLE ADDRESS LINE 20 ON IBM PC-AT
1188;
1189; This routine enables/disables address line 20 by twiddling bits
1190; in one of the keyboard controller registers.
1191;
1192; SEE ALSO
1193; IBM Technical Reference Personal Computer AT Manual #1502243
1194; Page 5-155
1195;
1196; ENTRY
1197; AH = 0DDH to disable A20
1198; AH = 0DFH to enable A20
1199; EXIT
1200; CY Failed
1201; NC Succeeded
1202; USES
1203; AL, FLAGS
1204;
1205; WARNING If this routine is called in a CLI state this routine has
1206; the side effect of enabling interrupts.
1207;
1208; This routine is specific to TYPE 1 driver
1209;
1210
1211A20:
1212ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1213;; CS override needed on S5_FLAG to avoid phase errors on
1214;; forward declaration of this variable.
1215 cmp cs:[S5_FLAG],S_OLIVETTI ;; test for 6300 PLUS
1216 jne test_vec ;; yes, do this code
1217 jmp a20s5
1218test_vec:
1219 cmp cs:[S5_FLAG],S_VECTRA
1220 jne test_ps2
1221 jmp VecA20
1222test_ps2:
1223 test cs:[sys_flg],M_PS2 ; is it a ps2 machine
1224 jne a20ps2 ; if yes it has separate a20 routine
1225old_a20:
1226 CLI
1227 call check_a20 ; check to see if it can be enb /disb
1228 jc a20suc ; no it may not be toggled
1229 CALL E_8042
1230 JNZ a20err
1231 MOV AL,0D1H
1232 OUT 64H,AL
1233 CALL E_8042
1234 JNZ a20err
1235 MOV AL,AH
1236 OUT 60H,AL
1237 CALL E_8042
1238 JNZ a20err
1239 ;
1240 ; We must wait for the a20 line to settle down, which (on an AT)
1241 ; may not happen until up to 20 usec after the 8042 has accepted
1242 ; the command. We make use of the fact that the 8042 will not
1243 ; accept another command until it is finished with the last one.
1244 ; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
1245 ; time is on the order of 30 usec, easily satisfying the IBM 8042
1246 ; settling requirement. (Thanks, CW!)
1247 ;
1248 mov al,0FFh ;* Pulse Output Port (pulse no lines)
1249 out 64H,al ;* send cmd to 8042
1250 CALL E_8042 ;* wait for 8042 to accept cmd
1251 jnz A20Err
1252
1253A20Suc: sti
1254 clc
1255 RET
1256A20Err: sti
1257 stc
1258 ret
1259;
1260; Helper routine for A20. It waits for the keyboard controller to be "ready".
1261;
1262E_8042:
1263ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1264 PUSH CX
1265 XOR CX,CX
1266E_LOOP:
1267 IN AL,64H
1268 AND AL,2
1269 LOOPNZ E_LOOP
1270 POP CX
1271 RET
1272;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1273; A20 status checking. If request is to enable a20 we must check to
1274; see if it is already enabled. If so we just set the sys_flg to
1275; indicate this. On disabling the routine checks to see if disabling
1276; is allowed
1277;
1278check_a20:
1279assume ds:nothing,es:nothing,ss:nothing
1280 cmp ah,0ddh ; is it a disable operation
1281 jne check_a20_enable
1282;
1283; check if a20 disabling allowed
1284;
1285 test cs:[sys_flg],a20_st
1286 jne no_toggle
1287toggle: clc
1288 ret
1289;
1290; a20 enabling, check if allowed
1291;
1292check_a20_enable:
1293 and cs:[sys_flg], not A20_ST
1294 push cx
1295 push ds
1296 push si
1297 push es
1298 push di
1299 lds si,cs:low_mem
1300 les di,cs:high_mem
1301 mov cx,3
1302 cld
1303repe cmpsw
1304 pop di
1305 pop es
1306 pop si
1307 pop ds
1308 jcxz not_enabled
1309 pop cx
1310 or cs:[sys_flg],A20_ST
1311no_toggle:
1312 stc
1313 ret
1314not_enabled:
1315 pop cx
1316 clc
1317 ret
1318
1319;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1320; A20 routine for PS2s. The PS2 A20 hardware has shifted and toggling
1321; a bit in the system port is all that is required.
1322A20PS2:
1323assume ds:nothing,es:nothing,ss:nothing
1324 cli
1325;
1326; first separate disable operation from enable operation
1327;
1328 cmp ah,0ddh
1329 je disbl_PS2
1330;
1331; enabling the a20
1332;
1333 and cs:[sys_flg],not A20_ST
1334 in al,PS2_PORTA ; input a20 status
1335 test al,GATE_A20 ; is the a20 line set
1336 je set_it ;
1337 or cs:[sys_flg],A20_ST ; indicate that it was already set
1338ps2a20suc:
1339 clc
1340 sti
1341 ret
1342
1343set_it: push cx
1344 xor cx,cx
1345 or al,GATE_A20
1346 out PS2_PORTA,al ; set it
1347see_agn:
1348 in al,PS2_PORTA ; read status again
1349 test al,GATE_A20
1350 loopz see_agn
1351 pop cx
1352 jz ps2err
1353 clc
1354 sti
1355 ret
1356;
1357; disabling the ps2
1358;
1359disbl_PS2:
1360 test cs:[sys_flg],A20_ST
1361 jne ps2a20suc
1362;
1363 push cx
1364 xor cx,cx
1365 in al,PS2_PORTA
1366 and al,not GATE_A20
1367 out PS2_PORTA,al
1368see_agn1:
1369 in al,PS2_PORTA
1370 test al,GATE_A20
1371 loopnz see_agn1
1372 pop cx
1373 jnz ps2err
1374 clc
1375 sti
1376 ret
1377;
1378ps2err:
1379 stc
1380 sti
1381 ret
1382
1383;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1384;;* VECA20 - Address enable/disable routine for Vectra family computers
1385;;
1386;; This routine does the same function as A20 for Vectra machines.
1387;; Vectra machines require writing single byte as opposed to
1388;; double byte commands to the 8041. This is due to a bug
1389;; in older versions in the Vectra 8041 controllers. IBM
1390;; machines must use double byte commands due to lack of
1391;; implementation of single byte commands in some of their machines.
1392;;
1393;; Uses al, flags
1394;; Has same results as A20
1395;;
1396VecA20:
1397 CLI
1398 call check_a20
1399 jc VecA20Suc
1400 call E_8042
1401 jnz VecA20Err
1402 mov al,ah ;sigle byte command is code passed
1403 out 64H,al
1404 call E_8042
1405 jnz VecA20Err
1406;
1407; See A20 for a description of the following code. It simply makes
1408; sure that the previous command has been completed. We cannot
1409; pulse the command reg since there is a bug in some Vectra 8041s
1410; instead we write the command again knowing that when the second
1411; command is accepted the first was already processed.
1412 mov al,ah ; send command again
1413 out 64H,al
1414 call E_8042
1415 jnz VecA20Err
1416VecA20Suc:
1417 sti
1418 clc
1419 ret
1420VecA20Err:
1421 sti
1422 stc
1423 ret
1424
1425
1426;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1427;;* A20S5 - Address enable/disable routine for the 6300 PLUS.
1428;;
1429;; This routine enables lines A20-A23 on the PLUS by writing
1430;; to port 03f20h. Bit 7 turns the lines on, and bit 4 sets
1431;; the power-up bit. To disable the lines, the processor
1432;; must be reset. This is done by saving the world and
1433;; jumping to the ROM 80286 reset code. Since the power-up bit
1434;; is set, the data segment is set to the BiosSeg at 40h
1435;; and a jump is then made to the address at RealLoc1.
1436;; At RealLoc1, one can find the CS:IP where the code
1437;; is to continue.
1438;;
1439;; Uses ax, flags.
1440;; Returns with zero flag set.
1441;;
1442A20S5:
1443; test [reboot_flg],0ffh ;; sunilp
1444; jne a20s5boot ;; sunilp
1445 cli
1446 or al,al ;; if zero, then resetting processor
1447 jnz A20S5Next
1448 call RSet ;; must return with entry value of ax
1449A20S5Next:
1450 push dx ;; set/reset port
1451 mov dx,3f20h
1452 out dx,al
1453 pop dx
1454 clc ;; sunilp modification cy flag now important
1455 STI
1456 RET
1457
1458;;* a20S5BOOT - This code bypasses the processor reset on a reboot
1459;; of the 6300 PLUS. Otherwise the machine hangs.
1460a20s5BOOT: ;; use this code before reboot
1461 cli
1462 jmp short a20s5next
1463
1464OldStackSeg dw 0 ;; used during PLUS processor reset
1465 ;; to save the stack segment
1466
1467;;* Rset - Reset the 80286 in order to turn off the address lines
1468;; on the 6300 PLUS. Only way to do this on the
1469;; current hardware. The processor itself can be
1470;; reset by reading or writing prot 03f00h
1471;;
1472;; Uses flags.
1473;;
1474RSet:
1475 pusha ;; save world
1476 push ds ;; save segments
1477 push es
1478 mov ax,BiosSeg ;; point to the bios segment
1479 mov ds,ax ;; ds -> 40h
1480assume ds:BiosSeg
1481 push word ptr [RealLoc1] ;; save what might have been here
1482 push word ptr [RealLoc1+2]
1483 mov word ptr [RealLoc1],cs:[offset ReturnBack] ;; load our return address
1484 mov word ptr [RealLoc1+2],cs
1485assume ds:nothing
1486 mov [OldStackSeg],ss ;; save the stack segment, too
1487 mov dx,03f00h ;; reset the processor
1488 in ax,dx
1489 nop
1490 nop
1491 nop
1492 cli
1493 hlt ;; should never get here
1494ReturnBack:
1495 mov ss,[OldStackSeg] ;; start the recovery
1496assume ds:BiosSeg
1497 pop word ptr [RealLoc1+2]
1498 pop word ptr [RealLoc1]
1499 pop es
1500 pop ds
1501 popa
1502 ret
1503;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1504blkmov_386: ;_protect:
1505assume ds:ramcode,es:nothing,ss:nothing
1506;
1507; Compute 32 bit address of start of I/O
1508;
1509 add ax,word ptr [base_addr]
1510 adc dx,word ptr [base_addr + 2]
1511;
1512 push cx
1513;
1514; Are we in virtual mode
1515;
1516 smsw cx
1517 test cx,01B ; is the pe bit set
1518 je pr_mode_tran
1519
1520 jmp int_15_tran
1521;
1522; Dispatch on function
1523;
1524pr_mode_tran:
1525 or bh,bh
1526 jz read_it_1
1527;
1528; Write
1529;
1530; Update ES descriptor with address of track in cache
1531;
1532 mov si,offset es_des
1533 mov [si].bas_0_15,ax
1534 mov [si].bas_16_23,dl
1535 mov [si].bas_24_31,dh
1536;
1537; Update DS descriptor with transfer address
1538;
1539 mov ax,es
1540 mov cx,16
1541 mul cx
1542 mov si,offset ds_des
1543 mov [si].bas_0_15,ax
1544 mov [si].bas_16_23,dl
1545 mov [si].bas_24_31,dh
1546
1547
1548; Switch SI and DI for write transfer
1549
1550 mov si,di
1551 xor di,di
1552
1553 jmp short set_trans_1
1554
1555read_it_1:
1556;
1557; Update DS descriptor with address of track in cache
1558;
1559 mov si,offset ds_des
1560 mov [si].bas_0_15,ax
1561 mov [si].bas_16_23,dl
1562 mov [si].bas_24_31,dh
1563;
1564; Update ES descriptor with transfer address
1565;
1566 mov ax,es
1567 mov cx,16
1568 mul cx
1569 mov si,offset es_des
1570 mov [si].bas_0_15,ax
1571 mov [si].bas_16_23,dl
1572 mov [si].bas_24_31,dh
1573;
1574; Keep SI and DI the same for read transfer
1575;
1576 xor si,si
1577
1578set_trans_1:
1579;
1580; Restore Transfer Count
1581;
1582 pop cx
1583
1584;
1585 mov ax,cs:[A20On]
1586 call A20
1587 jc nr_err_1
1588;
1589; we shall do the transfer 1024 words at a time
1590;
1591 db 66h
1592 push ax
1593 mov bx,cx
1594assume ds:nothing
1595pr_io_agn_1:
1596 mov cx,1024
1597 cmp bx,cx
1598 ja pr_strt_1
1599 mov cx,bx
1600pr_strt_1:
1601 sub bx,cx
1602 cli ; Un interruptable
1603 cld
1604 lgdt fword ptr emm_gdt
1605
1606
1607;
1608; Switch to protected mode
1609;
1610 db 66h,0Fh, 20h, 0 ;mov eax,cr0
1611 or ax,1
1612 db 66h,0Fh,22h, 0 ;mov cr0,eax
1613;
1614; Clear prefetch queue
1615;
1616 db 0eah ; far jump
1617 dw offset flush_prefetch
1618 dw cs_des - start_gdt
1619;
1620flush_prefetch:
1621 assume cs:nothing
1622;
1623; Initialize segment registers
1624;
1625 mov ax,ds_des - start_gdt
1626 mov ds,ax
1627 assume ds:nothing
1628 mov ax,es_des - start_gdt
1629 mov es,ax
1630 assume es:nothing
1631 shr cx,1 ; convert word count into dword count
1632 db 0f3h,066h,0a5h ; rep movsd
1633; rep movsw ; Move data
1634;
1635;
1636; Return to Real Mode
1637;
1638;
1639 db 66h,0Fh, 20h, 0 ; mov eax,cr0
1640 and ax,0FFFEh
1641 db 66h,0Fh, 22h, 0 ; mov cr0,eax
1642;
1643; Flush Prefetch Queue
1644;
1645 db 0EAh ; Far jump
1646 dw offset flushcs
1647cod_seg dw ? ; Fixed up at initialization time
1648 assume cs:ramcode
1649flushcs:
1650;
1651 sti
1652; see if transfer done else go to do next block
1653;
1654 or bx,bx
1655 jne pr_io_agn_1
1656;
1657 db 66h
1658 pop ax
1659 mov ax,cs
1660 mov es,ax
1661 assume es:nothing
1662 mov ds,ax
1663 assume ds:ramcode
1664
1665 mov cx,800h ; Retry this many times
1666offlp_1:
1667 mov ax,cs:[A20Off]
1668 call A20 ; Disable address line 20
1669 jnc offlp1_out
1670 loop offlp_1
1671offlp1_out:
1672 clc
1673 ret
1674
1675nr_err_1:
1676
1677 mov al,02 ; Drive not ready error
1678 stc
1679 ret
1680;
1681int_15_tran:
1682assume ds:ramcode,es:nothing,ss:nothing
1683 or bh,bh
1684 jz read_it_2
1685;
1686; Write
1687;
1688; Update tgt descriptor with address of track in cache
1689;
1690 mov si,offset tgt
1691 mov [si].bas_0_15,ax
1692 mov [si].bas_16_23,dl
1693 mov [si].bas_24_31,dh
1694;
1695; Update src descriptor with transfer address
1696;
1697 mov ax,es
1698 mov cx,16
1699 mul cx
1700 add ax,di
1701 adc dx,0
1702 mov si,offset src
1703 mov [si].bas_0_15,ax
1704 mov [si].bas_16_23,dl
1705 mov [si].bas_24_31,dh
1706;
1707 jmp short set_trans_2
1708
1709read_it_2:
1710;
1711; Update src descriptor with address of track in cache
1712;
1713 mov si,offset src
1714 mov [si].bas_0_15,ax
1715 mov [si].bas_16_23,dl
1716 mov [si].bas_24_31,dh
1717;
1718; Update tgt descriptor with transfer address
1719;
1720 mov ax,es
1721 mov cx,16
1722 mul cx
1723 add ax,di
1724 adc dx,0
1725 mov si,offset tgt
1726 mov [si].bas_0_15,ax
1727 mov [si].bas_16_23,dl
1728 mov [si].bas_24_31,dh
1729;
1730set_trans_2:
1731;
1732; Restore Transfer Count
1733;
1734 pop bx
1735
1736;
1737; we shall do the transfer 1024 words at a time
1738;
1739pr_io_agn_2:
1740 mov cx,1024
1741 cmp bx,cx
1742 ja pr_strt_2
1743 mov cx,bx
1744pr_strt_2:
1745 sub bx,cx
1746 push cs
1747 pop es
1748 mov si,offset int15_gdt
1749 mov ax,emm_blkm shl 8
1750 int emm_int
1751 jc nr_err_1
1752;
1753;
1754; see if transfer done else fo to do next block
1755;
1756 or bx,bx
1757 je io_exit
1758;
1759 add [src.bas_0_15],2048
1760 adc [src.bas_16_23],0
1761 adc [src.bas_24_31],0
1762;
1763 add [tgt.bas_0_15],2048
1764 adc [tgt.bas_16_23],0
1765 adc [tgt.bas_24_31],0
1766;
1767 jmp pr_io_agn_2
1768io_exit:
1769 clc
1770 ret
1771;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1772;** SEG_SET - Set up a LOADALL segment descriptor as in REAL mode
1773;
1774; This routine sets the BASE value in the segment descriptor
1775; pointed to by DS:SI with the segment value in AX as the 80286
1776; does in REAL mode. This routine is used to set a descriptor
1777; which DOES NOT have an extended 24 bit address.
1778;
1779; SEE ALSO
1780; INTEL special documentation of LOADALL instruction
1781;
1782; ENTRY:
1783; DS:SI -> Seg register descriptor
1784; AX is seg register value
1785; EXIT:
1786; NONE
1787; USES:
1788; AX
1789;
1790; This routine is specific to TYPE 1 driver
1791;
1792
1793SEG_SET:
1794ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1795 PUSH DX
1796 PUSH CX
1797 MOV CX,16
1798 MUL CX ; Believe or not, this is faster than a 32 bit SHIFT
1799 MOV WORD PTR [SI.SEG_BASE],AX
1800 MOV BYTE PTR [SI.SEG_BASE + 2],DL
1801 POP CX
1802 POP DX
1803 RET
1804
1805;** FIX_DESCRIPTOR - Shuffle GTD IDT descriptors
1806;
1807; The segment descriptors for the IDT and GDT are stored
1808; by the SIDT instruction in a slightly different format
1809; than the LOADALL instruction wants them. This routine
1810; performs the transformation by PUSHing the contents
1811; of the descriptor, and then POPing them in a different
1812; order.
1813;
1814; SEE ALSO
1815; INTEL special documentation of LOADALL instruction
1816; INTEL 80286 processor handbook description of SIDT instruction
1817;
1818; ENTRY:
1819; DS:SI points to IDT or GDT descriptor in SIDT form
1820; EXIT:
1821; DS:SI points to IDT or GDT descriptor in LOADALL form
1822; USES:
1823; 6 words of stack
1824;
1825; NOTE: The transformation is reversable, so this routine
1826; will also work to transform a descriptor in LOADALL
1827; format to one in SIDT format.
1828;
1829; Specific to TYPE 1 driver
1830;
1831
1832FIX_DESCRIPTOR:
1833ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
1834 PUSH WORD PTR [SI + 4]
1835 PUSH WORD PTR [SI + 2]
1836 PUSH WORD PTR [SI]
1837 POP WORD PTR [SI + 4]
1838 POP WORD PTR [SI]
1839 POP WORD PTR [SI + 2]
1840 RET
1841
1842;** DATA SPECIFIC TO THE LOADALL INSTRUCTION USAGE
1843;
1844; SWAP_80 and LOADALL_TBL are data elements specific to the use
1845; of the LOADALL instruction by TYPE 1 drivers.
1846;
1847
1848;
1849; Swap buffer for contents of 80:0
1850;
1851 EVEN ; Force word alignment of SWAP_80 and LOADALL_TBL
1852
1853SWAP_80 DB 102 DUP(?)
1854ssSave dw ?
1855
1856;
1857; LOADALL data buffer placed at 80:0
1858;
1859LOADALL_TBL LABEL BYTE
1860 DB 6 DUP(0)
1861LDSW DW ?
1862 DB 14 DUP (0)
1863TR DW 0
1864FLAGS DW 0 ; High 4 bits 0, Int off, Direction clear
1865 ; Trace clear. Rest don't care.
1866LIP DW OFFSET AFTER_LOADALL
1867LDT DW 0
1868LDSS DW 8000h
1869LSSS DW ?
1870LCSS DW ?
1871LESS DW ?
1872LDI DW ?
1873LSI DW ?
1874LBP DW ?
1875LSP DW ?
1876LBX DW ?
1877LDX DW ?
1878LCX DW ?
1879LAX DW 80H
1880ESDES SEGREG_DESCRIPTOR <>
1881CSDES SEGREG_DESCRIPTOR <>
1882SSDES SEGREG_DESCRIPTOR <>
1883DSDES SEGREG_DESCRIPTOR <>
1884GDTDES DTR_DESCRIPTOR <>
1885LDTDES DTR_DESCRIPTOR <0D000H,0,0FFH,0088H>
1886IDTDES DTR_DESCRIPTOR <>
1887TSSDES DTR_DESCRIPTOR <0C000H,0,0FFH,0800H>
1888
1889;** TRUE LOCATION OF ABOVE_PID
1890;
1891; Define the TRUE (runtime TYPE 2 driver) location of ABOVE_PID.
1892; This is the only piece of TYPE 2 specific data that we need
1893; in the resident image. We must define it HERE rather than down
1894; at ABOVE_BLKMOV so that we have its TRUE location after the
1895; TYPE 2 code is swapped in at initialization. If we defined
1896; it down at ABOVE_BLKMOV any instruction like:
1897;
1898; MOV DX,[ABOVE_PID]
1899;
1900; Would have to be "fixed up" when we moved the ABOVE_BLKMOV
1901; code into its final location.
1902;
1903
1904ABOVE_PID EQU WORD PTR $ - 2 ; TRUE location of ABOVE_PID
1905
1906;
1907; The following label defines the end of the region where BLKMOV code
1908; may be swapped in. BLKMOV code to be swapped in MUST fit
1909; between DRIVE_CODE and DRIVE_END
1910;
1911DRIVE_END LABEL WORD
1912
1913
1914BREAK <BPB POINTER ARRAY>
1915
1916;** BPB pointer array data
1917;
1918; BPB pointer array returned by INIT call. Must be part of resident image.
1919;
1920; SEE ALSO
1921; MS-DOS Technical Reference manual section on
1922; Installable Device Drivers
1923;
1924
1925INITAB DW RDRIVEBPB
1926
1927;
1928; The following label defines the end of the RAMDrive resident code
1929; for cases where no INT 9/19 code is included.
1930;
1931DEVICE_END LABEL BYTE
1932
1933BREAK <INT 19/9/15 Handlers. Incl if FIRST driver in system or /A or new alloc>
1934
1935;
1936; As discussed above in the documentation of the EMM_CTRL sector it
1937; is necessary to hear about system re-boots so that the EMM_ISDRIVER
1938; bits in the EMM_REC structures can be manipulated correctly.
1939;
1940; On the IBM PC family of machines there are two events which cause a
1941; "soft" system re-boot which we might expect the EMM_CTRL sector to
1942; survive through. One is software INT 19H, the other is the Ctrl-Alt-Del
1943; character sequence which can be detected by "listening" on INT 9 for
1944; it. The code below consists of a handler for INT 19H, a handler
1945; for INT 9, and a drive TYPE dependant piece of code.
1946;
1947; The drive TYPE dependant piece of code works as follows:
1948;
1949; TYPE 1 uses EMM_CTRL sector so it scans the EMM_CTRL sector
1950; looking for all EMM_ALLOC and EMM_MSDOS EMM_REC
1951; structures and turns off the EMM_ISDRIVER bit.
1952; Since this scan is GLOBAL for all EMM_MSDOS
1953; marked structures we need only ONE INT 19/INT 9
1954; handler even if we have more than one TYPE 1
1955; RAMDrive in the system. The handler is always
1956; in the FIRST TYPE 1 RAMDrive installed at boot
1957; time.
1958;
1959; TYPE 2 DOES NOT use the EMM_CTRL sector but it still has
1960; a handler. What this handler does is issue an
1961; ABOVE_DEALLOC call to deallocate the Above Board
1962; memory allocated to the RAMDrive. In current versions
1963; of the EMM device driver this step is unnecessary
1964; as the EMM device driver is thrown away together
1965; with all of the allocation information when the system
1966; is re-booted. We do it anyway because some future version
1967; of the EMM device driver may be smarter and retain
1968; allocation information through a warm-boot. Currently,
1969; doing this doesn't hurt anything. Since this code cannot
1970; do a global ABOVE_DEALLOC for all TYPE 2 drivers in the
1971; system, it does an ABOVE_DEALLOC only for its memory
1972; and EACH TYPE 2 driver in the system includes the INT 19/9
1973; code.
1974;
1975; TYPE 3 uses EMM_CTRL sector so it scans the EMM_CTRL sector
1976; looking for all EMM_ALLOC and EMM_MSDOS EMM_REC
1977; structures and turns off the EMM_ISDRIVER bit.
1978; Since this scan is GLOBAL for all EMM_MSDOS
1979; marked structures we need only ONE INT 19/INT 9
1980; handler even if we have more than one TYPE 3
1981; RAMDrive in the system. The handler is always
1982; in the FIRST TYPE 3 RAMDrive installed at boot
1983; time.
1984;
1985; TYPE 4 does not use EMM_CTRL or have any other need to hear
1986; about re-boots since this type of RAMDrive CANNOT
1987; live through a warm boot. So TYPE 4 drivers NEVER
1988; include the INT 19/9 code.
1989;
1990
1991;
1992; Storage locations for the "next" INT 19 and INT 9 vectors, the ones
1993; that were in the interrupt table when the device driver was loaded.
1994; They are initialized to -1 to indicate they contain no useful information.
1995;
1996OLD_19 LABEL DWORD
1997 DW -1
1998 DW -1
1999
2000;OLD_9 LABEL DWORD
2001; DW -1
2002; DW -1
2003;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2004; modification to meet new memory allocation standard
2005OLD_15 LABEL DWORD
2006 DW -1
2007 DW -1
2008int15_size dw 0
2009;
2010;
2011INT_15:
2012ASSUME DS:NOTHING,SS:NOTHING,ES:NOTHING
2013;
2014; This piece of code determines the size of extended memory
2015; which was allocated before this driver and then subtracts
2016; the amount it has allocated for itself
2017;
2018; inputs: ah = 88h is of interest
2019; outputs: ax = size of extended memory allocated by all before and
2020; including us
2021; regs used: flags
2022;
2023 pushf
2024 cmp ah,88h
2025 je mem_det
2026 popf
2027 jmp [old_15]
2028mem_det:
2029 mov ax,[int15_size]
2030 popf
2031 clc
2032 sti
2033 iret
2034
2035;** INT 9 Keyboard handler
2036;
2037; All this piece of code does is look for the Ctrl-Alt-Del event.
2038; If key is not Ctrl-Alt-Del, it jumps to OLD_9 without doing
2039; anything. If the Ctrl-Alt-Del key is detected it calls
2040; RESET_SYSTEM to perform driver TYPE specific re-boot code
2041; and then jumps to OLD_9 to pass on the event.
2042;
2043; NOTE THAT UNLIKE INT 19 THIS HANDLER DOES NOT NEED TO RESET
2044; THE INT 9 AND INT 19 VECTORS. This is because the Ctrl-Alt-Del
2045; IBM ROM re-boot code resets these vectors.
2046;
2047; SEE ALSO
2048; INT 9 IBM ROM code in ROM BIOS listing of
2049; IBM PC Technical Reference manual for any PC family member
2050;
2051; ENTRY
2052; NONE
2053; EXIT
2054; NONE, via OLD_9
2055; USES
2056; FLAGS
2057;
2058; THIS CODE IS USED BY TYPE 1,2 and 3 drivers.
2059;
2060
2061;INT_9:
2062;ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2063; PUSH AX
2064; PUSH DS
2065; IN AL,60H
2066; CMP AL,83 ; DEL key?
2067; JNZ CHAIN ; No
2068; XOR AX,AX
2069; MOV DS,AX
2070; MOV AL,BYTE PTR DS:[417H] ; Get KB flag
2071; NOT AL
2072; TEST AL,0CH ; Ctrl Alt?
2073; JNZ CHAIN ; No
2074; CALL RESET_SYSTEM ; Ctrl Alt DEL
2075;CHAIN:
2076; POP DS
2077; POP AX
2078; JMP [OLD_9]
2079
2080;** INT 19 Software re-boot handler
2081;
2082; All this piece of code does is sit on INT 19 waiting for
2083; a re-boot to be signaled by being called. It calls
2084; RESET_SYSTEM to perform driver TYPE specific re-boot code,
2085; resets the INT 19 and INT 9 vectors,
2086; and then jumps to OLD_19 to pass on the event.
2087;
2088; NOTE THAT UNLIKE INT 9 THIS HANDLER NEEDS TO RESET
2089; THE INT 9 AND INT 19 VECTORS. This is because the INT 19
2090; IBM ROM re-boot code DOES NOT reset these vectors, and we
2091; don't want to leave them pointing to routines that are not
2092; protected from getting stomped on by the re-boot.
2093;
2094; SEE ALSO
2095; INT 19 IBM ROM code in ROM BIOS listing of
2096; IBM PC Technical Reference manual for any PC family member
2097;
2098; ENTRY
2099; NONE
2100; EXIT
2101; NONE, via OLD_19
2102; USES
2103; FLAGS
2104;
2105; THIS CODE IS USED BY TYPE 1,2 and 3 drivers.
2106;
2107
2108INT_19:
2109ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2110 CALL RESET_SYSTEM
2111 PUSH AX
2112 PUSH DS
2113 XOR AX,AX
2114 MOV DS,AX
2115 ;
2116 ; Since INT 19 DOES NOT reset any vectors (like INT 9 Ctrl Alt DEL does),
2117 ; we must replace those vectors we have mucked with.
2118 ;
2119 ; NOTE THAT WE RESET VECTORS DIRECTLY!!!!!!!!!!!!!!!!!!
2120 ; We are not sure that DOS is reliable enough to call.
2121 ;
2122 MOV AX,WORD PTR [OLD_19]
2123 CLI
2124 MOV WORD PTR DS:[19H * 4],AX
2125 MOV AX,WORD PTR [OLD_19 + 2]
2126 MOV WORD PTR DS:[(19H * 4) + 2],AX
2127; MOV AX,WORD PTR [OLD_9]
2128; MOV WORD PTR DS:[9H * 4],AX
2129; MOV AX,WORD PTR [OLD_9 + 2]
2130; MOV WORD PTR DS:[(9H * 4) + 2],AX
2131;
2132 mov ax,word ptr [old_15]
2133 cmp ax,word ptr [old_15+2]
2134 jne res_15
2135 cmp ax,-1
2136 je skip_res
2137res_15:
2138 mov word ptr ds:[15h*4],ax
2139 mov ax,word ptr [old_15+2]
2140 mov word ptr ds:[(15h*4) +2],ax
2141
2142skip_res:
2143 POP DS
2144 POP AX
2145 JMP [OLD_19]
2146
2147;** RESET_SYSTEM perform TYPE 1 (/E) driver specific reboot code
2148;
2149; This code performs the EMM_ISDRIVER reset function as described
2150; in EMM.ASM for all EMM_REC structures which are EMM_ALLOC and
2151; EMM_ISDRIVER and of type EMM_MSDOS. We use the same LOADALL
2152; method described at BLKMOV to address the EMM_CTRL sector
2153; at the start of extended memory and perform our changes in
2154; place.
2155;
2156; NOTE: RESET_SYSTEM ALSO defines the start of ANOTHER piece of
2157; driver TYPE specific code that TYPE 2, 3 and 4 drivers
2158; will have to swap in a different piece of code for.
2159;
2160; note: type 1 drivers allocation schemes have changed. so now
2161; only the olivetti special configuration has an emm
2162; control record. this is a 286 machine and we can stick
2163; to the code given below for that. would have preferred
2164; to give complete support here
2165;
2166; ENTRY
2167; NONE
2168; EXIT
2169; NONE
2170; USES
2171; NONE
2172;
2173; This code is specific to TYPE 1 drivers
2174;
2175
2176RESET_SYSTEM:
2177ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2178;
2179; this piece of code is now redundant with the new aallocation scheme.
2180; for type 1 drivers we use the emm control record only in /u option
2181; and for that driver this piece of code is never executed
2182;
2183; this piece of code cannot be removed because other guys relocate
2184; on top of this
2185;
2186 jmp reset_ret
2187;
2188 PUSHA
2189 PUSH DS
2190 PUSH ES
2191 PUSH CS
2192 POP DS
2193ASSUME DS:RAMCODE
2194 ;
2195 ; Set up to address EMM_CTRL sector
2196 ;
2197 MOV [LIP],OFFSET AFTER_LDA
2198 MOV WORD PTR [DSDES.SEG_BASE],EXTMEM_LOW
2199 MOV BYTE PTR [DSDES.SEG_BASE + 2],EXTMEM_HIGH
2200 MOV [LSI],0
2201 MOV [LDI],EMM_RECORD
2202 MOV [LCX],EMM_NUMREC
2203 MOV SI,OFFSET ESDES
2204 MOV AX,ES
2205 CALL SEG_SET ; Set ES segreg
2206 MOV AX,SS
2207 MOV [LSSS],AX
2208 MOV SI,OFFSET SSDES
2209 CALL SEG_SET ; Set SS segreg
2210 MOV [LSP],SP
2211ON20:
2212 MOV AH,0DFH
2213 CALL A20 ; Enable adress 20
2214 CLI ; A20 STIs
2215 JNZ ON20
2216
2217 MOV AX,80H
2218 MOV DS,AX
2219ASSUME DS:NOTHING
2220 PUSH CS
2221 POP ES
2222 XOR SI,SI
2223 MOV DI,OFFSET SWAP_80
2224 MOV CX,102/2
2225 CLD
2226 CLI
2227 REP MOVSW ; Transfer out 80:0
2228 PUSH DS
2229 PUSH ES
2230 POP DS
2231 POP ES
2232 XOR DI,DI
2233 MOV SI,OFFSET LOADALL_TBL
2234 MOV CX,102/2
2235 REP MOVSW ; Transfer in LOADALL info
2236 DW 050FH ; LOADALL INSTRUCTION
2237AFTER_LDA:
2238 ;
2239 ; Scan EMM_CTRL for MS-DOS ISDRIVER regions and turn off ISDRIVER
2240 ;
2241
2242LOOK_RECY:
2243 TEST [DI.EMM_FLAGS],EMM_ALLOC
2244 JZ DONEY ; Hit free record, done
2245 TEST [DI.EMM_FLAGS],EMM_ISDRIVER
2246 JZ NEXTRECY ; No Driver
2247 CMP [DI.EMM_SYSTEM],EMM_MSDOS
2248 JNZ NEXTRECY ; Wrong system
2249 AND [DI.EMM_FLAGS],NOT EMM_ISDRIVER ; No longer a driver
2250NEXTRECY:
2251 ADD DI,SIZE EMM_REC
2252 LOOP LOOK_RECY
2253DONEY:
2254 MOV ES,AX ; LOADALL puts 80H in AX
2255 XOR DI,DI
2256 PUSH CS
2257 POP DS
2258ASSUME DS:RAMCODE
2259 MOV SI,OFFSET SWAP_80
2260 MOV CX,102/2
2261 REP MOVSW ; Restore 80:0
2262
2263OFF20:
2264 MOV AH,0DDH ; Disable adress line 20
2265 CALL A20
2266 CLI ; A20 STIs
2267 JNZ OFF20
2268 POP ES
2269 POP DS
2270ASSUME DS:NOTHING
2271 POPA
2272reset_ret:
2273 RET
2274
2275;
2276; The following label performs two functions. It defines the end of the
2277; Driver TYPE specific RESET_SYSTEM code which will have to be replaced
2278; for different driver TYPEs as the code between RESET_SYSTEM and
2279; RESET_INCLUDE. Swapped in code MUST FIT between RESET_SYSTEM and
2280; RESET_INCLUDE. It also defines the end of the resident device driver
2281; code for a driver which wants to include the INT 19/ INT 9 code.
2282;
2283RESET_INCLUDE LABEL BYTE
2284
2285BREAK <COMMON INIT CODE>
2286
2287;** DISPOSABLE INIT DATA
2288;
2289; INIT data which need not be part of resident image
2290;
2291
2292DRIVER_SEL DB 2 ; 0 if /E (TYPE 1), 1 if /A (TYPE 2),
2293 ; 2 if resmem (TYPE 3 or 4)
2294
2295DEV_SIZE DW 64 ; Size in K of this device
2296
2297U_SWITCH db 0 ;; for the oliv's special config
2298
2299special_mem dw 0 ;; at&t special memory
2300
2301new_all db 0 ; to indicate new allocation scheme
2302
2303EXT_K DW ? ; Size in K of Exteneded memory.
2304
2305NUM_ARG DB 1 ; Counter for order dependent numeric
2306 ; arguments bbbb ssss dddd.
2307
2308INIT_DRIVE DB 1 ; 0 means drive is inited
2309 ; 1 means drive is to be inited
2310 ; MUST BE DEFAULT SETTING
2311 ; 2 means drive is to be inited
2312 ; REGARDLESS of the existence of
2313 ; a valid DOS volume signature.
2314
2315GOTSWITCH DB 0 ; 0 if no switch, NZ if switch seen
2316
2317DIRSEC DW ? ; Number of directory SECTORS
2318
2319TERM_ADDR LABEL DWORD ; Address to return as break address in INIT packet
2320 DW OFFSET DEVICE_END ; INIT to NOT include INT 19/9 code
2321 DW ? ; RAMDrive CS filled in at INIT
2322
2323TRUE_CS DW ? ; Used to store the "true" location of
2324 ; the driver when the relocation at
2325 ; RAMDrive_RELOC is performed.
2326
2327RESMEM_SPECIAL DB 0 ; 0 means NORMAL TYPE 3 RAMDrive
2328 ; NZ means SPECIAL TYPE 4 RESMEM version
2329 ; see code at RAMDrive_RELOC
2330
2331VALID_EMM db 0 ;
2332;
2333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2334sys_det proc near
2335;
2336; author: sunilp, august 1, 1987. thanks to rickha for most of this
2337; routine.
2338;
2339; purpose: to determine whether extended memory cache can be installed
2340; on this system. also to determine and store in the system
2341; flag the machine identification.
2342;
2343; inputs: none
2344;
2345; outputs: CY set if this machine doesn't allow extended memory cache.
2346; CY clear if this machine allows extended memory cache and
2347; the system flag is set according to the machine type.
2348;
2349; registers used: ax,es,flags
2350;----------------------------------
2351; Clear the state of the system flag
2352;
2353assume ds:ramcode,es:nothing,ss:nothing
2354 xor ax,ax ; 0000 into AX
2355; mov [sys_flg],al ; clear system flag
2356;----------------------------------
2357; Determine if 8086/8088 system. If so we should abort immediately.
2358;
2359 push ax ; ax has 0
2360 popf ; try to put that in the flags
2361 pushf
2362 pop ax ; look at what really went into flags
2363 and ax,0F000h ; mask off high flag bits
2364 cmp ax,0F000h ; Q: was high nibble all ones ?
2365 je cpu_err ; Y: it's an 8086 (or 8088)
2366;----------------------------------
2367; Determine if 80286/80386 machine.
2368;
2369 mov ax,0F000h ; N: try to set the high bits
2370 push ax
2371 popf ; ... in the flags
2372 pushf
2373 pop ax ; look at actual flags
2374 and ax,0F000h ; Q: any high bits set ?
2375 je cpu_286 ; N: it's an 80286
2376;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2377; It is a 386 cpu. We should next try to determine if the ROM is
2378; B0 or earlier. We don't want these guys.
2379;
2380cpu_386:
2381 pushf ; clear
2382 pop ax ; NT
2383 and ax,not 0F000h ; and
2384 push ax ; IOPL
2385 popf ; bits
2386;----------------------------------
2387; the next three instructions were removed because we are loaded
2388; in real mode. So there is no need to check for virtual mode.
2389;
2390; smsw ax ;check for Virtual Mode
2391; test ax,0001 ; Q: Currently in Virtual Mode ?
2392; jnz cpu_exit ; Y: quit with error message
2393;----------------------------------
2394 ; N: check 386 stepping for B0
2395 call is_b0 ; Q: B0 ?
2396 jc cpu_err ; Y: abort
2397;----------------------------------
2398; We have a valid 386 guy. Set the flag to indicate this.
2399;
2400 or [sys_flg],M_386 ; set 386 bit
2401 jmp short PS2Test
2402
2403;----------------------------------
2404; This is a 286 guy. Check for AT model byte. We don't want non-ATs.
2405; Set 286 bit if AT type. Then check for PS/2
2406;
2407cpu_286:
2408 mov ax,0ffffh
2409 mov es,ax
2410 cmp byte ptr es:[0eh],0fch ; AT model byte
2411 jne cpu_err ; if not abort
2412;
2413 or [sys_flg],M_286 ; set 286 flag bit
2414;
2415;
2416; Determine if this is a PS/2 system
2417;
2418PS2Test:
2419 call IsPS2Machine
2420 or ax,ax
2421 jz NCRTest
2422 or [sys_flg],M_PS2
2423
2424NCRTest:
2425 call IsNCRMachine
2426 or ax,ax
2427 jz cpu_suc
2428
2429 ; We're on an NCR machine, send D7 and D5 to the 8042 in order
2430 ; to toggle A20 instead of the DF and DD we usually send.
2431 ; ChipA 06-16-88
2432 mov cs:[A20On],0D790h
2433 mov cs:[A20Off],0D500h
2434
2435
2436;----------------------------------
2437; success exit:--
2438cpu_suc:
2439 clc
2440 ret
2441
2442;----------------------------------
2443; error exit:--
2444cpu_err:
2445 stc
2446 ret
2447;
2448sys_det endp
2449
2450
2451;*--------------------------------------------------------------------------*
2452;* *
2453;* IsPS2Machine HARDWARE DEP. *
2454;* *
2455;* Check for PS/2 machine *
2456;* *
2457;* ARGS: None *
2458;* RETS: AX = 1 if we're on a valid PS/2 machine, 0 otherwise *
2459;* REGS: AX and Flags clobbered *
2460;* *
2461;*--------------------------------------------------------------------------*
2462
2463IsPS2Machine proc near
2464
2465 mov ax,0C300h ; Try to disable the Watchdog timer
2466 stc
2467 int 15h
2468 jc IPMNoPS2 ; Error? Not a PS/2.
2469
2470IPMFoundIt: mov ax,1 ; Return 1
2471 ret
2472
2473IPMNoPS2: xor ax,ax
2474 ret
2475
2476IsPS2Machine endp
2477
2478
2479;*--------------------------------------------------------------------------*
2480;* *
2481;* IsNCRMachine HARDWARE DEP. *
2482;* *
2483;* Check for NCR machine *
2484;* *
2485;* ARGS: None *
2486;* RETS: AX = 1 if we're on a valid NCR machine, 0 otherwise *
2487;* REGS: AX and Flags clobbered *
2488;* *
2489;*--------------------------------------------------------------------------*
2490
2491; Look for 'NC' at F000:FFEA
2492
2493IsNCRMachine proc near
2494
2495 mov ax,0F000h
2496 mov es,ax
2497 mov ax,word ptr es:[0FFEAh]
2498 cmp ax,'CN'
2499 je INMFoundIt
2500 xor ax,ax
2501 ret
2502
2503INMFoundIt: mov ax,1
2504 ret
2505
2506IsNCRMachine endp
2507
2508
2509;******************************************************************************
2510; IS_B0 - check for 386-B0
2511;
2512; This routine takes advantage of the fact that the bit INSERT and
2513; EXTRACT instructions that existed in B0 and earlier versions of the
2514; 386 were removed in the B1 stepping. When executed on the B1, INSERT
2515; and EXTRACT cause an INT 6 (invalid opcode) exception. This routine
2516; can therefore discriminate between B1/later 386s and B0/earlier 386s.
2517; It is intended to be used in sequence with other checks to determine
2518; processor stepping by exercising specific bugs found in specific
2519; steppings of the 386.
2520;
2521; ENTRY: REAL MODE on 386 processor (CPU ID already performed)
2522; EXIT: CF = 0 if B1 or later
2523; CF = 1 if B0 or prior
2524;
2525; ENTRY:
2526; EXIT:
2527; USED: AX, flags
2528; STACK:
2529;------------------------------------------------------------------------------
2530is_b0 proc near
2531 push bx
2532 push cx
2533 push dx
2534 push ds
2535
2536 xor bx,bx
2537 mov ds,bx ; DS = 0000 (real mode IDT)
2538assume ds:R_Mode_IDT
2539 push [bx+(6*4)]
2540 pop cs:[int6_save] ; save old INT 6 offset
2541 push [bx+(6*4)+2]
2542 pop cs:[int6_save+2] ; save old INT 6 segment
2543
2544 mov word ptr [bx+(6*4)],offset int6
2545 mov [bx+(6*4)+2],cs ; set vector to new INT 6 handler
2546;
2547; Attempt execution of Extract Bit String instruction. Execution on
2548; B0 or earlier with length (CL) = 0 will return 0 into the destination
2549; (CX in this case). Execution on B1 or later will fail and dummy INT 6
2550; handler will return execution to the instruction following the XBTS.
2551; CX will remain unchanged in this case.
2552;
2553 xor ax,ax
2554 mov dx,ax
2555 mov cx,0FF00h ; Extract length (CL)=0, CX=non-zero
2556 db 0Fh,0A6h,0CAh ; XBTS CX,DX,AX,CL
2557
2558 xor bx,bx
2559 mov ds,bx ; DS = 0000 (real mode IDT)
2560 push cs:[int6_save] ; restore original INT 6 offset
2561 pop [bx+(6*4)] ;
2562 push cs:[int6_save+2] ; restore original INT 6 segment
2563 pop [bx+(6*4)+2]
2564
2565 or cx,cx ; Q: CX = 0 (meaning <=B0) ?
2566 jz ib_exit ; Y: exit (carry clear)
2567 stc ; N: set carry to indicate >=B1
2568ib_exit:
2569 cmc ; flip carry tense
2570 pop ds
2571 pop dx
2572 pop cx
2573 pop bx
2574 ret ; *** RETURN ***
2575is_b0 endp
2576;
2577; Temporary INT 6 handler - assumes the cause of the exception was the
2578; attempted execution of an XTBS instruction.
2579;
2580int6 proc near
2581 push bp
2582 mov bp,sp
2583 add word ptr [bp+2],3 ; bump IP past faulting instruction
2584 pop bp
2585 iret ; *** RETURN ***
2586int6_save dw 0000,0000
2587int6 endp
2588;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2589
2590;** PRINT - Print a "$" terminated message on stdout
2591;
2592; This routine prints "$" terminated messages on stdout.
2593; It may be called with only the DX part of the DS:DX message
2594; pointer set, the routine puts the correct value in DS to point
2595; at the RAMDrive messages.
2596;
2597; ENTRY:
2598; DX pointer to "$" terminated message (RAMCODE relative)
2599; EXIT:
2600; NONE
2601; USES:
2602; AX
2603;
2604; COMMON TO TYPE 1, 2, 3, 4 drivers
2605;
2606
2607PRINT:
2608ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2609 PUSH DS
2610 PUSH CS
2611 POP DS
2612 MOV AH,Std_Con_String_Output
2613 INT 21H
2614 POP DS
2615 RET
2616
2617;** ITOA - Print Decimal Integer on stdout
2618;
2619; Print an unsigned 16 bit value as a decimal integer on stdout
2620; with leading zero supression. Prints from 1 to 5 digits. Value
2621; 0 prints as "0".
2622;
2623; Routine uses divide instruction and a recursive call. Maximum
2624; recursion is four (five digit number) plus one word on stack
2625; for each level.
2626;
2627; ENTRY AX has binary value to be printed
2628; EXIT NONE
2629; USES AX,CX,DX,FLAGS
2630;
2631; COMMON TO TYPE 1, 2, 3, 4 drivers
2632;
2633
2634ITOA:
2635ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
2636
2637 MOV CX,10
2638 XOR DX,DX
2639 DIV CX ; DX is low digit, AX is higher digits
2640 OR AX,AX
2641 JZ PRINT_THIS_DIGIT ; No more higher digits
2642 PUSH DX ; Save this digit
2643 CALL ITOA ; Print higher digits first
2644 POP DX ; Recover this digit
2645PRINT_THIS_DIGIT:
2646 ADD DL,"0" ; Convert to ASCII
2647 MOV AH,Std_CON_Output
2648 INT 21H
2649 RET
2650
2651
2652;** RAM$INIT - Device Driver Initialization routine
2653;
2654; RAMDRIVE Initialization routine. This is the COMMON initialization
2655; code used by ALL driver TYPEs. Its jobs are to:
2656;
2657; 1. Initialize various global values
2658; 2. Check for correct DOS version and do changes to the device
2659; based on the DOS version if needed.
2660; 3. Parse the command line and set values accordingly
2661; 4. Call a TYPE specific INIT routine based on the Parse
2662; to set up a specific driver TYPE.
2663; 5. Initialize the DOS volume in the RAMDrive memory if appropriate
2664; 6. Print out report of RAMDrive parameters
2665; 7. Set the return INIT I/O packet values
2666;
2667; The first two lines perform step 1. Step two starts after and
2668; goes through VER_OK. Step 3 starts at VER_OK and goes through
2669; ARGS_DONE. Step 4 starts at ARGS_DONE and goes through I001.
2670; Step 5 starts at I001 and goes through DRIVE_SET. Step 6 starts
2671; at DRIVE_SET and goes through SETBPB. Step 7 starts at SETBPB
2672; and ends at the JMP DEVEXIT 10 lines later.
2673;
2674; At any time during the above steps an error may be detected. When
2675; this happens one of the error messages is printed and RAMDrive
2676; "de-installs" itself by returning a unit count of 0 in the INIT
2677; device I/O packet. The DOS device installation code is responsible
2678; for taking care of the details of re-claiming the memory used by
2679; the device driver. All RAMDrive needs to do is make sure any INT
2680; vectors it changed (INT 9 and INT 19) get restored to what they
2681; were when RAMDrive first started. If an EMM_CTRL sector is being
2682; used (TYPE 1 and 3) and one of the EMM_REC structures has been
2683; marked EMM_ISDRIVER by this driver, it must turn that bit back off
2684; since the driver did not install. A TYPE 2 driver must make sure it
2685; ABOVE_DEALLOCs any memory it allocated from the EMM device. The duty
2686; of reclaiming EMM_CTRL or Above Board memory and re-setting vectors
2687; is done by the DISK_ABORT routine which may be called by either
2688; this COMMON INIT code, or the TYPE specific INIT code.
2689;
2690; Step 1 initializes the segment part of TERM_ADDR to the correct
2691; value for type 1, 2 and 3 drivers. A TYPE 4 driver will put a
2692; different value in TERM_ADDR as it must include the space taken up
2693; by the RAMDrive memory itself which is part of the device. TRUE_CS
2694; is also initialized. This datum is relevant to the RESMEM_SPECIAL
2695; (TYPE 4) driver which relocates the driver code at RAMDrive_RELOC.
2696; This datum stores the CS of the REAL driver (the driver location
2697; BEFORE the relocation took place).
2698;
2699; Step 2 checks to make sure that we are running on a DOS in the
2700; 2.X or 3.X series which this driver is restricted to. If running
2701; on a 2.X series the device header attribute word and device command
2702; table are patched to exclude those device calls that don't exist
2703; on DOS 2.X. The HEADERMES message is also patched to not include
2704; the DOS drive letter part because 2.X DOS does not provide this
2705; information to the device at INIT time.
2706;
2707; Step 3 uses the "DEVICE = xxxxxxxxx" line pointer provided by
2708; DOS to look for the various device parameters. NOTE: This pointer
2709; IS NOT DOCUMENTED in the DOS 2.X tech ref material, but it does
2710; exist in the same way as 3.X. This code is simple even though
2711; it looks rather long. First it skips over the device name field
2712; to get to the arguments. In then parses the arguments as they are
2713; encountered. All parameter errors are detected here. NOTE THAT
2714; THIS ROUTINE IS NOT RESPONSIBLE FOR SETTING DEFAULT VALUES OF
2715; PARAMETER VARIABLES. This is accomplished by static initialization
2716; of the parameter variables.
2717;
2718; Step 4 calls a device TYPE specific initialization routine based
2719; on the parse in step 3 (presence or absense of /E and /A switches).
2720; NOTE THAT THERE IS ONE ROUTINE FOR TYPE 3 AND 4 DRIVERS. It is up
2721; to this routine itself to make the distinction between TYPE 3 and
2722; TYPE 4. NOTE that one of the prime jobs of these device TYPE specific
2723; routines is to set all of the variables that are needed by Step
2724; 5 and 7 that haven't been set by the COMMON init code:
2725;
2726; DEV_SIZE set to TRUE size of device
2727; BASE_ADDR set to TRUE start of device so MEMIO
2728; can be called
2729; BASE_RESET set so DISK_ABORT can be called
2730; TERM_ADDR set to correct end of device
2731; INIT_DRIVE set to indicate if DOS volume needs to
2732; be set up
2733; RESMEM_SPECIAL set if TYPE 4 driver
2734;
2735; Step 5 looks at the INIT_DRIVE variable to see if the DOS volume
2736; needs to be initialized. The only time we do not need to INITialize
2737; the DOS volume is when the driver TYPE specific INIT code finds
2738; that there is a VALID DOS volume in the RAMDrive memory it just
2739; set up. If the DOS volume does not need to be initialized, we
2740; go on to step 6. Otherwise the device BPB must be set, the
2741; RESERVED (boot) sector, FAT sectors, and root directory sectors
2742; must be initialized and written out to the RAMDrive. The first step
2743; is to initialize all of the BPB values. The code is a typical piece
2744; of MS-DOS code which given BYTES/SECTOR, TOTAL DISK SIZE
2745; and NUMBER OF ROOT DIRECTORY ENTRIES inputs figures out reasonable
2746; values for SEC/CLUSTER and SECTORS/FAT and TOTAL NUMBER OF CLUSTERS.
2747; NOTE THAT THIS CODE IS TUNED AND SPECIFIC TO 12 BIT FATS. Don't
2748; expect it to work AT ALL with a 16 bit FAT. The next step is to write
2749; out the BOOT record containing the BPB to sector 0, write out
2750; a FAT with all of the clusters free, and write out a root directory
2751; with ONE entry (the Volume ID at VOLID). Take CAREFUL note of the
2752; special code and comments at RAMDrive_RELOC.
2753;
2754; Step 6 makes the status report display of DEVICE SIZE, SECTOR SIZE,
2755; CLUSTER SIZE, and DIRECTORY SIZE by simply printing out the values
2756; from the BPB.
2757;
2758; Step 7 sets the INIT I/O packet return values for # of units,
2759; Break address, and BPB array pointer and returns via DEVEXIT.
2760;
2761; SEE ALSO
2762; MS-DOS Technical Reference manual section on
2763; Installable Device Drivers
2764;
2765; ENTRY from RAM$IN
2766; EXIT Through DEVEXIT
2767; USES ALL
2768;
2769; COMMON TO TYPE 1, 2, 3, 4 drivers
2770;
2771
2772RAM$INIT:
2773ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
2774 ;
2775 ; 1. Initialize various global values
2776 ;
2777 MOV WORD PTR [TERM_ADDR + 2],CS
2778 MOV [TRUE_CS],CS
2779 mov [sys_flg],0
2780 ;
2781 ; 2. Check for correct DOS version and do changes to the device
2782 ; based on the DOS version if needed.
2783 ;
2784 CLD
2785 MOV AH,GET_VERSION
2786 INT 21H
2787 XCHG AH,AL
2788 CMP AX,(2 SHL 8) + 00
2789 JB BADVER ; Below 2.00, BAD
2790 CMP AX,(3 SHL 8) + 00
2791 JB VER2X ; 2.X requires some patches
2792 CMP AX,(4 SHL 8) + 00
2793 je ldl_buf_present ; indicate that there is a hole for loadall
2794 Ja BADVER ; 3.X ok, 4.0 or above bad
2795 cmp al,30 ; 3.30
2796 jb ver_ok ; if below we cannot take advantage of 80:0
2797ldl_buf_present:
2798 or [sys_flg],DOS_33 ; indicate we have dos 3.3 or above
2799 jmp ver_ok
2800
2801BADVER:
2802 MOV DX,OFFSET BADVERMES
2803 JMP DEVABORT
2804
2805VER2X:
2806 AND [DEVATS],NOT DEVOPCL ; No such bit in 2.X
2807 MOV BYTE PTR [RAMTBL],11 ; Fewer functions too
2808 MOV WORD PTR [PATCH2X],0A0DH ; Don't know DOS drive
2809 MOV BYTE PTR [PATCH2X + 2],"$"
2810VER_OK:
2811;;
2812;; 2.5 Check here for 6300 PLUS machine. First look for Olivetti Copy-right
2813;; and if found, check id byte at f000:fffd.
2814;;
2815
2816 push es ;; Olivetti Machine?
2817 mov ax,0fc00h ;; Look for 'OL' at fc00:50
2818 mov es,ax
2819 cmp es:[0050h],'LO'
2820 jnz notS5 ;; not found
2821 mov ax,0f000h
2822 mov es,ax
2823 cmp word ptr es:[0fffdh],0fc00h ;; look for 6300 plus
2824 jnz notS5
2825 mov [S5_FLAG],S_OLIVETTI ;; yep, set flag
2826 jmp notHP
2827notS5:
2828;; Check here for an HP Vectra machine. Look for HP id byte.
2829;;
2830 mov ax,0f000H
2831 mov es,ax
2832 cmp es:[0f8H],'PH'
2833 jnz notHP
2834 mov [S5_FLAG],S_VECTRA
2835notHP:
2836 pop es
2837;
2838; 3. Parse the command line and set values accordingly
2839;
2840 LDS SI,[PTRSAV]
2841ASSUME DS:NOTHING
2842 MOV AL,[SI.INIT_DOSDEV] ; DOS drive letter
2843 ADD CS:[DOS_DRV],AL ; Need explicit over, this is a forward ref
2844 MOV DX,OFFSET HEADERMES
2845 CALL PRINT
2846 LDS SI,[SI.INIT_BPB] ; DS:SI points to config.sys
2847SKIPLP1: ; Skip leading delims to start of name
2848 LODSB
2849 CMP AL," "
2850 JZ SKIPLP1
2851 CMP AL,9
2852 JZ SKIPLP1
2853 CMP AL,","
2854 JZ SKIPLP1
2855 JMP SHORT SKIPNM
2856
2857ARGS_DONEJ:
2858 JMP ARGS_DONE
2859
2860SWITCHJ:
2861 JMP SWITCH
2862
2863SKIPLP2: ; Skip over device name
2864 LODSB
2865SKIPNM:
2866 CMP AL,13
2867 JZ ARGS_DONEJ
2868 CMP AL,10
2869 JZ ARGS_DONEJ
2870 CMP AL," "
2871 JZ FIRST_ARG
2872 CMP AL,9
2873 JZ FIRST_ARG
2874 CMP AL,","
2875 JZ FIRST_ARG
2876 CMP AL,0 ; Need this for 2.0 2.1
2877 JNZ SKIPLP2
2878SCAN_LOOP: ; PROCESS arguments
2879 LODSB
2880FIRST_ARG:
2881 OR AL,AL ; Need this for 2.0 2.1
2882 JZ ARGS_DONEJ
2883 CMP AL,13
2884 JZ ARGS_DONEJ
2885 CMP AL,10
2886 JZ ARGS_DONEJ
2887 CMP AL," "
2888 JZ SCAN_LOOP
2889 CMP AL,9
2890 JZ SCAN_LOOP
2891 CMP AL,","
2892 JZ SCAN_LOOP
2893 CMP AL,"/"
2894 JZ SWITCHJ
2895 CMP AL,"0"
2896 JB BAD_PARMJ
2897 CMP AL,"9"
2898 JA BAD_PARMJ
2899 DEC SI
2900 CALL GETNUM
2901 CMP [NUM_ARG],3
2902 JA BAD_PARMJ ; Only 3 numeric arguments
2903 JZ SET_DIR
2904 CMP [NUM_ARG],2
2905 JZ SET_SECTOR
2906SET_SIZE:
2907 CMP BX,16
2908 JB BAD_PARMJ
2909 CMP BX,4096
2910 JA BAD_PARMJ
2911 MOV [DEV_SIZE],BX
2912 JMP SHORT NUM_DONE
2913
2914BAD_PARMJ:
2915 JMP BAD_PARM
2916
2917SET_SECTOR:
2918 MOV AL,6
2919 CMP BX,128
2920 JZ SET_SEC
2921 INC AL
2922 CMP BX,256
2923 JZ SET_SEC
2924 INC AL
2925 CMP BX,512
2926 JZ SET_SEC
2927 INC AL
2928 CMP BX,1024
2929 JNZ BAD_PARM
2930SET_SEC:
2931 MOV [SSIZE],BX
2932 MOV [SEC_SHFT],AL
2933 JMP SHORT NUM_DONE
2934
2935SET_DIR:
2936 CMP BX,2
2937 JB BAD_PARM
2938 CMP BX,1024
2939 JA BAD_PARM
2940 ;
2941 ; NOTE: Since DIRNUM is the 3rd numeric arg and SSIZE is the first,
2942 ; we know the desired sector size has been given.
2943 ;
2944 MOV DI,[SSIZE]
2945 MOV CL,5 ; 32 bytes per dir ent
2946 SHR DI,CL ; DI is number of dir ents in a sector
2947 MOV AX,BX
2948 XOR DX,DX
2949 DIV DI ; Rem in DX is partial dir sector
2950 OR DX,DX
2951 JZ SET_DSZ ; User specified groovy number
2952 SUB DI,DX ; Figure how much user goofed by
2953 ADD BX,DI ; Round UP by DI entries
2954SET_DSZ:
2955 MOV [DIRNUM],BX
2956NUM_DONE:
2957 INC [NUM_ARG] ; Next numeric argument
2958SCAN_LOOPJ:
2959 JMP SCAN_LOOP
2960
2961BAD_PARM:
2962 MOV DX,OFFSET ERRMSG1
2963DEVABORT:
2964 CALL PRINT
2965DEVABORT_NOMES:
2966 XOR AX,AX ;Indicate no devices
2967 JMP SETBPB ;and return
2968
2969SWITCH:
2970 MOV AL,0FFH
2971 XCHG AL,[GOTSWITCH] ; Switch already?
2972 OR AL,AL
2973 JNZ BAD_PARM ; Yes, only one allowed
2974 LODSB
2975 CMP AL,"E"
2976 JZ EXT_SET
2977 CMP AL,"e"
2978 JNZ ABOVE_TEST
2979EXT_SET:
2980 MOV [DRIVER_SEL],0
2981 JMP SCAN_LOOP
2982
2983ABOVE_TEST:
2984;; Added for /u switch
2985 cmp al,'u' ;; Look for U switch for PLUS
2986 jz S5_TEST
2987 cmp al,'U' ;;
2988 jnz A_TEST
2989S5_TEST:
2990 cmp [S5_FLAG],S_OLIVETTI ;; No good unless PLUS
2991 jne bad_parm
2992; xchg al,[gotswitch] ; switch already
2993; or al,al
2994; jnz bad_parm
2995;
2996 cmp [U_SWITCH],0
2997 jne bad_parm
2998 dec [U_SWITCH]
2999 jmp ext_set
3000A_TEST:
3001
3002 CMP AL,"A"
3003 JZ ABOVE_SET
3004 CMP AL,"a"
3005 JNZ BAD_PARM
3006ABOVE_SET:
3007 MOV [DRIVER_SEL],1
3008 JMP SCAN_LOOP
3009
3010ARGS_DONE:
3011;
3012; 4. Call a TYPE specific INIT routine based on the Parse
3013; to set up a specific driver TYPE.
3014;
3015 PUSH CS
3016 POP DS
3017ASSUME DS:RAMCODE
3018 MOV AL,[DRIVER_SEL] ; Find out which init to call
3019 OR AL,AL
3020 JNZ NEXTV
3021 CALL AT_EXT_INIT
3022 JMP SHORT INI_RET
3023
3024NEXTV:
3025 DEC AL
3026 JNZ DORESM
3027 CALL ABOVE_INIT
3028 JMP SHORT INI_RET
3029
3030DORESM:
3031 CALL RESMEM_INIT
3032INI_RET:
3033 JNC I001
3034 JMP DEVABORT_NOMES
3035
3036I001:
3037;
3038; 5. Initialize the DOS volume in the RAMDrive memory if appropriate
3039;
3040 CMP [INIT_DRIVE],0
3041 JNZ INIDRV ; Need to initialize drive
3042 JMP DRIVE_SET ; All set to go
3043
3044INIDRV:
3045;
3046; We must figure out what to do.
3047; All values are set so we can call MEMIO to read and write disk
3048; SSIZE is user sector size in bytes
3049; DIRNUM is user directory entries
3050; DEV_SIZE is size of device in K bytes
3051;
3052 ; Figure out total number of sectors in logical image
3053 MOV AX,[DEV_SIZE]
3054 MOV CX,1024
3055 MUL CX ; DX:AX is size in bytes of image
3056 DIV [SSIZE] ; AX is total sectors
3057 ; Any remainder in DX is ignored
3058 MOV [SECLIM],AX
3059 ; Compute # of directory sectors
3060 MOV AX,[DIRNUM]
3061 MOV CL,5 ; Mult by 32 bytes per entry
3062 SHL AX,CL ; Don't need to worry about overflow, # ents
3063 ; is at most 1024
3064 XOR DX,DX
3065 DIV [SSIZE]
3066 OR DX,DX
3067 JZ NOINC
3068 INC AX
3069NOINC: ; AX is # sectors for root dir
3070 MOV [DIRSEC],AX
3071 ADD AX,2 ; One reserved, At least one FAT sector
3072 CMP AX,[SECLIM]
3073 JB OK001 ; we're OK
3074 MOV [DIRNUM],16 ; Smallest reasonable number
3075 XOR DX,DX
3076 MOV AX,512 ; 16*32 = 512 bytes for dir
3077 DIV [SSIZE]
3078 OR DX,DX
3079 JZ NOINC2
3080 INC AX
3081NOINC2: ; AX is # sectors for root dir
3082 MOV [DIRSEC],AX
3083 ADD AX,2 ; One reserved, At least one FAT sector
3084 CMP AX,[SECLIM]
3085 JB OK001 ; 16 directory sectors got us to OK
3086 CALL DISK_ABORT ; Barf
3087 MOV DX,OFFSET ERRMSG2
3088 JMP DEVABORT
3089
3090OK001:
3091 mov si,64 ; set a loop bound for the homing process
3092 ; to avoid oscillation in homing
3093CLUSHOME:
3094 ; Figure a reasonable cluster size
3095 MOV AX,[SECLIM] ; AX is total sectors on disk
3096 SUB AX,[RESSEC] ; Sub off reserved sectors
3097 MOV CL,[FATNUM] ; CX is number of FATs
3098 XOR CH,CH
3099FATSUB:
3100 SUB AX,[FATSEC] ; Sub off FAT sectors
3101 LOOP FATSUB
3102 SUB AX,[DIRSEC] ; Sub off directory sectors, AX is # data sectors
3103 MOV BX,1 ; Start at 1 sec per alloc unit
3104 CMP AX,4096-10
3105 JB CSET ; 1 sector per cluster is OK
3106 MOV BX,2
3107 CMP AX,(4096-10) * 2
3108 JB CSET ; 2 sector per cluster is OK
3109 MOV BX,4
3110 CMP AX,(4096-10) * 4
3111 JB CSET ; 4 sector per cluster is OK
3112 MOV BX,8
3113 CMP AX,(4096-10) * 8
3114 JB CSET ; 8 sector per cluster is OK
3115 MOV BX,16 ; 16 sector per cluster is OK
3116CSET:
3117 ; Figure FAT size. AX is reasonable approx to number of DATA sectors
3118 ; BX is reasonable sec/cluster
3119 XOR DX,DX
3120 DIV BX ; AX is total clusters, ignore remainder
3121 ; can't have a "partial" cluster
3122 MOV CX,AX
3123 SHR CX,1
3124 JNC ADDIT
3125 INC CX
3126ADDIT:
3127 ADD AX,CX ; AX is Bytes for fat (1.5 * # of clusters)
3128 ADD AX,3 ; Plus two reserved clusters
3129 XOR DX,DX
3130 DIV [SSIZE] ; AX is # sectors for a FAT this size
3131 OR DX,DX
3132 JZ NOINC4
3133 INC AX ; Round up
3134NOINC4: ; AX is # sectors for FAT
3135 XCHG AX,[FATSEC] ; Set newly computed value
3136 XCHG BL,[CSIZE] ; Set newly computed value
3137 dec si ; have we looped enough?
3138 jz homfin ; yes, time to get out
3139 CMP BL,[CSIZE] ; Did we compute a different size?
3140 JNZ CLUSHOME ; Keep performing FATSEC and CSIZE computation
3141 ; until the values don't change.
3142 CMP AX,[FATSEC] ; Did we compute a different size?
3143 JNZ CLUSHOME ; Keep performing FATSEC and CSIZE computation
3144 ; until the values don't change.
3145HOMFIN:
3146 ;
3147 ; 6. Print out report of RAMDrive parameters
3148 ;
3149 MOV DX,OFFSET STATMES1
3150 CALL PRINT
3151 MOV AX,[DEV_SIZE]
3152 CALL ITOA
3153 MOV DX,OFFSET STATMES2
3154 CALL PRINT
3155 MOV AX,[SSIZE]
3156 CALL ITOA
3157 MOV DX,OFFSET STATMES3
3158 CALL PRINT
3159 MOV AL,[CSIZE]
3160 XOR AH,AH
3161 CALL ITOA
3162 MOV DX,OFFSET STATMES4
3163 CALL PRINT
3164 MOV AX,[DIRNUM]
3165 CALL ITOA
3166 MOV DX,OFFSET STATMES5
3167 CALL PRINT
3168 CMP [RESMEM_SPECIAL],0
3169 JZ NO_RELOC
3170 ;
3171 ; We are in a special case. The RAMDrive driver area starts at DEVICE_END.
3172 ; If we left this INIT code where it is and executed it the act of
3173 ; Initializing the boot sector, FAT, and root directory would overwrite
3174 ; this INIT code as we are executing it. So what we do is COPY this
3175 ; code into the DATA area of the RAMDrive and execute it from there.
3176 ;
3177RAMDrive_RELOC:
3178 MOV AX,1 ; AX is sec # of start of FAT
3179 ADD AX,[FATSEC] ; AX is sec # of start of directory
3180 ADD AX,[DIRSEC] ; AX is sec # of start of DATA
3181 MUL [SSIZE] ; DX:AX is byte offset of start of DATA
3182 ADD AX,WORD PTR [BASE_ADDR]
3183 ADC DX,WORD PTR [BASE_ADDR + 2] ; DX:AX is 32 addr of first byte of DATA
3184 ADD AX,15 ; PARA round up
3185 ADC DX,0
3186 MOV CX,16
3187 DIV CX ; AX is Seg addr of DATA region
3188 ;
3189 ; At this point we need to do a little check. We need to make
3190 ; sure the distance between where we are now, and where we
3191 ; are relocating to is AT LEAST as much as we are moving
3192 ; so that we don't modify ourselves while we're moving
3193 ;
3194 MOV BX,AX
3195 MOV DX,CS
3196 SUB BX,DX ; BX is para between segs
3197 CMP BX,((OFFSET RAMDrive_END - OFFSET RAMDEV) + 15) / 16 ; CMP to para moving
3198 JAE OKMOV ; Distance is enough
3199 MOV AX,CS ; Move far enough away
3200 ADD AX,((OFFSET RAMDrive_END - OFFSET RAMDEV) + 15) / 16
3201OKMOV:
3202 MOV ES,AX
3203 XOR SI,SI
3204 MOV DI,SI
3205 MOV CX,OFFSET RAMDrive_END ; Amount to move
3206 CLD
3207 REP MOVSB ; Reloc to data region
3208 PUSH ES ; Push FAR return
3209 MOV AX,OFFSET NO_RELOC
3210 PUSH AX
3211 PUSH ES
3212 POP DS ; DS is NEW RAMCODE
3213RELOCR PROC FAR
3214 RET
3215RELOCR ENDP
3216
3217NO_RELOC:
3218 PUSH CS
3219 POP ES
3220 XOR DX,DX ; Sector 0
3221 MOV CX,1 ; One sector
3222 MOV DI,OFFSET BOOT_SECTOR ; Boot sector
3223 MOV BH,1 ; Write
3224 CALL INIMEMIO
3225 INC DX ; First FAT sector
3226 MOV DI,OFFSET SECTOR_BUFFER
3227 XOR AX,AX
3228 MOV CX,512
3229 CLD
3230 REP STOSW
3231 MOV DI,OFFSET SECTOR_BUFFER
3232 MOV CX,1
3233 MOV WORD PTR ES:[DI],0FFF8H
3234 MOV BYTE PTR ES:[DI + 2],0FFH
3235 CALL INIMEMIO
3236 INC DX ; Next sector
3237 MOV WORD PTR ES:[DI],0
3238 MOV BYTE PTR ES:[DI + 2],0
3239 MOV CX,[FATSEC]
3240 DEC CX
3241 JCXZ FATDONE
3242FATZERO:
3243 PUSH CX
3244 MOV CX,1
3245 CALL INIMEMIO
3246 INC DX ; Next sector
3247 POP CX
3248 LOOP FATZERO
3249FATDONE:
3250 MOV CX,1
3251 MOV DI,OFFSET VOLID
3252 CALL INIMEMIO ; FIRST directory sector
3253 INC DX
3254 MOV CX,[DIRSEC]
3255 DEC CX
3256 JCXZ DRIVE_SET
3257 MOV DI,OFFSET SECTOR_BUFFER
3258DIRZERO:
3259 PUSH CX
3260 MOV CX,1
3261 CALL INIMEMIO
3262 INC DX ; Next sector
3263 POP CX
3264 LOOP DIRZERO
3265;
3266DRIVE_SET:
3267;
3268; BPB IS NOW ALL SET
3269;
3270 MOV AL,1 ;Number of ramdrives
3271;
3272; NOTE FALL THROUGH!!!!!!!
3273;
3274
3275;** SETBPB - Set INIT packet I/O return values
3276;
3277; This entry is used in ERROR situations to return
3278; a unit count of 0 by jumping here with AL = 0.
3279; The successful code path falls through to here
3280; with AL = 1
3281;
3282; ENTRY
3283; AL = INIT packet unit count
3284; EXIT
3285; through DEVEXIT
3286; USES
3287; DS, BX, CX
3288;
3289; COMMON TO TYPE 1, 2, 3, 4 drivers
3290;
3291
3292SETBPB:
3293ASSUME DS:NOTHING
3294 ;
3295 ; 7. Set the return INIT I/O packet values
3296 ;
3297 LDS BX,[PTRSAV]
3298 MOV [BX.INIT_NUM],AL
3299 MOV CX,WORD PTR [TERM_ADDR]
3300 MOV WORD PTR [BX.INIT_BREAK],CX ;SET BREAK ADDRESS
3301 MOV CX,WORD PTR [TERM_ADDR + 2]
3302 MOV WORD PTR [BX.INIT_BREAK + 2],CX
3303 MOV WORD PTR [BX.INIT_BPB],OFFSET INITAB ;SET POINTER TO BPB ARRAY
3304 MOV CX,[TRUE_CS]
3305 MOV WORD PTR [BX.INIT_BPB + 2],CX
3306 JMP DEVEXIT
3307
3308;** INIMEMIO call MEMIO but preserve registers
3309;
3310; MEMIO is very register destructive, all this routine
3311; does is provide a less destructive way to call MEMIO.
3312;
3313; ENTRY
3314; Same as MEMIO
3315; EXIT
3316; Same as MEMIO
3317; USES
3318; AX, SI, BP
3319;
3320; COMMON TO TYPE 1, 2, 3, 4 drivers
3321;
3322
3323INIMEMIO:
3324ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
3325 PUSH ES
3326 PUSH DI
3327 PUSH DS
3328 PUSH CX
3329 PUSH DX
3330 PUSH BX
3331 CALL MEMIO
3332 POP BX
3333 POP DX
3334 POP CX
3335 POP DS
3336 POP DI
3337 POP ES
3338 RET
3339
3340;** GETNUM - Read an unsigned integer
3341;
3342; This routine looks at DS:SI for a decimal unsigned integer.
3343; It is up to the caller to make sure DS:SI points to the start
3344; of a number. If it is called without DS:SI pointing to a valid
3345; decimal digit the routine will return 0. Any non decimal digit
3346; defines the end of the number and SI is advanced over the
3347; digits which composed the number. Leading "0"s are OK.
3348;
3349; THIS ROUTINE DOES NOT CHECK FOR NUMBERS LARGER THAN WILL FIT
3350; IN 16 BITS. If it is passed a pointer to a number larger than
3351; 16 bits it will return the low 16 bits of the number.
3352;
3353; This routine uses the MUL instruction to multiply the running
3354; number by 10 (initial value is 0) and add the numeric value
3355; of the current digit. Any overflow on the MUL or ADD is ignored.
3356;
3357; ENTRY:
3358; DS:SI -> ASCII text of number
3359; EXIT:
3360; BX is binary for number
3361; SI advanced to point to char after number
3362; USES:
3363; AX,BX,DX,SI
3364;
3365; COMMON TO TYPE 1, 2, 3, 4 drivers
3366;
3367
3368GETNUM:
3369ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
3370
3371 XOR BX,BX
3372GETNUM1:
3373 LODSB
3374 SUB AL,"0"
3375 JB NUMRET
3376 CMP AL,9
3377 JA NUMRET
3378 CBW
3379 XCHG AX,BX
3380 MOV DX,10
3381 MUL DX
3382 ADD BX,AX
3383 JMP GETNUM1
3384
3385NUMRET:
3386 DEC SI
3387 RET
3388
3389BREAK <INITIAL EMM control sector>
3390
3391;** INITIAL EMM_CTRL sector
3392;
3393; This is a datum which represents a correct initial EMM_CTRL
3394; sector as discussed in the EMM_CTRL documentation. It is used
3395; to check for the presense of a valid EMM_CTRL by comparing
3396; the signature strings, and for correctly initializing the
3397; EMM_CTRL sector if needed.
3398;
3399; The DWORD at BASE_RESET, which is the EMM_BASE of the NULL
3400; 0th EMM_REC structure, is used as a storage location of
3401; the address of the EMM_CTRL sector (PLUS 1024!!!!!!).
3402; This value can be used if it is necessary to re-address the
3403; EMM_CTRL sector during initialization. See the DISK_ABORT routine.
3404; NOTE THAT BASE_RESET CAN NOT BE USED AT RUNTIME AS THIS DATUM
3405; IS NOT PART OF THE RESIDENT IMAGE.
3406;
3407; This data is appropriate to TYPE 1 and TYPE 3 drivers
3408;
3409
3410EMM_CONTROL LABEL BYTE
3411 DB "MICROSOFT EMM CTRL VERSION 1.00 CONTROL BLOCK "
3412 DW 0
3413 DW 0
3414 ; NULL 0th record
3415 DW EMM_ALLOC + EMM_ISDRIVER
3416 DW EMM_EMM
3417BASE_RESET LABEL DWORD ; RESMEM driver must patch this value
3418 DW EXTMEM_LOW + 1024
3419 DW EXTMEM_HIGH
3420 DW 0
3421
3422 DB 950 DUP(0)
3423 DB "ARRARRARRA"
3424
3425
3426BREAK <RAMDrive COMMON INIT ROUTINES>
3427
3428;** DISK_ABORT - De-install RAMDrive after init
3429;
3430; This routine MUST BE CALLED to de-install a RAMDrive driver
3431; if the de-installation takes place:
3432;
3433; AFTER INT 19/INT 9 vectors are replaced
3434; AFTER ABOVE_PID is valid for TYPE 2
3435; AFTER an EMM_REC structure in the EMM_CTRL sector
3436; has been marked EMM_ISDRIVER for TYPE 1 or 3.
3437;
3438; NOTE: Since a TYPE 4 driver does NONE of the above things it is
3439; not necessary to call this routine, but the routine is
3440; designed so that it is OK to call for a TYPE 4 driver.
3441;
3442; In all cases the INT 9 and INT 19 vectors are replaced if the
3443; value of both words of OLD_19 is NOT -1. This is why the initial value
3444; of this datum is -1. In the event that the INT 9 and INT 19 vectors
3445; are replaced, this datum takes on some value other than -1.
3446;
3447; If this is a TYPE 1 or TYPE 3 driver the EMM_ISDRIVER bit is
3448; turned off in the LAST EMM_MSDOS EMM_REC structure.
3449; NOTE THAT A TYPE 1 or TYPE 3 DRIVER MUST NOT USE THIS ROUTINE
3450; IF IT HAS NOT "TURNED ON" AN EMM_ISDRIVER BIT IN ONE OF THE EMM_REC
3451; STRUCTURES. If this is done, this code MAY turn off the WRONG
3452; EMM_ISDRIVER bit (probably a bit for a previously installed RAMDrive
3453; of the same TYPE).
3454;
3455; If this is a TYPE 2 driver, an ABOVE_DEALLOC call is made on
3456; ABOVE_PID.
3457;
3458; ENTRY:
3459; NONE
3460;
3461; BASE_RESET valid if TYPE 1 or TYPE 3
3462; ABOVE_PID valid if TYPE 2
3463;
3464; EXIT:
3465; NONE
3466; USES:
3467; ALL but DS
3468;
3469; COMMON TO TYPE 1, 2, 3, 4 drivers
3470;
3471
3472DISK_ABORT:
3473ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
3474
3475 CMP [DRIVER_SEL],1
3476 JNZ NOT_ABOVE
3477AGAIN:
3478 ;
3479 ; TYPE 2, De-alloc the Above Board memory
3480 ;
3481 MOV DX,[ABOVE_PID]
3482 MOV AH,ABOVE_DEALLOC
3483 INT 67H
3484 CMP AH,ABOVE_ERROR_BUSY
3485 JZ AGAIN
3486 JMP SHORT RET002
3487
3488NOT_ABOVE:
3489 CMP [RESMEM_SPECIAL],0
3490 JNZ RET002 ; No EMM_CTRL on TYPE 4
3491;
3492; sp new int15 allocation for ext memory (except for oli memory) so no
3493; emm control for these
3494;
3495 ;
3496 cmp [new_all],0 ;new allocation scheme
3497 jne ret002 ; if yes then skip emm updates
3498 ;
3499 ; TYPE 1 or 3, turn off last EMM_ISDRIVER
3500 ;
3501 MOV AX,WORD PTR [BASE_RESET]
3502 MOV DX,WORD PTR [BASE_RESET + 2]
3503 SUB AX,1024 ; Backup to EMM_CTRL
3504 SBB DX,0
3505 MOV WORD PTR [BASE_ADDR],AX
3506 MOV WORD PTR [BASE_ADDR + 2],DX
3507 XOR BH,BH ; READ
3508 CALL CTRL_IO ; Get EMM_CTRL
3509 JC RET002
3510 MOV DI,OFFSET SECTOR_BUFFER
3511 MOV SI,DI
3512 ADD DI,EMM_RECORD
3513 MOV BX,-1 ; Init to "no such record"
3514 MOV CX,EMM_NUMREC
3515LOOK_RECX:
3516 ;
3517 ; Look for last installed MS-DOS region
3518 ;
3519 TEST [DI.EMM_FLAGS],EMM_ALLOC
3520 JZ DONE
3521 TEST [DI.EMM_FLAGS],EMM_ISDRIVER
3522 JZ NEXTRECX ; No Driver
3523 CMP [DI.EMM_SYSTEM],EMM_MSDOS
3524 JNZ NEXTRECX
3525 MOV BX,DI
3526NEXTRECX:
3527 ADD DI,SIZE EMM_REC
3528 LOOP LOOK_RECX
3529DONE:
3530 CMP BX,-1 ; DIDn't find it
3531 JZ RET002
3532 AND [BX.EMM_FLAGS],NOT EMM_ISDRIVER ; Undo install
3533 MOV BH,1 ; WRITE
3534 CALL CTRL_IO ; EMM_CTRL back out
3535RET002:
3536 ;
3537 ; Reset INT 9 and/or INT 19 if OLD_19 is not -1
3538 ;
3539 PUSH DS
3540 LDS DX,[OLD_19]
3541ASSUME DS:NOTHING
3542 MOV AX,DS
3543 CMP AX,-1
3544 JNZ RESET_VECS
3545 CMP AX,DX
3546 JZ NO_VECS
3547RESET_VECS:
3548 MOV AX,(Set_Interrupt_Vector SHL 8) OR 19H
3549 INT 21H
3550; LDS DX,[OLD_9]
3551; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
3552; INT 21H
3553;
3554; sp we have to deinstall the int15 handler also if it was installed
3555;
3556 lds dx,[old_15] ; get the old 15h handler addressin ds:dx
3557 mov ax,ds
3558 cmp ax,-1
3559 jne reset_15
3560 cmp ax,dx
3561 je no_vecs
3562reset_15:
3563 mov ax,(set_interrupt_vector shl 8) or 15h
3564 int 21h
3565NO_VECS:
3566 POP DS
3567 RET
3568
3569;** CTRL_IO - Read/Write the first 1024 bytes at BASE_ADDR
3570;
3571; This routine is used at INIT time to read the first 1024
3572; bytes at BASE_ADDR. If TYPE 1 or TYPE 3 and BASE_ADDR points
3573; to the EMM_CTRL address (initial value), the EMM_CTRL sector
3574; is read/written. If TYPE 1 or TYPE 3 and BASE_ADDR has been set
3575; to the start of a RAMDrive, the first 1024 bytes of the DOS volume
3576; are read/written. If TYPE 2 or TYPE 4, the first 1024 bytes of
3577; the DOS volume are read/written. All this routine does is
3578; set inputs to BLKMOV to transfer 1024 bytes at offset 0 to/from
3579; SECTOR_BUFFER.
3580;
3581; ENTRY:
3582; BH = 0 for READ, 1 for WRITE
3583; EXIT:
3584; SECTOR_BUFFER filled in with 1024 bytes at BASE_ADDR
3585; USES:
3586; ALL but DS
3587;
3588; COMMON TO TYPE 1, 2, 3, 4 drivers
3589;
3590
3591CTRL_IO:
3592ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
3593 XOR DX,DX
3594 MOV AX,DX ; Offset 0
3595 MOV CX,512 ; 1024 bytes
3596 PUSH CS
3597 POP ES
3598 MOV DI,OFFSET SECTOR_BUFFER
3599 PUSH DS
3600 CALL BLKMOV ; Read in EMM_CTRL
3601 POP DS
3602 RET
3603
3604;** MM_SETDRIVE - Look for/Init EMM_CTRL and DOS volume
3605;
3606; This routine is used by TYPE 1 and 3 drivers to check for/initialize
3607; the EMM_CTRL sector, and check for a valid DOS volume if approriate.
3608;
3609; This routine reads the EMM_CTRL sector in to SECTOR_BUFFER
3610; CALLS FIND_VDRIVE to check out and alloc or find an EMM_REC
3611; Sets BASE_ADDR to point to the start of the RAMDrive memory
3612; Writes the updated EMM_CTRL back out from SECTOR_BUFFER
3613; JUMPs to CHECK_DOS_VOL to snoop for a valid DOS volume if
3614; the return from FIND_VDRIVE indicates this is worth
3615; doing, OTHERWISE return leaving INIT_DRIVE set to the
3616; default value of 1 (needs to be INITed).
3617;
3618; ENTRY:
3619; BASE_ADDR initialized to point at START of extended memory
3620; so that the EMM_CTRL sector can be accessed by
3621; doing I/O at offset 0.
3622; EXT_K is set to size of extended memory
3623; DEV_SIZE is set to user requested device size
3624; EXIT:
3625; CARRY SET - error, message already printed
3626; CARRY CLEAR
3627; BASE_ADDR set for this drive
3628; INIT_DRIVE set
3629; DEV_SIZE set to TRUE size
3630;
3631; WARNING! Exit conditions MUST match CHECK_DOS_VOL as it transfers
3632; to that routine.
3633;
3634; USES
3635; ALL but DS
3636;
3637; Used by TYPE 1 and TYPE 3 drivers
3638;
3639
3640MM_SETDRIVE:
3641ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
3642 XOR BH,BH ; READ
3643 CALL CTRL_IO ; Get EMM_CTRL
3644 MOV DX,OFFSET INIT_IO_ERR
3645 JC ERR_RET2
3646 CALL FIND_VDRIVE ; Snoop
3647 JC RET001
3648 PUSHF ; Save zero status for DOS VOL snoop
3649 PUSH ES ; Save EMM_BASE from EMM_REC
3650 PUSH DI
3651;
3652; once again if we installed according to new int15 standard we should
3653; not write emm back
3654;
3655 ;
3656 ; test if we installed according to new standard
3657 ;
3658 cmp [new_all],0 ; did we install according to new standard
3659 jne skip_emm_write ; skip writing back emm
3660;
3661 MOV BH,1 ; WRITE
3662 CALL CTRL_IO ; Write EMM_CTRL back out
3663 MOV DX,OFFSET INIT_IO_ERR
3664 JC ERR_RET2P
3665skip_emm_write:
3666 POP WORD PTR [BASE_ADDR] ; Set final correct BASE_ADDR
3667 POP WORD PTR [BASE_ADDR + 2]
3668 POPF
3669;
3670; NOTE TRANSFER TO DIFFERENT ROUTINE
3671;
3672 JZ CHECK_DOS_VOL
3673 CLC ; Leave INIT_DRIVE set
3674RET001:
3675 RET
3676
3677ERR_RET2P:
3678 ADD SP,6
3679ERR_RET2:
3680 CALL PRINT
3681 STC
3682 RET
3683
3684;** CHECK_DOS_VOL examine RAMDrive region for valid DOS volume.
3685;
3686; This routine is used by TYPE 1, 2 and 3 drivers to check and see
3687; if the RAMDrive memory contains a valid DOS volume (one that lived
3688; through a re-boot). Its prime job is to set INIT_DRIVE to indicate
3689; whether the DOS volume needs to be initialized.
3690;
3691; First the first 1024 bytes of the drive are read in to SECTOR_BUFFER
3692; Next we check for a match of the signature areas up at BOOT_SECTOR
3693; to see if this drive contains a VALID RAMDrive boot record.
3694; IF the signatures are valid AND INIT_DRIVE != 2 (ignore valid signature)
3695; We check to make sure that SSIZE and DIRNUM set by the user
3696; match the values in the BPB we just found.
3697; IF they match
3698; we set INIT_DRIVE to 0 (don't init)
3699; and transfer the BPB out of the boot sector on the drive
3700; (in SECTOR_BUFFER) into the BPB for this driver at
3701; RDRIVEBPB.
3702; ELSE
3703; Leave INIT_DRIVE set to whatever it was on input (1 or 2)
3704; indicating that the drive must be INITed.
3705; ELSE
3706; Leave INIT_DRIVE set to whatever it was on input (1 or 2)
3707; indicating that the drive must be INITed.
3708;
3709; WARNING! This routine DOES NOT check to make sure that the size of
3710; the device as indicated in the BPB transfered in if a valid
3711; DOS volume is found is consistent with the actual size
3712; of the memory allocated to the device (DEV_SIZE). It
3713; is up to the caller to check this if so desired.
3714;
3715; ENTRY:
3716; BASE_ADDR set to point at START of DOS device
3717; EXIT:
3718; CARRY SET - error, message already printed
3719; CARRY CLEAR
3720; INIT_DRIVE set
3721; SECTOR_BUFFER contains first 1024 bytes of device
3722; USES:
3723; All but DS
3724;
3725; WARNING! Exit conditions MUST match MM_SETDRIVE as it jumps to this
3726; routine.
3727;
3728; Used by TYPE 1, 2 and 3 drivers
3729;
3730
3731CHECK_DOS_VOL:
3732ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
3733 XOR BH,BH ; READ
3734 ;
3735 ; NOTE: WE CANNOT CALL MEMIO, WE MUST STILL USE CTRL_IO because the BPB
3736 ; is not set up.
3737 ;
3738 CALL CTRL_IO ; Since BASE_ADDR is set, reads start of DEVICE
3739 MOV DX,OFFSET INIT_IO_ERR
3740 JC ERR_RET2
3741 PUSH CS
3742 POP ES
3743 MOV DI,OFFSET SECTOR_BUFFER
3744 MOV SI,OFFSET BOOT_SECTOR
3745 MOV CX,OFFSET RDRIVEBPB - OFFSET BOOT_SECTOR
3746 CLD
3747 REPE CMPSB
3748 JNZ OK_RET ; No DOS device
3749 ADD DI,OFFSET BOOT_START - OFFSET RDRIVEBPB
3750 ADD SI,OFFSET BOOT_START - OFFSET RDRIVEBPB
3751 MOV CX,OFFSET BOOT_END - OFFSET BOOT_START
3752 REPE CMPSB
3753 JNZ OK_RET ; No DOS device
3754 CMP [INIT_DRIVE],2
3755 JZ NOT_VALID ; Current value 2 means we CANNOT
3756 ; assume this BPB is valid.
3757 ;
3758 ; Check to make sure found BPB has same SSIZE and DIRNUM values
3759 ;
3760 MOV SI,OFFSET SECTOR_BUFFER + (OFFSET SSIZE - OFFSET BOOT_SECTOR)
3761 LODSW
3762 CMP AX,[SSIZE]
3763 JNZ NOT_VALID ; Sector size different than user request
3764 MOV SI,OFFSET SECTOR_BUFFER + (OFFSET DIRNUM - OFFSET BOOT_SECTOR)
3765 LODSW
3766 CMP AX,[DIRNUM]
3767 JNZ NOT_VALID ; Sector size different than user request
3768
3769 MOV [INIT_DRIVE],0 ; Found a DOS drive
3770 MOV DI,OFFSET RDRIVEBPB
3771 MOV SI,OFFSET SECTOR_BUFFER + (OFFSET RDRIVEBPB - OFFSET BOOT_SECTOR)
3772 MOV CX,OFFSET BOOT_START - OFFSET RDRIVEBPB
3773 REP MOVSB ; Set correct BPB
3774NOT_VALID:
3775OK_RET:
3776 CLC
3777 RET
3778
3779;** FIND_VDRIVE - Check out EMM_CTRL and alloc
3780;
3781; This code checks for a valid EMM_CTRL and sets up
3782; an initial one if there isn't. It then performs the
3783; algorithm described in the EMM_CTRL documentation
3784; to either allocate a NEW EMM_REC of type EMM_MSDOS,
3785; or find an existing EMM_REC which is EMM_MSDOS and has
3786; its EMM_ISDRIVER bit clear. In the later case it
3787; checks to see if DEV_SIZE is consistent with EMM_KSIZE
3788; and tries to make adjustments to EMM_KSIZE or DEV_SIZE
3789; if they are not consistent.
3790;
3791; As a side effect of scanning the EMM_CTRL sector for
3792; EMM_RECs with EMM_MSDOS and EMM_ISDRIVER we also find
3793; out if this is the first TYPE 1 or TYPE 3 driver in the
3794; system. If this is the first, then the INT 9/INT 19 code
3795; is installed.
3796;
3797; First the EMM_CTRL signature strings are checked.
3798; If they are not valid we go to SETCTRL to set up a new
3799; empty EMM_CTRL in SECTOR_BUFFER.
3800; If the signatures are valid, EMM_TOTALK is checked
3801; against EXT_K. If they are the same, the EMM_CTRL sector is
3802; valid and we skip to SCAN_DEV. Otherwise we initialize the
3803; EMM_CTRL sector at SETCTRL. All we need to do to set up the initial
3804; EMM_CTRL sector is transfer the record at EMM_CONTROL into
3805; SECTOR_BUFFER and set EMM_TOTALK and EMM_AVAILK to EXT_K - 1.
3806;
3807; In either case, finding a valid EMM_CTRL or setting up a correct
3808; initial one, we end up at SCAN_DEV. This code performs the
3809; scan of the EMM_REC structures looking for a "free" one
3810; or an allocated one which is EMM_MSDOS and has its EMM_ISDRIVER
3811; bit clear as described in the EMM_CTRL sector documentation.
3812; NOTE THAT THIS SCAN SETS THE BX REGISTER TO INDICATE WHETHER
3813; WE FOUND ANY EMM_REC STRUCTURES WHICH WERE EMM_MSDOS AND HAD
3814; THEIR EMM_ISDRIVER BIT SET. If we found such an EMM_REC structure
3815; then this IS NOT the first driver in the system and the INT 9/INT 19
3816; code SHOULD NOT be installed.
3817;
3818; If we find a "free" EMM_REC structure we go to GOT_FREE_REC
3819; and try to allocate some memory. This attempt will fail if
3820; EMM_AVAILK is less than 16K. We then call SET_RESET to do
3821; the INT 9/INT 19 setup if the BX register set by the EMM_REC
3822; scan indicates we should. We adjust DEV_SIZE to equal the
3823; available memory if DEV_SIZE is > EMM_AVAILK. Then all we do
3824; is set EMM_AVAILK and all of the fields in the EMM_REC structure
3825; as described in the EMM_CTRL sector documentation. We return
3826; with zero reset as there cannot be a valid RAMDrive in this
3827; region because we just allocated it.
3828;
3829; If we find an EMM_REC structure with EMM_MSDOS and EMM_ISDRIVER
3830; clear then we know this region MIGHT have a valid DOS volume
3831; so we will return with zero set (this is set up at OK_SET_DEV).
3832; At CHECK_SYS plus 5 lines we:
3833;
3834; Call SET_RESET to do INT 9/INT 19 setup if BX indicates
3835; IF the EMM_REC structure we found is the LAST EMM_REC structure
3836; we cannot edit any sizes and whatever the EMM_KSIZE
3837; is we stuff it into DEV_SIZE and set the EMM_ISDRIVER
3838; bit, and we're done.
3839; NOTE: We DO NOT check that EMM_KSIZE is at least
3840; 16K as we know this EMM_REC was created
3841; by some PREVIOUS RAMDrive program who
3842; DID make sure it was at least 16K
3843; ELSE
3844; IF EMM_KSIZE == DEV_SIZE
3845; set EMM_ISDRIVER and we're done
3846; IF EMM_KSIZE < DEV_SIZE
3847; either the user has edited his DEVICE = line since
3848; the last time the system was re-booted, or at the
3849; time we initially allocated this region EMM_AVAILK
3850; was less than DEV_SIZE and we had to trim the device
3851; size back.
3852; This case is handled at INSUFF_MEM.
3853; IF the next EMM_REC structure is not allocated
3854; IF EMM_AVAILK == 0
3855; We can't do anything, so set DEV_SIZE
3856; to EMM_KSIZE and we're done.
3857; ELSE
3858; allocate appropriate amount off of EMM_AVAILK
3859; and add it to EMM_KSIZE.
3860; Set INIT_DRIVE to 2 and we're done.
3861; The reason we set INIT_DRIVE to 2 is because
3862; we just changed the size of this block from
3863; what it was before so there is no way the BPB
3864; in the region (if there is one) can be valid.
3865; Setting INIT_DRIVE to 2 means "I don't care if
3866; there is a valid boot record in this region,
3867; re-initialize it based on DEV_SIZE
3868; ELSE
3869; We can't do anything, so set DEV_SIZE
3870; to EMM_KSIZE and we're done.
3871; ELSE
3872; This is the EMM_KSIZE > DEV_SIZE case, it means the
3873; user MUST have edited his DEVICE = line.
3874; IF next EMM_REC is NOT free
3875; We can't shrink the allocation block,
3876; but we'll leave DEV_SIZE set to the user
3877; specification and let him waste memory.
3878; We set INIT_DRIVE to 2 because we're not
3879; sure what to do and this is safe and we're done.
3880; NOTE that this drive will get re-initialized
3881; on EVERY re-boot. Tough cookies.
3882; ELSE
3883; SHRINK the allocation block by adding
3884; the extra memory back onto EMM_AVAILK
3885; and subtracting it from EMM_KSIZE. Set
3886; INIT_DRIVE to 2 because we changed the
3887; allocation block size, and we're done.
3888;
3889; ENTRY:
3890; SECTOR_BUFFER containes POSSIBLE EMM_CTRL sector
3891; MUST BE CHECKED
3892; EXT_K is set to size of extended memory
3893; DEV_SIZE is set to user requested device size
3894; EXIT:
3895; CARRY SET
3896; Error, message already printed
3897; CARRY CLEAR
3898; ES:DI = BASE_ADDR for this drive from EMM_BASE of EMM_REC
3899; EMM_REC is marked EMM_ISDRIVER
3900; SECTOR_BUFFER must be written out, it contains an updated
3901; EMM_CTRL sector
3902; DEV_SIZE set to TRUE size
3903; Zero SET
3904; An existing disk was found, region should be checked
3905; for valid MS-DOS volume
3906; Zero RESET
3907; A new block was allocated from the EMM_CTRL sector
3908; TERM_ADDR may be adjusted to include RESET_SYSTEM code and
3909; INT 19 and 9 vector patched if this is the first
3910; TYPE 1 or TYPE 3 RAMDrive in the system (no other
3911; EMM_MSDOS EMM_REC structures marked EMM_ISDRIVER).
3912;
3913; USES:
3914; ALL but DS
3915;
3916; Specific to TYPE 1 and 3 drivers
3917;
3918
3919FIND_VDRIVE:
3920ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
3921 PUSH CS
3922 POP ES
3923 MOV DI,OFFSET SECTOR_BUFFER
3924 MOV SI,OFFSET EMM_CONTROL
3925 MOV CX,50
3926 CLD
3927 REPE CMPSB
3928 JNZ no_emm_rec ; No EMM_CTRL
3929 ADD SI,EMM_TAIL_SIG - 50
3930 ADD DI,EMM_TAIL_SIG - 50
3931 MOV CX,10
3932 REPE CMPSB
3933 jnz no_emm_rec
3934;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3935; JNZ SETCTRL ; No EMM_CTRL
3936; MOV DI,OFFSET SECTOR_BUFFER
3937; MOV AX,[EXT_K]
3938; DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
3939; CMP AX,[DI.EMM_TOTALK]
3940; JZ SCAN_DEV ; EMM_CTRL is valid
3941;SETCTRL:
3942;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3943;
3944 dec [valid_emm] ; signal prescence of emm record
3945no_emm_rec:
3946;
3947; we have to decide which standard to use for installing the driver, the old or
3948; the new. driver type 3 - old, driver type 2 not u - new, u driver - old
3949;
3950 ;
3951 ; check if driver in extended
3952 ;
3953 cmp [driver_sel],0 ; if driver not in extended memory
3954 jne old_st ; install according to old standard
3955 cmp [u_switch],0h ; is it a u driver
3956 jne old_st ; if not go to install acc to new int15
3957 jmp new_st ; standard
3958;
3959; for olivetti u memory we still have to install according to ol' microsoft st
3960;
3961old_st:
3962 cmp [valid_emm],0h ; do we have a valid emm
3963 jne scan_dev ; if yes go to scan structures
3964set_ctrl: ; else we have to install a new one
3965 MOV DI,OFFSET SECTOR_BUFFER
3966 PUSH DI
3967 MOV SI,OFFSET EMM_CONTROL
3968 MOV CX,1024/2
3969 REP MOVSW ; Move in initial EMM_CTRL
3970 POP DI
3971 MOV AX,[EXT_K]
3972 DEC AX ; Size in EMM_CTRL doesn't include EMM_CTRL
3973 MOV [DI.EMM_TOTALK],AX
3974 MOV [DI.EMM_AVAILK],AX
3975SCAN_DEV:
3976 XOR BX,BX ; Will get tripped if a DOS dev found
3977 MOV SI,OFFSET SECTOR_BUFFER ; DS:SI points to EMM_CTRL
3978 MOV DI,SI
3979 ADD DI,EMM_RECORD ; DS:DI points to EMM records
3980 MOV CX,EMM_NUMREC
3981LOOK_REC:
3982 TEST [DI.EMM_FLAGS],EMM_ALLOC
3983 JNZ CHECK_SYS
3984 JMP GOT_FREE_REC ; Must alloc new region
3985
3986CHECK_SYS:
3987 CMP [DI.EMM_SYSTEM],EMM_MSDOS
3988 JNZ NEXTREC ; Not MS-DOS
3989 TEST [DI.EMM_FLAGS],EMM_ISDRIVER
3990 JNZ NEXTRECI ; Driver already in, I am not first driver
3991 CALL SET_RESET ; Set up INT 19,9 as per BX
3992 MOV AX,[DI.EMM_KSIZE]
3993 CMP CX,1
3994 JBE OK_SET_DEV ; If this is last record, must
3995 ; select this size
3996 CMP AX,[DEV_SIZE]
3997 JZ OK_SET_DEV ; Exact match, Okay
3998 JB INSUFF_MEM ; User asked for more
3999 ; Size of found block is bigger than requested size.
4000 ; User MUST have edited CONFIG.SYS.
4001 PUSH DI
4002 ADD DI,SIZE EMM_REC
4003 TEST [DI.EMM_FLAGS],EMM_ALLOC
4004 POP DI
4005 JZ SHRINK_BLOCK ; Next block is free, shrink
4006 MOV AX,[DEV_SIZE]
4007 JMP SHORT SET_2
4008
4009SHRINK_BLOCK:
4010 SUB AX,[DEV_SIZE] ; AX is amount to shrink
4011 ADD [SI.EMM_AVAILK],AX
4012 MOV AX,[DEV_SIZE]
4013 MOV [DI.EMM_KSIZE],AX
4014 JMP SHORT SET_2
4015
4016INSUFF_MEM: ; Size of found block is smaller
4017 ; than requested size.
4018 PUSH DI
4019 ADD DI,SIZE EMM_REC
4020 TEST [DI.EMM_FLAGS],EMM_ALLOC
4021 POP DI
4022 JNZ OK_SET_DEV ; Next block is NOT free, can't grow
4023TRY_TO_GROW_BLOCK:
4024 CMP [SI.EMM_AVAILK],0
4025 JZ OK_SET_DEV ; Need SPECIAL check for this case so
4026 ; that INIT_DRIVE doesn't get set to 2
4027 ; when it shouldn't
4028 SUB AX,[DEV_SIZE]
4029 NEG AX ; AX is amount we would like to grow
4030 SUB [SI.EMM_AVAILK],AX
4031 JNC GOT_THE_MEM
4032 ADD AX,[SI.EMM_AVAILK] ; AX is MAX we can grow
4033 MOV [SI.EMM_AVAILK],0 ; We take all that's left
4034GOT_THE_MEM:
4035 ADD [DI.EMM_KSIZE],AX
4036 MOV AX,[DI.EMM_KSIZE]
4037SET_2:
4038 MOV [INIT_DRIVE],2 ; CANNOT TRUST BPB in boot sector
4039OK_SET_DEV:
4040 MOV [DEV_SIZE],AX
4041 OR [DI.EMM_FLAGS],EMM_ISDRIVER
4042 LES DI,[DI.EMM_BASE]
4043 XOR AX,AX ; Set zero, clear carry
4044 RET
4045
4046NEXTRECI:
4047 INC BX ; Flag that we ARE NOT first DOS device
4048NEXTREC:
4049 ADD DI,SIZE EMM_REC ; Next record
4050 LOOP LOOK_RECJ
4051VERRR:
4052 MOV DX,OFFSET ERRMSG2
4053 CALL PRINT
4054 STC
4055 RET
4056
4057LOOK_RECJ:
4058 JMP LOOK_REC
4059
4060GOT_FREE_REC:
4061 MOV AX,[SI.EMM_AVAILK]
4062 CMP AX,16
4063 JB VERRR ; 16K is smallest device
4064 CALL SET_RESET ; Set INT 19,9 as per BX
4065 CMP AX,[DEV_SIZE]
4066 JBE GOTSIZE ; Not enough for user spec
4067 MOV AX,[DEV_SIZE] ; User size is OK
4068GOTSIZE:
4069 MOV [DEV_SIZE],AX
4070 SUB [SI.EMM_AVAILK],AX
4071 MOV [DI.EMM_KSIZE],AX
4072 MOV [DI.EMM_SYSTEM],EMM_MSDOS
4073 MOV [DI.EMM_FLAGS],EMM_ALLOC + EMM_ISDRIVER
4074 PUSH DI
4075 SUB DI,SIZE EMM_REC ; Look at prev record to compute base
4076 MOV AX,[DI.EMM_KSIZE]
4077 LES BX,[DI.EMM_BASE]
4078 MOV DI,ES ; DI:BX is prev base
4079 MOV CX,1024
4080 MUL CX ; Mult size by 1024 to get # bytes
4081 ADD AX,BX ; Add size onto base to get next base
4082 ADC DX,DI
4083 POP DI
4084 MOV WORD PTR [DI.EMM_BASE],AX
4085 MOV WORD PTR [DI.EMM_BASE + 2],DX
4086 LES DI,[DI.EMM_BASE]
4087 XOR AX,AX ; Set zero, clear carry
4088 INC AX ; RESET zero
4089 RET
4090;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4091; the new int15 standard
4092;
4093new_st:
4094 dec [new_all] ; indicate new standard allocation
4095 mov bx,[ext_k] ; contiguous memory reported by int15
4096 cmp [valid_emm],0 ; is there a valid emm record
4097 je no_adjust ; if not there no need to adjust
4098 ; the memory available
4099; else we have to find how much memory is already allocated by the microsoft
4100; emm control block and subtract this from the amount that is available. the
4101; memory allocated is totalk - availk + 1
4102;
4103 sub bx,1 ; subtract the emm ctrl record size
4104 mov di,offset sector_buffer ; set up to address the ctrl record
4105 ; read in
4106 mov ax,[di.emm_totalk] ; ax <- totalk
4107 sub ax,[di.emm_availk] ; ax <- totalk - availk
4108 sub bx,ax ; adjust memory available
4109 jc verrr ; if no memory go to abort
4110;
4111 cmp bx,128 ; is it the minimum required
4112 jb verrr ; if less go to abort
4113;
4114; the memory available has been found and is in bx. now compare it with
4115; requested device size and take the minimum of the two
4116;
4117no_adjust:
4118 cmp [dev_size],bx ;
4119 jb skip_adj_dev_size ; if enough space we don't need to adj
4120 ; dev_size
4121 mov [dev_size],bx ; else we have compromise on dev size
4122skip_adj_dev_size:
4123;
4124; now that we have the correct dev size we should proceed with the installation
4125; of a new int 15 handler which will account for the memory grabbed by this guy
4126;
4127 mov bx,[ext_k] ; get memory which was reported by int15
4128 add bx,[special_mem] ; account for olivetti guys
4129 sub bx,[dev_size] ;
4130 mov [int15_size],bx ; this is the size thaat will be reported
4131 ; by the int 15 handler
4132; now install the int15 handler
4133;
4134 push ax
4135 push dx
4136 push bx
4137 push es
4138 mov ax,(get_interrupt_vector shl 8) or 15h
4139 int 21h
4140 mov word ptr [old_15],bx
4141 mov word ptr [old_15+2],es
4142 mov dx,offset int_15
4143 mov ax,(set_interrupt_vector shl 8) or 15h
4144 int 21h
4145 pop es
4146 pop bx
4147 pop dx
4148 pop ax
4149;
4150; set up int19 vector
4151;
4152 xor bx,bx ; for int19 to be installed
4153 call set_reset
4154;
4155; now fill device base address in es:di
4156;
4157 mov ax,[ext_k]
4158 sub ax,[dev_size] ; this now has memory left
4159 mov cx,1024 ; we are going to find size in bytes
4160 mul cx ; dx:ax = ax * 1024
4161 add ax,word ptr [base_addr] ;
4162 adc dx,word ptr [base_addr+2] ;
4163 mov es,dx ;
4164 mov di,ax ;
4165 xor ax,ax ; to say that there
4166 inc ax ; was no dos volume reset 0
4167 ret
4168
4169;** SET_RESET - Set up INT 19/INT 9 vectors
4170;
4171; This routine will do nothing if BX is non-zero
4172; otherwise it will install the INT 9 and INT 19
4173; code by saving the current INT 9 and INT 19
4174; vectors in OLD_9 and OLD_19 (NOTE: the change in the value of OLD_19
4175; to something other than -1 indicates that the vectors have been
4176; replaced), setting the vectors to point to INT_9 and INT_19,
4177; and adjusting TERM_ADDR to include the code as part of the resident
4178; image.
4179;
4180; ENTRY:
4181; BX is 0 if INT 19/9 code to be installed
4182; EXIT:
4183; NONE
4184; USES:
4185; None
4186;
4187; COMMON TO TYPE 1, 2, 3, 4 drivers
4188;
4189
4190SET_RESET:
4191ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
4192 OR BX,BX
4193 JNZ RET005
4194 cmp [u_switch],0 ; for uswitch don't bother
4195 jne ret005
4196 PUSH AX
4197 PUSH DX
4198 PUSH BX
4199 PUSH ES
4200 MOV AX,(Get_Interrupt_Vector SHL 8) OR 19H
4201 INT 21H
4202 MOV WORD PTR [OLD_19],BX
4203 MOV WORD PTR [OLD_19 + 2],ES
4204 MOV DX,OFFSET INT_19
4205 MOV AX,(Set_Interrupt_Vector SHL 8) OR 19H
4206 INT 21H
4207; MOV AX,(Get_Interrupt_Vector SHL 8) OR 9H
4208; INT 21H
4209; MOV WORD PTR [OLD_9],BX
4210; MOV WORD PTR [OLD_9 + 2],ES
4211; MOV DX,OFFSET INT_9
4212; MOV AX,(Set_Interrupt_Vector SHL 8) OR 9H
4213; INT 21H
4214 MOV WORD PTR [TERM_ADDR],OFFSET RESET_INCLUDE
4215 POP ES
4216 POP BX
4217 POP DX
4218 POP AX
4219RET005:
4220 RET
4221
4222BREAK </E INIT Code>
4223
4224;** AT_EXT_INIT - Perform /E (TYPE 1) specific initialization
4225;
4226; This code does the drive TYPE specific initialization for TYPE 1
4227; drivers.
4228;
4229; Make sure running on 80286 IBM PC-AT compatible system by
4230; making sure the model byte at FFFF:000E is FC.
4231; Get the size of extended memory by using 8800H call to INT 15.
4232; and make sure it is big enough to accomodate a RAMDrive.
4233; Limit DEV_SIZE to the available memory found in the previous step
4234; by making DEV_SIZE smaller if necessary.
4235; Initialize the GLOBAL parts of the LOADALL information which
4236; are not set by each call to BLKMOV.
4237; CALL MM_SETDRIVE to look for EMM_CTRL and perform all the
4238; other initialization tasks.
4239;
4240; ENTRY:
4241; Invokation line parameter values set.
4242; EXIT:
4243; CARRY SET
4244; Error, message already printed. Driver not installed.
4245; EMM_CTRL not marked (but MAY be initialized if
4246; a valid one was not found).
4247; CARRY CLEAR
4248; BASE_ADDR set for this drive from EMM_BASE of EMM_REC
4249; BASE_RESET set from BASE_ADDR
4250; EMM_REC is marked EMM_ISDRIVER
4251; DEV_SIZE set to TRUE size
4252; INIT_DRIVE set appropriatly
4253; TERM_ADDR set to correct device end.
4254; RESET_SYSTEM code and INT 9/INT 19 code included,
4255; INT 19 and 9 vector patched if this is the first
4256; TYPE 1 RAMDrive in the system.
4257;
4258; USES:
4259; ALL but DS
4260;
4261; Code is specific to TYPE 1 driver
4262;
4263
4264AT_EXT_INIT:
4265ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
4266 push ds
4267 call sys_det ; new routine to do more comprehensive checking
4268 pop ds
4269 jnc at001 ; sp
4270;
4271 MOV DX,OFFSET BAD_AT
4272ERR_RET:
4273 CALL PRINT
4274 STC
4275 RET
4276
4277AT001:
4278;; patch the values of base_reset and base_addr to get the addressing right.
4279;;
4280 cmp [U_SWITCH],0 ;; patch the code for /U option
4281 jz AT001A
4282 mov ax,00fah
4283; mov word ptr [emm_ctrl_addr+2],ax ;; in resident part for reset code
4284 mov word ptr [base_reset+2],ax ;; patching upper address
4285 mov word ptr [base_addr+2],ax ;; to FA from 10
4286AT001A:
4287 MOV AX,8800H
4288 INT 15H ; Get extended memory size
4289 MOV DX,OFFSET NO_MEM
4290 OR AX,AX
4291 JZ ERR_RET
4292
4293;; If running on a 6300 PLUS, it is necessary to subtract any upper extended
4294;; memory from the value obtained by int 15 to determine the correct memory
4295;; available for a type /E RAMDrive. If loading a /U RAMDrive, it is necessary
4296;; to find out if there IS any upper extended memory.
4297
4298 cmp [U_SWITCH],0 ;; did we ask for upper extended memory
4299 jz olstuff ;; no
4300 call UpperMemCheck ;; yes, see if anything there
4301 jc ERR_RET ;; no, quit
4302 mov ax,384 ;; yes, but max allowed is 384K
4303 jmp short at001b
4304olstuff:
4305 cmp [S5_FLAG],S_OLIVETTI ;; if not 6300 PLUS, go on
4306 jne at001b
4307 call UpperMemCheck ;; yes, see if 384K is there
4308 jc at001b ;; no, so int 15h is right
4309 sub ax,384 ;; yes, subtract 384K
4310 mov [special_mem],384 ;; store special memory size
4311AT001B:
4312
4313 MOV DX,OFFSET ERRMSG2
4314 cmp ax,16
4315; CMP AX,17 ; 1k ident block plus 16k min Ramdrive
4316 JB ERR_RET
4317 MOV [EXT_K],AX
4318 MOV BX,AX
4319; DEC BX ; BX is MAX possible disk size
4320 CMP [DEV_SIZE],BX
4321 JBE AT002 ; DEV_SIZE OK
4322 MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available
4323AT002:
4324;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4325; 386 modification
4326 test [sys_flg],M_386
4327 je loadall_setup
4328 mov ax,cs
4329 mov word ptr [cod_seg],ax
4330; set cs descriptor
4331 mov cx,16
4332 mul cx
4333 mov si,offset cs_des
4334 mov [si].bas_0_15,ax
4335 mov [si].bas_16_23,dl
4336 mov [si].bas_24_31,dh
4337; set gdt base
4338 mov si,offset emm_gdt
4339 add ax,offset start_gdt
4340 adc dx,0
4341 mov [si].gdt_base_0,ax
4342 mov [si].gdt_base_2,dx
4343 jmp common_setup
4344;
4345loadall_setup:
4346 ;
4347 ; Init various pieces of LOADALL info
4348 ;
4349;;;; SMSW [LDSW]
4350;;;; SIDT QWORD PTR [IDTDES]
4351;;;; SGDT QWORD PTR [GDTDES]
4352;;;; ;
4353;;;; ; NOW The damn SXXX instructions store the desriptors in a
4354;;;; ; different order than LOADALL wants
4355;;;; ;
4356;;;; MOV SI,OFFSET IDTDES
4357;;;; CALL FIX_DESCRIPTOR
4358;;;; MOV SI,OFFSET GDTDES
4359;;;; CALL FIX_DESCRIPTOR
4360 MOV [LCSS],CS
4361 MOV SI,OFFSET CSDES
4362 MOV AX,CS
4363 CALL SEG_SET
4364common_setup:
4365 CALL MM_SETDRIVE
4366 RET
4367;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4368;;* UpperMemCheck - Called by 6300 PLUS to verify existence of
4369;; upper extended memory of 384K at FA0000h
4370;;
4371;; Returns carry set if no upper extended memory.
4372;;
4373;; This routine is called only by a 6300 PLUS, and
4374;; it reads the hardware switch DSW2 to do the job.
4375;;
4376UpperMemCheck:
4377 push ax
4378 in al,66h
4379 and al,00001111b
4380 cmp al,00001011b
4381 pop ax
4382 jnz nomem
4383 clc
4384 ret
4385nomem:
4386 stc
4387 ret
4388
4389
4390
4391BREAK </A INIT Code>
4392
4393;** EMM device driver name
4394;
4395; The following datum defines the Above Board EMM 8 character
4396; device driver name that is looked for as part of TYPE 2
4397; specific initialization.
4398;
4399; This datum is specific to TYPE 2 drivers
4400;
4401
4402ABOVE_DEV_NAME DB "EMMXXXX0"
4403
4404;** ABOVE_INIT - Perform /A (TYPE 2) specific initialization
4405;
4406; This code performes the driver specific initialization for
4407; type 2 drivers.
4408;
4409; Swap ABOVE_BLKMOV code in for TYPE 1 code at BLKMOV
4410; Swap ABOVE_RESET code in for TYPE 1 code at RESET_SYSTEM
4411; Check to make sure EMM Above Board device driver is installed
4412; by looking for device name relative to INT 67H segment
4413; address. This is method 2 described on page 36 and 37
4414; of the Expanded Memory Manager Programming Specification.
4415;
4416; WARNING! If run on a version of DOS where all INT vectors
4417; are managed by the kernel, or on a system where some
4418; foreign program (not EMM.SYS) is also using INT 67H, this
4419; method will fail to find the EMM device driver.
4420; The reason this method was used rather than the more portable
4421; method 1 described on pages 33 and 34 of the EMM Programming
4422; Specification is that the DOS Installable Device Driver
4423; document makes a statement about which DOS system calls
4424; may be made in a device initialization routine, and
4425; OPEN, IOCTL, and CLOSE are not included in the allowed
4426; set. Adherance to the Installable Device Driver document,
4427; therefore, excludes the use of method 1.
4428;
4429; Check the EMM device status
4430; Get the EMM map window address and set BASE_ADDR
4431; Get the available Above Board memory
4432; Adjust DEV_SIZE to be consistent with the available memory if needed,
4433; and also round DEV_SIZE up so that it is a multiple of the 16K
4434; granularity of the Above Board memory.
4435; Allocate DEV_SIZE worth of Above Board memory and set ABOVE_PID.
4436; After this point we can use CTRL_IO and/or BLKMOV to
4437; read/write the memory we have allocated.
4438; Install the INT 9 and INT 19 code by calling SET_RESET with BX = 0.
4439; Adjust the TERM_ADDR set by SET_RESET to a more appropriate size.
4440; Call CHECK_DOS_VOL to look for a DOS volume and set INIT_DRIVE.
4441; IF INIT_DRIVE indicates that a DOS volume was found
4442; Check to make sure that the size of the found DOS
4443; volume is consistent with DEV_SIZE.
4444; IF it is not
4445; Set INIT_DRIVE to 2 to indicate that the found volume
4446; is invalid and needs to be re-initialized.
4447;
4448; SEE ALSO
4449; INTEL Expanded Memory Manager Programming Specification
4450;
4451; ENTRY:
4452; Invokation line parameter values set.
4453; EXIT:
4454; ABOVE_BLKMOV code swapped in at BLKMOV
4455; ABOVE_RESET code swapped in at RESET_SYSTEM
4456; CARRY SET
4457; Error, message already printed. Driver not installed.
4458; No Above Board memory allocated.
4459; CARRY CLEAR
4460; BASE_ADDR set to segment address of Above Board map window
4461; ABOVE_PID contains PID of allocated above board memory
4462; DEV_SIZE set to TRUE size
4463; INIT_DRIVE set appropriatly
4464; TERM_ADDR set to correct device end.
4465; RESET_SYSTEM code and INT 9/INT 19 code included.
4466;
4467; USES:
4468; ALL but DS
4469;
4470; Code is specific to TYPE 2 driver
4471;
4472
4473ABOVE_INIT:
4474ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
4475 ;
4476 ; Swap above code into place
4477 ;
4478 PUSH CS
4479 POP ES
4480 MOV SI,OFFSET ABOVE_CODE
4481 MOV DI,OFFSET DRIVE_CODE
4482 MOV CX,OFFSET DRIVE_END - OFFSET DRIVE_CODE
4483 REP MOVSB
4484 MOV SI,OFFSET ABOVE_RESET
4485 MOV DI,OFFSET RESET_SYSTEM
4486 MOV CX,OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM
4487 REP MOVSB
4488 ;
4489 ; Check for presence of Above board memory manager
4490 ;
4491 MOV AX,(Get_Interrupt_Vector SHL 8) OR 67H
4492 INT 21H
4493 MOV DI,SDEVNAME
4494 MOV SI,OFFSET ABOVE_DEV_NAME
4495 MOV CX,8
4496 REPE CMPSB
4497 JZ GOT_MANAGER
4498 MOV DX,OFFSET NO_ABOVE
4499ABOVE_ERR:
4500 CALL PRINT
4501 STC
4502 RET
4503
4504GOT_MANAGER:
4505 ;
4506 ; Check memory status
4507 ;
4508 MOV CX,8000H
4509STLOOP:
4510 MOV AH,ABOVE_STATUS
4511 INT 67H
4512 CMP AH,ABOVE_SUCCESSFUL
4513 JZ MEM_OK
4514 CMP AH,ABOVE_ERROR_BUSY
4515 LOOPZ STLOOP
4516ST_ERR:
4517 MOV DX,OFFSET BAD_ABOVE
4518 JMP ABOVE_ERR
4519
4520MEM_OK:
4521 ;
4522 ; Get base address of map region and set BASE_ADDR
4523 ;
4524 MOV AH,ABOVE_GET_SEG
4525 INT 67H
4526 CMP AH,ABOVE_ERROR_BUSY
4527 JZ MEM_OK
4528 CMP AH,ABOVE_SUCCESSFUL
4529 JNZ ST_ERR
4530 MOV WORD PTR [BASE_ADDR],0
4531 MOV WORD PTR [BASE_ADDR + 2],BX
4532 ;
4533 ; Allocate drive memory
4534 ;
4535GET_AVAIL:
4536 MOV AH,ABOVE_GET_FREE
4537 INT 67H
4538 CMP AH,ABOVE_ERROR_BUSY
4539 JZ GET_AVAIL
4540 CMP AH,ABOVE_SUCCESSFUL
4541 JNZ ST_ERR
4542 MOV AX,DX ; AX is total 16K pages
4543 ; BX is un-allocated 16K pages
4544 MOV DX,OFFSET NO_MEM
4545 OR AX,AX
4546 JZ ABOVE_ERR
4547 MOV DX,OFFSET ERRMSG2
4548 OR BX,BX ; 16k is min Ramdrive
4549 JZ ABOVE_ERR
4550 TEST BX,0F000H
4551 JNZ AB001 ; Avialable K is REAL big
4552 MOV CX,4
4553 SHL BX,CL ; BX is un-allocated K
4554 CMP [DEV_SIZE],BX
4555 JBE AB001 ; DEV_SIZE OK
4556 MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available
4557AB001:
4558 MOV BX,[DEV_SIZE]
4559 ;
4560 ; BX is K we want to allocate (limited by available K)
4561 ; BX is at least 16
4562 ;
4563 MOV AX,BX
4564 MOV CX,4 ; Convert back to # of 16K pages
4565 SHR BX,CL
4566 TEST AX,0FH ; Even????
4567 JZ OKAYU ; Yes
4568 INC BX ; Gotta round up
4569 PUSH BX
4570 MOV CX,4
4571 SHL BX,CL
4572 MOV [DEV_SIZE],BX ; Correct dev size too by rounding it up to
4573 ; next multiple of 16K, no sense wasting
4574 ; part of a page.
4575 POP BX
4576OKAYU:
4577 MOV AH,ABOVE_ALLOC
4578 INT 67H
4579 CMP AH,ABOVE_ERROR_BUSY
4580 JZ OKAYU
4581 CMP AH,ABOVE_SUCCESSFUL
4582 JZ GOT_ID
4583 CMP AH,ABOVE_ERROR_MAP_CNTXT
4584 JZ ST_ERRJ
4585 CMP AH,ABOVE_ERROR_OUT_OF_PIDS
4586 JB ST_ERRJ
4587 MOV DX,OFFSET ERRMSG2
4588 JMP ABOVE_ERR
4589
4590ST_ERRJ:
4591 JMP ST_ERR
4592
4593GOT_ID:
4594 MOV [ABOVE_PID],DX
4595 ;
4596 ; INSTALL ABOVE RESET handler
4597 ;
4598 XOR BX,BX
4599 CALL SET_RESET
4600 ;
4601 ; The above RESET_SYSTEM handler is real small, and since we include it in
4602 ; EACH driver, we make sure the size is minimal
4603 ;
4604 MOV WORD PTR [TERM_ADDR],OFFSET RESET_SYSTEM + (OFFSET ABOVE_RESET_END - OFFSET ABOVE_RESET)
4605 ;
4606 ; We are now in good shape. Can call BLKMOV to read drive
4607 ;
4608 CALL CHECK_DOS_VOL ; Snoop for DOS volume
4609 JNC DOUBLE_CHECK
4610 CALL DISK_ABORT
4611 STC
4612 RET
4613
4614DOUBLE_CHECK:
4615 CMP [INIT_DRIVE],0
4616 JNZ RETAB ; No DOS volume found
4617 ;
4618 ; We MUST check to see if the FOUND DOS volume is consistent
4619 ; with DEV_SIZE.
4620 ;
4621 MOV AX,[SECLIM]
4622 MUL [SSIZE] ; DX:AX is size of volume in bytes
4623 MOV CX,1024
4624 DIV CX ; AX is size in K
4625 CMP AX,[DEV_SIZE]
4626 JE RETAB ; Volume is OK
4627RE_INIT:
4628 MOV [INIT_DRIVE],2 ; Force re-compute of volume
4629RETAB:
4630 CLC
4631 RET
4632
4633BREAK <Drive code for /A driver. Swapped in at BLKMOV>
4634
4635;
4636; This label defines the start of the code swapped in at DRIVE_CODE
4637;
4638ABOVE_CODE LABEL WORD
4639
4640;
4641; WARNING DANGER!!!!!!!
4642;
4643; This code is tranfered over the /E driver code at DRIVE_CODE
4644;
4645; ALL jmps etc. must be IP relative.
4646; ALL data references must be to cells at the FINAL, TRUE location
4647; (no data cells may be named HERE, must be named up at BLKMOV).
4648; OFFSET of ABOVE_BLKMOV relative to ABOVE_CODE MUST be the same as
4649; the OFFSET of BLKMOV relative to DRIVE_CODE.
4650; SIZE of stuff between ABOVE_CODE and ABOVE_END MUST be less than
4651; or equal to size of stuff between DRIVE_CODE and DRIVE_END.
4652
4653IF2
4654 IF((OFFSET ABOVE_BLKMOV - OFFSET ABOVE_CODE) NE (OFFSET BLKMOV - OFFSET DRIVE_CODE))
4655 %out ERROR BLKMOV, ABOVE_BLKMOV NOT ALIGNED
4656 ENDIF
4657 IF((OFFSET ABOVE_END - OFFSET ABOVE_CODE) GT (OFFSET DRIVE_END - OFFSET DRIVE_CODE))
4658 %out ERROR ABOVE CODE TOO BIG
4659 ENDIF
4660ENDIF
4661
4662 DD ? ; 24 bit address of start of this RAMDRV
4663;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4664;** ABOVE_BLKMOV - Perform transfer for TYPE 2 driver
4665;
4666; This routine is the transfer routine for moving bytes
4667; to and from the Above Board memory containing the cache.
4668;
4669; The Above Board is implemented as 4 16K windows into the Above
4670; Board memory, giving a total window of 64K wich starts on some
4671; 16K boundary of the Above Board memory. Given that a DOS I/O
4672; request is up to 64K bytes starting on some sector boundary,
4673; the most general I/O picture is:
4674;
4675; |------------|------------|------------|------------|------------|
4676; | Above Brd | Above Brd | Above Brd | Above Brd | Above Brd |
4677; |Log page n |Log page n+1|Log page n+2|log page n+3|Log page n+4|
4678; |------------|------------|------------|------------|------------|
4679; |---|---| | |
4680; | | |---------------- 64K bytes of sectors -------------|
4681; Byte | | |
4682; offset|------------------|------------------------| |
4683; of first| Number of words in | |
4684; byte of | first part of I/O that |---|---|
4685; I/O in | can be performed once Number
4686; first | logical pages n - n+3 of words
4687; Log page| are mapped into physical in tail
4688; | pages 0 - 3 part of I/O
4689; Location of that have
4690; first byte to be done
4691; of sector M, once logical
4692; the start sector page n+4 is
4693; of the I/O mapped into
4694; physical page
4695; 0
4696;
4697; One or both of "Byte offset of first byte of I/O in first page" and
4698; "Number of words in tail part of I/O" may be zero depending on the
4699; size of the I/O and its start offset in the first logical page it is
4700; possible to map.
4701;
4702; WARNING: IF A PRE-EMPTIVE MULTITASKING SYSTEM SCHEDULES A TASK WHICH
4703; IS USING THE ABOVE BOARD DURING THE TIME THIS DRIVER IS IN THE
4704; MIDDLE OF PERFORMING AN I/O, THE SYSTEM HAD BETTER MANAGE THE A
4705; BOARD MAPPING CONTEXT CORRECTLY OR ALL SORTS OF STRANGE UNPLEASANT
4706; THINGS WILL OCCUR.
4707;
4708; SEE ALSO
4709; INTEL Expanded Memory Manager Programming Specification
4710;
4711; ENTRY:
4712; ES:DI is packet transfer address.
4713; CX is number of words to transfer.
4714; DX:AX is 32 bit start byte offset (0 = start of cache)
4715; BH is 1 for WRITE, 0 for READ
4716;
4717; BASE_ADDR set to point to Above Board mapping window in main memory
4718; This "input" is not the responsibility of the caller. It
4719; is up to the initialization code to set it up when the
4720; device is installed
4721;
4722; EXIT:
4723; Carry Clear
4724; OK, operation performed successfully
4725; Carry Set
4726; Error during operation, AL is error number
4727;
4728; USES:
4729; ALL
4730;
4731; This routine is specific to TYPE 2 driver
4732;
4733; sunilp - note that this has one limitation. in the case where
4734; one is using the above board for ramdrive and for
4735; the buffer then one is limited to 32k byte transfers
4736;
4737; tonyg - above limitation removed - now handles 64kb transfers
4738; which can overlap the page frame
4739;
4740above_blkmov:
4741assume ds:ramcode,es:nothing,ss:nothing
4742;
4743; save mapping context and return with error if save fails
4744;
4745 save_mapping_context
4746 jnc ab_blk$1
4747 ret
4748;
4749; find logical page number, offset of i/o in first page
4750;
4751ab_blk$1:
4752 push cx
4753 mov cx,1024*16 ; 16k bytes / page
4754 div cx ; dx:ax / 16k --> log page numb in ax
4755 ; --> offset of i/o in dx
4756 mov si,dx ; transfer offset to si
4757 mov dx,ax ; store the page number in dx
4758 pop cx
4759;
4760; find case and dispatch accordingly
4761;
4762; case 0 : user buffer below page map, can use aaron's code
4763; case 1 : user buffer above page map, can use aaron's code
4764; case 2 : user buffer partly/totally in page map, use pai's code
4765;
4766 push bx
4767 push cx
4768;
4769; if( final_user_off < pm_base_addr ) then case 0
4770;
4771 mov ax,di ; get user buffer initial offset into ax
4772 add ax,1 ; round up (add to get carry)
4773 rcr ax,1 ; convert to word offset
4774 dec cx ; convert word count to 0 based number
4775 add ax,cx ; user buffer final word offset
4776 shr ax,1 ; convert to segment
4777 shr ax,1 ;
4778 shr ax,1 ;
4779 mov bx,es ; get segment of buffer
4780 add ax,bx ; now we have the last segment of the user buffer
4781 ; with offset < 16
4782 sub ax,word ptr [base_addr+2] ; compare against page map
4783 jc aar_cd ; if end below page map then execute old code
4784;
4785; if( initial_user_off < pm_base_addr ) then case 2
4786;
4787 mov cx,4
4788 mov bp,di ; get initial segment in bp
4789 shr bp,cl ;
4790 add bp,bx ;
4791 sub bp,word ptr [base_addr +2]
4792 jc within_pm ; case 2
4793;
4794; if ( initial_user_off >= pm_end_addr ) then case1
4795;
4796 cmp bp,4*1024 ;
4797 jae aar_cd ; case 1
4798;
4799; case 2
4800;
4801within_pm: jmp new_code ; user buffer in page map
4802 ; so we need to execute new code
4803aar_cd:
4804 pop cx
4805 pop bx
4806;
4807; Referring back to the diagram given above the following routine is
4808; to take care of transfer of the most general case.
4809; What this routine does is break every I/O down into the above parts.
4810; The first or main part of the I/O is performed by mapping 1 to 4
4811; sequential logical pages into the 4 physical pages and executing one
4812; REP MOVSW. If the tail word count is non-zero then the fith sequential
4813; logical page is mapped into physical page 0 and another REP MOVSW is
4814; executed.
4815;
4816; METHOD:
4817; Break I/O down as described above into main piece and tail piece
4818; Map the appropriate number of sequential pages (up to 4)
4819; into the page window at BASE_ADDR to set up the main piece
4820; of the I/O.
4821; Set appropriate seg and index registers and CX to perform the
4822; main piece of the I/O into the page window
4823; REP MOVSW
4824; IF there is a tail piece
4825; Map the next logical page into physical page 0
4826; Reset the appropriate index register to point at phsical page 0
4827; Move tail piece word count into CX
4828; REP MOVSW
4829; Restore Above Board page mapping context
4830;
4831 XOR BP,BP ; No tail page
4832 PUSH BX
4833 ;
4834 ; DX is first page #, SI is byte offset of start of I/O in first page
4835 ;
4836 MOV AX,DX
4837 MOV BX,SI
4838 SHR BX,1 ; # Words in first 16k page which are not part
4839 ; of I/O
4840 PUSH CX
4841 ADD BX,CX ; # of words we need to map to perform I/O
4842 MOV DX,BX
4843 AND DX,1FFFH ; DX is number of words to transfer last page
4844 ; remainder of div by words in 16K bytes
4845 MOV CL,13 ; Div by # words in 16K
4846 SHR BX,CL ; BX is number of pages to map (may need round up)
4847 OR DX,DX ; Remainder?
4848 JZ NO_REM
4849 INC BX ; Need one more page
4850NO_REM:
4851 MOV CX,BX ; CX is total pages we need to map
4852 MOV BX,AX ; BX is first logical page
4853 CMP CX,4 ; We can map up to 4 pages
4854 JBE NO_TAIL
4855 MOV BP,DX ; Words to move in tail page saved in BP
4856 DEC CX ; Need second map for the 5th page
4857 POP AX
4858 SUB AX,DX ; Words to move in first 4 pages is input
4859 ; word count minus words in tail page
4860 PUSH AX ; Count for first mapping back on stack
4861NO_TAIL:
4862 ; Map CX pages
4863 MOV DX,[ABOVE_PID]
4864 MOV AX,ABOVE_MAP SHL 8 ; Physical page 0
4865 PUSH AX
4866MAP_NEXT:
4867 POP AX ; Recover correct AX register
4868 PUSH AX
4869 PUSH BX
4870 PUSH DX
4871 INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX
4872 POP DX
4873 POP BX
4874 OR AH,AH
4875 JNZ MAP_ERR1 ; error
4876IF2
4877 IF (ABOVE_SUCCESSFUL)
4878 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
4879 ENDIF
4880ENDIF
4881NEXT_PAGE:
4882 INC BX ; Next logical page
4883 POP AX
4884 INC AL ; Next physical page
4885 PUSH AX
4886 LOOP MAP_NEXT
4887 POP AX ; Clean stack
4888 POP CX ; Word count for first page mapping
4889 POP AX ; Operation in AH
4890 ;
4891 ; BX has # of next logical page (Tail page if BP is non-zero)
4892 ; BP has # of words to move in tail page (0 if no tail)
4893 ; CX has # of words to move in current mapping
4894 ; SI is offset into current mapping of start of I/O
4895 ; AH indicates READ or WRITE
4896 ;
4897 PUSH AX ; Save op for possible second I/O
4898 OR AH,AH
4899 JZ READ_A
4900 ;
4901 ; WRITE
4902 ;
4903 PUSH ES
4904 PUSH DI
4905 MOV DI,SI ; Start page offset to DI
4906 POP SI ; DS:SI is transfer addr
4907 POP DS
4908ASSUME DS:NOTHING
4909 MOV ES,WORD PTR [BASE_ADDR + 2] ; ES:DI -> start
4910 JMP SHORT FIRST_MOVE
4911
4912READ_A:
4913ASSUME DS:ramcode
4914 MOV DS,WORD PTR [BASE_ADDR + 2] ; DS:SI -> start
4915ASSUME DS:NOTHING
4916FIRST_MOVE:
4917 REP MOVSW
4918 OR BP,BP ; Tail?
4919 JNZ TAIL_IO ; Yup
4920ALL_DONE:
4921 POP AX
4922 CLC
4923REST_CONT:
4924 ; Restore page mapping context
4925 PUSH AX ; Save possible error code
4926 PUSHF ; And carry state
4927REST_AGN:
4928 MOV DX,[ABOVE_PID]
4929 MOV AH,ABOVE_RESTORE_MAP_PID
4930 INT 67H
4931 OR AH,AH
4932 JZ ROK
4933IF2
4934 IF (ABOVE_SUCCESSFUL)
4935 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
4936 ENDIF
4937ENDIF
4938 CMP AH,ABOVE_ERROR_BUSY
4939 JZ REST_AGN
4940 CMP AH,ABOVE_ERROR_NO_CNTXT
4941 JZ ROK ; Ignore the invalid PID error
4942 POP DX
4943 POP DX ; Clean stack
4944 MOV AL,0cH ; General failure
4945 STC
4946 RET
4947
4948ROK:
4949 POPF ; Recover carry state
4950 POP AX ; and possible error code
4951 RET
4952
4953TAIL_IO:
4954 MOV DX,[ABOVE_PID]
4955MAP_AGN:
4956 MOV AX,ABOVE_MAP SHL 8 ; map logical page BX to phys page 0
4957 PUSH BX
4958 PUSH DX
4959 INT 67H ; Damn call ABOVE_MAP zaps BX,DX,AX
4960 POP DX
4961 POP BX
4962 OR AH,AH
4963 JNZ MAP_ERR2 ; Error
4964IF2
4965 IF (ABOVE_SUCCESSFUL)
4966 %out ASSUMPTION IN CODE THAT ABOVE_SUCCESSFUL = 0 IS INVALID
4967 ENDIF
4968ENDIF
4969SECOND_MOVE:
4970 POP AX ; Recover Op type
4971 PUSH AX
4972 OR AH,AH
4973 JZ READ_SEC
4974 ;
4975 ; WRITE
4976 ;
4977 XOR DI,DI ; ES:DI -> start of tail
4978 JMP SHORT SMOVE
4979
4980READ_SEC:
4981 XOR SI,SI ; DS:SI -> start of tail
4982SMOVE:
4983 MOV CX,BP
4984 REP MOVSW
4985 JMP ALL_DONE
4986
4987MAP_ERR1:
4988 CMP AH,ABOVE_ERROR_BUSY ; Busy?
4989 JZ MAP_NEXT ; Yes, wait till not busy (INTs are ON)
4990 ADD SP,6 ; Clean stack
4991 JMP SHORT DNR_ERR
4992
4993MAP_ERR2:
4994 CMP AH,ABOVE_ERROR_BUSY
4995 JZ MAP_AGN
4996 ADD SP,2
4997DNR_ERR:
4998 MOV AL,02H ; Drive not ready
4999 STC
5000 JMP REST_CONT
5001;
5002;
5003; this code has been written to handle te cases of overlapping usage
5004; of the above board page frame segment by the cache and user buffer
5005; assumption: in dos tracks cannot be more than 64 sectors long so
5006; in the worst case we shall have the user buffer occupying three
5007; pages is the page frame. we attempt to find the page that is
5008; available for the cache and use it repeatedly to access the cache
5009;
5010; above comment was for smartdrv. 128 sector reads are possible here
5011; see the kludge in step 2 and step 4 to handle this
5012
5013
5014;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5015; the algorithm is:
5016; ******************************************************
5017; [STEP1: determine the page we can use for the cache]
5018;
5019; if (initial_para_offset_user in page 1, 2 or 3 ) then {
5020; physical_cache_page = 0;
5021; cache_segment = above board segment;
5022; }
5023; else {
5024; physical_cache_page = 3;
5025; cache_segment = above_board_segment + 3*1024;
5026; }
5027;
5028; ******************************************************
5029; [STEP2: initial setup]
5030;
5031; count = user_count_requested;
5032; number_to_be_transferred = min ( count, (16K - si) >> 2 );
5033; exchange source and destination if necessary;
5034;
5035; *******************************************************
5036; [STEP3: set up transfer and do it]
5037;
5038; count = count - number_to_be_transferred;
5039; map_page cache_handle,physical_cache_page,logical_cache_page
5040; mov data
5041;
5042; *******************************************************
5043; [STEP4: determine if another transfer needed and setup if so]
5044;
5045; if ( count == 0 ) then exit;
5046; if ( operation == read ) then source_offset = 0;
5047; else dest_offset = 0;
5048; number_to_be_transferred = min ( count, 8*1024 );
5049; logical_page_number++ ;
5050;
5051; *******************************************************
5052; [STEP5: go to do next block]
5053;
5054; goto [STEP3]
5055;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5056;
5057new_code:
5058 assume ds:ramcode,es:nothing,ss:nothing
5059;
5060; input parameters:
5061;
5062; bp : start para offset of user buffer from start of physical page frame
5063; ax : end para offset of user buffer in physical page frame
5064; di : transfer offset of user buffer
5065; es : transfer segment of user buffer
5066; dx : logical page number in cache
5067; si : offset from start in logical page number
5068;
5069; on stack { cx,bx } where cx = number of words, bx = read / write status
5070;
5071; [STEP1: finding physical cache page and page frame]
5072;
5073 ;
5074 ; assume is physical page 0
5075 ;
5076 xor al, al ; use page 0 for cache
5077 mov bx,word ptr [base_addr+2]
5078 ;
5079 ; see if this assumption valid
5080 ;
5081 cmp bp, 4*1024 ; base is below start of page frame
5082 jae ab$300
5083 cmp bp,1024 ; is initial in page 1 or above
5084 jae ab$30 ; if so or assumption is valid
5085 ;
5086 ; else we have to correct our assumption
5087 ;
5088ab$300:
5089 mov al, 3 ; use page 3 for cache
5090 add bx, 3*1024 ; segment of page 3
5091 ;
5092 ; initialise page frame segment
5093 ;
5094ab$30:
5095 add bp, 2*1024 ; base of second transfer
5096 mov cx, bp
5097 mov ds,bx
5098 ;
5099assume ds:nothing
5100;
5101; [STEP2: initialising transfer parameters]
5102;
5103 ;
5104 pop bp ; bp will have count of words left to be transferred
5105 pop bx ; read / write status
5106;
5107; kludged to handle 64k byte transfers
5108;
5109 push cx ; base of second transfer
5110 ;
5111 ; initialise the number of words needed for a second transfer to 0
5112 ;
5113 xor cx,cx ;
5114 ;
5115 ; compare the number to be transferred to 16k words. any more than this
5116 ; will have to be done in the second transfer
5117 ;
5118 cmp bp,16*1024 ; more than 16k word transfers
5119 jbe ab$301 ; if not cx is fine
5120 mov cx,bp ; else cx = number of words - 16*1024
5121 mov bp,16*1024 ; and bp = 16*1024
5122 sub cx,bp ;
5123ab$301:
5124 ;
5125 ; store this on stack
5126 ;
5127 push cx
5128;
5129; end of kludge in step 2
5130;
5131 push bx ; save it back again
5132 push dx ; save this too
5133 ;
5134 ; initially si offset into logical page, so we can only do 16*1024 - si
5135 ; byte transfer
5136 ;
5137 mov cx,16*1024
5138 sub cx,si
5139 shr cx,1 ; convert to word count
5140 ;
5141 ; number to be transferred is the minimum of this and the user requested
5142 ; count
5143 ;
5144 cmp cx,bp
5145 jb ab$31
5146 mov cx,bp
5147 ;
5148ab$31:
5149 ;
5150 ; see if write, then we have to switch source with destination
5151 ;
5152 or bh,bh
5153 je ab$32 ; if read we don't have to do anything
5154 ; else we have to switch
5155 src_dest_switch
5156ab$32:
5157 ;
5158 ; set direction flag so that we don't have to do it repeatedly
5159 ;
5160 cld
5161;
5162; [STEP3: set up transfer and do it]
5163;
5164ab$33:
5165 ;
5166 ; update count of words still left to be transferred after this
5167 ;
5168 sub bp,cx
5169 ;
5170 ; map the logical page in cache to the physical page selected
5171 ;
5172 mov bx,dx ; get logical page into bx
5173 ; al already holds the physical page #
5174 map_page
5175 jnc ab$34 ; suceeded ?
5176 ;
5177 ; else report error
5178 ;
5179 add sp,6
5180 stc
5181 jmp restore_mp ; and go to restore page map
5182ab$34:
5183 ;
5184 ; succeeded, do the transfer
5185 ;
5186rep movsw
5187 ;
5188;
5189; [STEP4: check if transfer done, if not set up for next block]
5190; [STEP5: go back to STEP3]
5191 ;
5192 ; check if done
5193 ;
5194 or bp,bp ; count 0
5195 je ab$40 ; yes, go to finish up
5196 ;
5197 ; recover original dx and bx, increment dx and then save both again
5198 ;
5199 pop dx
5200 pop bx
5201 inc dx
5202 push bx
5203 push dx
5204 ;
5205 ; words to be transferred minimum of count and 8*1024 words
5206 ;
5207 mov cx,8*1024 ; 8k words in a page
5208 cmp cx,bp ;
5209 jbe ab$35 ; if below or equal this is what we want
5210 ;
5211 mov cx,bp ; else we can transfer the whole count
5212ab$35:
5213 ;
5214 ; see whether cache src or dest and accordingly reset either si or di
5215 ;
5216 or bh,bh ; read?
5217 jne ab$36 ; if write go to modify
5218 ;
5219 ; read, zero si and go back to step3
5220 ;
5221 xor si,si
5222 jmp short ab$33 ; to step 3
5223ab$36:
5224 ;
5225 ; write, zero di and go back to step3
5226 ;
5227 xor di,di
5228 jmp short ab$33 ; to step 3
5229;
5230; finishing up we have to restore the page map
5231;
5232ab$40:
5233;
5234; also kludged to handle 64k byte transfers
5235;
5236 pop dx
5237 pop bx
5238 pop bp ; number of words for second transfer
5239 pop ax ; base of second transfer
5240 or bp,bp ; are we done?
5241 jne ab$407 ; no, we have to do another transfer
5242 jmp ab$405 ; yes we can go to finish up
5243ab$407: ; apologies for such abominations
5244 push ax ; dummy transfer base
5245 xor cx, cx
5246 push cx ; zero count for next time
5247;
5248; restore the mapping context
5249;
5250 clc
5251 push dx ; dx is destroyed by restore mapping context
5252 restore_mapping_context
5253 pop dx ;
5254 jnc ab$401
5255;
5256; error we should quit here
5257;
5258 add sp, 4 ; throw base & count
5259 ret
5260;
5261; we need to save the mapping context again
5262;
5263ab$401:
5264 save_mapping_context
5265 jnc ab$406 ; if we couldn't save it then error
5266 add sp, 4
5267 ret
5268;
5269; reset physical page to be mapped to 0 and ds or es to page map base
5270; and increment logical page if we have si = 0 (read) or di=0 (write)
5271;
5272ab$406:
5273 mov cx, word ptr [base_addr+2]
5274 cmp ax, 1024 ; new base in page 0?
5275 jb ab$4060
5276 cmp ax, 4*1024
5277 jae ab$4060
5278 xor ax, ax
5279 jmp short ab$4061
5280ab$4060:
5281 mov al, 3
5282 add cx, 3*1024
5283ab$4061:
5284 or bh,bh ; read or write?
5285 jne ab$402 ; if write branch
5286;
5287 ;
5288 ; read, reset ds to base address
5289 ;
5290 mov ds,cx
5291 mov cx,16*1024 ;
5292 cmp si, cx ; at end of page?
5293 jbe ab$4030
5294 inc dx
5295 xor si, si
5296ab$4030:
5297 sub cx,si
5298 shr cx,1
5299
5300ab$403:
5301 push bx ; save these
5302 push dx
5303;
5304 cmp cx,bp ; is the cx appropriate
5305 jbe ab$404 ; if yes go to do transfer
5306 mov cx,bp ; else cx <--- bp
5307ab$404:
5308 jmp ab$33 ; and go to do transfer
5309;
5310ab$402:
5311 ;
5312 ; write, reset es to base address
5313 ;
5314 mov es,cx
5315 mov cx,16*1024
5316 cmp di, cx
5317 jb ab$4020
5318 xor di, di
5319 inc dx
5320ab$4020:
5321 sub cx,di
5322 shr cx,1
5323 jmp short ab$403
5324;
5325; add sp,4
5326ab$405:
5327 clc
5328restore_mp:
5329 restore_mapping_context
5330 ret
5331
5332 DW ? ; SPACE for ABOVE_PID
5333
5334;
5335; This label defines the end of the code swapped in at DRIVE_CODE
5336;
5337ABOVE_END LABEL WORD
5338
5339BREAK <Drive code for /A driver. Swapped in at RESET_SYSTEM>
5340
5341
5342;
5343; WARNING DANGER!!!!!!!
5344;
5345; This code is tranfered over the /E driver code at RESET_SYSTEM
5346;
5347; ALL jmps etc. must be IP relative.
5348; ALL data references must be to cells at the FINAL, TRUE location
5349; (no data cells may be named HERE, must be named up at RESET_SYSTEM).
5350; SIZE of stuff between ABOVE_RESET and ABOVE_RESET_END MUST be less than
5351; or equal to size of stuff between RESET_SYSTEM and RESET_INCLUDE.
5352;
5353; NOTE: EACH ABOVE BOARD driver has an INT 19 and 9 handler. This is
5354; different from /E and RESMEM in which only the first
5355; driver has an INT 19 and 9 handler.
5356;
5357
5358IF2
5359 IF((OFFSET ABOVE_RESET_END - OFFSET ABOVE_RESET) GT (OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM))
5360 %out ERROR ABOVE_RESET CODE TOO BIG
5361 ENDIF
5362ENDIF
5363
5364;** ABOVE_RESET perform TYPE 2 (/A) driver specific reboot code
5365;
5366; This code issues an ABOVE_DEALLOC call for the memory
5367; associated with this particular TYPE 2 RAMDrive since the
5368; system is being re-booted and the driver is "gone".
5369;
5370; ENTRY
5371; NONE
5372; EXIT
5373; NONE
5374; USES
5375; NONE
5376;
5377; This code is specific to TYPE 2 drivers
5378;
5379
5380ABOVE_RESET:
5381ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5382 PUSH AX
5383 PUSH DX
5384AGAIN_RESET:
5385 MOV DX,[ABOVE_PID]
5386 MOV AH,ABOVE_DEALLOC ; Close PID
5387 INT 67H
5388 CMP AH,ABOVE_ERROR_BUSY
5389 JZ AGAIN_RESET
5390 POP DX
5391 POP AX
5392 RET
5393
5394;
5395; This label defines the end of the code swapped in at RESET_SYSTEM
5396;
5397ABOVE_RESET_END LABEL BYTE
5398
5399BREAK <RESMEM INIT Code>
5400
5401;** RESMEM specific data
5402;
5403; The following datums are specific to the RESMEM (TYPE 3
5404; or 4) drivers
5405;
5406; Specific to TYPE 3 or TYPE 4 drivers
5407;
5408
5409HIGH_SEG DW ? ; Segment addr of "end of memory" from INT 12
5410
5411RAMSEG DW 0 ; Segment addr of the start of RAMDrive memory.
5412 ; Basically a segment register version of
5413 ; BASE_ADDR
5414
5415CRTSEG EQU 0A000H ; Memory past this segment value is RESERVED
5416 ; Memory scan must stop here.
5417
5418
5419;** RESMEM_INIT - Perform RESMEM (TYPE 3 or 4) specific initialization
5420;
5421; This code performs the driver TYPE specific initialization for
5422; TYPE 3 and TYPE 4 drivers.
5423;
5424; Memory scan
5425; The method used by this code to "find" valid RAM between
5426; the "end of memory" as determined from the INT 12 memory
5427; size and CRTSEG is to look for memory which will correctly
5428; store data. It looks on 1K boundaries. If the first 2 words
5429; of a 1k block are good, it is assumed that the rest of the
5430; 1K block is good without explicitly checking it. The scan
5431; is interested only in the FIRST block it finds. If two
5432; separated (by invalid RAM) blocks of RAM exist in the
5433; above range, the second block WILL NOT be found.
5434; NOTE that this can be fooled by a bad memory chip in
5435; a block of RAM. In this case RAMDrive will use the
5436; memory up to the bad spot and ignore the rest.
5437; Also note that since 16K is the minimum RAMDrive
5438; size, and the EMM_CTRL sector takes 1k, a block
5439; of size < 17K results in an insufficient memory error.
5440;
5441; Since access to invalid RAM (RAM that isn't present)
5442; results in a parity error, the above scan must be done
5443; with parity checking disabled.
5444;
5445; Since the ROM BIOS memory initialization code and tests
5446; is only run on the memory indicated by INT 12, one of
5447; the things this code must do when it finds memory "above
5448; INT 12" is make sure all of the parity bits are set correctly.
5449; This is accomplished easily by just copying the memory to
5450; itself.
5451;
5452; The scan is NON-DESTRUCTIVE so that any data contained in
5453; the memory will not be destroyed.
5454;
5455; The result of this scan also makes the determination between
5456; a TYPE 3 and TYPE 4 RAMDrive. If memory is found, then we're
5457; TYPE 3. If no memory is found, then we're TYPE 4.
5458;
5459;
5460; RESMEM_BLKMOV code swapped in at BLKMOV
5461; RESMEM_RESET code swapped in at RESET_SYSTEM
5462; NOTE: This step is not needed for a TYPE 4 driver
5463; since TYPE 4 NEVER has an INT 9 or INT 19 handler,
5464; but it isn't harmful either, so we do it always.
5465; Issue INT 12 to get size of memory
5466; Convert INT 12 result to segment address of first byte after system
5467; memory.
5468; IF this segment address is equal to or grater than CRTSEG
5469; There cannot be any memory "above INT 12" so we are TYPE 4.
5470; Skip the memory scan since there is no memory to scan and
5471; go to the TYPE 4 init code at CASE1.
5472; Disable parity checking so access to non-existent RAM won't crash
5473; the system.
5474; Perform the memory scan. This starts at FOO and ends at HAVE_MEM
5475; if we find some valid memory, or at CASE1 if we don't.
5476; A word about the scan.
5477; There are two cases for valid RAM.
5478; 1.) Valid memory starts at the INT 12 address
5479; 2.) There is invalid RAM for a while, then valid RAM starts.
5480; The DX register is used to tell us what is going on. It is
5481; non-zero if we are skipping over invalid RAM looking for
5482; some valid RAM (case 2), or 0 is we have found some valid RAM
5483; (case 1, or case 2 after skipping invalid RAM) and are scanning
5484; to set parity and find the end of the valid RAM.
5485; RAMSEG is given the initial value of 0 to indicate we have not
5486; found the start of a valid block.
5487; When the scan is finished ENABLE_PARITY is called to turn parity
5488; checking back on.
5489; IF we have valid RAM and end at HAVE_MEM
5490; We are TYPE 3.
5491; RAMSEG contains the segment address of the start of the block
5492; BX is the segment address of the end of the block
5493; Subtract RAMSEG from BX to get size of region in paragraphs
5494; Convert size in Paragraphs to size in K
5495; Check that size is AT LEAST 17k (minimum size)
5496; Jump to GOT_RESMEM if OK else error
5497; Set EXT_K to size of block
5498; Adjust DEV_SIZE if bigger than EXT_K - 1 (-1 for EMM_CTRL)
5499; Convert RAMSEG to 32 bit address and set it into BASE_ADDR
5500; This sets BASE_ADDR to point to EMM_CTRL sector.
5501; Set BASE_RESET to BASE_ADDR plus 1024
5502; Call MM_SETDRIVE to complete TYPE 3 specific initialization
5503; ELSE we end up at CASE1
5504; We are TYPE 4.
5505; Set RESMEM_SPECIAL to indicate TYPE 4
5506; Set INIT_DRIVE to 2 (DOS volume MUST be initialized)
5507; Set BASE_ADDR to be the first para boundary after the resident
5508; code (which DOES NOT include INT 19/INT 9 code).
5509; Compute TERM_ADDR based on DEV_SIZE Kbytes of device starting at
5510; BASE_ADDR.
5511; NOTE: We must make sure the specified DEV_SIZE is reasonable:
5512; It must not be bigger than 10 bits (1 Meg)
5513; as this is the memory limit of the 8086.
5514; It must not be so big that there is less than 48k of system
5515; memory after the device is installed.
5516; This is checked by computing the segment address
5517; of the end of the device and comparing it to the
5518; INT 12 memory end address minus 48k worth of paragraphs
5519;
5520; ENTRY:
5521; Invokation line parameter values set.
5522; EXIT:
5523; RESMEM_BLKMOV code swapped in at BLKMOV
5524; RESMEM_RESET code swapped in at RESET_SYSTEM
5525; Determination of TYPE 3 or TYPE 4 made by setting RESMEM_SPECIAL
5526; if TYPE 4.
5527; CARRY SET
5528; Error, message already printed. Driver not installed.
5529; If TYPE 3
5530; EMM_CTRL not marked (but MAY be initialized if
5531; a valid one was not found).
5532; CARRY CLEAR
5533; DEV_SIZE set to TRUE size
5534; INIT_DRIVE set appropriatly
5535; IF TYPE 3
5536; BASE_ADDR set for this drive from EMM_BASE of EMM_REC
5537; BASE_RESET set from BASE_ADDR
5538; EMM_REC is marked EMM_ISDRIVER
5539; TERM_ADDR set to correct device end.
5540; RESET_SYSTEM code and INT 9/INT 19 code included,
5541; INT 19 and 9 vector patched if this is the first
5542; TYPE 3 RAMDrive in the system.
5543; IF TYPE 4
5544; BASE_ADDR set for this drive by computing address of
5545; start of memory after RAMDrive code.
5546; BASE_RESET set from BASE_ADDR
5547; TERM_ADDR set to correct device end which includes
5548; the memory taken up by the RAMDrive itself.
5549;
5550; USES:
5551; ALL but DS
5552;
5553; Code is specific to TYPE 3 and TYPE 4 drivers
5554;
5555
5556RESMEM_INIT:
5557ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
5558 ;
5559 ; Swap RESMEM code into place
5560 ;
5561 PUSH CS
5562 POP ES
5563 MOV SI,OFFSET RESMEM_CODE
5564 MOV DI,OFFSET DRIVE_CODE
5565 MOV CX,OFFSET DRIVE_END - OFFSET DRIVE_CODE
5566 REP MOVSB
5567 MOV SI,OFFSET RESMEM_RESET
5568 MOV DI,OFFSET RESET_SYSTEM
5569 MOV CX,OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM
5570 REP MOVSB
5571 ;
5572 ; We have THREE cases to contend with:
5573 ;
5574 ; 1. There is NO memory above the INT 12H switch setting.
5575 ; In this case we will use the user specified device
5576 ; size (within limits) to allocate some memory as part
5577 ; of the RAMDRIVE.SYS resident image.
5578 ; NOTE: This type of a RAMDrive will not live through a warm boot
5579 ;
5580 ; 2. There is memory immediately after the INT 12H memory size.
5581 ; We will check for a EMM_CTRL there etc.
5582 ;
5583 ; 3. There is memory after the INT 12H memory size, but not
5584 ; Immediately after.
5585 ; We will check for a EMM_CTRL there etc.
5586 ;
5587 INT 12H ; Get size of memory set on switches
5588
5589IF DEBUG
5590
5591 JMP SHORT DEB1
5592
5593DEB1MES DB 13,10,"INT 12 returned $"
5594
5595DEB1:
5596 PUSH CX
5597 PUSH DX
5598 PUSHF
5599 PUSH AX
5600 MOV DX,OFFSET DEB1MES
5601 CALL PRINT
5602 POP AX
5603 PUSH AX
5604 CALL ITOA
5605 POP AX
5606 POPF
5607 POP DX
5608 POP CX
5609ENDIF
5610
5611 MOV CL,6
5612 SHL AX,CL ; Convert to Segment register value
5613 MOV BX,AX ; Save in BX
5614 MOV [HIGH_SEG],AX ; And here
5615
5616;
5617;*****************************************************************************
5618; Ramdrives installed between int12 reported memory and crtseg (A000h) are
5619; no longer allowed because on several machines including the model 50/60
5620; and the Tandy AT clone this area is used for something else. The idea to
5621; install a ramdrive in system memory is bad anyway but we shall still support
5622; the installation of a ramdrive in low memory as part of the driver. isp
5623;
5624; **START OF CODE REMOVED
5625;
5626;
5627; CMP BX,CRTSEG
5628;
5629;IF DEBUG
5630; JB DEBX
5631; JMP CASE1
5632;DEBX:
5633;ELSE
5634; JAE CASE1 ; No memory to scan
5635;ENDIF
5636;
5637; IN AL,61H
5638; OR AL,20H ; Turn off parity interrupt
5639; JMP FOO ; 286 back to back IN OUT bug fix
5640;FOO: OUT 61H,AL
5641; ;
5642; ; SCAN memory
5643; ;
5644; XOR DI,DI
5645; MOV SI,DI
5646; MOV ES,BX ;Segment to scan for valid memory
5647; MOV DS,BX
5648;ASSUME DS:NOTHING
5649; CALL TEST_RAM
5650; JNZ NO_RAM
5651; ; We have case 2
5652;HAVE_START:
5653; XOR DX,DX ; DX = 0 means skipping memory
5654; MOV [RAMSEG],BX ; This is the start of our memory
5655;
5656;IF DEBUG
5657;
5658; JMP SHORT DEB2
5659;
5660;DEB2MES DB 13,10,"CASE 1 Ramseg $"
5661;
5662;DEB2:
5663; PUSH CX
5664; PUSH DX
5665; PUSHF
5666; PUSH AX
5667; MOV DX,OFFSET DEB2MES
5668; CALL PRINT
5669; MOV AX,[RAMSEG]
5670; CALL ITOA
5671; POP AX
5672; POPF
5673; POP DX
5674; POP CX
5675;ENDIF
5676;
5677; JMP SHORT NEXT_K
5678;
5679;NO_RAM:
5680; MOV DX,1 ; DX = 1 means skipping hole
5681; CMP [RAMSEG],0 ; If ramseg is NZ we are done,
5682; JZ NEXT_K ; have case 2 or 3
5683; CALL ENABLE_PARITY
5684;HAVE_MEM:
5685; ;
5686; ; Driver is TYPE 3
5687; ;
5688; SUB BX,[RAMSEG] ; BX is Para of RAMDRV region
5689; MOV CX,6
5690; SHR BX,CL ; BX is K in region
5691; CMP BX,17 ; Ik EMM_CTRL, 16k min ramdrive
5692;
5693;IF DEBUG
5694;
5695; JMP SHORT DEB3
5696;
5697;DEB3MESA DB 13,10,"CASE 3 Ramseg $"
5698;DEB3MESB DB " AVAIL K $"
5699;
5700;DEB3:
5701; PUSH CX
5702; PUSH DX
5703; PUSHF
5704; PUSH AX
5705; MOV DX,OFFSET DEB3MESA
5706; CALL PRINT
5707; MOV AX,[RAMSEG]
5708; CALL ITOA
5709; MOV DX,OFFSET DEB3MESB
5710; CALL PRINT
5711; MOV AX,BX
5712; CALL ITOA
5713; POP AX
5714; POPF
5715; POP DX
5716; POP CX
5717;ENDIF
5718;
5719; JB RES_NOMEMJ
5720; JMP GOT_RESMEM
5721;
5722;RES_NOMEMJ:
5723; JMP RES_NOMEM
5724;
5725;CONT_SCAN:
5726; XOR DI,DI
5727; MOV SI,DI
5728; MOV ES,BX ;Segment to scan for valid memory
5729; MOV DS,BX
5730; CALL TEST_RAM
5731; JNZ AT_DIS ;No, detected discontinuity
5732; OR DX,DX
5733; JZ NEXT_K
5734; JMP HAVE_START
5735;
5736;AT_DIS:
5737; OR DX,DX
5738; JZ NO_RAM
5739;NEXT_K:
5740; ADD BX,64 ; Next K
5741; CMP BX,CRTSEG
5742; JB CONT_SCAN
5743; CALL ENABLE_PARITY
5744; CMP [RAMSEG],0
5745; JNZ HAVE_MEM
5746;***END OF CODE REMOVED***
5747;*****************************************************************************
5748CASE1:
5749 ;
5750 ; Have CASE 1.
5751 ; Driver is TYPE 4
5752 ;
5753
5754IF DEBUG
5755
5756 JMP SHORT DEB4
5757
5758DEB4MES DB 13,10,"CASE 1$"
5759
5760DEB4:
5761 PUSH CX
5762 PUSH DX
5763 PUSHF
5764 PUSH AX
5765 MOV DX,OFFSET DEB4MES
5766 CALL PRINT
5767 POP AX
5768 POPF
5769 POP DX
5770 POP CX
5771ENDIF
5772
5773 PUSH CS
5774 POP DS
5775ASSUME DS:RAMCODE
5776 INC [RESMEM_SPECIAL] ; Flag SPECIAL case for INIDRV
5777 MOV [INIT_DRIVE],2 ; This type must ALWAYS be inited
5778 ;
5779 ; Compute BASE_ADDR to be right after DEVICE_END, NO INT 19/9 handler
5780 ;
5781 MOV AX,OFFSET DEVICE_END
5782 ADD AX,15 ; Para round up
5783 MOV CL,4
5784 SHR AX,CL ; # of para in RAMDrive resident code
5785 MOV DX,CS
5786 ADD AX,DX ; AX is seg addr of start of RAMDrive
5787 PUSH AX
5788 MOV CX,16
5789 MUL CX ; DX:AX is byte offset of that many paras
5790 MOV WORD PTR [BASE_ADDR],AX
5791 MOV WORD PTR [BASE_ADDR + 2],DX
5792 POP AX
5793 ;
5794 ; Compute correct ending address and set TERM_ADDR
5795 ; Check that there is at least 48k of system memory after device end
5796 ; AX is the segment address of the start of the device
5797 ;
5798 MOV DX,[DEV_SIZE] ; Get size in K
5799 ;
5800 ; DEV_SIZE can be at most a 10 bit number as that is 1 Meg, the memory
5801 ; limit on the 8086
5802 ;
5803 TEST DX,0FC00H ; If any of high 6 bits set, too big
5804 JNZ RES_NOMEM
5805 MOV CL,6
5806 SHL DX,CL ; DX is # of PARA in that many k
5807 ADD AX,DX ; AX is end seg addr
5808 JC RES_NOMEM ; Overflow
5809 ;
5810 ; Make sure at least 48K left after device
5811 ;
5812 MOV DX,[HIGH_SEG]
5813 SUB DX,0C00H ; 48K worth of PARAs left for system
5814
5815IF DEBUG
5816
5817 JMP SHORT DEB5
5818
5819DEB5MESA DB " Max end is $"
5820DEB5MESB DB " end is $"
5821
5822DEB5:
5823 PUSH CX
5824 PUSHF
5825 PUSH DX
5826 PUSH AX
5827 MOV DX,OFFSET DEB5MESA
5828 CALL PRINT
5829 POP DX
5830 POP AX
5831 PUSH AX
5832 PUSH DX
5833 CALL ITOA
5834 MOV DX,OFFSET DEB5MESB
5835 CALL PRINT
5836 POP AX
5837 PUSH AX
5838 CALL ITOA
5839 POP AX
5840 POP DX
5841 POPF
5842 POP CX
5843ENDIF
5844
5845 JC RES_NOMEM
5846 CMP AX,DX
5847 JA RES_NOMEM ; Too big
5848 MOV WORD PTR [TERM_ADDR],0
5849 MOV WORD PTR [TERM_ADDR + 2],AX
5850
5851IF DEBUG
5852
5853 JMP SHORT DEB6
5854
5855DEB6MES DB " OK term $"
5856
5857DEB6:
5858 PUSH CX
5859 PUSHF
5860 PUSH DX
5861 PUSH AX
5862 MOV DX,OFFSET DEB6MES
5863 CALL PRINT
5864 POP AX
5865 PUSH AX
5866 CALL ITOA
5867 POP AX
5868 POP DX
5869 POPF
5870 POP CX
5871ENDIF
5872 CLC
5873 RET
5874
5875RES_NOMEM:
5876ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5877 MOV DX,OFFSET ERRMSG2
5878 CALL PRINT
5879 PUSH CS
5880 POP DS
5881 STC
5882 RET
5883
5884GOT_RESMEM:
5885ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5886;
5887; Completion of TYPE 3 initialization.
5888; RAMSEG is start seg addr of ramdrv region, BX is its size in K
5889;
5890 PUSH CS
5891 POP DS
5892ASSUME DS:RAMCODE
5893 MOV [EXT_K],BX
5894 DEC BX ; BX is MAX possible disk size
5895 CMP [DEV_SIZE],BX
5896 JBE RES002 ; DEV_SIZE is OK
5897 MOV [DEV_SIZE],BX ; Limit DEV_SIZE to available K
5898RES002:
5899 MOV AX,[RAMSEG]
5900 MOV CX,16
5901 MUL CX
5902 MOV WORD PTR [BASE_ADDR],AX
5903 MOV WORD PTR [BASE_ADDR + 2],DX
5904 ADD AX,1024
5905 ADC DX,0
5906 MOV WORD PTR [BASE_RESET],AX
5907 MOV WORD PTR [BASE_RESET + 2],DX
5908 CALL MM_SETDRIVE
5909 RET
5910
5911
5912;** ENABLE_PARITY - Turn on parity checking of IBM PC AT XT
5913;
5914; This routine enables the memory parity checking on an IBM PC
5915; family machine
5916;
5917; ENTRY NONE
5918; EXIT NONE
5919; USES AL
5920;
5921; SEE ALSO
5922; IBM PC Technical Reference manual for any PC family member
5923;
5924; Code is specific to TYPE 3 and TYPE 4 drivers
5925;
5926
5927ENABLE_PARITY:
5928ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5929 IN AL,61H
5930 AND AL,NOT 20H ;Re-enable parity checking
5931 JMP BAR ; 286 back to back IN OUT bug fix
5932BAR: OUT 61H,AL
5933 RET
5934
5935
5936;** TEST_RAM - Check if valid RAM exists and reset parity if it does
5937;
5938; This routine checks for valid RAM is a 1k block by performing
5939; various tests on the first two words of the block. If the RAM
5940; is valid, the parity of the 1k block is set by copying the block
5941; to itself.
5942;
5943; TESTS
5944; See if first word will store its own compliment
5945; See if read first word writes out correctly (also resets first
5946; word to its original value)
5947; See if second word will store a fixed value "AR"
5948; On this test we wait a while between the store and
5949; the test to allow the buss to settle.
5950;
5951; ENTRY
5952; DS:SI = ES:DI -> a 1k region of RAM to be tested
5953; PARITY CHECKING DISABLED
5954; EXIT
5955; Zero set if RAM is valid
5956; Zero reset if RAM is invalid
5957; USES
5958; AX, SI, DI
5959;
5960; Code is specific to TYPE 3 and TYPE 4 drivers
5961;
5962
5963TEST_RAM:
5964ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
5965 LODSW ; See what's there
5966 NOT AX
5967 MOV [DI],AX ; See if memory can store complement
5968 CMP AX,[DI] ; Memory OK?
5969 JNZ RET007 ; Not valid RAM
5970 NOT AX
5971 STOSW ; Restore correct value
5972 CMP AX,[DI - 2] ; Memory OK?
5973 JNZ RET007 ; Not valid RAM
5974 LODSW ; Next word
5975 MOV WORD PTR [DI],"AR" ; Store fixed value
5976 NOP ; Wait
5977 NOP
5978 NOP
5979 NOP
5980 CMP WORD PTR [DI],"AR" ; Did it store?
5981 JNZ RET007 ; Not Valid RAM
5982 STOSW ; Restore correct value
5983 MOV CX,510 ; Copy to self to reset parity in this 1k block
5984 REP MOVSW
5985RET007:
5986 RET
5987
5988BREAK <Drive code for resmem driver. Swapped in at BLKMOV>
5989
5990;
5991; This label defines the start of the TYPE 3 and 4 code swapped
5992; in at BLKMOV
5993;
5994RESMEM_CODE LABEL WORD
5995
5996;
5997; WARNING DANGER!!!!!!!
5998;
5999; This code is tranfered over the /E driver code at DRIVE_CODE
6000;
6001; ALL jmps etc. must be IP relative.
6002; ALL data references must be to cells at the FINAL, TRUE location
6003; (no data cells may be named HERE, must be named up at BLKMOV).
6004; OFFSET of RESMEM_BLKMOV relative to RESMEM_CODE MUST be the same as
6005; the OFFSET of BLKMOV relative to DRIVE_CODE.
6006; SIZE of stuff between RESMEM_CODE and RESMEM_END MUST be less than
6007; or equal to size of stuff between DRIVE_CODE and DRIVE_END.
6008
6009IF2
6010 IF((OFFSET RESMEM_BLKMOV - OFFSET RESMEM_CODE) NE (OFFSET BLKMOV - OFFSET DRIVE_CODE))
6011 %out ERROR BLKMOV, RESMEM_BLKMOV NOT ALIGNED
6012 ENDIF
6013 IF((OFFSET RESMEM_END - OFFSET RESMEM_CODE) GT (OFFSET DRIVE_END - OFFSET DRIVE_CODE))
6014 %out ERROR RESMEM CODE TOO BIG
6015 ENDIF
6016ENDIF
6017
6018 DD ? ; 24 bit address of start of this RAMDRV
6019
6020;** RESMEM_BLKMOV - Perform transfer for TYPE 3 and 4 driver
6021;
6022; This routine is the transfer routine for moving bytes
6023; to and from a RAMDrive located in main memory.
6024;
6025; METHOD:
6026; Convert start address into segreg index reg pair
6027; Mov computed segreg index reg pairs into correct registers
6028; Execute REP MOVSW to perform transfer
6029;
6030; ENTRY:
6031; ES:DI is packet transfer address.
6032; CX is number of words to transfer.
6033; DX:AX is 32 bit start byte offset (0 = sector 0 of RAMDrive drive)
6034; BH is 1 for WRITE, 0 for READ
6035;
6036; BASE_ADDR set to point to start of RAMDrive memory
6037; This "input" is not the responsibility of the caller. It
6038; is up to the initialization code to set it up when the
6039; device is installed
6040;
6041; EXIT:
6042; Carry Clear
6043; OK, operation performed successfully
6044; Carry Set
6045; Error during operation, AL is error number
6046;
6047; USES:
6048; ALL
6049;
6050; This routine is specific to TYPE 3 and 4 drivers
6051;
6052
6053RESMEM_BLKMOV:
6054ASSUME DS:RAMCODE,ES:NOTHING,SS:NOTHING
6055
6056 ADD AX,WORD PTR [BASE_ADDR]
6057 ADC DX,WORD PTR [BASE_ADDR + 2]
6058 PUSH CX
6059 MOV CX,16
6060 DIV CX ; AX is seg reg value, DX is index register
6061 POP CX
6062 OR BH,BH
6063 JZ READ_ITR
6064 ;
6065 ; WRITE
6066 ;
6067 PUSH ES
6068 POP DS
6069ASSUME DS:NOTHING
6070 MOV SI,DI
6071 MOV ES,AX
6072 MOV DI,DX
6073TRANS:
6074 REP MOVSW
6075 CLC
6076 RET
6077
6078READ_ITR:
6079 MOV DS,AX
6080ASSUME DS:NOTHING
6081 MOV SI,DX
6082 JMP TRANS
6083
6084;
6085; This label defines the end of the RESMEM code swapped in at BLKMOV
6086;
6087RESMEM_END LABEL WORD
6088
6089BREAK <Drive code for resmem driver. Swapped in at RESET_SYSTEM>
6090
6091
6092;
6093; WARNING DANGER!!!!!!!
6094;
6095; This code is tranfered over the /E driver code at RESET_SYSTEM
6096;
6097; ALL jmps etc. must be IP relative.
6098; ALL data references must be to cells at the FINAL, TRUE location
6099; (no data cells may be named HERE, must be named up at RESET_SYSTEM).
6100; SIZE of stuff between RESMEM_RESET and RESMEM_RESET_END MUST be less than
6101; or equal to size of stuff between RESET_SYSTEM and RESET_INCLUDE.
6102
6103IF2
6104 IF((OFFSET RESMEM_RESET_END - OFFSET RESMEM_RESET) GT (OFFSET RESET_INCLUDE - OFFSET RESET_SYSTEM))
6105 %out ERROR RESMEM_RESET CODE TOO BIG
6106 ENDIF
6107ENDIF
6108
6109;** RESMEM_RESET perform TYPE 3 (RESMEM) driver specific reboot code
6110;
6111; This code performs the EMM_ISDRIVER reset function as described
6112; in EMM.ASM for all EMM_REC structures which are EMM_ALLOC and
6113; EMM_ISDRIVER and of type EMM_MSDOS.
6114;
6115; ENTRY
6116; NONE
6117; EXIT
6118; NONE
6119; USES
6120; NONE
6121;
6122; This code is specific to TYPE 3 drivers
6123;
6124
6125RESMEM_RESET:
6126ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
6127 PUSH SI
6128 PUSH DI
6129 PUSH AX
6130 PUSH BX
6131 PUSH CX
6132 PUSH DX
6133 PUSH DS
6134 PUSH ES
6135 PUSH CS
6136 POP DS
6137ASSUME DS:RAMCODE
6138 MOV AX,WORD PTR [BASE_ADDR]
6139 MOV DX,WORD PTR [BASE_ADDR + 2]
6140 SUB AX,1024 ; Point back to EMM block
6141 SBB DX,0
6142;
6143; NOTE: We can address the EMM block by just backing up
6144; by 1024 bytes from BASE_ADDR because the RESET_SYSTEM handler
6145; is in the FIRST RAMDrive driver
6146;
6147 MOV CX,16
6148 DIV CX ; AX is seg reg, DX is index reg
6149 MOV DS,AX
6150ASSUME DS:NOTHING
6151 MOV SI,DX ; DS:SI -> EMM_CTRL
6152 MOV DI,SI
6153 ADD DI,EMM_RECORD
6154 MOV CX,EMM_NUMREC
6155LOOK_RECRY:
6156 ;
6157 ; Scan EMM_CTRL for all ISDRIVER MS-DOS regions and turn off ISDRIVER
6158 ;
6159 TEST [DI.EMM_FLAGS],EMM_ALLOC
6160 JZ DONERY
6161 TEST [DI.EMM_FLAGS],EMM_ISDRIVER
6162 JZ NEXTRECRY ; No Driver
6163 CMP [DI.EMM_SYSTEM],EMM_MSDOS
6164 JNZ NEXTRECRY
6165 AND [DI.EMM_FLAGS],NOT EMM_ISDRIVER
6166NEXTRECRY:
6167 ADD DI,SIZE EMM_REC
6168 LOOP LOOK_RECRY
6169DONERY:
6170 POP ES
6171 POP DS
6172ASSUME DS:NOTHING
6173 POP DX
6174 POP CX
6175 POP BX
6176 POP AX
6177 POP DI
6178 POP SI
6179 RET
6180
6181;
6182; This label defines the end of the RESMEM code swapped in at RESET_SYSTEM
6183;
6184RESMEM_RESET_END LABEL BYTE
6185
6186BREAK <messages and common data>
6187
6188;** Message texts and common data
6189;
6190; Init data. This data is disposed of after initialization.
6191; it is mostly texts of all of the messages
6192;
6193; COMMON to TYPE 1,2,3 and 4 drivers
6194;
6195;
6196; translatable messages moved to message module (SP)
6197
6198 EXTRN NO_ABOVE:BYTE,BAD_ABOVE:BYTE,BAD_AT:BYTE,NO_MEM:BYTE
6199 EXTRN ERRMSG1:BYTE,ERRMSG2:BYTE,INIT_IO_ERR:BYTE,BADVERMES:BYTE
6200 EXTRN HEADERMES:BYTE,PATCH2X:BYTE,DOS_DRV:BYTE
6201 EXTRN STATMES1:BYTE,STATMES2:BYTE,STATMES3:BYTE
6202 EXTRN STATMES4:BYTE,STATMES5:BYTE
6203 db "RAMDrive is a trademark of Microsoft Corporation."
6204 db "This program is the property of Microsoft Corporation."
6205
6206VOLID DB 'MS-RAMDRIVE',ATTR_VOLUME_ID
6207 DB 10 DUP (0)
6208 DW 1100000000000000B ;12:00:00
6209 DW 0000101011001001B ;JUN 9, 1985
6210 DW 0,0,0
6211
6212SECTOR_BUFFER DB 1024 DUP(0)
6213
6214RAMDrive_END LABEL BYTE
6215
6216RAMCODE ENDS
6217 END
6218 \ No newline at end of file
diff --git a/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK
new file mode 100644
index 0000000..98a3458
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/RAMDRIVE.LNK
@@ -0,0 +1,3 @@
1ramdrive messages
2ramdrive.exe
3ramdrive.map -map;
diff --git a/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC b/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC
new file mode 100644
index 0000000..9761b0c
--- /dev/null
+++ b/v4.0/src/DEV/RAMDRIVE/SYSCALL.INC
@@ -0,0 +1,146 @@
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
91Wait 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