summaryrefslogtreecommitdiff
path: root/v4.0/src/DEV/XMAEM
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/XMAEM
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0/src/DEV/XMAEM')
-rw-r--r--v4.0/src/DEV/XMAEM/INDEACC.INC218
-rw-r--r--v4.0/src/DEV/XMAEM/INDEDAT.INC535
-rw-r--r--v4.0/src/DEV/XMAEM/INDEDES.MAC173
-rw-r--r--v4.0/src/DEV/XMAEM/INDEDMA.ASM660
-rw-r--r--v4.0/src/DEV/XMAEM/INDEEMU.ASM653
-rw-r--r--v4.0/src/DEV/XMAEM/INDEEXC.ASM799
-rw-r--r--v4.0/src/DEV/XMAEM/INDEGDT.ASM379
-rw-r--r--v4.0/src/DEV/XMAEM/INDEI15.ASM503
-rw-r--r--v4.0/src/DEV/XMAEM/INDEIDT.ASM512
-rw-r--r--v4.0/src/DEV/XMAEM/INDEINI.ASM1474
-rw-r--r--v4.0/src/DEV/XMAEM/INDEINS.MAC923
-rw-r--r--v4.0/src/DEV/XMAEM/INDEMAUS.ASM73
-rw-r--r--v4.0/src/DEV/XMAEM/INDEMSG.ASM96
-rw-r--r--v4.0/src/DEV/XMAEM/INDEMSUS.ASM76
-rw-r--r--v4.0/src/DEV/XMAEM/INDEMSUS.INC64
-rw-r--r--v4.0/src/DEV/XMAEM/INDEOVP.MAC111
-rw-r--r--v4.0/src/DEV/XMAEM/INDEPAT.ASM74
-rw-r--r--v4.0/src/DEV/XMAEM/INDEXMA.ASM781
-rw-r--r--v4.0/src/DEV/XMAEM/INDEXMAE.SYS8
-rw-r--r--v4.0/src/DEV/XMAEM/MAKEFILE57
-rw-r--r--v4.0/src/DEV/XMAEM/XMAEM.ARF13
-rw-r--r--v4.0/src/DEV/XMAEM/XMAEM.LC19
-rw-r--r--v4.0/src/DEV/XMAEM/XMAEM.LNK13
-rw-r--r--v4.0/src/DEV/XMAEM/XMAEM.MAK66
-rw-r--r--v4.0/src/DEV/XMAEM/XMAEM.SKL16
25 files changed, 8296 insertions, 0 deletions
diff --git a/v4.0/src/DEV/XMAEM/INDEACC.INC b/v4.0/src/DEV/XMAEM/INDEACC.INC
new file mode 100644
index 0000000..01a28b2
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEACC.INC
@@ -0,0 +1,218 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEACC *
5* *
6* *
7* 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation *
8* *
9* DESCRIPTIVE NAME: Access rights byte definitions for 80386 XMA emulator *
10* *
11* STATUS (LEVEL) : Version (0) Level (1.0) *
12* *
13* FUNCTION : This file defines the access rights bytes used in *
14* descriptors that define the code and data segments. *
15* *
16* MODULE TYPE : INC *
17* *
18* REGISTER USAGE : 80386 Standard *
19* *
20* RESTRICTIONS : None *
21* *
22* DEPENDENCIES : None *
23* *
24* EXTERNAL *
25* REFERENCES : None *
26* *
27* CHANGE ACTIVITY : *
28* *
29* $MAC(INDEACC) COMP(LOAD) PROD(3270PC) : *
30* *
31* $D0=D0004700 410 870530 D : NEW FOR WSP RELEASE 1.1 *
32* $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "INC" *
33* *
34* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
35#
36
37PAGE
38; RECORD DEFINITIONS FOR ACCESS RIGHTS BYTES
39; ====== =========== === ====== ====== =====
40;
41; Data Segments - Interpretation of access rights for DS/ES/SS
42
43
44; Define the bit fields for the access rights byte
45
46DATA_ACC RECORD PRESENT:1,DPL:2,SEG_TYPE:1,XQTBLE:1,EXPDIR:1,WRTBLE:1,ACCESSED:1
47
48 ; PRESENT (1 bit) 0 = segment not present in memory
49 ; 1 = segment present in memory
50 ;
51 ; DPL (2 bits) Descriptor privilege level -- 0 to 3
52 ;
53 ; SEG_TYPE (1 bit) 0 = system segment
54 ; 1 = application segment
55 ;
56 ; XQTBL (1 bit) 0 = segment is not executable (i.e., data)
57 ; 1 = segment is executable (i.e., code)
58 ;
59 ; EXPDIR (1 bit) 0 = expand up, i.e., normal data segment
60 ; 1 = expand down, i.e., stack segment
61 ;
62 ; WRTBLE (1 bit) 0 = data segment is read only
63 ; 1 = data segment is read/write
64 ;
65 ; ACCESSED (1 bit) 0 = segment has not been accessed
66 ; 1 = segment has been accessed
67
68
69; Privilege level 3 read/write data segment access rights byte
70
71CPL3_DATA_ACCESS EQU 11110011B ; Present
72 ; DPL = 3
73 ; Application segment
74 ; Not executable (i.e. data)
75 ; Expand up
76 ; Readable/Writable
77 ; Accessed
78
79; Privilege level 0 read/write data segment access rights byte
80
81CPL0_DATA_ACCESS EQU 10010011B ; Present
82 ; DPL = 0
83 ; Application segment
84 ; Not executable (i.e. data)
85 ; Expand up
86 ; Readable/Writable
87 ; Accessed
88
89
90NULL_ACCESS EQU 00000000B ; Null (Not present)
91
92
93; Descriptor privilege levels. These can be ANDed or ORed with the access
94; rights byte to get the desired DPL for the descriptor.
95
96DPL3 EQU 01100000B
97DPL2 EQU 01000000B
98DPL1 EQU 00100000B
99DPL0 EQU 00000000B
100
101PAGE
102; Code Segments - Interpretation of access rights for CS.
103; Identical to data segments except for two fields.
104
105
106CODE_ACC RECORD DATA_HI:5,CONFORM:1,READABLE:1,DATA_LO:1
107
108 ; DATA_HI (5 bits) Same five bits as described for data segments
109 ; PPRESENT (1), DPL (2), SEG_TYPE (1) and
110 ; XQTBL (1)
111 ;
112 ; CONFORM (1 bit) 0 = Non-conforming - cannot be called by
113 ; someone with a different CPL
114 ; 1 = Conforming - can be called by anyone
115 ; regardless of CPL. CPL remains the same
116 ;
117 ; READABLE (1 bit) 0 = code segment is execute only
118 ; 1 = data segment is executable and readable
119 ;
120 ; DATA_LO (1 bit) Same bit as described for data segments
121 ; ACCESSED (1)
122
123
124; Privilege level 3 conforming readable code segment access rights byte
125; BUT...
126; We switched the DPL to 0. Why? Because the DPL of the current code segment
127; determines the current privilege level (CPL). Whatever is running at the
128; time can only access data with a DPL >= CPL. So if the DPL for the code
129; segment were 3 and we tried to access data with a DPL of 0 we would get a
130; fault. By setting the DPL of the code segment to 0 we can access all data
131; and will never be bothered by faults.
132
133CPL3_CODE_ACCESS EQU 10011111B ; Present
134 ; DPL = 0
135 ; Application segment
136 ; Executable (i.e. code)
137 ; Conforming
138 ; Readable
139 ; Accessed
140
141; Access rights to be able to read and write to a code segment. Code segments
142; may not be written to. So this access byte will define the segment as a
143; read/write data segment. It is the same as CPL3_DATA_ACCESS.
144
145COMP_CODE_ACCESS EQU CPL3_DATA_ACCESS
146
147; Privilege level 0 non-conforming readable code segment access rights byte
148
149CPL0_CODE_ACCESS EQU 10011011B ; Present
150 ; DPL = 0
151 ; Application segment
152 ; Executable (i.e. code)
153 ; Non-conforming
154 ; Readable
155 ; Accessed
156
157PAGE
158; System Segments - Interpretation of access rights for TR/LDTR as well as
159; the four gate types. The access rights byte for the
160; GDTR and IDTR is undefined, meaning anyone can access
161; the table (although not necessarily the segments
162; defined in the table). The uppermost 4 bits are
163; identical to those for data segments; the type field
164; occupies the lowermost 4 bits.
165
166
167SYSTEM_ACC RECORD DATA_H:4,DESC_TYPE:4
168
169 ; DATA_H (4 bits) Same four bits as described for data segments
170 ; PPRESENT (1), DPL (2) and SEG_TYPE (1)
171 ;
172 ; DESC_TYPE(4 bits) 0000 Intel Reserved
173 ; 0001 Available 286 TSS
174 ; 0010 LDT
175 ; 0011 Busy 286 TSS
176 ; 0100 Call Gate
177 ; 0101 Task Gate
178 ; 0110 286 Interrupt Gate
179 ; 0111 286 Trap Gate
180 ; 1000 Intel Reserved
181 ; 1001 Available 386 TSS
182 ; 1010 Intel Reserved
183 ; 1011 Busy 386 TSS
184 ; 1100 386 Call Gate
185 ; 1101 Intel Reserved
186 ; 1110 386 Interrupt Gate
187 ; 1111 386 Trap Gate
188 ;
189
190
191; These equates cover the topmost 4 bits for system segment access
192; rights bytes. They define the privilege level.
193
194LDT_ACCESS EQU 11100000B ; Present, DPL = 3 for LDTs
195
196TSS_ACCESS EQU 10000000B ; Present, DPL = 0 for TSSs
197
198GATE_ACCESS EQU 10000000B ; Present, DPL = 0 for Gates
199
200
201; These are for the type field. When "OR"ed with one of the above,
202; you have a complete access rights byte.
203
204LDT_DESC EQU 00000010B OR LDT_ACCESS
205
206FREE_TSS EQU 00000001B OR TSS_ACCESS
207FREE_TSS_386 EQU 00001001B OR TSS_ACCESS
208
209BUSY_TSS EQU 00000011B OR TSS_ACCESS
210
211CALL_GATE EQU 00000100B OR GATE_ACCESS
212
213TASK_GATE EQU 00000101B OR GATE_ACCESS
214
215INT_GATE EQU 00000110B OR GATE_ACCESS
216
217TRAP_GATE EQU 00000111B OR GATE_ACCESS
218
diff --git a/v4.0/src/DEV/XMAEM/INDEDAT.INC b/v4.0/src/DEV/XMAEM/INDEDAT.INC
new file mode 100644
index 0000000..6c58eef
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEDAT.INC
@@ -0,0 +1,535 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEDAT *
5* *
6* *
7* 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation *
8* *
9* DESCRIPTIVE NAME: Sytem data structures and equates for 386 XMA emulator *
10* *
11* STATUS (LEVEL) : Version (0) Level (1.0) *
12* *
13* FUNCTION : This file defines the overlays and constants for most of *
14* the system data. The following structures are defined *
15* here: *
16* The resister save area on our stack *
17* 80386 Task State Segment (TSS) *
18* The Global Descriptor Table (GDT) *
19* 80286 Segment Descriptor *
20* 80286 Gate Descriptor *
21* 80286 Task State Segment (TSS) *
22* *
23* MODULE TYPE : INC *
24* *
25* REGISTER USAGE : 80386 Standard *
26* *
27* RESTRICTIONS : None *
28* *
29* DEPENDENCIES : None *
30* *
31* EXTERNAL *
32* REFERENCES : None *
33* *
34* CHANGE ACTIVITY : *
35* *
36* $MAC(INDEDAT) COMP(LOAD) PROD(3270PC) : *
37* *
38* $D0=D0004700 410 870529 D : NEW FOR WSP RELEASE 1.1 *
39* $P1=P0000311 410 870804 D : RENAME MODULES'S LIBRARY FILE TYPE TO "INC" *
40* $P2=P0000410 410 870918 D : RELOCATE DATA TO MAKE ROOM FOR I/O BIT MAP *
41* *
42* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
43#
44
45; BPSTACK is an overlay for our stack when we receive control from an
46; interrupt that we want to handle. The entry points for these interrupts
47; push a 32 but error code and the interrupt number (16 bits) onto the stack.
48; Then control goes to INDEEXC which saves the current register values on the
49; stack. BP is set to point to the beginning of the register save area. This
50; is the mapping of the resulting stack.
51
52BPSTACK STRUC
53
54BP_ES DW 0 ; Interrptee's ES
55BP_DI DW 0 ; Interruptee's EDI (32 bit DI)
56 DW 0 ;
57BP_SI DW 0 ; Interruptee's ESI (32 bit SI)
58 DW 0 ;
59BP_BP DW 0 ; Interruptee's EBP (32 bit BP)
60 DW 0 ;
61BP_PASP DW 0 ; Interruptee's ESP (32 bit SP)
62BP_PSP2 DW 0 ; (ESP as it was before the PUSHA)
63BP_BX DW 0 ; Interruptee's EBX (32 bit BX)
64 DW 0 ;
65BP_DX DW 0 ; Interruptee's EDX (32 bit DX)
66 DW 0 ;
67BP_CX DW 0 ; Interruptee's ECX (32 bit CX)
68 DW 0 ;
69BP_AX DW 0 ; Interruptee's EAX (32 bit AX)
70 DW 0 ;
71BP_DS DW 0 ; Interruptee's DS
72BP_EX DW 0 ; Exception ID
73BP_EC DW 0 ; Error Code
74 DW 0
75
76; The following values are placed on our stack by the 80386
77
78BP_IP DW 0 ; Interruptee's EIP (32 bit IP)
79BP_IP2 DW 0
80BP_CS DW 0 ; Interruptee's CS (16 bit CS plus 16 bit trash)
81BP_CS2 DW 0
82BP_FL DW 0 ; Interruptee's flags (32 bits)
83BP_FL2 DW 0
84BP_SP DW 0 ; Interruptee's ESP - saved on an inter-level
85BP_SP2 DW 0 ; interrupt
86BP_SS DW 0 ; Interruptee's SSP - also saved on inter-level
87BP_SS2 DW 0 ; interrupt
88BP_VMES DW 0 ; Virtual mode ES
89BP_VME2 DW 0
90BP_VMDS DW 0 ; Virtual mode DS
91 DW 0
92BP_VMFS DW 0 ; Virtual mode FS
93 DW 0
94BP_VMGS DW 0 ; Virtual mode GS
95 DW 0
96BP_STK DW 0 ; The rest of the stack
97
98BPSTACK ENDS
99
100BP_START EQU 0 ; Offset from BP of the start of the stack info
101
102SUBTTL 80386 TSS - Task State Segment
103PAGE
104;*************************************************
105; *
106; Start of Debugger's 386 TSS *
107; *
108;*************************************************
109
110TSS386 STRUC
111 DW 0 ; Intel reserved
112ETSS_BACK_LINK DW 0 ; Back link to previous TSS
113ETSS_SP0 DW 0 ; ESP for privilege level 0
114 DW 0
115ETSS_SS0 DW 0 ; SS for privilege level 0
116 DW 0 ; Intel reserved
117ETSS_SP1 DD 0 ; ESP for privilege level 1
118ETSS_SS1 DW 0 ; SS for privilege level 1
119 DW 0 ; Intel reserved
120ETSS_SP2 DD 0 ; ESP for privilege level 2
121ETSS_SS2 DW 0 ; SS for privilege level 2
122 DW 0 ; Intel reserved
123ETSS_CR3 DD 0 ; CR3 - Page directory base register
124ETSS_IP DW 0 ; Task's EIP
125 DW 0
126ETSS_FL DW 0 ; Task's Eflags
127ETSS_FL2 DW 0
128ETSS_AX DD 0 ; Task's EAX
129ETSS_CX DD 0 ; Task's ECX
130ETSS_DX DD 0 ; Task's EDX
131ETSS_BX DD 0 ; Task's EBX
132ETSS_SP DW 0 ; Task's ESP
133 DW 0
134ETSS_BP DD 0 ; Task's EBP
135ETSS_SI DD 0 ; Task's ESI
136ETSS_DI DD 0 ; Task's EDI
137ETSS_ES DW 0 ; Task's ES
138 DW 0 ; Intel reserved
139ETSS_CS DW 0 ; Task's CS
140 DW 0 ; Intel reserved
141ETSS_SS DW 0 ; Task's SS
142 DW 0 ; Intel reserved
143ETSS_DS DW 0 ; Task's DS
144 DW 0 ; Intel reserved
145ETSS_FS DW 0 ; Task's FS
146 DW 0 ; Intel reserved
147ETSS_GS DW 0 ; Task's GS
148 DW 0 ; Intel reserved
149ETSS_LDT DW 0 ; Selector for task's LDT
150 DW 0 ; Intel reserved
151ETSS_TRAP DW 0 ; Trap bit - bit 0 (IBM bit 15)
152ETSS_BM_OFFSET DW 0 ; I/O bit map base
153ETSS_AVL DD 0
154TSS386 ENDS
155TSS_386_LEN EQU 68H ; Length of the TSS
156TSS_BM_LEN EQU 0FFFH-TSS_386_LEN ; Length of the I/O bit map
157 ; The bit map is in the same segment as the TSS
158 ; therefore the descriptor fot the TSS segment
159 ; must have enough room to include the bit map.
160
161SUBTTL GDT - Global Descriptor Table
162PAGE
163
164SUBTTL GDT - GLOBAL DESCRIPTOR TABLE
165
166; THE GLOBAL DESCRIPTOR TABLE DEFINITION
167; === ====== ========== ===== ==========
168;
169
170GDT_LEN EQU 512 * 8 ; 512 entries total
171
172GDT_DEF STRUC
173
174UNUSED_ENTRY DQ 0 ; Seg reg = 0 illegal - this entry is
175 ; not accessible
176GDT_PTR DQ 0 ; This entry points to this GDT table
177MON_IDT_PTR DQ 0 ; System interrupt descriptor table
178RSDA_PTR DQ 0 ; The real system data area (as opposed
179 ; to the virtual SDA's). XMA pages
180 ; start here
181HUGE_PTR DQ 0 ; Used to address 0-1M as data
182
183LA_PTR DQ 0 ; Pointer to the LOADALL area (000800H)
184
185C_BWCRT_PTR DQ 0 ; Compatible blanck and white display
186C_CCRT_PTR DQ 0 ; Compatible color display
187E_CCRT_PTR DQ 0 ; Enhanced color display (16 bytes)
188E_CCRT_PTR2 DQ 0
189
190SYS_ROM_CS DQ 0 ; CS for system IDT, ROM resident
191SYS_ROM_DS DQ 0 ; DS selector to access above as data
192SYS_PATCH_CS DQ 0 ; CS for system IDT, RAM patch area
193SYS_PATCH_DS DQ 0 ; DS selector to access above as data
194
195V_ROM_CS DQ 0 ; CS - virtual IDT, ROM resident
196V_ROM_DS DQ 0 ; DS selector to access above as data
197V_PATCH_CS DQ 0 ; CS - virtual IDT, RAM patch area
198V_PATCH_DS DQ 0 ; DS selector to access above as data
199
200ES_TEMP DQ 0 ; Dynamic pointer for ES
201CS_TEMP DQ 0 ; Dynamic pointer for CS
202SS_TEMP DQ 0 ; Dynamic pointer for SS
203DS_TEMP DQ 0 ; Dynamic pointer for DS
204
205; Monitor descriptors
206
207MON_LDTR DQ 0
208MON_DS DQ 0
209MON_ES DQ 0
210MON_SS DQ 0
211MON_CS DQ 0
212MON_TR_SS DQ 0 ; Task register value for single step
213MON_TR_BP DQ 0 ; " " " " breakpoint
214MON_TR_HWI DQ 0 ; Read/write (needs special hardware)
215MON_TR_OI DQ 0 ; " " " " control-break
216
217KBD_OWNER_SDA DQ 0 ; Fast path to keyboard owner's SDA
218
219VTIMER_VECTOR DB 16 DUP (8 DUP(0)) ; 16 VM timer-related descriptors
220
221; Below are the 32 system exception service routine descriptors.
222
223SEX_TSS DB 32 DUP (8 DUP(0))
224
225; Below are the 16 hardware interrupt service routine TSS descriptor
226; pairs. The first is suitable for TR loading (i.e. target selector
227; in the corresponding task gate) and the other is a TSS-as-data
228; descriptor.
229
230HWI_TSS DB 16 DUP (16 DUP(0))
231
232; This is the descriptor pair for the dispatcher (same format as HWI).
233
234DISPATCH_TASK DQ 0
235 DQ 0
236
237HWI_LDT DQ 0
238
239BASICS_SEG DQ 0 ; BASIC's segment (F600)
240
241BIOSS_SEG DQ 0 ; BIOS's segment (F000)
242
243;
244;
245; Any other GDT things go here. There are around 300 slots left.
246;
247;
248
249RSVD_GDT DQ 0
250 DB (GDT_LEN - (RSVD_GDT + 8) - (18 * 32)) DUP (0)
251
252 ; The above leaves space for the
253 ; descriptors needed for 18 VMs
254
255PM_VM DB 32 DUP (0) ; Program Manager's virtual machine
256 ; entries. This will function as
257 ; the highest priority machine.
258USER_CS DQ 0 ; Debugee's code segment
259USER_SS DQ 0 ; Debugee's stack segment
260USER_DS DQ 0 ; Debugee's data segment
261USER_ES DQ 0 ; Debugee's extra segment
262USER_TSS DQ 0 ; Debugee's Task State Segment
263USER_TSS_DAT DQ 0 ; Debugee's TSS as a data segment
264USER_LDT DQ 0 ; Debugee's LDT definition
265USER_LDT_DAT DQ 0 ; Debugee's LDT as a data segment
266
267USER_VMS DB 14 DUP (32 DUP(0)) ; 16 user VMs
268
269SCRUBBER DB 32 DUP (0) ; RAM scrubber - dispatched when no other
270 ; machine has work to do
271last_gdt_byte db 0 ; marker for last GDT byte + 1
272GDT_DEF ENDS
273
274SUBTTL Virtual Machine Entry
275PAGE
276; Virtual Machine Entry Definition - consists of 4 descriptors
277;
278; - Pointer to TSS, loadable into the Task Register
279; - Pointer to TSS, loadable into a regular segment register
280; - Pointer to the LDT, loadable into the LDT Register
281; - Pointer to the LDT, loadable into a regular segment register
282;
283; The first of each pair is for loading into the associated special
284; system registers, TR and LDTR. The second allows dynamic access
285; and modification of descriptors by the system.
286
287VM_GDT_ENTRY STRUC
288
289VM_TR DQ 0 ; TR value for this machine's TSS
290TSS_PTR DQ 0 ; Data pointer to this machine's TSS
291VM_LDTR DQ 0 ; LDTR value for this machine's LDT
292LDT_PTR DQ 0 ; Data pointer to this machine's LDT
293
294VM_GDT_ENTRY ENDS
295
296SUBTTL 80286 Segment Descriptor
297PAGE
298; DESCRIPTOR TABLE ENTRY STRUCTURES
299; ========== ===== ===== ==========
300;
301; Segment Descriptor
302;
303; The following type of descriptor applies to data segments, code
304; segments, local, global, and interrupt descriptor table segments,
305; and task state segments.
306
307DATA_DESC STRUC
308
309SEG_LIMIT DW 0 ; Segment limit (1 - 65535 bytes)
310BASE_LO_WORD DW 0 ; 24 bit segment physical address
311BASE_HI_BYTE DB 0 ; (0 - (16M-1))
312DATA_ACC_RIGHTS DB 0 ; Access rights byte
313DATA_RESERVED DW 0 ; Intel reserved
314
315DATA_DESC ENDS
316
317SHADOW_ID EQU DATA_RESERVED ; For garbage collection
318
319SUBTTL 80286 Gate Descriptor
320PAGE
321; 80286 Gate Descriptor
322
323; The following type of descriptor applies to task gates, call gates,
324; interrupt gates, and trap gates.
325
326GATE_DESC STRUC
327
328ENTRY_POINT DW 0 ; Destination routine entry point
329 ; within the target segment.
330 ; This is unused for task gates.
331CS_SELECTOR DW 0 ; Selector for destination segment.
332 ; For task gates, this must point
333 ; to a valid task state segment
334 ; descriptor. For call, trap, and
335 ; interrupt gates, this must point
336 ; to a valid code segment descriptor.
337 ; The segment defined in that
338 ; descriptor plus the aforementioned
339 ; entry-point defines the actual
340 ; routine address.
341WORD_COUNT DB 0 ; For call gates only - number of
342 ; words to copy from caller's
343 ; stack to callee's stack
344GATE_ACC_RIGHTS DB 0 ; Access rights byte
345GATE_RESERVED DW 0 ; Intel reserved
346
347GATE_DESC ENDS
348
349; Record for the fields in a selector
350
351SELECTOR RECORD INDEX:13,TI:1,RPL:2 ; Standard 286 selector format
352
353SUBTTL TSS - Task State Segment
354PAGE
355; TASK STATE SEGMENT
356; ==== ===== =======
357;
358; There are currently two styles of task state segment (TSS) - one for
359; VMs and one for the hardware interrupt service routines. There may
360; be more later, depending on the needs and/or whims of the Authors
361; of this and follow-on products. They will all have one thing in
362; common - they begin with a 44 byte 286-required machine state data
363; area. The first structure below is that area's definition. All
364; subsequent colors of TSS will start with space for that data, defined
365; like so:
366;
367; first_field_name DB (TYPE TASK_STATE_286) DUP (0)
368;
369; As a convenience, we use the highest part of the TSS for that
370; particular task's stack (or in some cases, stacks - for privilege
371; levels 0, 1, and 2). The intermediate area is used for task-specific
372; data.
373
374
375TASK_STATE_286 STRUC
376
377BACK_LINK DW 0 ; TSS selector from whence we came
378VM_SP0 DW 0 ; SS:SP for CPL 0
379VM_SS0 DW 0
380VM_SP1 DW 0 ; SS:SP for CPL 1
381VM_SS1 DW 0
382VM_SP2 DW 0 ; SS:SP for CPL 2
383VM_SS2 DW 0
384VM_IP DW 0 ; IP - next instruction to execute
385VM_FL DW 0 ; Flag word
386VM_AX DW 0 ;
387VM_CX DW 0 ; General
388VM_DX DW 0 ;
389VM_BX DW 0 ;
390VM_SP DW 0 ; Purpose
391VM_BP DW 0 ;
392VM_SI DW 0 ;
393VM_DI DW 0 ; Registers
394VM_ES DW 0 ;
395VM_CS DW 0 ; Segment
396VM_SS DW 0 ; Selectors
397VM_DS DW 0 ;
398VM_LDT DW 0 ; Selector for this task's LDT
399
400TASK_STATE_286 ENDS
401
402; Note that the actual stacks for CPLs 2, 1, and 0 are part of the
403; task state segment. CPL 3's stack is in its own address space.
404
405SUBTTL Length Equates
406PAGE
407; Length equates
408
409LA_LEN EQU GDT_LEN ; For new monitor
410
411SIDT_LEN EQU 256*8 ; Length of the IDT -- 256 interrupt
412 ; entries, 8 bytes each
413
414TSS_LEN EQU 68H + 2000H ; TSS structure length -- 68H for regs
415 ; 2000H for I/O bit map @P2C
416
417LDT_LEN EQU 00800H ; LDT structure length (2K)
418
419VM_ENTRY_LENGTH EQU TYPE VM_GDT_ENTRY ; Length of a VM entry
420
421VM_ENTRY_WIDTH EQU 5 ; Shift count for priority. Each
422 ; VM entry = 32 bytes, and SHL 5
423 ; is the same as MUL by 32.
424NEXT_DESC EQU TYPE DATA_DESC ; Length of a descriptor
425
426DESC_LEN EQU TYPE DATA_DESC ; Length of a descriptor
427
428DESC_WIDTH EQU 3 ; Shift count for desc len (8) is 3
429
430PM_VM_SIZE EQU 01000H ; Virtual Manager's VM size
431
432MCRT_SIZE EQU 4*1024 ; Monochrome display size
433
434CCRT_SIZE EQU 16*1024 ; Compatible color display size
435
436ECCRT_SIZE EQU 0FFFFH ; Size of each portion of the enhanced
437 ; color display buffer
438
439MAX_SEG_LEN EQU 0FFFFH ; Maximum segment length = 64K
440
441NULL_SEG_LEN EQU 00000H ; Null segment length = 0
442
443THIRTY_TWO_K EQU 08000H ; Unit of virtual machine size
444
445
446SUBTTL Location Equates
447PAGE
448
449
450; Location equates
451
452; These items are all pre-allocated, and have no SBDs. After these,
453; storage structures are all obtained through the memory manager.
454
455;-----------------------------------------------------------------------------
456
457; From here to the end marker, these guys must stay in order as this is
458; how they are allocated.
459
460GDT_LOC EQU 0C100H ; GDT location relative to CS @P2C
461
462SIDT_LOC EQU (GDT_LOC + GDT_LEN) ; The system IDT is next
463
464DISPATCH_LOC EQU (SIDT_LOC + SIDT_LEN)
465
466; End marker
467
468; Monitor equate used in m_state to tell the estep routine that we're
469; single stepping from within ego.
470GO_MODE EQU 1 ;
471; Monitor equate used in m_state to tell the hwi_int routine that we're
472; breaking on a memory read address that's executed
473MEMX EQU 2 ;
474; Monitor equate used in m_state to tell mon_go that a breakpoint has been
475; set so enable the breakpoint card
476CARD_ENABL EQU 4 ;
477S_MODE EQU 2000H ; Selector or segment mode flag
478
479BOOT_IP EQU 07C00H ; PC1 IP value for boot
480
481BOOT_CS EQU 00000H ; PC1 CS value for boot
482
483BOOT_SS EQU 00030H ; PC1 SS value for boot
484
485BOOT_SP EQU 07FFH ; PC1 SP value for boot
486
487BOOT_FL EQU 00200H ; Interrupts enabled
488
489CS_LO_CACHE EQU 00000H ; Code segment
490
491CS_HI_CACHE EQU 000H ; compatible cache
492
493SS_LO_CACHE EQU 00300H ; Stack segment
494
495SS_HI_CACHE EQU 000H ; compatible cache
496
497OTHER_CACHE EQU 00000H ; GP zero cache
498
499SUBTTL Display Equates
500PAGE
501
502; The next equates are system definitions for display buffer addresses.
503
504
505MCRT@_LO EQU 0000H ;
506 ; Monochrome display address
507MCRT@_HI EQU 0BH ; (0B0000H)
508
509CCRT@_LO EQU 8000H ;
510 ; Compatible color display address
511CCRT@_HI EQU 0BH ; (0B8000H)
512
513ECCRT@_LO_LO EQU 0000H ;
514 ; Enhanced color display address -
515ECCRT@_LO_HI EQU 0AH ; lower 64K (0A0000H)
516
517ECCRT@_HI_LO EQU 0000H ;
518 ; Enhanced color display address -
519ECCRT@_HI_HI EQU 0CH ; upper 64K (0C0000H)
520
521
522; Code segment addresses
523
524
525CSEG@_LO EQU 0000H ;
526 ; ROM code segment address
527CSEG@_HI EQU 0EH ; (0E0000H)
528
529NSEG@_LO EQU 0000H ;
530 ; Null segment address
531NSEG@_HI EQU 00H ;
532
533VIRTUAL_ENABLE EQU 0000000000000001B
534
535SUBTTL
diff --git a/v4.0/src/DEV/XMAEM/INDEDES.MAC b/v4.0/src/DEV/XMAEM/INDEDES.MAC
new file mode 100644
index 0000000..68d1776
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEDES.MAC
@@ -0,0 +1,173 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEDES *
5* *
6* *
7* 5669-196 (C) COPYRIGHT 1988 Microsoft *
8* *
9* DESCRIPTIVE NAME: Macros for setting up 80386 descriptors *
10* *
11* STATUS (LEVEL) : Version (0) Level (1.0) *
12* *
13* FUNCTION : DESCR_DEF - Define storage for a descriptor *
14* DESCR_INIT - Initialize a descriptor that has already *
15* been defined *
16* *
17* MODULE TYPE : MAC *
18* *
19* REGISTER USAGE : 80286 Standard *
20* *
21* CHANGE ACTIVITY : *
22* *
23* $MAC(INDEDES) COMP(LOAD) PROD(3270PC) : *
24* *
25* $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 *
26* $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" *
27* *
28* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29#
30
31; DESCR_DEF: Define a descriptor in-line using DWs and DBs.
32;
33; Input: For Segment descriptors, TYPE = SEG.
34; For Gate descriptors, TYPE = GATE.
35; Other parameters are as described by comments below.
36;
37; Output: DWs (define words) and DBs (define bytes) using the passed
38; values. Useful for copying descriptors directly out of the code
39; space, as when their values are forever static.
40;
41; Example: DESCR_DEF SEG, TSS0_LEN, TSS0_LOC, 0, CPL0_DATA_ACCESS
42;
43; This defines a segment format (limit/base/access) descriptor
44; based on the parameters, which are usually equated values. Note
45; that the low word of the address is TSS0_LOC and the high byte
46; is 0.
47
48
49DESCR_DEF MACRO TYPE,PARM1,PARM2,PARM3,ARB
50
51 IFIDN <&TYPE>,<SEG>
52;
53; Segment descriptor definition
54;
55 DW &PARM1 ; Segment limit
56 DW &PARM2 ; Segment base address - low word
57 DB &PARM3 ; Segment base address - high byte
58 DB &ARB ; Access rights byte
59 DW 0 ; Intel reserved
60
61 ENDIF
62
63 IFIDN <&TYPE>,<GATE>
64;
65; Gate descriptor definition
66;
67 DW &PARM1 ; Destination offset
68 DW &PARM2 ; Destination segment selector
69 DB &PARM3 ; Word count for stack-to-stack copy
70 ; (only for call gates when PL changes)
71 DB &ARB ; Access rights byte
72 DW 0 ; Intel reserved
73
74 ENDIF
75
76 ENDM
77
78PAGE
79
80; DESCR_INIT: Initialize a descriptor dynamically.
81;
82; NOTE: ES must already point to the BASE of table
83; where you want the descriptor to go.
84;
85;
86; Input: For Segment descriptors, TYPE = SEG.
87; For 4K granularity Segment descriptors, TYPE = BSEG.
88; For Gate descriptors, TYPE = GATE.
89; If the FIELD parameter is supplied, a MOV DI,FIELD is generated.
90; Otherwise, its current value is used. Other parameters are as
91; described by comments below.
92;
93;
94; Output: DI ends up as DI + 8 (i.e. pointing at next descriptor. This
95; is useful if you are initializing several consecutive
96; descriptors).
97;
98; The passed data is stored at ES:DI using string store. This
99; macro would be used when creating descriptors dynamically, as
100; when allocating virtual machines.
101;
102; Example: DESCR_INIT GATE,INT13_PTR,INT13_IP,INT13_CS,0,TRAP_GATE_ACCESS
103;
104; This stores the parameters in gate format (offset/ selector/word
105; count/access) through ES:DI, where DI is first loaded with
106; INT13_PTR.
107
108
109DESCR_INIT MACRO TYPE,FIELD,PARM1,PARM2,PARM3,ARB
110
111 PUSH AX ; Save the utility register
112
113 IFNB <&FIELD>
114
115 MOV DI,&FIELD ; Set up index value to proper descriptor
116 ADD DI,GDT_LOC
117
118 ENDIF
119
120
121 IFIDN <&TYPE>,<SEG>
122;
123; Segment descriptor initialization
124;
125 MOV AX,&PARM1 ; PARM1 = Segment Limit; load into AX
126 STOSW ; and store
127 MOV AX,&PARM2 ; PARM2 = BASE_LO_W; load into AX
128 STOSW ; and store
129 MOV AL,&PARM3 ; PARM3 = BASE_HI_B; load into AL, and
130 MOV AH,&ARB ; ARB = Access Rights Byte; load into AH
131 STOSW ; and store both
132 MOV AX,0 ; Make sure the Intel
133 STOSW ; reserved word is zero
134
135 ENDIF
136
137
138 IFIDN <&TYPE>,<BSEG>
139;
140; Big (4k granularity) segment descriptor initialization
141;
142 MOV AX,&PARM1 ; PARM1 = Segment Limit; load into AX
143 STOSW ; and store
144 MOV AX,&PARM2 ; PARM2 = BASE_LO_W; load into AX
145 STOSW ; and store
146 MOV AL,&PARM3 ; PARM3 = BASE_HI_B; load into AL, and
147 MOV AH,&ARB ; ARB = Access Rights Byte; load into AH
148 STOSW ; and store both
149 MOV AX,0080H ; 4k granularity bit
150 STOSW
151
152 ENDIF
153
154
155 IFIDN <&TYPE>,<GATE>
156;
157; Gate descriptor initialization
158;
159 MOV AX,&PARM1 ; PARM1 = Destination offset; load into AX
160 STOSW ; and store
161 MOV AX,&PARM2 ; PARM2 = Destination Selector;load into AX
162 STOSW ; and store
163 MOV AL,&PARM3 ; PARM3 = Word Count; load into AL, and
164 MOV AH,&ARB ; ARB = Access Rights Byte; load into AH
165 STOSW ; and store both
166 MOV AX,0 ; Make sure the Intel
167 STOSW ; reserved word is zero
168
169 ENDIF
170
171 POP AX ; Restore AX
172
173 ENDM
diff --git a/v4.0/src/DEV/XMAEM/INDEDMA.ASM b/v4.0/src/DEV/XMAEM/INDEDMA.ASM
new file mode 100644
index 0000000..84d73dc
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEDMA.ASM
@@ -0,0 +1,660 @@
1PAGE 60,132
2TITLE INDEDMA - 386 XMA Emulator - DMA Emulation
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEDMA *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation *
11* *
12* DESCRIPTIVE NAME: DMA handler for the 80386 XMA emulator *
13* *
14* STATUS (LEVEL) : Version (0) Level (1.0) *
15* *
16* FUNCTION : This module intercepts any I/O going to the DMA address *
17* ports. We can't let the DMA requests go to the virtual *
18* addresses. On the real XMA card the addresses on the *
19* bus lines are translated by the card so that it accesses *
20* the correct memory. But with our emulation the addresses *
21* are translated before they hit the bus lines. The DMA *
22* addresses go straight to the bus lines without being *
23* translated. This would result in DMA reading and writing *
24* data to the wrong memory location. Not good. Therefore *
25* we intercept the I/O that is going to the DMA address *
26* ports. We run these addresses through our paging mech- *
27* anism and then write the real addresses to the DMA *
28* address ports. *
29* *
30* MODULE TYPE : ASM *
31* *
32* REGISTER USAGE : 80386 Standard *
33* *
34* RESTRICTIONS : None *
35* *
36* DEPENDENCIES : None *
37* *
38* ENTRY POINTS : DMAIN - Entry point for "IN" instructions *
39* DMAOUT - Entry point for "OUT" instructions *
40* MANPORT - Entry point to issue an OUT to the manufacturing*
41* port to re-IPL the system *
42* *
43* LINKAGE : Jumped to by INDEXMA *
44* *
45* INPUT PARMS : None *
46* *
47* RETURN PARMS : None *
48* *
49* OTHER EFFECTS : None *
50* *
51* EXIT NORMAL : Jump to POPIO to return to the V86 task *
52* *
53* EXIT ERROR : None *
54* *
55* EXTERNAL *
56* REFERENCES : DISPLAY - Entry point in INDEEXC to signal an error *
57* POPIO - Entry point in INDEEMU to return to the V86 *
58* task *
59* PGTBLOFF - Word in INDEI15 that contains the offset of *
60* the page tables *
61* SGTBLOFF - Word in INDEI15 that contains the offset of *
62* the page directory *
63* NORMPAGE - Double Word in INDEI15 that contains the *
64* entry that goes into the first page directory *
65* entry so that it points to the normal page *
66* tables *
67* BUFF_SIZE - Word in INDEI15 that contains the size of the *
68* MOVEBLOCK buffer *
69* MAXMEM - Word in INDEI15 that contains the total *
70* number of K in the box *
71* WORD_FLAG - Byte in INDEXMA that indicates whether the *
72* I/O instruction was for a word or a byte *
73* *
74* SUB-ROUTINES : XLATE - Translate the virtual DMA address to a real DMA *
75* address *
76* *
77* MACROS : DATAOV - Add prefix for the next instruction so that it *
78* accesses data as 32 bits wide *
79* ADDROV - Add prefix for the next instruction so that it *
80* uses addresses that are 32 bits wide *
81* LJB - Long jump if below *
82* LJA - Long jump if above *
83* LJAE - Long jump if above or equal *
84* LJNE - Long jump if not equal *
85* *
86* CONTROL BLOCKS : INDEDAT.INC - System data structures *
87* *
88* CHANGE ACTIVITY : *
89* *
90* $MOD(INDEDMA) COMP(LOAD) PROD(3270PC) : *
91* *
92* $D0=D0004700 410 870101 D : NEW FOR RELEASE 1.1 *
93* $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES *
94* *
95* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
96#
97
98 .286P ; Enable recognition of 286 privileged instructs.
99
100 .XLIST ; Turn off the listing
101 INCLUDE INDEDAT.INC ; Include system data structures and equates
102
103 IF1 ; Only include macros on the first pass
104 INCLUDE INDEOVP.MAC ; Override prefix macros
105 INCLUDE INDEINS.MAC ; 386 instruction macros
106 ENDIF
107 .LIST ; Turn the listing back on
108
109PROG SEGMENT PARA PUBLIC 'PROG'
110
111 ASSUME CS:PROG
112 ASSUME DS:PROG
113 ASSUME ES:NOTHING
114 ASSUME SS:NOTHING
115
116INDEDMA LABEL NEAR
117
118 EXTRN DISPLAY:NEAR ; Entry point in INDEEXC to signal an error
119 EXTRN POPIO:NEAR ; Entry point in INDEEMU to return to the V86
120 ; task
121 EXTRN PGTBLOFF:WORD ; Word in INDEI15 that contains the offset of
122 ; the page tables
123 EXTRN SGTBLOFF:WORD ; Word in INDEI15 that contains the offset of
124 ; the page directory
125 EXTRN NORMPAGE:WORD ; Double Word in INDEI15 that contains the
126 ; entry that goes into the first page direct-
127 ; ory entry so that it points to the normal
128 ; page tables
129 EXTRN BUFF_SIZE:WORD ; Word in INDEI15 that contains the size of the
130 ; MOVEBLOCK buffer
131 EXTRN MAXMEM:WORD ; Word in INDEI15 that contains the total
132 ; number of K in the box
133 EXTRN WORD_FLAG:BYTE ; Byte in INDEXMA that indicates whether the
134 ; I/O instruction was for a word or a byte
135
136; Let these entry points be known to other modules
137
138 PUBLIC INDEDMA
139 PUBLIC DMAIN
140 PUBLIC DMAOUT
141 PUBLIC MANPORT
142
143PAGE
144
145; Define control blocks for each of the DMA channels 0 to 7. The control
146; blocks have information on where the user wanted to do DMA, where we will
147; actually do the DMA, the channel number and the page port. The following
148; is an overlay for the control blocks. After that the actual control
149; blocks are defined.
150
151DMACB STRUC ; DMA control block
152
153DMACHN DB 0 ; Channel number
154DMALSB DB 0 ; Least significant address byte
155DMAMSB DB 0 ; Most significant address byte (16 bits)
156DMAPAGE DB 0 ; Page - Hi-order of 24-bit address
157DMALR DB 0 ; Real Least significant address byte
158DMAMR DB 0 ; Real Most significant address byte (16 bits)
159DMAPR DB 0 ; Real Page - Hi-order of 24-bit address
160DMAPP DB 0 ; Compatability mode page port
161
162DMACB ENDS
163
164DMASTART EQU 0
165DMAENTRYLEN EQU DMAPP+1-DMASTART
166
167; Now, the channel control blocks
168
169DMATABLE DB 0 ; Channel number
170 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
171 DB 87H ; Page port
172
173 DB 1 ; Channel number
174 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
175 DB 83H ; Page port
176
177 DB 2 ; Channel number
178 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
179 DB 81H ; Page port
180
181 DB 3 ; Channel number
182 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
183 DB 82H ; Page port
184
185 DB 4 ; Channel number
186 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
187 DB 8FH ; Page port
188
189 DB 5 ; Channel number
190 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
191 DB 8BH ; Page port
192
193 DB 6 ; Channel number
194 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
195 DB 89H ; Page port
196
197 DB 7 ; Channel number
198 DB DMAENTRYLEN-2 DUP (0) ; The other stuff
199 DB 8AH ; Page port
200
201; And now some more variables
202
203DMACURRENT DB 0 ; Channel we're working on
204DMABYTE DB 0 ; This flag is toggled between 0 and 1
205 ; to indicated whether the least
206 ; significant or most significant byte
207 ; of the DMA address is being written
208DMA_ADV_CHN DB 0 ; Advanced mode channel number
209
210PAGE
211
212; Define the jump table. There are 32 entries in the table that correspond to
213; the first 32 ports, 0 to 20H. The code uses the port number as an index into
214; this table which then gives control to the appropriate routine for that port.
215; The table is initialized so that all entries jump to the code that will pass
216; the I/O back to the real port. Then the entries for the ports we want to
217; handle are set to the corresponding routines for those ports.
218
219OUT_TABLE:
220 .XLIST
221 REPT 32
222 JMP DOOUT
223 ENDM
224 .LIST
225OUT_TABLE_END:
226
227; Set the entries for the ports we want to handle.
228
229 ORG OUT_TABLE+(00H*3)
230 JMP CHN_0
231 ORG OUT_TABLE+(02H*3)
232 JMP CHN_1
233 ORG OUT_TABLE+(04H*3)
234 JMP CHN_2
235 ORG OUT_TABLE+(06H*3)
236 JMP CHN_3
237 ORG OUT_TABLE+(0CH*3)
238 JMP RESET_BYTE_PTR
239 ORG OUT_TABLE+(18H*3)
240 JMP CHK_FUNCTION
241 ORG OUT_TABLE+(1AH*3)
242 JMP CHK_BASE_REG
243
244 ORG OUT_TABLE_END
245
246PAGE
247
248; Control comes here from INDEXMA when it determines that the "IN" instruction
249; is not for one of the XMA ports. On entry, WORD_FLAG is already set for word
250; or byte operation. IP points to next instruction minus 1. DX has the port
251; value in it.
252
253DMAIN PROC NEAR
254 CMP WORD_FLAG,0 ; Is this "IN" for a word?
255 JNE GETWORDREAL ; Yes. Then go get a word.
256
257 IN AL,DX ; Else we'll just get a byte
258 MOV BYTE PTR SS:[BP+BP_AX],AL ; And put it into the user's AL reg.
259 JMP INEXIT ; Go return to the user
260
261GETWORDREAL:
262 IN AX,DX ; Get a word from the port
263 MOV WORD PTR SS:[BP+BP_AX],AX ; Put it into the user's AX register
264 MOV WORD_FLAG,0 ; Reset the word flag
265
266INEXIT:
267 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction, or past
268 ; the port value in the case of I/O
269 ; with an immediate port value
270 JMP POPIO ; Return to the V86 task
271
272PAGE
273
274; Control comes here from INDEXMA when it determines that the "OUT" instruction
275; is not for one of the XMA ports. On entry, WORD_FLAG is already set for word
276; or byte operation. IP points to next instruction minus 1. DX has the port
277; value in it.
278
279DMAOUT:
280
281; Check for DMA page registers in compatibility mode
282
283 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data
284 MOV DS,AX ; segment
285 CMP WORD_FLAG,0 ; Is this a word operation?
286 LJNE DISPLAY ; No? Sorry. We don't support word DMA
287 ; yet. We'll just have to signal an
288 ; error.
289 LEA BX,DMATABLE ; Point BX to the base of our channel
290 ; control blocks
291 CMP DX,0081H ; Is this out to the channel 2 page port
292 LJB NOT_DMA_PAGE ; If the port number is less than 81H
293 ; then the "OUT" is not to a DMA page
294 JA CHK_CHN_0 ; If the port number is above 81H, then
295 ; go check if it's below 87H, the page
296 ; port for channel 0
297 ADD BX,DMAENTRYLEN*2 ; If it's not below or above, then it
298 ; must be port 81H! Point BX to the
299 ; control block for channel 2
300 JMP CHNCOM ; Continue
301
302CHK_CHN_0:
303 CMP DX,0087H ; Is it the page port for channel 0?
304 JA CHK680 ; Nope. It's above that. Go check for
305 ; the Roundup IPL port
306 JE CHNCOM ; It IS the page port for channel 0.
307 ; BX already points to the control
308 ; block for channel 0.
309 CMP DX,0083H ; Is it the page port for channel 1?
310 JB SET_CHN_3 ; No. It's below that. Then it must
311 ; be the page port for channel 3!
312 LJA DISPLAY ; No. It's above it. We don't know any
313 ; ports between 83H and 87H. Go
314 ; signal an error.
315 ADD BX,DMAENTRYLEN*1 ; Yes. It's the page port for channel 1
316 ; Point BX to the control block for
317 ; channel 1.
318 JMP CHNCOM ; And continue
319
320; The port is greater than 87H
321
322CHK680:
323 CMP DX,680H ; Is it the manufacturing port (for IPL)
324 ; on the Roundup?
325 JE MANPORT ; Yes. Go IPL the system.
326 JMP DOOUT ; No. Pass the "OUT" on to the real
327 ; port.
328
329; The "OUT" is to the page port for channel 3
330
331SET_CHN_3:
332 ADD BX,DMAENTRYLEN*3 ; Point BX to the control block for
333 ; channel 3
334
335; Check to see if the value written to the page port is greater than 0FH.
336; Why? Let me tell you. Addresses are 20 bits, right? The user puts the
337; lower 16 bits into the channel port in two eight bit writes. The value
338; written to the page port is the upper eight bits of the address. But to
339; address 1M you only need 20 bits. Therefore, only the lower four bits are
340; valid if the address is to remain within the 1M address limit. So if the
341; value to be written to the page port is 10H or greater it is invalid, so
342; we will signal an error.
343
344CHNCOM:
345 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value that is to be written
346 ; to the page port
347 CMP AL,10H ; Is it 10H or greater?
348 JB CHNCONT ; Nope. We're still OK.
349
350; Oops. It's an invalid page port value. Time to signal an error. But wait.
351; If we just jump to DISPLAY as usual the code will just return to the V86
352; task. This is not good since we haven't Revised the DMA and it will end
353; up going to the wrong address. What we really want to do is kill the system.
354; To do this we will issue an interrupt 6, invalid instruction. The exception
355; handler checks to see from whence the interrupt came. If it came from the
356; emulator then it assumes something is terribly wrong and issues an NMI.
357; This is what we want. So we'll issue an INT 6 instead of a JMP DISPLAY.
358
359INVALID_PAGE:
360 INT 6 ; Signal and error
361 JMP INVALID_PAGE ; Do it again in case control comes
362 ; back here
363
364; At this point were still OK. BX points to the control block for the channel.
365; Let's translate the address we currently have to its real address and send
366; it out to the DMA channel.
367
368CHNCONT:
369 MOV BYTE PTR [BX+DMAPAGE],AL ; Put the page port value into the
370 ; control block
371 CALL XLATE ; Create the real address entries in
372 ; the control block
373 MOV DL,BYTE PTR [BX+DMACHN] ; Get the channel number from the c.b.
374 SHL DX,1 ; Convert it to a port address
375 MOV AL,BYTE PTR [BX+DMALR] ; Get the LSB of the real address
376 OUT DX,AL ; "OUT" it to the address port
377 JMP $+2 ; Wait a bit
378 MOV AL,BYTE PTR [BX+DMAMR] ; Get the MSB of the real address
379 OUT DX,AL ; "OUT" it to the address port
380 JMP $+2 ; Wait a bit
381 MOV DL,BYTE PTR [BX+DMAPP] ; Get the page port
382 MOV AL,BYTE PTR [BX+DMAPR] ; Get the real page number
383 OUT DX,AL ; Do the "OUT" to the DMA page port
384 JMP OUTEXITDMA ; That's it
385
386PAGE
387
388; This is where we come when we want to simply send the "OUT" to the real port.
389
390DOOUT:
391 CMP WORD_FLAG,0 ; Is this an "OUT" for a word?
392 JNE PUTWORDREAL ; Aye. Go put out a word.
393
394 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Nay. It is for a byte. Get the
395 ; byte from the user's AL register
396 OUT DX,AL ; And send it out to the port
397 JMP OUTEXITDMA ; Time to leave
398
399PUTWORDREAL:
400 MOV AX,WORD PTR SS:[BP+BP_AX] ; Get the word form the user's AX
401 OUT DX,AX ; And thrust it out to the port
402 MOV WORD_FLAG,0 ; Reset the word flag
403
404OUTEXITDMA:
405
406 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction, or past
407 ; the port value in the case of I/O
408 ; with an immediate port value
409 JMP POPIO ; Return to the V86 task
410
411PAGE
412
413; It's not an "OUT" to one of the DMA page ports.
414
415NOT_DMA_PAGE:
416 CMP DX,(OUT_TABLE_END-OUT_TABLE)/3 ; Is the port within the range
417 ; covered by our jump table, i.e.,
418 ; 0 to 20H
419 JAE NOTCOWBOY ; Nope. Let's go check if it's the IPL
420 ; port on the AT
421 MOV AL,DL ; Yes, it's handled by our jump table
422 MOV AH,3 ; Convert the port number to an index
423 MUL AH ; into the jump table by multiplying
424 ; by 3. Jump table entry are 3 bytes.
425 LEA CX,OUT_TABLE ; Get the offset of the jump table
426 ADD AX,CX ; And add it on to the index
427 JMP AX ; Jump to the jump table entry for this
428 ; port
429
430NOTCOWBOY:
431 CMP DX,80H ; Is it the manufacturing (IPL) port for
432 ; the AT?
433 JNE DOOUT ; Negative. Then let's just do a plain
434 ; vanilla "OUT" to the real port.
435MANPORT:
436 MOV AL,0FEH ; It's the IPL port! Send out a FEH to
437 OUT 064H,AL ; reset the system.
438
439HALT: HLT ; In case that trick didn't work @P1C
440 JMP HALT ; we'll just wait here until @P1C
441 ; somebody hits the big red switch.
442
443PAGE
444
445; This is the entry for an "OUT" to port 0CH. An "OUT" to this port will
446; reset the controller so that the next out will be to the least significant
447; byte of the address register. The way you set the lower 16 bits of the
448; address is by sending the two bytes to the same port, first the least
449; significant byte (LSB) and then the most significant byte (MSB). The port
450; knows that successive bytes to the port mean successively higher bytes of
451; the address. We emulate this with our DMABYTE flag. Since the user will
452; only be sending two bytes to an address port this flag will be toggled
453; between 0 and 1 indicating that the "OUT" was to the LSB if 0 and to the
454; MSB if 1. A write to port 0CH tells the controller that the next write
455; will be for the LSB. We emulate this by setting our DMABYTE flag to 0.
456
457RESET_BYTE_PTR:
458 MOV DMABYTE,0 ; Reset the byte flag
459 JMP DOOUT ; Send the "OUT" to the real port
460
461PAGE
462
463; The following entries handle the "OUT"s to the address ports for channels
464; 0 to 3. These are ports 00, 02, 04 and 06 respectively. As mentioned
465; above the address written to these ports is done in two steps. First the
466; least significant byte (LSB) is written, the the most significant byte (MSB)
467; is written. This results in a 16 bit value in the address port. Combine
468; this with the byte in the page port and you have a 24 bit DMA address. The
469; code below emulates this by putting the byte that is "OUT"ed to the LSB if
470; DMA BYTE is 0 and to the MSB if DMABYTE is 1. DMABYTE is toggled between 0
471; and 1 each time there is a write to the port. So the bytes go alternately
472; to the LSB and the MSB.
473
474; "OUT" is to port 00, the address port for channel 0.
475
476CHN_0:
477 LEA BX,DMATABLE ; Point BX to the control block for
478 ; channel 0
479 JMP MOVBYTE ; Go get the byte
480
481; "OUT" is to port 02, the address port for channel 1.
482
483CHN_1:
484 LEA BX,DMATABLE+(1*DMAENTRYLEN) ; Point BX to the control block for
485 ; channel 1
486 JMP MOVBYTE ; Go get the byte
487
488; "OUT" is to port 04, the address port for channel 2.
489
490CHN_2:
491 LEA BX,DMATABLE+(2*DMAENTRYLEN) ; Point BX to the control block for
492 ; channel 2
493 JMP MOVBYTE ; Go get the byte
494
495; "OUT" is to port 06, the address port for channel 3.
496
497CHN_3:
498 LEA BX,DMATABLE+(3*DMAENTRYLEN) ; Point BX to the control block for
499 ; channel 3
500
501MOVBYTE:
502 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the byte from the user's AL
503 XOR DMABYTE,1 ; Toggle the DMABYTE flag
504 JZ MOVMSB ; Was the flag set to 1? If so, go
505 ; put the byte to the MSB
506 MOV BYTE PTR [BX+DMALSB],AL ; Else it was 0 so put the byte in the
507 ; LSB for this channel
508 JMP OUTEXITDMA ; And exit
509
510MOVMSB:
511 MOV BYTE PTR [BX+DMAMSB],AL ; Put the byte in the MSB for this
512 ; channel
513 JMP OUTEXITDMA ; And exit
514
515PAGE
516
517; This is the entry point for an "OUT" to port 18H. It has something to do
518; with the advanced DMA channels 4 thru 7. If the function number in the high
519; nibble of AL is 2, set the base register, then we'll save the advanced channel
520; number given in the low nibble of AL. If the function is not 2 then we will
521; inhibit the setting of the base register.
522
523CHK_FUNCTION:
524 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value to be "OUT"ed to 18H
525 SHR AL,4 ; Shift the function number into AL
526 CMP AL,2 ; Is this the function to set the base
527 ; register?
528 JE SAVE_CHN ; Yup. Go save the channel number.
529 MOV DMABYTE,3 ; Nope. Inhibit setting the base reg.
530 JMP DOOUT ; Send the "OUT" to the real port
531
532SAVE_CHN:
533 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Get the value in AL again
534 AND AL,07H ; Mask off the function number leaving
535 ; the channel number
536 MOV DMA_ADV_CHN,AL ; And save it
537 JMP RESET_BYTE_PTR ; Go reset the byte flag
538
539PAGE
540
541; This is the entry for an "OUT" to port 1AH.
542
543CHK_BASE_REG:
544 CMP DMABYTE,3 ; Are we inhibiting setting the base
545 ; register?
546 LJAE DOOUT ; Yes. Then just sent the "OUT" to the
547 ; real port
548 LEA BX,DMATABLE ; Point BX to the channel control blocks
549 MOV AL,DMA_ADV_CHN ; Get the current advanced channel
550 MOV AH,DMAENTRYLEN ; and multiply by the size of a
551 MUL AH ; control block. Now AX is the index
552 ; for the current control block
553 ADD BX,AX ; Add this on to the base and BX points
554 ; to the control block
555 SUB AX,AX ; Purge AX
556 MOV AL,DMABYTE ; Get the byte flag
557 ADD BX,AX ; And add it on to BX
558 MOV CL,BYTE PTR SS:[BP+BP_AX] ; Get the out value into CL
559
560; Now put it in the control block. Notice that BX is the base of the control
561; block plus the byte flag. Now we add on the offset for the LSB entry. A
562; little pondering of this code will reveal that for DMABYTE = 0 the byte in
563; CL goes to the LSB entry, for DMABYTE = 1 it goes to the MSB entry and for
564; DMABYTE = 2 it goes to the page entry.
565
566 MOV BYTE PTR [BX+DMALSB],CL ; Save the byte in the control block
567 INC DMABYTE ; Increment our byte counter
568 CMP DMABYTE,3 ; Was the page entry written?
569 LJNE OUTEXITDMA ; Nope. Let's just exit.
570
571 SUB BX,AX ; The page was written. Point BX back
572 ; to the start of the control block.
573 CMP CL,10H ; Does the page point to over 1M?
574 LJAE INVALID_PAGE ; Yes. Better signal an error.
575
576 CALL XLATE ; The page is OK. Translate the virtual
577 ; address to the real address
578 MOV AL,BYTE PTR [BX+DMALR] ; Get the LSB of the real address
579 OUT 1AH,AL ; "OUT" it to the port 1AH
580 JMP $+2 ; Wait a bit
581 MOV AL,BYTE PTR [BX+DMAMR] ; Get the MSB of the real address
582 OUT 1AH,AL ; "OUT" it to the port 1AH
583 JMP $+2 ; Wait a bit
584 MOV AL,BYTE PTR [BX+DMAPR] ; Get the real page number
585 OUT 1AH,AL ; Do the "OUT" to port 1AH
586 JMP OUTEXITDMA ; That's all
587
588PAGE
589
590; XLATE is a procedure to translate the virtual DMA address to the real DMA
591; address. It takes the virtual address that was "OUT"ed to the DMA ports
592; and follows it through the page tables to get the real address. It puts
593; the real address into the current channel control block.
594
595XLATE PROC
596
597; Calcuate the page fram offset of the real address, the lower 12 bits.
598
599 MOV AX,WORD PTR [BX+DMALSB] ; Get the virtual LSB and MSB
600 AND AH,0FH ; Wipe out the top nibble. This leaves
601 ; us with only the offset into the 4K
602 ; page frame. This real address will
603 ; have the same offset into the page
604 ; frame
605 MOV WORD PTR [BX+DMALR],AX ; So save this in the real LSB
606
607; Pick up page table address.
608
609 MOV SI,SGTBLOFF ; Point ST to the first page directory
610 ; entry
611 DATAOV ; Get the address of the current page
612 LODSW ; table
613 SUB AL,AL ; Clear the access rights byte. This
614 ; makes it a real offset.
615 DATAOV ; Point SI to the page table
616 MOV SI,AX
617 MOV AX,WORD PTR [BX+DMAMSB] ; Get the MSB and page
618 SHR AX,4 ; Shift the top four bits off the end
619 ; of the register these four bits are
620 ; not used. We are dealing with a 24
621 ; bit address where only 20 bits are
622 ; used.
623 SHL AX,4-2 ; Shift back 2 bits. This puts zeroes
624 ; in the high bits while converting
625 ; the address to a page table index.
626 ; Page table entries are 4 bytes long,
627 ; hence, shift left 2 bits.
628 ADD SI,AX ; Add the page table index on to the
629 ; offset of the page table. SI now
630 ; points to the correct page table
631 ; entry.
632 ADD SI,1 ; Step over the access rights byte
633
634 MOV AX,HUGE_PTR ; Load DS with a selector that accesses
635 MOV DS,AX ; all of memory as data
636 ADDROV ; Load the address of the page frame
637 LODSW ; into EAX
638 MOV CX,SYS_PATCH_DS ; Point DS back to our data segment
639 MOV DS,CX
640
641; Now AX contains the address of the page frame shifted right 8 bits. Remember
642; that we incremented SI to skip the access rights? This gave us the page
643; frame offset with out the lower byte. The lSB real address was already set
644; above, as well as the low nibble of the real MSB. AX now contains the page
645; and MSB of the real address. The low nibble of the MSB was already set so
646; we just OR on the high nibble of the MSB. Then we set the real page. Then
647; we're all done.
648
649 OR BYTE PTR [BX+DMAMR],AL ; Turn on high 4 bits of the real MSB
650 MOV BYTE PTR [BX+DMAPR],AH ; Set the real page
651
652 RET
653
654XLATE ENDP
655
656DMAIN ENDP
657
658PROG ENDS
659
660 END
diff --git a/v4.0/src/DEV/XMAEM/INDEEMU.ASM b/v4.0/src/DEV/XMAEM/INDEEMU.ASM
new file mode 100644
index 0000000..9534ac2
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEEMU.ASM
@@ -0,0 +1,653 @@
1PAGE 60,132
2TITLE INDEEMU - 386 XMA EMULATOR - Sensitive Instruction Emulator
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEEMU *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corporation *
11* *
12* DESCRIPTIVE NAME: 386 XMA emulator - emulate sensitive instructions *
13* *
14* STATUS (LEVEL) : VERSION (0) LEVEL (1.0) *
15* *
16* FUNCTION : When the I/O privilege level (IOPL) is less than 3 then *
17* the processor flags an exception and gives control to *
18* the emulator whenever the virtual 8086 (V86) task tries *
19* to execute a sensitive instruction. The set of sensitive *
20* instructions includes: STI, CLI, INT3, INTO, IRET, INT, *
21* PUSHF, POPF, LOCK, IN and OUT. This moudle will emulate *
22* these intructions for the V86 task. It will also set the *
23* IOPL to 3. This will keep the processor from raising *
24* further exceptions for these instructions. This in turn *
25* improves performance because the emulator will not be *
26* given control each time one of these instructions is *
27* executed by the V86 task. *
28* *
29* This module also has a small piece of code to handle *
30* exception 7, coprocessor not available. This exception *
31* is raised when the EM (EMulation), MP (Monitor Processor),*
32* and TS (Task Switch) bits in CR0 are on. When this *
33* happens it turns off these bits and retries the instruc- *
34* tion that faulted. *
35* *
36* MODULE TYPE : ASM *
37* *
38* REGISTER USAGE : 80386 Standard *
39* *
40* RESTRICTIONS : None *
41* *
42* DEPENDENCIES : None *
43* *
44* ENTRY POINT : EMULATE *
45* *
46* LINKAGE : Jumped to by INDEEXC *
47* *
48* INPUT PARMS : None *
49* *
50* RETURN PARMS : None *
51* *
52* OTHER EFFECTS : None *
53* *
54* EXIT NORMAL : IRET to the V86 task *
55* *
56* EXIT ERROR : Jump to error routine in INDEEXC *
57* *
58* EXTERNAL *
59* REFERENCES : POPREGS - Entry point in INDEEXC to pop the registers P1C*
60* off the stack and IRET to the V86 task. *
61* DISPLAY - Entry point in INDEEXC for the error routine *
62* that does the NMI to the error handler. *
63* INT15 - Entry point to INDEI15, the INT 15 handler. *
64* XMAIN - Entry point in INDEXMA to handle IN for a byte *
65* at the port address in DX *
66* INW - Entry point in INDEXMA to handle IN for a word *
67* at the port address in DX *
68* INIMMED - Entry point in INDEXMA to handle IN for a byte *
69* at the immediate port address given *
70* INWIMMED- Entry point in INDEXMA to handle IN for a word *
71* at the immediate port address given *
72* XMAOUT - Entry point in INDEXMA to handle OUT for a byte *
73* at the port address in DX *
74* OUTW - Entry point in INDEXMA to handle OUT for a word *
75* at the port address in DX *
76* XMAOUTIMMED - Entry point in INDEXMA to handle OUT for a *
77* byte at the immediate port address given *
78* XMAOUTWIMMED - Entry point in INDEXMA to handle OUT for a *
79* word at the immediate port address given *
80* MANPORT - Entry point in INDEDMA to issue an out to the *
81* port that will reIPL the system *
82* *
83* SUB-ROUTINES : None *
84* *
85* MACROS : DATAOV - Create a prefix for the following instruction *
86* so that it accesses data 32 bits wide *
87* ADDROV - Create a prefix for the following instruction *
88* so that it uses addresses that are 32 bits wide *
89* CMOV - Move to or from a control register *
90* *
91* CONTROL BLOCKS : INDEDAT.INC *
92* *
93* CHANGE ACTIVITY : *
94* *
95* $MOD(INDEEMU) COMP(LOAD) PROD(3270PC) : *
96* *
97* $D0=D0004700 410 870523 D : NEW FOR RELEASE 1.1 *
98* $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES *
99* *
100* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
101#
102
103 .286P ; Enable recognition of 286 privileged instructs.
104
105 .XLIST ; Turn off the listing
106 INCLUDE INDEDAT.INC
107
108 IF1 ; Only include macros on the first pass
109 INCLUDE INDEOVP.MAC
110 INCLUDE INDEINS.MAC
111 ENDIF
112 .LIST ; Turn on the listing
113
114 PUBLIC INDEEMU
115
116PROG SEGMENT PARA PUBLIC 'PROG'
117
118 ASSUME CS:PROG
119 ASSUME DS:NOTHING
120 ASSUME ES:NOTHING
121 ASSUME SS:NOTHING
122
123INDEEMU LABEL NEAR
124
125 ; The following entries are in other modules
126
127 EXTRN XMAIN:NEAR ; Byte IN from port # in DX
128IN_INST EQU XMAIN ; @P1C
129 EXTRN INW:NEAR ; Word IN from port # in DX
130 EXTRN INIMMED:NEAR ; Byte IN from immediate port #
131 EXTRN INWIMMED:NEAR ; Word IN from immediate port #
132 EXTRN XMAOUT:NEAR ; Byte OUT to port # in DX
133OUT_INST EQU XMAOUT ; @P1C
134 EXTRN OUTW:NEAR ; Word OUT to port # in DX
135 EXTRN XMAOUTIMMED:NEAR ; Byte OUT to immediate port #
136OUTIMMED EQU XMAOUTIMMED ;
137 EXTRN OUTWIMMED:NEAR ; Word OUT to immediate port #
138 EXTRN DISPLAY:NEAR ; Signal the error handler
139 EXTRN MANPORT:NEAR ; ReIPL the system
140 EXTRN INT15:NEAR ; Handle INT 15
141 EXTRN POPREGS:NEAR ; Pop the registers and IRET to V86 task @P1C
142
143PAGE
144;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
145;; The following is a jump table for each of the instructions. There are 256 ;;
146;; entries, each three bytes long, one for each possible op-code. The op- ;;
147;; code is used as an index into the table. Each entry is a jump instruction ;;
148;; instruction telling where to jump for each particular op-code. The table ;;
149;; is initialized such that all in- structions jump to the routin for ;;
150;; unexpected op-codes. Then the entries for the instructions we want to ;;
151;; emulate are set to jump to the appropriate routine. ;;
152;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
153
154TABLE:
155 .XLIST
156 REPT 256 ; Initialize the table so that all instructions
157 JMP UNEXPECTED ; jump to UNEXPECTED
158 ENDM
159 .LIST
160
161; Now set up the entries for the instructions we want to emulate
162
163TABLE_END:
164 ORG TABLE+(0FBH*3) ; 0FBH is the op-code for STI.
165 JMP STI_INST ; @P1C
166 ORG TABLE+(0FAH*3) ; 0FAH is the op-code for CLI.
167 JMP CLI_INST ; @P1C
168 ORG TABLE+(0F0H*3) ; 0F0H is the op-code for LOCK.
169 JMP LOCK_INST ; @P1C
170 ORG TABLE+(0EFH*3) ; 0EFH is the op-code for OUT for a word.
171 JMP OUTW ;
172 ORG TABLE+(0EEH*3) ; 0EEH is the op-code for OUT for a byte.
173 JMP OUT_INST ; @P1C
174 ORG TABLE+(0EDH*3) ; 0EDH is the op-code for IN for a word.
175 JMP INW
176 ORG TABLE+(0ECH*3) ; 0ECH is the op-code for IN for a byte.
177 JMP IN_INST ; @P1C
178 ORG TABLE+(0E7H*3) ; 0E7H is the op-code for OUT for a word to
179 JMP OUTWIMMED ; an immediate port value.
180 ORG TABLE+(0E6H*3) ; 0E6H is the op-code for OUT for a byte to
181 JMP OUTIMMED ; an immediate port value.
182 ORG TABLE+(0E5H*3) ; 0E5H is the op-code for IN for a word to
183 JMP INWIMMED ; an immediate port value.
184 ORG TABLE+(0E4H*3) ; 0E4H is the op-code for IN for a byte to
185 JMP INIMMED ; an immediate port value.
186 ORG TABLE+(0CFH*3) ; 0CFH is the op-code for IRET.
187 JMP IRET_INST ; @P1C
188 ORG TABLE+(0CEH*3) ; 0CEH is the op-code for INTO.
189 JMP INTO_INST ; @P1C
190 ORG TABLE+(0CDH*3) ; 0CDH is the op-code for INT.
191 JMP INT_INST ; @P1C
192 ORG TABLE+(0CCH*3) ; 0CCH is the op-code for INT3.
193 JMP INT3 ;
194 ORG TABLE+(09DH*3) ; 09DH is the op-code for POPF.
195 JMP POPF_INST ; @P1C
196 ORG TABLE+(09CH*3) ; 09CH is the op-code for PUSHF.
197 JMP PUSHF_INST ; @P1C
198 ORG TABLE+(00FH*3) ; 00FH is the op-code for POP CS.
199 JMP MANPORT ; Expedient until 0F opcode properly emulated
200
201 ORG TABLE_END
202
203VALUE3 DB 3
204
205 PUBLIC EMULATE
206 PUBLIC POPIO
207 PUBLIC INTCOM
208
209EMULATE PROC NEAR
210
211 CLD
212
213PAGE
214;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
215;; Get the op-code that faulted from real memory. Use it as an index into ;;
216;; the jump table to go to the appropriate routine. ;;
217;; ;;
218;; Note: The DATAOV macro creates a prefix that makes the instruction that ;;
219;; immediately follows access all data as 32 bits wide. Similarly, ;;
220;; the ADDROV macro creates a prefix that makes the instruction that ;;
221;; immediately follows use addresses that are 32 bits wide. ;;
222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
223
224 MOV AX,HUGE_PTR ; Load DS with a selector that will
225 MOV DS,AX ; access all of memory as data
226
227 MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86
228 MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP
229
230 DATAOV
231 MOV SI,SS:[BP+BP_IP] ; Get the V86 IP into our SI. The high
232 DATAOV ; order word is zeroes.
233 MOV AX,SS:[BP+BP_CS] ; Get the V86 CS into AX. Again, the
234 DATAOV ; high order word is zeroes.
235 SHL AX,4 ; Multiply CS by 16 to convert it to an
236 DATAOV ; offset.
237 ADD SI,AX ; Add on IP. Now SI contains the offset
238 ; from 0 of the instruction that
239 ; faulted.
240 ADDROV
241 LODSB ; Get the op-code into AL
242
243 ADDROV ; Intel bug # A0-119
244 NOP ; Intel bug # A0-119
245
246 MUL VALUE3 ; Multiply the op-code by 3 to get an
247 LEA BX,TABLE ; index into the jump table
248 ADD AX,BX ; Add on the offset of the base of the
249 ; table
250 JMP AX ; Jump to the entry in the table. This
251 ; entry will then jump us to the
252 ; routine that handles this op-code.
253
254PAGE
255;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
256;; Woops! We got an op-code that we did not expect to fault. First let's ;;
257;; check if this instruction faulted because the coprocessor was not avail- ;;
258;; able. This will be signalled by an exception code of 07. If this is the ;;
259;; case then reset the the following bits in CR0: EM (EMulation) says that ;;
260;; coprocessor functions are emulated by software when set to 0; MP (monitor ;;
261;; Processor), when set to 1 raises an exception 7 when TS (Task Switched) ;;
262;; is set to 1 and a WAIT instruction is executed. TS is set every time ;;
263;; there is a task switch. ;;
264;; ;;
265;; If it was not an execption 7 then we'll check the I/O privilege level ;;
266;; (IOPL). An IOPL other less than 3 will cause all I/O and some sensitive ;;
267;; instructions to fault. We really don't want to be bothered by all these ;;
268;; faulting instructions so we'll set the IOPL to 3 which will allow anyone ;;
269;; to do I/O and the sensitive instructions. This will improve performance ;;
270;; since the V86 task will be interrupted less often. But first we'll check ;;
271;; to see if the IOPL is already 3. If so then we got trouble. Most likely ;;
272;; it's an invalid op-code. In this case we'll signal the error handler in ;;
273;; INDEEXC. ;;
274;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
275
276UNEXPECTED:
277 CMP SS:WORD PTR [BP+BP_EX],0007H
278 ; Check if it's an 07 exception -- co-
279 ; processor not available
280 JNE TRYIOPL3 ; If no then try setting the IOPL to 3
281
282 MOV AX,8000H ; Set the paging enabled bit
283 DATAOV
284 SHL AX,16 ; It's the one all the way on the left
285 MOV AX,0001H ; Set protect mode on. Leave all other
286 ; bits off.
287 CMOV CR0,EAX ; Reset CR0
288 JMP POPREGS ; Return to the V86 task @P1C
289
290; Try setting the IOPL to 3
291
292TRYIOPL3:
293 MOV BX,AX ; Save the faulty op-code in BX
294 MOV AX,SS:WORD PTR [BP+BP_FL] ; Get the V86 flags and check if
295 AND AX,3000H ; IOPL is already set to 3
296 CMP AX,3000H
297 JE WHOOPS ; If we're already at IOPL 3 the some-
298 ; things fishy. Time to signal an
299 ; error.
300 OR SS:WORD PTR [BP+BP_FL],3000H
301 ; Otherwise set IOPL to 3 and return to
302 JMP POPREGS ; the V86 task and let it try to @P1C
303 ; execute the instruction again.
304
305; We got trouble.
306
307WHOOPS:
308
309; Convert jump address back to opcode in al
310
311 MOV AX,BX ; Put the jump table index back into AX
312 LEA BX,TABLE ; Subtract the offset of the base of the
313 SUB AX,BX ; jump table
314 DIV VALUE3 ; Divide AX by 3 to get the opcode back.
315 JMP DISPLAY ; Go to the error routine in INDEEXC
316
317PAGE
318;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
319;; Emulate the LOCK instruction. This is an instruction we really don't want ;;
320;; to emulate so we will set the IOPL to 3 so that further LOCKs won't bother ;;
321;; us. If the exception code is for "invalid op-code" then we will just jump ;;
322;; to the routine above to set the IOPL to 3. Otherwise we will just step IP ;;
323;; past the LOCK instruction thus treating it as a NOP. ;;
324;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
325
326LOCK_INST: ; @P1C
327 CMP SS:WORD PTR [BP+BP_EX],0006H ; Check if it's an invalid op code
328 JNE TRYIOPL3 ; Try setting the IOPL to 3
329 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction
330 JMP POPIO ; thus treating it as a NOP
331
332PAGE
333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
334;; Emulate the STI, enable interupts, instruction. This is pretty simple to ;;
335;; do. Just get the V86 task's flags and flip on the enable interrupts bit. ;;
336;; And while we're at it we'll set the IOPL to 3. ;;
337;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
338
339STI_INST: ; @P1C
340 OR WORD PTR SS:[BP+BP_FL],3200H ; Set the enable interrupts bit
341 ; and set IOPL to 3
342 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past STI instruction
343 JMP POPIO
344
345PAGE
346;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
347;; Emulate the CLI, disable interrupts, instruction. Just as in STI above, ;;
348;; all that is needed is to turn of the enable interrups bit. And again, set ;;
349;; the IOPL to 3 so that we won't get control again. ;;
350;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
351
352CLI_INST: ; @P1C
353 AND WORD PTR SS:[BP+BP_FL],3DFFH ; Set interrupts disabled
354 OR WORD PTR SS:[BP+BP_FL],3000H ; Insure IOPL = 3 for speed
355 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past instruction
356 JMP POPIO
357
358PAGE
359;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
360;; Emulate the INT3 instruction. To do this we put a 3 in the exception code ;;
361;; and jump to the portion of the code that emulates the INT instruction. ;;
362;; That code uses the exception code to get the interrupt vector from real ;;
363;; memory and gives control to the V86 task at the interrupt address. ;;
364;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365
366INT3:
367 MOV WORD PTR SS:[BP+BP_EX],3 ; Put a 3 in the exception field
368 ; This will cause the INTCOM
369 ; section to go to interrupt 3
370 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past INT3 inscruction
371 JMP INTCOM ; Go get the vector from real
372 ; memory
373
374PAGE
375;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
376;; Emulate the INTO instruction. This is done just like the INT3 above. It ;;
377;; puts a 4 in the exception code and jumps to the code in the INT emulator ;;
378;; that will get the real address of the interrupt. ;;
379;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
380
381INTO_INST: ; @P1C
382 MOV WORD PTR SS:[BP+BP_EX],4 ; Put a 4 in the exception field
383 ; This will cause the INTCOM
384 ; section to go to interrupt 4
385 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past INTO inscruction
386 JMP INTCOM ; Go get the vector from real
387 ; memory
388
389PAGE
390;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
391;; Emulate the IRET instruction. Get CS, IP and the flags off of the V86 ;;
392;; task's stack and place them in the register values on our stack. When we ;;
393;; return control to the V86 task these values will be taken off of our stack ;;
394;; and placed in the V86 task's registers. ;;
395;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
396
397IRET_INST: ; @P1C
398 DATAOV ; Get the user's ESP (32 bit SP)
399 MOV AX,SS:[BP+BP_SP] ; and save it in ESI.
400 DATAOV
401 MOV SI,AX
402 ADD AX,6 ; Add 6 to the user's SP. This
403 MOV SS:WORD PTR [BP+BP_SP],AX ; skips over the IP, CS and
404 ; flags on the user's stack.
405 ; This puts SP where it would be
406 ; after the IRET. It assumes
407 ; there are at least six bytes
408 ; on the stack.
409 DATAOV
410 MOV AX,SS:[BP+BP_SS] ; Get the user's SS and multiply
411 DATAOV ; by 16. This converts the
412 SHL AX,4 ; segment value to an offset.
413 DATAOV ; Add this on to the ESP value in
414 ADD SI,AX ; ESI and now ESI is the offset
415 ; from 0 of the user's stack.
416 ADDROV
417 LODSW ; Get the user's EIP into EAX
418
419 ADDROV ; Intel bug # A0-119
420 NOP ; Intel bug # A0-119
421
422 MOV WORD PTR SS:[BP+BP_IP],AX ; Put IP into the register values
423 ; on our stack
424 ADDROV
425 LODSW ; Get the user's CS into EAX
426
427 ADDROV ; Intel bug # A0-119
428 NOP ; Intel bug # A0-119
429
430 MOV WORD PTR SS:[BP+BP_CS],AX ; Put CS into the register values
431 ; on our stack
432 ADDROV
433 LODSW ; Get the user's flags (32 bits)
434
435 ADDROV ; Intel bug # A0-119
436 NOP ; Intel bug # A0-119
437
438 AND AX,3FFFH ; Clean up the flags
439 OR AX,3000H ; Set IOPL to 3
440 MOV WORD PTR SS:[BP+BP_FL],AX ; Put the flags into the register
441 ; values on our stack
442 JMP POPREGS ; Go return to the V86 task @P1C
443
444;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
445;; Emulate the INT instruction. Step the V86 task's CS and IP past the INT ;;
446;; instruction. Push the flags, CS and IP in the task's stack. Get the ;;
447;; interrupt number and use it to find the appropriate interrupt vector in ;;
448;; low memory. Set the task's CS and IP to the interrupt vector and return ;;
449;; control to the task. ;;
450;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
451
452INT_INST: ; @P1C
453
454; Get the interrupt number from the instruction. It is the second byte of the
455; instruction. DS:SI was used to get the op-code. Now DS:SI points to the next
456; byte of the instruction. All we have to do is get it.
457
458 ADDROV
459 LODSB ; Get the interrupt number
460
461 ADDROV ; Intel bug # A0-119
462 NOP ; Intel bug # A0-119
463
464 MOV AH,0 ; Clear the high byte
465 MOV WORD PTR SS:[BP+BP_EX],AX ; Save the interrupt number in
466 ; the exception code field
467
468; Step IP past the INT instruction.
469
470 ADD WORD PTR SS:[BP+BP_IP],2 ; STEP IP PAST INT INSTRUCTION
471
472; Check for INT 15. This is handled by INDEI15.
473
474INTCONT:
475 CMP AL,15H ; Is it interrupt 15?
476 JNE INTCOM ; If not, continue
477 JMP INT15 ; Else go to INDEI15
478
479; Now use the interrupt number to get the appropriate interrupt vector from
480; low core.
481
482INTCOM:
483 MOV AX,HUGE_PTR ; Load ES with the selector that
484 MOV ES,AX ; accesses all of memory as data
485 DATAOV
486 MOV DI,SS:[BP+BP_SP] ; Load EDI with the user's ESP
487 ; Now ES:EDI points to the user's
488 ; stack
489 SUB DI,6 ; Decrement "SP" to make space for
490 ; the flags, CS snd IP
491 MOV SS:WORD PTR [BP+BP_SP],DI ; Set the user's new SP
492
493 DATAOV
494 MOV AX,SS:[BP+BP_SS] ; Get the user's SS and shift it
495 DATAOV ; left four bits to convert it
496 SHL AX,4 ; to an offset
497 DATAOV ; Add it to EDI so that EDI now
498 ADD DI,AX ; contains the physical offset
499 ; of the user's stack
500
501; Now put the flags, CS and IP on the V86 task's stack. They are put on in the
502; order IP, CS, flags. This is backwards from the INT push order of flags, CS
503; and then IP. This is because we are moving forward through memory (CLD)
504; whereas the stack grows backwards through memory as things apushed on to it.
505
506 MOV AX,SS:[BP+BP_IP]
507 ADDROV
508 STOSW ; Put IP on the V86 task's stack
509 ADDROV ; Intel bug # A0-119
510 NOP ; Intel bug # A0-119
511
512 MOV AX,SS:[BP+BP_CS]
513 ADDROV
514 STOSW ; Put CS on the V86 task's stack
515 ADDROV ; Intel bug # A0-119
516 NOP ; Intel bug # A0-119
517
518 MOV AX,SS:[BP+BP_FL] ; Get the v86 task's flags
519 OR AX,3000H ; Set IPOL to 3 while we're here
520 ADDROV
521 STOSW ; Put the flags on the v86 task's
522 ; stack
523
524 ADDROV ; INTEL BUG # A0-119
525 NOP ; INTEL BUG # A0-119
526 AND AX,3CFFH ; Clean up flags for our IRET
527 MOV WORD PTR SS:[BP+BP_FL],AX
528
529; Use the interrupt number to get the CS and IP of the interrupt routine
530
531 MOV SI,SS:[BP+BP_EX] ; Get the interrupt number
532 SHL SI,2 ; Multiply by 4 since interrupt
533 ; vectors are 4 bytes long
534 LODSW ; Get the IP for the vector
535 MOV WORD PTR SS:[BP+BP_IP],AX ; Put it in the V86 task's IP
536 LODSW ; Get the CS for the vector
537 MOV WORD PTR SS:[BP+BP_CS],AX ; Put it in the V86 task's CS
538
539 JMP POPREGS ; Go return to the V86 task @P1C
540
541;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
542;; Emulate the PUSHF instruction. Get the V86 task's flags and put them on ;;
543;; its stack. ;;
544;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
545
546PUSHF_INST: ; @P1C
547 MOV AX,HUGE_PTR ; Load ES with the selector that
548 MOV ES,AX ; accesses all of memory as data
549
550 DATAOV
551 MOV DI,SS:[BP+BP_SP] ; Load EDI with the V86 task's SP
552 SUB DI,2 ; Decrement "SP" by one word to
553 ; make room for the flags
554 MOV SS:WORD PTR [BP+BP_SP],DI ; Store the new V86 task's SP
555 DATAOV
556 MOV AX,SS:[BP+BP_SS] ; Get the user's SS and shift it
557 DATAOV ; left four bits to convert it
558 SHL AX,4 ; to an offset
559 DATAOV ; Add it to EDI so that EDI now
560 ADD DI,AX ; contains the physical offset
561 ; of the user's stack
562 MOV AX,SS:[BP+BP_FL] ; Get the v86 task's flags
563 OR AX,3000H ; Set IPOL to 3 so that we won't
564 ADDROV ; be bothered anymore
565 STOSW ; Put the flags on the stack
566 ADDROV ; Intel bug # A0-119
567 NOP ; Intel bug # A0-119
568
569 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past PUSHF instruction
570
571 JMP POPIO ; Go return to the V86 task
572
573;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
574;; Emulate the POPF instruction. Get the next word off of the V86 task's ;;
575;; stack, set IOPL to 3 and put it in the V86 task's flags. ;;
576;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
577
578POPF_INST: ; @P1C
579 MOV AX,HUGE_PTR ; Big segment selector
580 MOV DS,AX ; Stack seg
581 DATAOV ; Create 32-bit operand prefix for next instruction
582 MOV AX,SS:[BP+BP_SP] ; stack ptr
583 DATAOV ; Create 32-bit operand prefix for next instruction
584 MOV SI,AX ; SI = stack ptr
585 ADD AX,2
586 MOV SS:WORD PTR [BP+BP_SP],AX ; NEW STACK POINTER
587 DATAOV ; Create 32-bit operand prefix for next instruction
588 MOV AX,SS:[BP+BP_SS] ; Convert ss to 20 bit address
589 DATAOV ; Create 32-bit operand prefix for next instruction
590 SHL AX,4
591 DATAOV ; Create 32-bit operand prefix for next instruction
592 ADD SI,AX ; Now have 32-bit offset from 0
593 ADDROV ; Use 32-bit offset
594 LODSW ; GET REAL MODE FLAGS
595 ADDROV ; INTEL BUG # A0-119
596 NOP ; INTEL BUG # A0-119
597 AND AX,0FFFH ; CLEAN UP FLAGS FOR OUR IRET
598; A POPF at level 3 will not change IOPL - WE WANT TO KEEP IT AT IOPL = 3
599 OR AX,3000H ; SET IOPL = 3
600 MOV WORD PTR SS:[BP+BP_FL],AX
601 ADD WORD PTR SS:[BP+BP_IP],1 ; STEP IP PAST INSTRUCTION
602 JMP POPIO ; CHECK FOR SINGLE STEP
603
604;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
605;; The following entry point, POPIO, is the exit routine for situations when ;;
606;; a single step condition would be lost by a normal IRET to the V86 task. ;;
607;; You see, in real mode the single step interrupt gets control whenever the ;;
608;; single step flag is on. However, we just got control and emulated the ;;
609;; instruction. If we just return to the V86 task at CS:IP then the step ;;
610;; between the instruction we just emulated and the next instruction will be ;;
611;; missed by the single step routine. Therefore we check the V86 task's flags;;
612;; to see if the single step flag is on. If so, then we give control to the ;;
613;; singel step interrupt. Otherwise we just IRET to the V86 task's CS:IP. ;;
614;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
615
616POPIO:
617 CMP SS:WORD PTR [BP+BP_EX],1 ; First check if the reason we got
618 ; control was because of a
619 ; single step
620 JE POPCONT ; If so, then we don't have to
621 ; give control to the single
622 ; step routine 'cause we already
623 ; did it.
624 TEST WORD PTR SS:[BP+BP_FL],0100H ; Was the single step flag on?
625 JZ POPCONT ; If not then just IRET
626 MOV SS:WORD PTR [BP+BP_EX],1 ; Otherwise put a 1 (single step
627 JMP INTCOM ; interrupt number) in the
628 ; exception code and go to
629 ; INTCOM to give control to the
630 ; interrupt
631POPCONT:
632
633; Restore the registers. On entry, in INDEEXC, the registers were pushed as:
634; DS, all registers, ES.
635
636 POP ES ; Restore ES
637 DATAOV
638 POPA ; Restore all the registers (32 bits wide)
639 POP DS ; Restore DS
640 ADD SP,(BP_IP-BP_EX); Move SP past the exception ID an error code
641 ; that were put on our stack when the 386
642 ; gave us control for the exception.
643 ; SS:SP now points to the V86's IP, CS, flags
644 ; for the IRET
645 DATAOV ; IP, CS, and flags are saved 32 bits wide
646 IRET ; Give control back to the V86 task
647
648EMULATE ENDP
649
650PROG ENDS
651
652 END
653
diff --git a/v4.0/src/DEV/XMAEM/INDEEXC.ASM b/v4.0/src/DEV/XMAEM/INDEEXC.ASM
new file mode 100644
index 0000000..a8faaa5
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEEXC.ASM
@@ -0,0 +1,799 @@
1PAGE 60,132
2TITLE INDEEXC - 386 XMA EMULATOR - System Exception Handler
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEEXC *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
11* *
12* DESCRIPTIVE NAME: 80386 XMA Emulator System Exception Handler *
13* *
14* STATUS (LEVEL) : VERSION (0) LEVEL (1.0) *
15* *
16* FUNCTION : This module gets control whenever an interrupt 00 - 07, *
17* 09 - 0E or 15 occurs. This is because this module's *
18* entry point was placed in the IDT entries for these *
19* interrupts. It determines what course of action to take *
20* on the interrupt/exception. *
21* *
22* First thing it does is is to check to see who caused the *
23* exception. If the exception came from the virtual 8086 *
24* (V86) task then it will try to emulate the interrupt if *
25* necessary. If the exception came from the emulator it- *
26* self then we may have problems. If it was a general *
27* protection exception (INT 0D) then it just ignores it and *
28* passes control back to the V86 task. If it was a page *
29* fault (INT 14) then it assumes that whatever is running in*
30* the V86 task came up with a bad address so it terminates *
31* the application since it is obviously bad. If it is *
32* neither of these two errors then something has gone bad *
33* in the emulator. When this happens it signals the error *
34* handler to prompt the user to take a dump or reIPL the *
35* system. *
36* *
37* The old error routine used to display a panel with the *
38* contents of the registers and the stack. The new error *
39* routine just forces the V86 task to run the NMI code. *
40* The old routine was left in place for debugging purposes. *
41* *
42* MODULE TYPE : ASM *
43* *
44* REGISTER USAGE : 80386 Standard *
45* *
46* RESTRICTIONS : None *
47* *
48* DEPENDENCIES : None *
49* *
50* ENTRY POINT : VEXCPT13 *
51* *
52* LINKAGE : This entry point is placed in the IDT for each interrupt *
53* we want to handle. Whenever one of those interrupts is *
54* execupted, control comes here. *
55* *
56* INPUT PARMS : None *
57* *
58* RETURN PARMS : None *
59* *
60* OTHER EFFECTS : None *
61* *
62* EXIT NORMAL : IRET to the virtual 8086 task *
63* *
64* EXIT ERROR : Force the V86 task to execute an NMI *
65* *
66* EXTERNAL *
67* REFERENCES : EMULATE - Entry point for INDEEMU *
68* INT15 - Entry point for INDEI15 *
69* *
70* SUB-ROUTINES : HEXD - Display the double word in EAX *
71* HEXW - Display the word in AX *
72* HEXB - Display the byte in AL *
73* *
74* MACROS : DATAOV - Create a prefix for the following instruction *
75* so that it accesses data 32 bits wide *
76* ADDROV - Create a prefix for the following instruction *
77* so that it uses addresses that are 32 bits wide *
78* *
79* CONTROL BLOCKS : INDEDAT.INC *
80* *
81* CHANGE ACTIVITY : *
82* *
83* $MOD(INDEEXC) COMP(LOAD) PROD(3270PC) : *
84* *
85* $D0=D0004700 410 870523 D : NEW FOR RELEASE 1.1 *
86* $P1=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES *
87* *
88* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
89#
90
91 .286P ; Enable recognition of 286 privileged instructs.
92
93 .XLIST ; Turn off the listing
94 INCLUDE INDEDAT.INC ; Include system data
95
96 IF1 ; Only include macros on the first pass of
97 INCLUDE INDEOVP.MAC ; of the assembler
98 ENDIF
99 .LIST ; Turn on the listing
100
101SEX_ATTR EQU 04B00H
102STACK_ATTR EQU 00700H
103BLANK EQU 00020H
104BP_START EQU 0
105
106 PUBLIC INDEEXC
107
108PROG SEGMENT PARA PUBLIC 'PROG'
109
110 ASSUME CS:PROG
111 ASSUME DS:NOTHING
112 ASSUME ES:NOTHING
113 ASSUME SS:NOTHING
114
115INDEEXC LABEL NEAR
116
117 ; External entry points
118
119 EXTRN EMULATE:NEAR ; Entry point to INDEEMU
120 EXTRN INT15:NEAR ; Entry point to INDEI15
121
122 ; External variables
123
124 EXTRN CRT_SELECTOR:WORD ; Selector for the display buffer (INDEI15)
125 EXTRN XMATID:BYTE ; Current bank ID (INDEXMA)
126
127PAGE
128
129VEXCPT13 LABEL NEAR
130
131 PUBLIC SEX
132 PUBLIC POPREGS ; P1C
133 PUBLIC HEXD
134 PUBLIC HEXW
135 PUBLIC HEXB
136 PUBLIC VEXCPT13
137 PUBLIC DISPLAY
138
139SEX PROC NEAR
140
141 CLD ; All moves go forward
142
143; Save the registers on the stack. These are the registers of the task that
144; got interrupted.
145
146SAVE_REGS:
147 PUSH DS ; Save DS
148
149 DATAOV ; Save all the registers (32 bits wide). They are
150 PUSHA ; pushed in the order: AX, CX, DX, BX, original
151 ; SP (before the PUSHA), BP, SI, DI.
152
153 PUSH ES ; Save ES
154 MOV BP,SP ; Point BP to the start of the register save area
155
156PAGE
157; First let's check to see who caused the exception, the V86 task or us. This
158; is done by checking the flags of the routine that was interrupted. The VM
159; flag is set for every routine that is running in V86 mode. There are really
160; only two entities in the system, the emulator and the V86 task. The V86 task
161; has the VM bit set when it is running, the emulator does not. So we can read
162; this bit to determine who was interrupted.
163
164 MOV AX,SS:WORD PTR [BP+BP_FL2] ; Get hi-order word of the flags
165 TEST AL,02H ; Check the VM bit
166 JZ DISPLAY ; Uh oh! It's us.
167 JMP LONGWAY ; It's the V86 task
168
169PAGE
170; The following entry point, DISPLAY, is know to other modules. They jump here
171; when they encounter a severe error and want to call the error handler.
172
173DISPLAY:
174; JMP DODISP ; Just display the registers.
175 ; Comment out for final product.
176
177; Check if it was a general protection exception. If so, then we'll just pass
178; control back to the V86 task and let it worry about it.
179
180 MOV BP,SP ; Point BP to the saved registers
181 CMP SS:WORD PTR [BP+BP_EX],0DH ; Was it a general protection
182 ; exception
183 JNE DISPCONT ; If not, the continue
184 JMP POPREGS ; Else just return to the V86 @P1C
185 ; task
186
187; Check if it was a page fault. Page faults only occur when the page that is
188; addressed is marked not present. When the emulator sets up memory it marks
189; all pages as present. And this is true because the emulator does no page
190; swapping. It messes with the page tables but it doesn't remove pages from
191; memory. Therefore, if the page is not present then whatever is running in
192; the V86 task came up with some wierd non-existant address. This guy obviously
193; has gone west or doesn't know what he's doing. So we forcr the application
194; to be terminated.
195
196DISPCONT:
197 CMP SS:WORD PTR [BP+BP_EX],0EH ; Was it a page fault?
198 JNE CHKVM ; Nope. Continue checking.
199 JMP PAGE_FAULT ; Yup. Assume application had bad
200 ; addresses. Therefore, termin-
201 ; ate the application.
202
203; Lastly we'll check who had the error, them or us. We need to check again
204; because anybody can jump to the DISPLAY label above. If the V86 task had
205; the exception then we will just terminate whatever was running in the V86
206; task. If the emulator had the exception, then obviously WE don't know
207; what WE'RE doing. Oops! In this case we will force an NMI and bring down
208; the whole system. If the emulator isn't healthy then nothing else should
209; run either. It may sould selfish, but if the emulator is damaged then the
210; rest of the system will die soon anyway.
211
212CHKVM:
213 MOV AX,SS:WORD PTR [BP+BP_FL2] ; Check the VM bit in the flags
214 TEST AL,02H ; to see who was running
215 JZ ERROR ; It was us. Better Force an NMI.
216 JMP TERM_APP ; It was them. Terminate whatever
217 ; is running.
218
219PAGE
220ERROR:
221
222;----------------------------------------------------------------------------D1A
223; We're in big trouble now. Something has gone west and there's no way to D1A
224; get back home. At this point we give up and send up a flare. We signal D1A
225; the error handler by forcing the V86 task to execute the NMI interrupt. D1A
226; We put a marker of 0DEADH at the fixed location 0:4F2. This is in the D1A
227; BIOS communication area. The error handler will look here for our marker D1A
228; to determine if the NMI came from the emulator. If it finds it, it will D1A
229; put up a severe error with our return code and ask the user to take a dump D1A
230; or reIPL. The code following this new code is old code to display a debug D1A
231; panel with the contents of the registers and stack. It is left here for D1A
232; debugging but will not be executed when the new code is in place. D1A
233;----------------------------------------------------------------------------D1A
234 ; D1A
235 MOV AX,HUGE_PTR ; Load ES with a selector that @D1A
236 MOV ES,AX ; accesses all of memory as data @D1A
237 ; D1A
238 MOV DI,4F2H ; Put our 0DEADH marker at the @D1A
239 MOV WORD PTR ES:[DI],0DEADH ; fixed location 0:4F2. D1A
240 MOV WORD PTR SS:[BP+BP_EX],2; Put a 2, the NMI interrupt number,@D1A
241 ; in the exception field. The D1A
242 ; code after LONGWAY4 will use D1A
243 ; this number to get the interrupt D1A
244 ; vector. D1A
245 JMP LONGWAY4 ; Go do the NMI @D1A
246
247PAGE
248; The following code will not be executed. It is left as a debugging tool.
249
250DODISP:
251; Blank the display screen
252 MOV DI,CRT_SELECTOR ; Load ES with the selector for the
253 MOV ES,DI ; display buffer
254 XOR DI,DI ; DI points to the start of the buffer
255 MOV CX,80*15 ; Only clear 15 lines
256 MOV AX,STACK_ATTR+BLANK ; AH = white on black attribute
257 ; AL = ASCII for a blank
258 REP STOSW ; Write 15 rows of while blanks on black
259
260; Highlite the display area
261
262 XOR DI,DI ; DI points to the start of the buffer
263 MOV CX,80*6 ; Highlite 6 lines
264 MOV AX,SEX_ATTR+BLANK ; AH = white on red attribute
265 ; AL = ASCII for a blank
266 REP STOSW ; Highlight the 6 lines
267
268; Display the registers one at at time
269
270 MOV CX,21 ; 18 regs + excpt id + task id + error code
271 MOV SI,SYS_PATCH_DS ; Load DS with the selector for our data
272 MOV DS,SI ; area
273 MOV SI,OFFSET REG_TABLE ; DS:SI now points to the reg table
274 SUB AX,AX ; Clear AH
275 MOV AL,XMATID ; Load AL with the current XMA bank ID
276 MOV WORD PTR SS:[BP+BP_PSP2],AX ; The bank ID gets displayed as
277 ; the task ID
278
279; Display one register
280
281DO_REG:
282
283; Calculate the offset into the display buffer
284
285 LODSB ; Get the row coordinate
286 MOV AH,160 ; Multiply by 160 byte to a row
287 MUL AH ; (80 bytes of character, attribute)
288 ADD AL,DS:BYTE PTR [SI] ; Add on the number of columns
289 ADC AH,0 ; Don't forget the carry
290 ADD AL,DS:BYTE PTR [SI] ; Add the columns again (remember -
291 ADC AH,0 ; character, attribute)
292 INC SI ; Point to next entry in the reg table
293 MOV DI,AX ; Load DI with the offset into the
294 ; display buffer
295
296DO_ID:
297
298; Put the register name on the screen.
299
300 MOV BX,SEX_ATTR ; Load the attribute byte into AH
301 MOV AH,BH
302 LODSB ; Get the character to display
303 CMP AL,0 ; Are we at the end of the string yet?
304 JZ DID_ID ; Yup. Then go display the register
305 ; value.
306 STOSW ; Else put the next character of the
307 ; register name on the screen
308 JMP DO_ID ; Go get the next character
309
310DID_ID:
311
312; Put the register value on the screen.
313
314 MOV BP,SP ; BP points the start of the register
315 ; save area
316 LODSW ; Get the offset of this register's
317 ; save area
318 ADD BP,AX ; Add to BP. BP ponts to the register
319 ; value.
320 LODSW ; Get the length of this register's
321 MOV DX,AX ; save area
322 CMP DX,2 ; If the length is not two words
323 JNE MORE ; Then go to the one word code
324
325 DATAOV ; Grab all 32 bits of the register
326 MOV AX,SS:WORD PTR [BP]
327 ADD BP,4 ; Point BP past the register value
328 CALL HEXD ; Display the 32 bit value
329 JMP LOOPREG ; Jump over the one word code
330
331MORE:
332 MOV AX,SS:WORD PTR [BP] ; Get the word value into AX
333 ADD BP,2 ; Step BP past the register value
334 CALL HEXW ; Display the 16 bit value
335
336LOOPREG:
337 LOOP DO_REG ; Go do another register
338
339PAGE
340;
341; Let's go put up the stack for everyone to see !!!
342;
343 MOV BP,SP ; Reset BP to point to the beginning
344 ; of the register save area
345
346; If the V86 task faulted, display its stack. Else display our stack.
347
348 MOV AX,SS:WORD PTR [BP+BP_FL2] ; Alright, whose fault was it?
349 TEST AL,02H ; Check the VM flag
350 JZ NOTVM86 ; Gulp! It's us.
351
352; It was the V86 task that faulted. Set DS:SI to point to their stack.
353
354 MOV AX,HUGE_PTR ; Load DS with a slector that accesses
355 MOV DS,AX ; all of memory as data
356 DATAOV
357 SUB SI,SI ; Clear all 32 bits of ESI
358 MOV SI,SS:[BP+BP_SP] ; Load SI wiht the V86 task's SP
359 DATAOV
360 SUB AX,AX ; Clear all 32 bits of EAX
361 MOV AX,SS:[BP+BP_SS] ; Get the V86 task's SS
362 DATAOV ; Shift it left 4 bits to convert it
363 SHL AX,4 ; to an offset
364 DATAOV ; Add it on to SP. Now SI contains
365 ADD SI,AX ; the offest of the stack from 0
366
367 MOV BP,0FFFFH ; I don't know what this code does but
368 DATAOV ; I left it anyway. The following
369 ; comment is the only clue.
370 SHL BP,16 ; Make stack seg limit very large
371 JMP COMSTACK
372
373; It was us that faulted. Set DS:SI to point to our stack.
374
375NOTVM86:
376 MOV AX,SS ; Load DS with our own SS
377 MOV DS,AX
378 DATAOV
379 SUB SI,SI ; Clear all 32 bits of ESI
380 MOV SI,SP ; Now DS:SI points to our stack
381
382; DS:SI points to the beginning of a stack. Now display it.
383
384COMSTACK:
385 MOV DI,1120 ; Load DI with the offset into the
386 ; display buffer of where we want
387 ; to display the stack
388 MOV CX,70H ; Display 70H words of the stack
389 MOV BX,STACK_ATTR ; Load BH with the attribute byte
390
391DISP_STACK:
392
393 ADDROV ; Get a word off of the stack
394 LODSW
395 ADDROV ; Intel bug # A0-119
396 NOP ; Intel bug # A0-119
397 CALL HEXW ; Display the word
398 MOV AX,STACK_ATTR+BLANK ; Put a blank after each word
399 STOSW ; Put that on the screen
400 LOOP DISP_STACK ; Do the rest of the stack
401
402; Wait for the operator to press the system request key to go to
403; the monitor, or the escape key to perform the reset operation
404
405WAIT_HERE:
406
407 IN AL,064H ; Poll the keystroke port
408 TEST AL,000000001B ; Did the user hit a key?
409 JZ WAIT_HERE ; Nope. Go check again.
410
411 IN AL,060H ; Get the keystroke
412 CMP AL,054H ; System request key?
413 JNE CHK_ESC ; No. Check for Esc key.
414
415 CMP SS:WORD PTR [BP+BP_EX],0EH ; It was system request key. Now
416 ; check for a page fault.
417 JE PAGE_FAULT ; If so, go remove the extra return code
418 ; from the stack and terminate the
419 ; application running in the V86 task.
420 JMP POPREGS ; Else just return to the V86 task @P1C
421
422CHK_ESC:
423 CMP AL,001H ; Was the Esc key hit?
424 JNE CHKPRT ; Nope. Go check for Print Screen and
425 ; Ctrl-Alt-Del.
426 MOV BP,SP ; Point BP to the register save area
427 CMP SS:WORD PTR [BP+BP_EX],0EH ; Check for a page fault
428 JE PAGE_FAULT ; If so, go remove the extra return
429 ; code from the stack and terminate
430 ; the application running in the
431 ; V86 task.
432 MOV AX,SS:WORD PTR [BP+BP_FL2] ; Else, Esc key hit and no page fault
433 TEST AL,02H ; Check who faulted, them or us
434 JZ DO_RESET ; If it's us, then reIPL.
435
436TERM_APP:
437 MOV SS:WORD PTR [BP+BP_EX],21H ; If it's them, termintate whatever
438 MOV SS:WORD PTR [BP+BP_AX],4CFFH ; is running by forcing a DOS
439 ; termintate. Return code is FF.
440 JMP DO_MONITOR ; Go pass the interrupt to the V86
441 ; task
442
443PAGE_FAULT:
444;
445; On a page fault the 80386 processor puts an extra error code on our stack.
446; (How handy!) We now need to remove the extra error code so that when we pop
447; the registers off our stack at the end we end up with our stack possitioned
448; correctly for the IRET. To do this, we move everything on the stack that is
449; below the extra error code up four bytes. The error code takes up four bytes.
450;
451
452 STD ; Shift into reverse, 'cause stacks
453 ; grow down
454 MOV CX,(BP_EC-BP_START)/2 ; Load CX with the number of words
455 MOV DI,(BP_EC+2-BP_START) ; Point DI to the last word of the
456 ADD DI,BP ; extra error code
457 MOV SI,(BP_EC-2-BP_START) ; Point SI to the last word of the
458 ADD SI,BP ; exception code
459 MOV AX,SS ; Set up the selectors
460 MOV ES,AX
461 MOV DS,AX
462STACK_LOOP:
463 LODSW ; Get a word off the stack
464 STOSW ; And move it up four bytes
465 LOOP STACK_LOOP ; Do that trick again
466
467 CLD ; Shift back into forward
468 ADD BP,4 ; Scoot BP up four bytes to point to
469 ; pur new register save area
470 MOV SP,BP ; Adjust SP, too
471 JMP TERM_APP ; Go kill whatever is running in the V86
472 ; task
473CHKPRT:
474 CMP AL,053H ; Was the Del (as in Ctrl-Alt-Del) key
475 ; pressed?
476 JE DO_RESET ; If so, then reIPL
477
478 CMP AL,037H ; Was the print screen key pressed?
479 JNE WAIT_HERE ; Nope. Must be an invalid key. Go get
480 ; another keystroke.
481
482 MOV BP,SP ; It was a print screen. Reset BP to
483 ; point to our register save area.
484 MOV AX,SS:WORD PTR [BP+BP_FL2] ; If is was us that had the problem
485 TEST AL,02H ; then we don't allow print screen
486 ; because the system is not healthy
487 JZ WAIT_HERE ; Go get another key
488
489 MOV SS:WORD PTR [BP+BP_EX],05H ; If it was them then we can do a
490 JMP DO_MONITOR ; print screen. Force the V86
491 ; task to do an INT 5 (Prt Sc).
492
493;
494; Reset the system, i.e. reIPL. Put a 1234 in the BIOS reset flag at 472H.
495; This will keep BIOS from running through the whole POST upon reIPL.
496;
497
498DO_RESET:
499 MOV AX,HUGE_PTR ; Load ES with a selector that accesses all
500 MOV ES,AX ; of memory as data
501 DATAOV
502 SUB DI,DI ; Clear EDI (32 bit DI)
503 MOV DI,472H ; Load the offset of the BIOS reset flag
504 MOV AX,1234H
505 ADDROV
506 STOSW ; Put 1234 in the BIOS reset flag
507
508 ADDROV ; Intel bug # A0-119
509 NOP ; Intel bug # A0-119
510
511 MOV AL,0FEH ; Now OUT a FE to port 64H. This will cause
512 OUT 064H,AL ; the machine to reIPL.
513
514HALT: HLT ; Just in case we don't reIPL, this halt @P1C
515 JMP HALT ; loop will keep the processor from doing @P1C
516 ; anything else
517
518DO_MONITOR:
519
520; If the exception camefrom the V86 task then pass the interrupt to the
521; real mode interrupt vector.
522
523 MOV BP,SP ; Reset BP to point to our register save area
524 ; on the stack
525 MOV AX,SS:WORD PTR [BP+BP_FL2] ; Check if it was the V86 task that
526 TEST AL,02H ; faulted
527 JNZ LONGWAY ; If so, pass the interrupt on
528 JMP POPREGS ; Otherwise just return @P1C
529
530PAGE
531
532; We come here if the check up front said it was the V86 task that faulted.
533
534LONGWAY:
535 MOV SS:WORD PTR [BP+BP_SP2],0 ;Purify high-order words of SP, SS
536 MOV SS:WORD PTR [BP+BP_SS2],0 ; and IP
537 MOV SS:WORD PTR [BP+BP_IP2],0
538
539; Test for interrupt versus exception.
540
541 CMP SS:WORD PTR [BP+BP_EX],13 ; Check if it was a general
542 ; protection exception
543 JNE LONGWAY2 ; If not, continue checking
544 JMP EMULATE ; If so, then go to INDEEMU to
545 ; emulate the instruction
546LONGWAY2:
547 CMP SS:WORD PTR [BP+BP_EX],6 ; Was it an invalid op-code
548 ; exception?
549 JB LONGWAY4 ; If lower, then pass the
550 ; interrupt back to the V86 task
551 CMP SS:WORD PTR [BP+BP_EX],7 ; Was it a coprocessor not avail-
552 ; able exception?
553 JA LONGWAY3 ; If greater then do more checking
554 JMP EMULATE ; Emulation needed for interrupts
555 ; 6 and 7
556LONGWAY3:
557 CMP SS:WORD PTR [BP+BP_EX],15H ; Check if it was INT 15
558 JNE LONGWAY4 ; Nope, pass interrupt back to
559 ; the V86 task
560 JMP INT15 ; Emulation needed for INT 15
561
562LONGWAY4:
563
564; Pass the interrupt back to the V86 task.
565
566 MOV AX,HUGE_PTR ; Load ES with a selector that accesses
567 MOV ES,AX ; all of memory as data
568 DATAOV
569 SUB DI,DI ; Clear all 32 bits of EDI
570 MOV DI,SS:[BP+BP_SP] ; Load DI with the V86 task's SP
571 SUB DI,6 ; Decrement "SP" to make room for the
572 ; push of IP, CS and the flags.
573 ; Note that this assumes there are at
574 ; least 6 bytes keft on the stack.
575 MOV SS:WORD PTR [BP+BP_SP],DI ; Put the new SP into the V86 register
576 ; save area
577 DATAOV
578 SUB AX,AX ; Clear all 32 bits of EAX
579 MOV AX,SS:[BP+BP_SS] ; Load AX with the V86 task's SS
580 DATAOV ; Shift it left four bits to convert
581 SHL AX,4 ; it to an offset
582 DATAOV ; Add it on to SP. Now DI contains
583 ADD DI,AX ; the offest of the stack from 0
584
585; Now put the V86 task's IP, CS and flags on the stack. They are put on in
586; reverse order because the stack grows down, but we are going up as we put
587; the stuff on the stack.
588
589 MOV AX,SS:[BP+BP_IP] ; Get the V86 task's IP
590 ADDROV
591 STOSW ; Put it on his stack
592 ADDROV ; Intel bug # A0-119
593 NOP ; Intel bug # A0-119
594
595 MOV AX,SS:[BP+BP_CS] ; Get the V86 task's CS
596 ADDROV
597 STOSW ; Put it on his stack
598 ADDROV ; Intel bug # A0-119
599 NOP ; Intel bug # A0-119
600
601 MOV AX,SS:[BP+BP_FL] ; Get the V86 task's flags
602 ADDROV
603 STOSW ; Put them on his stack
604 ADDROV ; Intel bug # A0-119
605 NOP ; Intel bug # A0-119
606 AND AX,3CFFH ; Clean up the flags for our IRET
607 MOV WORD PTR SS:[BP+BP_FL],AX
608
609 MOV SI,SS:[BP+BP_EX] ; Get the interrupt vector
610 SHL SI,2 ; Multiply by four because interrupt
611 ; vectorsare four bytes long
612 MOV AX,HUGE_PTR ; Load DS with a selector that accesses
613 MOV DS,AX ; all of memory as data
614 LODSW ; Get the IP for the interrupt
615 MOV WORD PTR SS:[BP+BP_IP],AX ; Store it in the V86 task's IP
616 LODSW ; Get the CS for the interrupt
617 MOV WORD PTR SS:[BP+BP_CS],AX ; Store it in the V86 task's CS
618
619PAGE
620POPREGS: ; @P1C
621
622; Pop the saved registers off of our stack and IRET to the V86 task.
623
624 POP ES ; Restore ES
625 DATAOV ; Restore all the registers
626 POPA ; (32 bit registers)
627 POP DS ; Restore DS
628 ADD SP,(BP_IP-BP_EX) ; Step SP past the error code placed
629 ; on our stack by the 80386
630 DATAOV
631 IRET ; IRET to the V86 task
632
633SEX ENDP
634
635SUBTTL HEXD - Convert DWORD in EAX to ASCII string at ES:DI
636PAGE
637;
638; INPUT: EAX = hex double word to display
639; BH = attribute byte
640; ES:DI = location in the display buffer where the characters are
641; to be placed
642;
643; OUTPUT: DI is incremented past last character displayed
644; Characters are placed on the screen
645;
646
647HEXD PROC NEAR
648 DATAOV
649 PUSH AX ; Save EAX on the stack
650 DATAOV
651 SHR AX,24 ; Shift the high order byte into AL
652 CALL HEXB ; Convert the byte in AL to ASCII at ES:DI
653 DATAOV
654 POP AX ; Restore the original EAX
655 PUSH AX ; Save the low word of EAX (i.e. AX)
656 DATAOV
657 SHR AX,16 ; Shift the second highest byte into AL
658 CALL HEXB ; Convert the byte in AL to ASCII at ES:DI
659 POP AX ; Restore the low word of EAX (i.e. AX)
660 PUSH AX ; And save it again
661 XCHG AH,AL ; Move the thrid highest byte into AL
662 CALL HEXB ; Convert the byte in AL to an ASCII string
663 POP AX ; Restore AX
664 CALL HEXB ; And conver the last byte to ASCII at ES:DI
665 RET
666
667HEXD ENDP
668
669SUBTTL HEXW - Convert WORD in AX to ASCII string at ES:DI
670PAGE
671;
672; INPUT: AX = hex word to display
673; BH = attribute byte
674; ES:DI = location in the display buffer where the characters are
675; to be placed
676;
677; OUTPUT: DI is incremented past last character
678; Characters are placed on the screen
679;
680
681HEXW PROC NEAR
682
683 PUSH AX ; Save the value in AX on the stack
684 XCHG AH,AL ; Move the high byte into AL
685 CALL HEXB ; Convert the byte in AL to a string at ES:DI
686 POP AX ; Restore AX
687 CALL HEXB ; Convert the low byte to ASCII at ES:DI
688 RET
689
690HEXW ENDP
691
692SUBTTL HEXD - Convert BYTE in AL to ASCII string at ES:DI
693PAGE
694;
695; INPUT: AL = hex byte to display
696; BH = attribute byte
697; ES:DI = location in the display buffer where the characters are
698; to be placed
699;
700; OUTPUT: DI is incremented past last character
701; Characters are placed on the screen
702;
703
704HEXB PROC NEAR
705
706 PUSH AX ; Save the value in AX
707 AND AL,0F0H ; Clear the low nibble of AL
708 SHR AL,1 ; Shift the high nibble into the low nibble
709 SHR AL,1
710 SHR AL,1
711 SHR AL,1
712 ADD AL,030H ; Add '0' to convert to ASCII
713 CMP AL,03AH ; Was this hex digit greater than 9?
714 JC OK1 ; Nope. It's OK, so go display it.
715 ADD AL,7 ; Yup. Then convert to 'A' to 'F'.
716OK1: MOV AH,BH ; Move the attribute into AH
717 STOSW ; Put the character & attribute into the display
718 ; buffer at ES:DI
719 POP AX ; Restore AX
720 AND AL,00FH ; Clear the high nibble of AL
721 ADD AL,030H ; Convert the low nibble to ASCII as before
722 CMP AL,03AH ; Hex digit greater than 9?
723 JC OK2 ; Nope. It's OK, so go display it.
724 ADD AL,7 ; Yup. Then convert to 'A' to 'F'.
725OK2: MOV AH,BH
726 STOSW
727 RET
728
729HEXB ENDP
730
731 PAGE
732
733REG MACRO NAME,ROW,COL,L
734 DB &ROW ; Display of register &NAME starts in
735 DB &COL ; row &ROW and column &COL
736 DB '&NAME:' ; Name to display for register &NAME
737 DB 0 ; End of string marker
738 DW BP_&NAME ; Offset of value of register &NAME
739 ; that we saved on our stack
740 DW &L ; Number of words in the register
741 ENDM
742
743SUBTTL Register table
744PAGE
745REG_TABLE LABEL NEAR
746;
747; Declare data used for displaying the registers on the screen. For each
748; register there is a structure that contains the row and column of where the
749; display of the register starts, the text or register name ended with a 0, the
750; offset into the stack where the value in the register was saved, and the
751; number of words in the register.
752;
753
754; First, lets fake a register to put the exception message on the screen.
755
756 DB 1 ; Row 1
757 DB 10 ; Column 10
758 DB 'System Exception - ' ; Text
759 DB 0 ; End of text
760 DW BP_EX ; Offset to hex value on the stack
761 DW 1 ; Number of words of data
762
763; Now, fake one to put the task id (bank ID) on the screen.
764
765 DB 1 ; Row 1
766 DB 50 ; Column 50
767 DB 'Task ID - ' ; Text
768 DB 0 ; End of text
769 DW BP_PSP2 ; Offset to hex value on the stack
770 DW 1 ; Number of words of data
771
772; Now, lets do the registers
773
774 REG CS,3,1,1
775 REG IP,3,9,2
776 REG SS,3,21,1
777 REG SP,3,29,2
778 REG DS,3,41,1
779 REG SI,3,49,2
780 REG ES,3,61,1
781 REG DI,3,69,2
782
783 REG AX,4,1,2
784 REG BX,4,13,2
785 REG CX,4,25,2
786 REG DX,4,37,2
787 REG BP,4,49,2
788 REG EC,4,61,2
789
790 REG FL,5,1,2
791 REG VMDS,5,18,1
792 REG VMES,5,33,1
793 REG VMFS,5,48,1
794 REG VMGS,5,63,1
795
796PROG ENDS
797
798 END
799
diff --git a/v4.0/src/DEV/XMAEM/INDEGDT.ASM b/v4.0/src/DEV/XMAEM/INDEGDT.ASM
new file mode 100644
index 0000000..e945373
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEGDT.ASM
@@ -0,0 +1,379 @@
1PAGE 60,132
2TITLE INDEGDT - 386 XMA Emulator - Build Global Descriptor Table
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEGDT *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
11* *
12* DESCRIPTIVE NAME: Build the Global Descriptor Table (GDT) *
13* *
14* STATUS (LEVEL) : Version (0) Level (1.0) *
15* *
16* FUNCTION : Build the Global Descriptor Table (GDT) for the 80386 *
17* XMA emulator *
18* *
19* MODULE TYPE : ASM *
20* *
21* REGISTER USAGE : 80386 Standard *
22* *
23* RESTRICTIONS : None *
24* *
25* DEPENDENCIES : None *
26* *
27* ENTRY POINT : GDT_BLD *
28* *
29* LINKAGE : Called NEAR from INDEINI *
30* *
31* INPUT PARMS : None *
32* *
33* RETURN PARMS : None *
34* *
35* OTHER EFFECTS : None *
36* *
37* EXIT NORMAL : Return to INDEINI *
38* *
39* EXIT ERROR : None *
40* *
41* EXTERNAL *
42* REFERENCES : None *
43* *
44* SUB-ROUTINES : SREG_2_24BITS - Convert the 16 bit value in AX to a 24 *
45* bit value in DH and AX. *
46* ADDOFF - Add the 16 bit offset in AX to the 24 bit value *
47* in DH and BX. *
48* *
49* MACROS : DESCR_DEF - Declare a descriptor entry *
50* DESCR_INIT - Initialize a descriptor *
51* *
52* CONTROL BLOCKS : INDEDAT - System data structures *
53* *
54* CHANGE ACTIVITY : *
55* *
56* $MOD(INDEGDT) COMP(LOAD) PROD(3270PC) : *
57* *
58* $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 *
59* $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS *
60* $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD *
61* $P3=P0000410 410 870918 D : RELOCATE DATA AREAS TO MAKE ROOM FOR BIT MAP *
62* *
63* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
64#
65
66 .286P ; Enable recognition of 286 privileged instructs.
67
68 .XLIST ; Turn off the listing
69 INCLUDE INDEDAT.INC ; Include system data structures
70 INCLUDE INDEACC.INC ; Include access byte definitions
71
72 IF1 ; Only include macros on the first pass
73 INCLUDE INDEDES.MAC ; Descriptor macros
74 ENDIF
75 .LIST ; Turn on the listing
76
77PROG SEGMENT PARA PUBLIC 'PROG'
78
79 ASSUME CS:PROG
80 ASSUME SS:NOTHING
81 ASSUME DS:PROG
82 ASSUME ES:NOTHING
83
84INDEGDT LABEL NEAR
85
86 PUBLIC INDEGDT
87 PUBLIC GDT_BLD
88 PUBLIC GDT_DATA_START
89 PUBLIC SREG_2_24BITS
90
91; The following data define a pre-initialized GDT. They represent
92; all structures which will exist when the emulator comes up.
93; THESE MUST BE INITIALIZED IN THE ORDER IN WHICH THEY APPEAR IN THE
94; GDT_DEF STRUCTURE DEFINITION AS IT APPEARS IN INDEDAT.INC. This data
95; area will be copied from the code segment to the final GDT resting
96; place during initialization.
97
98GDT_DATA_START LABEL WORD
99
100; First entry is unusable
101
102 DESCR_DEF SEG, 0, 0, 0, 0
103
104; The descriptor for GDT itself
105
106 DESCR_DEF SEG, GDT_LEN, GDT_LOC, 3, CPL0_DATA_ACCESS
107PAGE
108
109; The system IDT descriptor
110
111 DESCR_DEF SEG, SIDT_LEN, SIDT_LOC, 3, CPL0_DATA_ACCESS
112
113; The real system data area descriptor (XMA pages)
114
115 DESCR_DEF SEG, 0FFFFH, 0000H, 11H, CPL0_DATA_ACCESS
116
117; The virtual IDT descriptor (not needed so use for all memory)
118
119 DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS
120
121; The LOADALL descriptor
122
123 DESCR_DEF SEG, 0, 0, 0, 0
124PAGE
125
126; Compatible monochrome display
127
128 DESCR_DEF SEG, MCRT_SIZE, MCRT@_LO, MCRT@_HI, CPL0_DATA_ACCESS
129
130; Compatible color display
131
132 DESCR_DEF SEG, CCRT_SIZE, CCRT@_LO, CCRT@_HI, CPL0_DATA_ACCESS
133
134; Enhanced color display - one entry for each 64K P1C
135
136 DESCR_DEF SEG, ECCRT_SIZE, ECCRT@_LO_LO, ECCRT@_LO_HI, CPL0_DATA_ACCESS
137
138; Second part of enhanced display P1C
139
140 DESCR_DEF SEG, ECCRT_SIZE, ECCRT@_HI_LO, ECCRT@_HI_HI, CPL0_DATA_ACCESS
141PAGE
142
143; Code segment for ROM code, system IDT
144
145 DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS
146
147; Data segment for ROM code, system IDT
148
149 DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS
150
151; Temporarily, the monitor is installed using the patch
152; segment descriptors in the GDT
153
154MSEG@_LO EQU 00000H
155MSEG@_HI EQU 008H
156
157
158; Code segment for patch code, system IDT
159
160 DESCR_DEF SEG, MAX_SEG_LEN, MSEG@_LO, MSEG@_HI, CPL0_CODE_ACCESS
161
162; Data segment for patch code, system IDT
163
164 DESCR_DEF SEG, MAX_SEG_LEN, MSEG@_LO, MSEG@_HI, CPL0_DATA_ACCESS
165PAGE
166
167; Code segment for ROM code, virtual IDT
168
169 DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS
170
171; Data segment for ROM code, virtual IDT
172
173 DESCR_DEF SEG, MAX_SEG_LEN, CSEG@_LO, CSEG@_HI, CPL0_CODE_ACCESS
174
175; Code segment for patch code, virtual IDT
176
177 DESCR_DEF SEG, NULL_SEG_LEN, NSEG@_LO, NSEG@_HI, NULL_ACCESS
178
179; Data segment for patch code, virtual IDT
180
181 DESCR_DEF SEG, NULL_SEG_LEN, NSEG@_LO, NSEG@_HI, NULL_ACCESS
182PAGE
183
184; Temporary descriptors for ES, CS, SS, and DS
185
186 DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS
187
188 DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_CODE_ACCESS
189
190 DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS
191
192 DESCR_DEF SEG, MAX_SEG_LEN, NSEG@_LO, NSEG@_HI, CPL0_DATA_ACCESS
193PAGE
194
195; These DQ's pad out the space between the last MultiPC descriptor and the
196; PMVM descriptors. They don't need initialization.
197
198 DQ 9 DUP (0) ; These 9 are for the Monitor descriptors
199
200; This is for the keyboard owner (not used)
201
202 DQ 0
203
204; These 16 are for the virtual timer support
205
206 DQ 16 DUP (0)
207
208; The following 32 descriptors are for exception condition task gates.
209
210 REPT 32
211 DQ 0
212 ENDM
213
214; The following 16 pairs are for the hardware interrupt handling tasks.
215
216 REPT 16
217 DQ 0
218 DQ 0
219 ENDM
220
221; The following pair is for the DISPATCH task
222
223 DESCR_DEF SEG, TSS_LEN, DISPATCH_LOC, 3, <TSS_ACCESS OR FREE_TSS>
224 DESCR_DEF SEG, TSS_LEN, DISPATCH_LOC, 3, CPL0_DATA_ACCESS
225
226 DESCR_DEF SEG, 0, 0, 0,LDT_DESC
227
228; BASIC's segment
229
230 DESCR_DEF SEG, 07FFFH, 06000H, 0FH, CPL0_DATA_ACCESS
231
232; BIOS's segment
233
234 DESCR_DEF SEG, 01FFFH, 00000H, 0FH, CPL0_DATA_ACCESS
235
236 DQ 13 DUP (0) ; Reserved guys
237
238; The following guys are junk ! Used before the first TSS allocated. These
239; have to be in the PMVM location in the GDT.
240
241 DESCR_DEF SEG, TSS_LEN, 0C000H, 0, FREE_TSS ; For the TR
242
243 DESCR_DEF SEG, TSS_LEN, 0C000H, 0, CPL0_DATA_ACCESS ; TSS as data
244
245 DESCR_DEF SEG, GDT_LEN, 0D000H, 0, LDT_DESC ; For the LDTR
246
247 DESCR_DEF SEG, GDT_LEN, 0D000H, 0, CPL0_DATA_ACCESS ; LDT as data
248
249GDT_DATA_END LABEL WORD
250
251COPY_LEN EQU GDT_DATA_END-GDT_DATA_START
252
253;
254; End of pre-allocated GDT
255;
256
257PAGE
258
259GDT_BLD PROC NEAR
260
261; Copy the pre-initialized GDT into its proper location in memory
262
263 CLI ; All string operations go forward
264
265 MOV SI,OFFSET GDT_DATA_START ; DS:SI points to the pre-initialized
266 ; GDT above
267 MOV CX,COPY_LEN/2 ; CX = number of words to copy
268 MOV DI,GDT_LOC ; ES:DI points to the GDT location
269 REP MOVSW ; Copy GDT into its final resting place
270
271; Now let's initialize some of the GDT entries
272
273; Set up the descriptors for our code segment and data segment
274
275 MOV AX,CS ; Get our CS
276 CALL SREG_2_24BITS ; And convert it to a 24 bit offset
277 MOV BX,AX ; Get the monitor offset
278
279ALLSET:
280 DESCR_INIT SEG, SYS_PATCH_CS, 07FFFH, BX, DH, CPL0_CODE_ACCESS
281 DESCR_INIT SEG, SYS_PATCH_DS, 0FFFFH, BX, DH, CPL0_DATA_ACCESS
282
283; Initialize the descriptor for the GDT
284
285 MOV AX,ES ; Get the segment of the GDT
286 CALL SREG_2_24BITS ; Convert to a 24 bit offset
287 MOV DL,DH ; Save a copy of the hi byte
288 MOV BX,GDT_LOC ; Add on the offset of the GDT
289 CALL ADDOFF
290
291 DESCR_INIT SEG, GDT_PTR, GDT_LEN, BX, DH, CPL0_DATA_ACCESS
292
293; Initialize the descriptor for the IDT
294
295 MOV BX,SIDT_LOC ; DH,AX already contains the segment
296 ; converted to 24 bits so all we
297 CALL ADDOFF ; have to do is add on the offset
298
299 DESCR_INIT SEG, MON_IDT_PTR, SIDT_LEN, BX, DH, CPL0_DATA_ACCESS
300
301; Initialize the descriptor that accesses all of memory as data
302
303 DESCR_INIT BSEG, HUGE_PTR, 0FFFFH, 0, 0, CPL0_DATA_ACCESS
304
305; Initialize the descriptors for the V86 task's LDT
306
307 MOV BX,DISPATCH_LOC ; @P3C
308 CALL ADDOFF
309
310 DESCR_INIT SEG,SCRUBBER.VM_LDTR,00FFFH,BX,DH,LDT_DESC
311 DESCR_INIT SEG,SCRUBBER.LDT_PTR,00FFFH,BX,DH,CPL0_DATA_ACCESS
312
313; Initialize the descriptors for the V86 task's TR
314
315 MOV BX,DISPATCH_LOC ; @P3C
316 CALL ADDOFF
317
318 DESCR_INIT SEG,SCRUBBER.VM_TR,TSS_LEN,BX,DH,FREE_TSS_386 ; @P3C
319 DESCR_INIT SEG,SCRUBBER.TSS_PTR,TSS_LEN,BX,DH,CPL0_DATA_ACCESS; @P3C
320
321 RET
322
323GDT_BLD ENDP
324
325PAGE
326; SREG_2_24BITS converts the segment register 16 bit value in the AX register
327; into a 24 bit value in DH and AX
328;
329; Input : AX = segment register value
330;
331; Output: AX = 24 bit low word
332; DH = 24 bit high byte
333
334
335SREG_2_24BITS PROC NEAR
336
337; Put the high four bits of AH into the low four bits of DH
338
339 MOV DH,AH ; Get the high byte of the segment value
340 ; into DH
341 AND DH,0F0H ; Strip off the low nibble
342 SHR DH,4 ; Shift right four bits
343
344; Now shift AX left four bits
345
346 AND AH,00FH ; Strip high nibble from AH
347 ; This keeps the carry flag from being
348 ; set which could effect later ADDs.
349 SHL AX,4 ; Shift AX
350
351 RET
352
353SREG_2_24BITS ENDP
354
355PAGE
356; ADDOFF adds the 16 bit offset in BX to the 24 bit value in DL and AX. The
357; result is left in DH and BX.
358;
359; Input : DL = 24 bit high byte
360; AX = 24 bit low word
361; BX = offset to be added
362;
363; Output: DH = 24 bit high byte
364; BX = 24 bit low word
365
366ADDOFF PROC NEAR
367
368 MOV DH,DL ; Restore the high byte that was saved
369 ; in DL
370 ADD BX,AX ; Add on the offset
371 ADC DH,0 ; Add the carry, if any, to the high
372 ; byte
373 RET
374
375ADDOFF ENDP
376
377PROG ENDS
378
379 END
diff --git a/v4.0/src/DEV/XMAEM/INDEI15.ASM b/v4.0/src/DEV/XMAEM/INDEI15.ASM
new file mode 100644
index 0000000..047648d
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEI15.ASM
@@ -0,0 +1,503 @@
1PAGE 60,132
2TITLE INDEI15 - 386 XMA Emulator - Interrupt 15 handler
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEI15 *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
11* *
12* DESCRIPTIVE NAME: Interrupt 15H handler for the 80386 XMA emulator *
13* *
14* STATUS (LEVEL) : Version (0) Level (2.0) *
15* *
16* FUNCTION : This module emulates the MOVEBLOCK functions of interrupt *
17* 15H. The MOVEBLOCK functions are specified by an AH value*
18* of 87H to 89H. The user can use the MOVEBLOCK functions *
19* to copy a block of memory to another block of memory. *
20* This includes copying to and from memory above 1M. This *
21* is really where this function comes in handy. The user *
22* can reserve memory above 1M for use by the MOVEBLOCK *
23* functions by specifying the number of K to be reserved as *
24* a parameter on the line to load the emulator in the *
25* CONFIG.SYS file. *
26* *
27* DEVICE=INDXMAEM.SYS bbb *
28* *
29* "bbb" is the number of K to reserve for MOVEBLOCK *
30* functions *
31* *
32* We allocate a buffer for the MOVEBLOCK functions at the *
33* top of available memory. Any functions dealing with this *
34* buffer area must be handles by us. *
35* *
36* Function 87H is the actual MOVEBLOCK function. The user *
37* passes a 32 bit source address and a 32 bit destination *
38* address in a parameter list pointed to by ES:SI. CX *
39* contains the number of words to copy. We need to *
40* intercept this call and check the source and destination *
41* addresses. If either or both of these addresses is above *
42* 1M then we need to adjust the addresses so that they *
43* access the MOVEBLOCK buffer up at the top of memory. You *
44* see, the user thinks the extended memory starts right *
45* after the 1M boundary. We want to make it look like the *
46* MOVEBLOCK buffer sits right after the 1M boundary. So we *
47* monkey with the user's addresses so that they access the *
48* MOVEBLOCK buffer instead of real memory after 1M, because *
49* that memory is us. *
50* *
51* Function 88H queries how many K are above the 1M *
52* boundary. We can't tell him how much is really there *
53* because some of it is us and our XMA pages. So for this *
54* function we will just return the size of the MOVEBLOCK *
55* buffer. This function was moved to a real mode P3C*
56* interrupt handler in module INDE15H. P3C*
57* *
58* Function 89H is reserved for the MOVEBLOCK functions but *
59* is not in use right now. So for this function we just *
60* return a bad return code in AH and set the carry flag. *
61* *
62* MODULE TYPE : ASM *
63* *
64* REGISTER USAGE : 80386 Standard *
65* *
66* RESTRICTIONS : None *
67* *
68* DEPENDENCIES : None *
69* *
70* ENTRY POINT : INT15 *
71* *
72* LINKAGE : Jumped to from INDEEXC *
73* *
74* INPUT PARMS : None *
75* *
76* RETURN PARMS : None *
77* *
78* OTHER EFFECTS : None *
79* *
80* EXIT NORMAL : Go to POPIO in INDEEMU to IRET to the V86 task *
81* *
82* EXIT ERROR : None *
83* *
84* EXTERNAL *
85* REFERENCES : EMULATE - Entry point for INDEEMU *
86* POPIO - Entry in INDEEMU to check for single step *
87* interrupts, pop the registers and IRET to the *
88* V86 task *
89* POPREGS - Entry point in INDEEXC to pop the registers *
90* off the stack and IRET to the V86 task P2C*
91* *
92* SUB-ROUTINES : None *
93* *
94* MACROS : DATAOV - Add prefix for the next instruction so that it *
95* accesses data as 32 bits wide *
96* ADDROV - Add prefix for the next instruction so that it *
97* uses addresses that are 32 bits wide *
98* *
99* CONTROL BLOCKS : INDEDAT.INC *
100* *
101* CHANGE ACTIVITY : *
102* *
103* $MOD(INDEI15) COMP(LOAD) PROD(3270PC) : *
104* *
105* $D0=D0004700 410 870603 D : NEW FOR RELEASE 1.1 *
106* $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS *
107* $P2=P0000312 410 870804 D : CLEAN UP WARNING MESSAGES *
108* $D1=D0007100 410 870817 D : CHANGE TO EMULATE XMA 2 *
109* $P3=P0000xxx 120 880331 D : MOVE FUNCTION 88H HANDLING TO INDE15H *
110* *
111* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
112#
113
114 .286P ; Enable recognition of 286 privileged instructs.
115
116 .XLIST ; Turn off the listing
117 INCLUDE INDEDAT.INC ; Include the system data structures
118
119 IF1 ; Only include the macros on the first pass
120 INCLUDE INDEOVP.MAC
121 ENDIF
122 .LIST ; Turn on the listing
123
124PROG SEGMENT PARA PUBLIC 'PROG'
125
126 ASSUME CS:PROG
127 ASSUME DS:PROG
128 ASSUME ES:NOTHING
129 ASSUME SS:NOTHING
130
131INDEI15 LABEL NEAR
132
133 EXTRN EMULATE:NEAR ; Entry point for INDEEMU
134 EXTRN POPIO:NEAR ; Entry in INDEEMU to check for single
135 ; step interrupts and return to the
136 ; V86 task
137 EXTRN POPREGS:NEAR ; Entry in INDEEXC to return to the P2C
138 ; V86 task
139
140 PUBLIC INDEI15
141 PUBLIC INT15
142 PUBLIC TTTABLE
143
144PAGE
145
146INT15 PROC NEAR
147
148 CLD ; All string operations go forward
149
150; We handle the INT 15H functions for MOVEBLOCK interface. These functions
151; are specified by an AH value of 87H to 89H. Function 87H is the MOVEBLOCK
152; function. Function 88H queries the size of memory above 1M. Function 89H
153; is reserved but not supported so we return a return code of 86H.
154
155 CMP SS:BYTE PTR [BP+BP_AX+1],87H ; Is AH asking for function 87H?
156 JB NOTMINE ; No. It's too low. It's out of our
157 ; range so we'll pass it on to the
158 ; real vector.
159 JE MOVEBLK ; It is 87H! Let's go do the MOVEBLOCK.
160
161 CMP SS:BYTE PTR [BP+BP_AX+1],89H ; Is AH asking for function 89H?
162 JNE NOTMINE ; No. It's not our function so @P3C
163 ; so we'll pass it on to the real
164 ; vector.
165 ; @P3D
166 MOV SS:BYTE PTR [BP+BP_AX+1],86H ; It's 89H. Sorry we don't support
167 ; that function. Put an 86H return
168 ; code in AH.
169 OR WORD PTR SS:[BP+BP_FL],1 ; Set the carry flag
170 JMP POPIO ; And return to the V86 task
171
172; Hey, it's not MY interrupt.
173
174NOTMINE:
175 JMP DOINT ; Go pass the interrupt back to the
176 ; real INT 15H vector
177
178
179; Function 88H code to query the size of memory above 1M was moved to 3@P3D
180; INDE15H.
181
182PAGE
183; The user wants to move a block of memory. Now the source and target of the
184; MOVEBLOCK can each be below 1M or above 1M. For addresses above 1M we must
185; make adjustments so that the MOVEBLOCK is done to and/or from the MOVEBLOCK
186; buffer in high memory. The user passes a parameter list which is pointed
187; at by ES:SI. At offset 0EH is a 32 bit pointer to the source block. At
188; offset 1AH is a 32 bit pointer to the destination block. CX contains the
189; number of words to move. Here we go!
190
191MOVEBLK:
192 MOV AX,HUGE_PTR ; Load DS and ES with a selector that
193 MOV DS,AX ; accesses all of memory as data
194 MOV ES,AX
195
196; Get the user's ES:SI and convert it to a 32 bit offset in ESI.
197
198 DATAOV ; Purge ESI
199 SUB SI,SI
200 MOV SI,SS:[BP+BP_SI] ; Load SI with the user's SI
201
202 DATAOV ; Purge EBX
203 SUB BX,BX
204 MOV BX,10H ; Set EBX to 1M by loading it with 10H
205 DATAOV ; and shifting it left 16 bits to
206 SHL BX,16 ; multiply by 64K
207
208 DATAOV ; Sterilize EAX
209 SUB AX,AX
210 MOV AX,SS:[BP+BP_VMES] ; Load AX with the user's ES
211 DATAOV ; Shift it left four bits to convert it
212 SHL AX,4 ; to an offset
213
214 DATAOV ; Add the ES offset on to SI. Now ESI
215 ADD SI,AX ; is the offset from 0 of the user's
216 ; parameter list.
217 DATAOV ; Add 1AH to SI. Now it points to the
218 ADD SI,1AH ; 32 bit destination address.
219
220 DATAOV
221 ADDROV ; Get the 32 bit destination address
222 LODSW ; into EAX
223
224 ADDROV ; Intel bug # A0-119
225 NOP ; Intel bug # A0-119
226
227 DATAOV ; Clear the top eight bits of any
228 SHL AX,8 ; residual gunk. Only 24 bit ;P1C
229 DATAOV ; addresses (16M) are allowed anyway.
230 SHR AX,8 ; Shift the bits off the left end and
231 ; shift zeroes back in.
232 DATAOV ; Move this clean value into EDI
233 MOV DI,AX ; EDI now has the destination address
234
235 DATAOV ; Check if this address is over 1M. If
236 CMP DI,BX ; so then it's going to our MOVEBLOCK
237 ; buffer.
238 JB OK1 ; It's below 1M? OK. Leave it alone.
239
240; The destination is above 1M so we have to modify the destination address so
241; that it points to our MOVEBLOCK buffer.
242
243 PUSH DS ; Save DS
244 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data
245 MOV DS,AX ; segment
246
247 DATAOV ; Clean up EAX
248 SUB AX,AX
249 MOV AX,MAXMEM ; Load the total number of K on the box
250 SUB AX,BUFF_SIZE ; Subtract the MOVEBLOCK buffer size
251 SUB AX,1024 ; Subtract 1M (/1K) for 0 to 1M. This
252 ; leaves AX with the number of K from
253 ; 1M to the MOVEBLOCK buffer.
254 POP DS ; Restore DS
255 DATAOV ; Multiply EAX by 1K (shift left 10) to
256 SHL AX,10 ; convert it to an offset from 1M of
257 ; the MOVEBLOCK buffer
258 DATAOV ; Add this to EDI. EDI now points to
259 ADD DI,AX ; a location within (hopefully) the
260 ; MOVEBLOCK buffer as if the buffer
261 ; were located at the 1M boundary.
262
263; Now let's get the source address
264
265OK1:
266 DATAOV ; Subtract 0C from ESI to point ESI to
267 SUB SI,0CH ; offset 0E in the parameter list
268
269 DATAOV
270 ADDROV ; Get the 32 bit source address into
271 LODSW ; EAX
272
273 ADDROV ; Intel bug # A0-119
274 NOP ; Intel bug # A0-119
275
276 DATAOV ; Clear the top eight bits of any
277 SHL AX,8 ; residual gunk. Only 24 bit address
278 DATAOV ; (16M) are allowed. Shift the gunky
279 SHR AX,8 ; bits off the left end and shift
280 ; zeroes back in.
281 DATAOV ; Move this clean value into ESI
282 MOV SI,AX ; ESI now has the source address
283
284 DATAOV ; Check if this address is over 1M. If
285 CMP SI,BX ; so then it's goin' to our MOVEBLOCK
286 ; buffer.
287 JB OK2 ; It's below 1M? OK. Let it be.
288
289; The source is above 1M so we have to modify the source address so that it
290; points to our MOVEBLOCK buffer.
291
292 PUSH DS ; Save DS
293 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data
294 MOV DS,AX ; segment
295
296 DATAOV ; Sanitize up EAX
297 SUB AX,AX
298 MOV AX,MAXMEM ; Load the total number of K on the box
299 SUB AX,BUFF_SIZE ; Subtract the MOVEBLOCK buffer size
300 SUB AX,1024 ; Subtract 1M (/1K) for 0 to 1M. This
301 ; leaves AX with the number of K from
302 ; 1M to the MOVEBLOCK buffer.
303 POP DS ; Restore DS
304 DATAOV ; Multiply EAX by 1K (shift left 10) to
305 SHL AX,10 ; convert it to an offset from 1M of
306 ; the MOVEBLOCK buffer
307 DATAOV ; Add this to ESI. ESI now points to
308 ADD SI,AX ; a location within (hopefully) the
309 ; MOVEBLOCK buffer as if the buffer
310 ; were located at the 1M boundary.
311
312; Our pointers are all set. Let's get CX and do the copy for the guy.
313
314OK2:
315 MOV CX,SS:[BP+BP_CX] ; Get the user's CX
316 TEST CL,01H ; Is this an even number?
317 JZ MOV4 ; If so, we can make the copy faster
318 ; by moving double words
319 ADDROV ; Nope. It's odd. We'll just do the
320 REP MOVSW ; copy with words.
321
322 ADDROV ; Intel bug # A0-119
323 NOP ; Intel bug # A0-119
324
325 JMP MOVCOM ; Skip over the double word copy
326
327MOV4:
328 SHR CX,1 ; Divide the count by two since we'll
329 ; be copying double words
330 DATAOV ; Do it 32 bits wide
331 ADDROV ; Use the 32 bit ESI and EDI
332 REP MOVSW ; Ready? ZOOOOM!
333
334 ADDROV ; Intel bug # A0-119
335 NOP ; Intel bug # A0-119
336
337; Now let's set the flags and return code in AH to show that every thing went
338; A-OK.
339
340MOVCOM:
341 MOV SS:BYTE PTR [BP+BP_AX+1],0 ; Set a zero return code in AH
342 AND WORD PTR SS:[BP+BP_FL],0FFFEH ; Reset the carry flag
343 OR WORD PTR SS:[BP+BP_FL],40H ; Set the zero flag
344
345 JMP POPIO ; Return to the V86 task
346
347PAGE
348
349; It's not a MOVEBLOCK function so we'll just pass the interrupt on to the real
350; interrupt handler.
351
352DOINT:
353 MOV AX,HUGE_PTR ; Load ES with a selector that accesses
354 MOV ES,AX ; all of memory as data
355 DATAOV ; Load EDI with the user's ESP
356 MOV DI,SS:[BP+BP_SP]
357
358 SUB DI,6 ; Decrement "SP" by six to make room
359 ; for our simulated interrupt that
360 ; will put the flags, CS and IP on
361 ; the stack. This assumes that there
362 ; are indeed six bytes left on the
363 ; stack.
364 MOV SS:WORD PTR [BP+BP_SP],DI ; Set the user's new SP
365
366 DATAOV ; Get the user's SS into our AX
367 MOV AX,SS:[BP+BP_SS]
368 DATAOV ; Shift "SS" left four bits to convert
369 SHL AX,4 ; it to an offset
370 DATAOV ; Add this to "SP" in DI to make EDI
371 ADD DI,AX ; a 32 bit offset from 0 of the user's
372 ; stack
373
374; Now put the flags, CS and IP on the V86 task's stack. They are put on in the
375; order IP, CS, flags. This is backwards from the INT push order of flags, CS
376; and then IP. This is because we are moving forward through memory (CLD)
377; whereas the stack grows backwards through memory as things pushed on to it.
378
379 MOV AX,SS:[BP+BP_IP] ; Get the user's IP
380 ADDROV ; And put it on his stack
381 STOSW
382
383 ADDROV ; Intel bug # A0-119
384 NOP ; Intel bug # A0-119
385
386 MOV AX,SS:[BP+BP_CS] ; Get the user's CS
387 ADDROV ; And put it on his stack
388 STOSW
389
390 ADDROV ; Intel bug # A0-119
391 NOP ; Intel bug # A0-119
392
393 MOV AX,SS:[BP+BP_FL] ; Get the user's flags
394 OR AX,3000H ; Set the IOPL to 3 so we get fewer
395 ; faults
396 ADDROV ; And put them on his stack
397 STOSW
398
399 ADDROV ; Intel bug # A0-119
400 NOP ; Intel bug # A0-119
401
402 AND AX,3CFFH ; Clean up the flags for our IRET
403 MOV WORD PTR SS:[BP+BP_FL],AX ; Put them on our stack
404
405 MOV SI,SS:[BP+BP_EX] ; Get the interrupt number
406 SHL SI,2 ; Multiply by four 'cause interrupt
407 ; vectors are four bytes long
408 MOV AX,HUGE_PTR ; Load DS with a selector that accesses
409 MOV DS,AX ; all of memory as data
410 LODSW ; Get the IP of the interrupt vector
411 ; from the interrupt vector table
412 MOV WORD PTR SS:[BP+BP_IP],AX ; Put it in the IP saved on our stack
413 LODSW ; Get the CS of the interrupt vector
414 ; from the interrupt vector table
415 MOV WORD PTR SS:[BP+BP_CS],AX ; Put it in the CS saved on our stack
416
417 JMP POPREGS ; Now when we do an IRET we will @P2C
418 ; actually be giving control to the
419 ; real INT 15H vector.
420INT15 ENDP
421
422PAGE
423; Macros used to define data areas
424
425; DDL - Define a label and make it public
426
427DDL MACRO NAME,SIZE
428 PUBLIC &NAME
429&NAME LABEL &SIZE
430 ENDM
431
432
433; DDW - Define a word and make it public
434
435DDW MACRO NAME,VALUE
436 IFNB <&NAME> ;; If a name was given then make it public
437 PUBLIC &NAME
438 ENDIF
439 IFNB <&VALUE> ;; If a value was given then initialize the
440&NAME DW &VALUE ;; variable to that value
441 ELSE ;; Else initialize it to 0
442&NAME DW 0
443 ENDIF
444 ENDM
445
446
447; Now lets define some data. Remember, these are all PUBLIC even though they
448; are not listed at the top of the program as being such. It's easy to lose
449; these guys.
450
451 DDW REAL_SP,0 ; Our initial SP when we come up in real mode
452
453 DDW REAL_SS,0 ; Our initial SS when we come up in real mode
454
455 DDW REAL_CS,0 ; Our initial CS when we come up in real mode
456
457 DDW PGTBLOFF,0 ; The offset of the normal page tables
458
459 DDW SGTBLOFF,0 ; The offset of the page directory
460
461 DDW NORMPAGE,0 ; The entry for the first page directory entry
462 DDW ,0 ; which points to the first normal page table.
463 ; A 32 bit value
464 DDW XMAPAGE,7 ; Page directory entry that points to the first
465 DDW ,0011H ; XMA page table at 11000:0. Access and present
466 ; bits set. It, too, is a 32 bit value.
467 DDW BUFF_SIZE,0 ; Size of the MOVEBLOCK buffer. Initialized to 0.
468
469 DDW MAXMEM,1000H ; Total amount of K in the box. Initialized to 4M.
470
471 DDW CRT_SELECTOR,C_BWCRT_PTR ; Selector for the display buffer
472
473; And now, the world famous Translate Table!! YEAAAA!!
474;
475; The first 160 entries (0 to 640K) are initialized to blocks 0 to '9F'X. D1A
476; This is to emulate the XMA 2 device driver which uses these blocks to back D1A
477; the memory on the mother board from 0 to 640K which it disabled. It sets D1A
478; up the translate table for bank 0 such that it maps the XMA memory from 0 D1A
479; to 640K to conventional memory at 0 to 640K. So we emulate that here by D1A
480; initializing the firs 160 entries in the translate table. D1A
481
482TTTABLE:
483 BLOCK = 0 ; Start with block number 0 @D1A
484 REPT 20 ; Do 20 times (20 x 8 = 160) @D1A
485 DW BLOCK,BLOCK+1,BLOCK+2,BLOCK+3,BLOCK+4,BLOCK+5,BLOCK+6,BLOCK+7
486 ; Define eight translate table entries @D1A
487 ; initialized to the block number D1A
488 BLOCK = BLOCK + 8 ; Increment the block number to the next set @D1A
489 ENDM ; of eight translate table entries @D1A
490
491 DW 96 + 256*15 DUP(0FFFH) ; The rest of the translate table @D1C
492
493TTTABLE_END: ; Label to mark the end of the translate table
494
495
496; Define our stack for when we're in protect mode
497
498 DDW MON_STACK_BASE,<500 DUP(0)>
499 DDL SP_INIT,WORD ; Top of the stack. The initial SP points here.
500
501PROG ENDS
502
503 END
diff --git a/v4.0/src/DEV/XMAEM/INDEIDT.ASM b/v4.0/src/DEV/XMAEM/INDEIDT.ASM
new file mode 100644
index 0000000..28e9161
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEIDT.ASM
@@ -0,0 +1,512 @@
1PAGE 60,132
2TITLE INDEIDT - 386 XMA Emulator - Build Interrupt Descriptor Table
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEIDT *
8* *
9* *
10* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
11* *
12* DESCRIPTIVE NAME: Build the Interrupt Descriptor Table (IDT) *
13* *
14* STATUS (LEVEL) : Version (0) Level (2.0) *
15* *
16* FUNCTION : Build the Interrupt Descriptor Table for the 80386 XMA *
17* emulator. *
18* *
19* MODULE TYPE : ASM *
20* *
21* REGISTER USAGE : 80386 Standard *
22* *
23* RESTRICTIONS : None *
24* *
25* DEPENDENCIES : None *
26* *
27* ENTRY POINT : SIDT_BLD (not to be confused with SIDTBLD) *
28* *
29* LINKAGE : Called by INDEINI *
30* *
31* INPUT PARMS : None *
32* *
33* RETURN PARMS : None *
34* *
35* OTHER EFFECTS : None *
36* *
37* EXIT NORMAL : Return to INDEINI *
38* *
39* EXIT ERROR : None *
40* *
41* EXTERNAL *
42* REFERENCES : VEXCP13 - Entry point for INDEEXC *
43* *
44* SUB-ROUTINES : BLD_IDT - Put the entries into the IDT *
45* *
46* MACROS : DATAOV - Create a prefix for the following instruction *
47* so that it accesses data 32 bits wide *
48* ADDROV - Create a prefix for the following instruction *
49* so that it uses addresses that are 32 bits wide *
50* *
51* CONTROL BLOCKS : INDEDAT *
52* *
53* CHANGE ACTIVITY : *
54* *
55* $MOD(INDEIDT) COMP(LOAD) PROD(3270PC) : *
56* *
57* $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 *
58* $P1=P0000312 410 870803 D : CHANGE COMPONENT FROM MISC TO LOAD *
59* $P2=P0000xxx 120 880517 D : HANDLE INT 0D FROM V86 TASK, I.E., OPTICAL DISK *
60* *
61* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
62#
63
64 .286P ; Enable recognition of 286 privileged instructs.
65
66 .XLIST ; Turn off the listing
67 INCLUDE INDEDAT.INC ; System data structures and equates
68
69 IF1 ; Only include macros on the first pass
70 INCLUDE INDEOVP.MAC
71 ENDIF
72 .LIST ; Turn on the listing
73PAGE
74
75PROG SEGMENT PARA PUBLIC 'PROG'
76
77 ASSUME CS:PROG
78 ASSUME SS:NOTHING
79 ASSUME DS:NOTHING
80 ASSUME ES:NOTHING
81
82INDEIDT LABEL NEAR
83
84; Let these entry points be known to other modules.
85
86 PUBLIC INDEIDT
87 PUBLIC SIDT_BLD
88
89; This is the entry point to INDEEXC.
90
91 EXTRN VEXCPT13:NEAR
92
93PAGE
94; Define the stack structure for our fast path. For all the interrupts that we
95; don't want to handle we just pass the interrupt back to the real interrupt
96; vector. The entry points for these vectors push the interrupt vector offset
97; (interrupt number * 4) onto the stack and then call FASTPATH to pass the
98; interrupt to the real vector. FASTPATH pushes BP, AX, DI and SI on to the
99; stack. The following structure is a map of the stack after these registers
100; are pushed. This structure allows us to access info on the stack.
101
102SPSTACK STRUC
103
104SP_SI DW 0 ; Saved ESI (32 bit SI)
105 DW 0
106SP_DI DW 0 ; Saved EDI (32 bit DI)
107 DW 0
108SP_AX DW 0 ; Saved EAX
109 DW 0
110SP_BP DW 0 ; Saved BP (only 16 bits)
111SP_EX DW 0 ; Interrupt vector offset (interrupt number * 4)
112
113; The following information is saved by the 80386
114
115SP_IP DW 0 ; Interruptee's EIP (32 bit IP)
116SP_IP2 DW 0
117SP_CS DW 0 ; Interruptee's CS (16 bit CS and 16 bit junk)
118SP_CS2 DW 0
119SP_FL DW 0 ; Interruptee's Eflags (32 bit flags)
120SP_FL2 DW 0
121SP_SP DW 0 ; Interruptee's ESP
122SP_SP2 DW 0
123SP_SS DW 0 ; Interruptee's SS
124SP_SS2 DW 0
125SP_VMES DW 0 ; Interruptee's ES
126 DW 0
127SP_VMDS DW 0 ; Interruptee's DS
128 DW 0
129SP_VMFS DW 0 ; Interruptee's FS
130 DW 0
131SP_VMGS DW 0 ; Interruptee's GS
132 DW 0
133SP_STK DW 0 ; The rest of the stack
134
135SPSTACK ENDS
136
137SP_START EQU 0 ; Offset from BP of the start of the save area
138 ; BP is set ot point to the start of the save area
139
140PAGE
141
142SIDTBLD PROC NEAR
143
144; Generate the entry points for all (yes, ALL) 256 interrupt vectors. For
145; interrupt 0D (general Protection exception) we will check if it was the V86
146; task that faulted. If so, then we will just pass the interrupt back to the
147; V86 task. Else, we will go to our exception handler since the interrupt
148; happened because of the emulator.
149;
150; For interrupts 00, 01, 02, 03, 04, 05, 06, 07, 09, 0A, 0B, 0C, 0E and 15 we
151; will go to our exception handler.
152;
153; For all other interrupts we will go to the FASTPATH routine which will pass
154; the interrupt back to the V86 interrupt vector.
155;
156; Note: For interrupts that go to our exception handler we push a 32 bit error
157; code and then push the interrupt number. For the FASTPATH interrupts
158; we push the interrupt vector offset (interrupt number *4). This results
159; in different stack structures depending on how the interrupt is handled.
160; So be careful when you're trying to figure out what's on the stack.
161;
162
163; Interrupt 0D
164
165 IRP V,<0D>
166VEC&V:
167 PUSH 0&V&H ; Push the interrupt number (0D)
168 PUSH BP ; Save BP
169 DATAOV ; @P2A
170 PUSH AX ; Save EAX, all 32bits of it. @P2A
171 DATAOV ; @P2A
172 PUSH DI ; Save EDI @P2A
173 DATAOV ; @P2A
174 PUSH SI ; Save ESI @P2A
175 MOV BP,SP ; Point BP to the save area @P2A
176
177 ; Now we must check if the INT 0D came from the V86 task P2A
178 ; or if it was a General Protection exception. In the P2A
179 ; case of a General Protection exception the 80386 puts P2A
180 ; an error code on the stack after pushing the EFLAGS, CS P2A
181 ; and EIP. The error code is 32 bits wide. If the V86 P2A
182 ; task issues an INT 0D, an error code is NOT placed on P2A
183 ; the stack. In this case we want to pass the interrupt P2A
184 ; back to the V86 task instead of going to our exception P2A
185 ; handler. The way we check for an error code is by P2A
186 ; checking how much ESP has been decremented since the P2A
187 ; start of the interrupt. The original ESP is saved in P2A
188 ; the TSS. Our stack definition above does not include P2A
189 ; an error code. So if ESP has been decremented more than P2A
190 ; the size of our structure, we can know that an error P2A
191 ; code is on the stack and then go to our exception P2A
192 ; handler. P2A
193
194 MOV AX,SCRUBBER.TSS_PTR ; Load DS with the selector @P2A
195 MOV DS,AX ; that accesses the TSS as data @P2A
196 MOV SI,0 ; Base for reading the TSS @P2A
197 DATAOV ; @P2A
198 MOV AX,[SI].ETSS_SP0 ; Get the original SP before the @P2A
199 DATAOV ; interrupt @P2A
200 SUB AX,SP ; Subtract the current stack @P2A
201 ; pointer @P2A
202 CMP AX,SP_STK ; Check for an error code @P2A
203 ; @P2D
204 JG SKIP&V ; If there's an error code, go @P2C
205 ; handle the exception P2C
206 MOV WORD PTR [BP+SP_EX],0&V&H*4 ; If there is no error @P2A
207 ; code then multiply the vector P2A
208 ; number by four for the FASTPATH P2A
209 ; code. P2A
210 JMP PASS_ON ; Give the interrupt back to the @P2C
211 ; V86 task.
212SKIP&V: DATAOV ; @P2A
213 POP SI ; Restore ESI from off our stack @P2A
214 DATAOV ; @P2A
215 POP DI ; Restore EDI @P2A
216 DATAOV ; @P2A
217 POP AX ; Restore EAX @P2A
218 POP BP ; Take BP off the stack. This leaves
219 ; the interrupt number that we pushed
220 ; above and the error code that was
221 ; pushed by the 386 on the INT 0D.
222 JMP VEXCPT13 ; Go to the exception handler.
223
224 ENDM
225
226PAGE
227; For interrupts 00, 01, 02, 03, 04, 05, 06, 07, 09, 0A, 0B, 0C, 0E and 15
228; push a dummy error code of 0 and then the interrupt number. Then go to the
229; exception handler.
230
231 IRP V,<00,01,02,03,04,05,06,07,09,0A,0B,0C,0E,15>
232VEC&V:
233 PUSH 0 ; Push a dummy error code of 0
234 PUSH 0 ; 32 bits wide
235SKIP&V:
236 PUSH 0&V&H ; Push the interrupt number
237 JMP VEXCPT13 ; Go to the exception handler
238 ENDM
239
240PAGE
241; For the rest of the interrupts push the interrupt vector offset (interrupt
242; number * 4) and go to the fast path routine.
243;
244; INT 08H is given the FASTPATH. It's the double fault interrupt so we are
245; dead any way. This interrupt is normally used for the timer interrupt.
246;
247; INT 10H, BIOS video calls, is given the fastest code path by putting it just
248; before the FASTPATH routine.
249
250 IRP V,<08,0F,11,12,13,14,16,17,18,19,1A,1B,1C,1D,1E,1F>
251VEC&V:
252 PUSH 0&V&H*4 ; Push the interrupt vector offset
253 JMP FASTPATH ; Go to the fastpath routine
254 ENDM
255 IRP V,<20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F>
256VEC&V:
257 PUSH 0&V&H*4 ; Push the interrupt vector offset
258 JMP FASTPATH ; Go to the fastpath routine
259 ENDM
260 IRP V,<30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F>
261VEC&V:
262 PUSH 0&V&H*4 ; Push the interrupt vector offset
263 JMP FASTPATH ; Go to the fastpath routine
264 ENDM
265 IRP V,<40,41,42,43,44,45,46,47,48,49,4A,4B,4C,4D,4E,4F>
266VEC&V:
267 PUSH 0&V&H*4 ; Push the interrupt vector offset
268 JMP FASTPATH ; Go to the fastpath routine
269 ENDM
270 IRP V,<50,51,52,53,54,55,56,57,58,59,5A,5B,5C,5D,5E,5F>
271VEC&V:
272 PUSH 0&V&H*4 ; Push the interrupt vector offset
273 JMP FASTPATH ; Go to the fastpath routine
274 ENDM
275 IRP V,<60,61,62,63,64,65,66,67,68,69,6A,6B,6C,6D,6E,6F>
276VEC&V:
277 PUSH 0&V&H*4 ; Push the interrupt vector offset
278 JMP FASTPATH ; Go to the fastpath routine
279 ENDM
280 IRP V,<70,71,72,73,74,75,76,77,78,79,7A,7B,7C,7D,7E,7F>
281VEC&V:
282 PUSH 0&V&H*4 ; Push the interrupt vector offset
283 JMP FASTPATH ; Go to the fastpath routine
284 ENDM
285 IRP V,<80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8D,8E,8F>
286VEC&V:
287 PUSH 0&V&H*4 ; Push the interrupt vector offset
288 JMP FASTPATH ; Go to the fastpath routine
289 ENDM
290 IRP V,<90,91,92,93,94,95,96,97,98,99,9A,9B,9C,9D,9E,9F>
291VEC&V:
292 PUSH 0&V&H*4 ; Push the interrupt vector offset
293 JMP FASTPATH ; Go to the fastpath routine
294 ENDM
295 IRP V,<A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF>
296VEC&V:
297 PUSH 0&V&H*4 ; Push the interrupt vector offset
298 JMP FASTPATH ; Go to the fastpath routine
299 ENDM
300 IRP V,<B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF>
301VEC&V:
302 PUSH 0&V&H*4 ; Push the interrupt vector offset
303 JMP FASTPATH ; Go to the fastpath routine
304 ENDM
305 IRP V,<C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,CA,CB,CC,CD,CE,CF>
306VEC&V:
307 PUSH 0&V&H*4 ; Push the interrupt vector offset
308 JMP FASTPATH ; Go to the fastpath routine
309 ENDM
310 IRP V,<D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,DA,DB,DC,DD,DE,DF>
311VEC&V:
312 PUSH 0&V&H*4 ; Push the interrupt vector offset
313 JMP FASTPATH ; Go to the fastpath routine
314 ENDM
315 IRP V,<E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF>
316VEC&V:
317 PUSH 0&V&H*4 ; Push the interrupt vector offset
318 JMP FASTPATH ; Go to the fastpath routine
319 ENDM
320 IRP V,<F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,FA,FB,FC,FD,FE,FF>
321VEC&V:
322 PUSH 0&V&H*4 ; Push the interrupt vector offset
323 JMP FASTPATH ; Go to the fastpath routine
324 ENDM
325
326VEC10:
327 PUSH 010H*4 ; Push the interrupt vector offset
328
329PAGE
330FASTPATH:
331 PUSH BP ; Save BP
332 DATAOV
333 PUSH AX ; Save EAX, all 32bits of it.
334 DATAOV
335 PUSH DI ; Save EDI
336 DATAOV
337 PUSH SI ; Save ESI
338 MOV BP,SP ; Point BP to the save area
339
340PASS_ON: ; @P2C
341 CLD ; All string operations go forward
342
343 MOV AX,HUGE_PTR ; Load DS and ES with a selector that
344 MOV DS,AX ; accesses all of memory as data
345 MOV ES,AX
346 DATAOV
347 SUB DI,DI ; Clear EDI
348 MOV DI,SS:[BP+SP_SP] ; Load DI with the interruptee's SP
349 SUB DI,6 ; Decrement "SP" to simulate the pushing
350 ; of the flags, CS and IP on an INT.
351 MOV SS:WORD PTR [BP+SP_SP],DI ; Replace the user's SP
352
353 DATAOV
354 SUB AX,AX ; Clear EAX
355 MOV AX,SS:[BP+SP_SS] ; Load AX with the user's SS register
356 DATAOV ; Shift "SS" left four bits to convert
357 SHL AX,4 ; it to an offset
358 DATAOV ; Add on "SP" to get a 32 bit offset
359 ADD DI,AX ; from 0 of the user's stack.
360
361; Put the user's IP, CS and flags onto his stack. This is done in reverse
362; order because we are moving forward in memory whereas stacks grow backward.
363
364 MOV AX,SS:[BP+SP_IP] ; Get the user's IP
365 ADDROV
366 STOSW ; And put it on the stack
367 ADDROV ; Intel bug # A0-119
368 NOP ; Intel bug # A0-119
369
370 MOV AX,SS:[BP+SP_CS] ; Get the user's CS
371 ADDROV
372 STOSW ; And put it on the stack
373 ADDROV ; Intel bug # A0-119
374 NOP ; Intel bug # A0-119
375
376 MOV AX,SS:[BP+SP_FL] ; Get the user's flags
377 ADDROV
378 STOSW ; And put them on the stack
379 ADDROV ; Intel bug # A0-119
380 NOP ; Intel bug # A0-119
381
382 AND AX,3CFFH ; Clean up the flags for our IRET by
383 MOV WORD PTR SS:[BP+SP_FL],AX ; setting IOPL to 3
384
385; Replace the interruptee's CS:IP with the CS:IP of the interrupt vector. When
386; we IRET back to the V86 task control will go to the interrupt routine.
387
388 MOV SI,SS:[BP+SP_EX] ; Get the interrupt vector offset
389 LODSW ; Get the IP of the interrupt vector
390 MOV WORD PTR SS:[BP+SP_IP],AX ; Replace the user's IP
391 LODSW ; Get the CS of the interrupt vector
392 MOV WORD PTR SS:[BP+SP_CS],AX ; Replace the user's CS
393
394 DATAOV
395 POP SI ; Restore ESI from off our stack
396 DATAOV
397 POP DI ; Restore EDI
398 DATAOV
399 POP AX ; Restore EAX
400 POP BP ; Restore BP
401 ADD SP,(SP_IP-SP_EX) ; Step SP past the interrupt vector
402 ; offset
403 DATAOV
404 IRET ; Give control back to the interruptee
405
406PAGE
407
408; Build a talbe of the offsets of all the interrupt entry points. This table
409; is used as input to the procedure that builds the IDT.
410
411SIDT_OFFSETS LABEL WORD
412
413 IRP V,<00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F>
414 DW OFFSET VEC&V
415 ENDM
416 IRP V,<10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F>
417 DW OFFSET VEC&V
418 ENDM
419 IRP V,<20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F>
420 DW OFFSET VEC&V
421 ENDM
422 IRP V,<30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F>
423 DW OFFSET VEC&V
424 ENDM
425 IRP V,<40,41,42,43,44,45,46,47,48,49,4A,4B,4C,4D,4E,4F>
426 DW OFFSET VEC&V
427 ENDM
428 IRP V,<50,51,52,53,54,55,56,57,58,59,5A,5B,5C,5D,5E,5F>
429 DW OFFSET VEC&V
430 ENDM
431 IRP V,<60,61,62,63,64,65,66,67,68,69,6A,6B,6C,6D,6E,6F>
432 DW OFFSET VEC&V
433 ENDM
434 IRP V,<70,71,72,73,74,75,76,77,78,79,7A,7B,7C,7D,7E,7F>
435 DW OFFSET VEC&V
436 ENDM
437 IRP V,<80,81,82,83,84,85,86,87,88,89,8A,8B,8C,8D,8E,8F>
438 DW OFFSET VEC&V
439 ENDM
440 IRP V,<90,91,92,93,94,95,96,97,98,99,9A,9B,9C,9D,9E,9F>
441 DW OFFSET VEC&V
442 ENDM
443 IRP V,<A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF>
444 DW OFFSET VEC&V
445 ENDM
446 IRP V,<B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,BA,BB,BC,BD,BE,BF>
447 DW OFFSET VEC&V
448 ENDM
449 IRP V,<C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,CA,CB,CC,CD,CE,CF>
450 DW OFFSET VEC&V
451 ENDM
452 IRP V,<D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,DA,DB,DC,DD,DE,DF>
453 DW OFFSET VEC&V
454 ENDM
455 IRP V,<E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF>
456 DW OFFSET VEC&V
457 ENDM
458 IRP V,<F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,FA,FB,FC,FD,FE,FF>
459 DW OFFSET VEC&V
460 ENDM
461PAGE
462SIDT_BLD:
463
464; Build the system IDT. The system IDT will contain 256 interrupt gates.
465
466 MOV AX,CS ; Set DS:SI to point to the table of
467 MOV DS,AX ; interrupt entry points
468 MOV SI,OFFSET SIDT_OFFSETS
469
470 MOV DI,SIDT_LOC ; Set ES:DI to point to the beginning
471 ; of the IDT
472 MOV BX,SYS_PATCH_CS ; Load BX with the selector for the
473 ; segment of the interrupt routines.
474 ; It's our code segment.
475
476; DX contains the second highest word of the interrupt descriptor.
477
478 MOV DH,0EEH ; Set DPL to 3 to reduce the number of
479 ; exceptions
480 MOV DL,0 ; The word count field is unused
481
482 MOV CX,256 ; 256 interrupt gates
483
484 CALL BLD_IDT ; Go build the IDT
485
486 RET ; Return to INDEINI
487
488PAGE
489
490; This loop builds descriptors in the IDT. DS:SI points to a table of 16 bit
491; offsets for the interrupt entry points. ES:DI points to the start of the IDT.
492; BX contains the segment selector of the interrupt entry points. DX contains
493; the DPL of the interrupt gates.
494
495BLD_IDT:
496 MOVSW ; Get an interrupt routine entry point
497 ; and put it in the offset field
498 MOV AX,BX ; Get the segment selector
499 STOSW ; and put it in the selector field
500 MOV AX,DX ; Get the interrupt gate DPL
501 STOSW ; and put it in the access rights field
502 MOV AX,0 ; Zero out the reserved portions
503 STOSW
504 LOOP BLD_IDT ; Repeat for all interrupt vectors
505
506 RET
507
508SIDTBLD ENDP
509
510PROG ENDS
511
512 END
diff --git a/v4.0/src/DEV/XMAEM/INDEINI.ASM b/v4.0/src/DEV/XMAEM/INDEINI.ASM
new file mode 100644
index 0000000..19c8b79
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEINI.ASM
@@ -0,0 +1,1474 @@
1PAGE 60,132
2TITLE INDEINI - 386 XMA EMULATOR - Initialization
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEINI *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: 80386 XMA EMULATOR INITIALIZATION *
12* *
13* STATUS (LEVEL) : VERSION (0) LEVEL (2.0) *
14* *
15* FUNCTION : Do all the initialization needed for the 386 XMA emulator.*
16* *
17* The 386 XMA emulator is installed by putting the follow- *
18* ing command in the CONFIG.SYS file: *
19* *
20* DEVICE=\386XMAEM.SYS bbb *
21* *
22* where "bbb" is the number of K reserved for the MOVEBLOCK *
23* function. If EMS is used, this command must appear *
24* before the command to load EMS. *
25* *
26* This module first of all does all the stuff to set up *
27* the device driver linkage to DOS. The driver is a *
28* character device. The only command it recognizes is P3C*
29* "initialize". When it receives the initialize command *
30* it does all the set up for the emulator. For information *
31* on device drivers see the DOS Technical Reference. *
32* *
33* Then it checks to see if we're on a model_80 and the *
34* emulator has not been previously installed. If this is *
35* the case, then it procedes to do the following: *
36* Get the MOVEBLOCK buffer size from the parameter list *
37* Save the maximum XMA block number in the header *
38* Relocate to high memory *
39* Initialize the page directory and page tables *
40* Call INDEIDT to initialize the IDT *
41* Call INDEGDT to initialize the GDT *
42* Switch to virtual mode *
43* Initialize the TSS for the virtual 8086 task *
44* Initialize the XMA page tables *
45* Enable paging *
46* *
47* This module also contains code to handle the Generic D2A*
48* IOCTL call which is used to query the highest valid D2A*
49* XMA block number. This code is left resident. D2A*
50* *
51* MODULE TYPE : ASM *
52* *
53* REGISTER USAGE : 80386 STANDARD *
54* *
55* RESTRICTIONS : None *
56* *
57* DEPENDENCIES : None *
58* *
59* LINKAGE : Invoked as a DOS device driver *
60* *
61* INPUT PARMS : The number of 1K blocks reserved for the MOVE BLOCK *
62* service can be specified after the DEVICE command in the *
63* CONFIG.SYS file. 0K is the default. *
64* *
65* RETURN PARMS : A return code is returned to DOS in the device header *
66* at offset 3. *
67* *
68* OTHER EFFECTS : None *
69* *
70* EXIT NORMAL : Return to DOS after device driver is loaded *
71* *
72* EXIT ERROR : Return to DOS after putting up error messages *
73* *
74* EXTERNAL *
75* REFERENCES : SIDT_BLD - Entry point for INDEIDT to build the IDT *
76* GDT_BLD - Entry point for INDEGDT to build the GDT *
77* WELCOME - The welcome message *
78* GOODLOAD - Message saying we loaded OK *
79* NO_80386 - Error message for not running on a model_80 *
80* WAS_INST - Error message for protect mode in use *
81* SP_INIT - Initial protect mode SP *
82* REAL_CS - Place to save our real mode CS *
83* REAL_SS - Place to save our real mode SS *
84* REAL_SP - Place to save our real mode SP *
85* PGTBLOFF - Offset of the page tables *
86* SGTBLOFF - Offest of the page directory *
87* NORMPAGE - Normal page directory entry *
88* XMAPAGE - Page directory entry for the first XMA page D1A*
89* BUFF_SIZE- Size of the MOVEBLOCK buffer *
90* MAXMEM - Maximum amount of memory on the box *
91* CRT_SELECTOR - Selector for the display buffer *
92* *
93* SUB-ROUTINES : GATE_A20 - Gate on or off address bit 20 *
94* GET_PARMS - Get the MOVEBLOCK buffer size specified on *
95* the command in CONFIG.SYS and convert to *
96* binary. *
97* *
98* MACROS : DATAOV - Add prefix for the next instruction so that it *
99* accesses data as 32 bits wide *
100* ADDROV - Add prefix for the next instruction so that it *
101* uses addresses that are 32 bits wide *
102* CMOV - Move to and from control registers *
103* JUMPFAR - Build an instruction that will jump to the *
104* offset and segment specified *
105* *
106* CONTROL BLOCKS : INDEDAT.INC *
107* *
108* CHANGE ACTIVITY : *
109* *
110* $MOD(INDEINI) COMP(LOAD) PROD(3270PC) : *
111* *
112* $D0=D0004700 410 870521 D : NEW FOR RELEASE 1.1. CHANGES TO THE ORIGINAL *
113* CODE ARE MARKED WITH D0A. *
114* $P1=P0000281 410 870730 D : SAVE 32 BIT REGISTERS ON model_80 *
115* $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD *
116* $P3=P0000335 410 870811 D : HEADER INFORMATION ALL SCREWED UP *
117* $D1=D0007100 410 870810 D : CHANGE TO EMULATE XMA 2 *
118* CHANGE ID STRING TO "386XMAEMULATOR10" *
119* $P4=P0000649 411 880125 D : A20 NOT ENABLED WHEN PASSWORD SET *
120* $P5=P0000650 411 880128 D : COPROCESSOR APPLICATIONS FAIL *
121* $P6=P0000740 411 880129 D : IDSS CAPTURED DCR 87 CODE. REMOVE IT. *
122* $D2=D0008700 120 880206 D : SUPPORT DOS 3.4 IOCTL CALL *
123* $P7=P0000xxx 120 880331 D : FIX INT 15. LOAD AS V86 MODE HANDLER. *
124* *
125* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
126#
127
128 .286P ; Enable recognition of 286 privileged instructs.
129
130 .XLIST ; Turn off the listing
131 INCLUDE INDEDAT.INC
132
133 IF1 ; Only include the macros in the first pass
134 INCLUDE INDEOVP.MAC ; of the assembler
135 INCLUDE INDEINS.MAC
136 ENDIF
137 .LIST ; Turn on the listing
138
139 ; Let these variables be known to external procedures
140
141 PUBLIC POST
142 PUBLIC INDEINI
143
144PROG SEGMENT PARA PUBLIC 'PROG'
145
146 ASSUME CS:PROG
147 ASSUME SS:NOTHING
148 ASSUME DS:PROG
149 ASSUME ES:NOTHING
150
151INDEINI LABEL NEAR
152
153 ; These variables are located in INDEI15
154
155 EXTRN SP_INIT:WORD ; Initial protect mode SP
156 EXTRN REAL_CS:WORD ; Place to save our real mode CS
157 EXTRN REAL_SS:WORD ; Place to save our real mode SS
158 EXTRN REAL_SP:WORD ; Place to save our real mode SP
159 EXTRN PGTBLOFF:WORD ; Offset of the page tables
160 EXTRN SGTBLOFF:WORD ; Offest of the page directory
161 EXTRN NORMPAGE:WORD ; Normal page directory entry. Points to the
162 ; page table that maps the real 0 to 4M.
163 EXTRN XMAPAGE:WORD ; Page directory entry for the first XMA
164 ; page table (page table for bank 0) @D1A
165 EXTRN BUFF_SIZE:WORD ; Size of the MOVEBLOCK buffer
166 EXTRN MAXMEM:WORD ; Maximum amount of memory on the box
167 EXTRN CRT_SELECTOR:WORD ; Selector for the display buffer
168
169 ; These are the messages
170
171 EXTRN WELCOME:BYTE ; The welcome message
172 EXTRN GOODLOAD:BYTE ; Message saying we loaded OK
173 EXTRN NO_80386:BYTE ; Error message for not running on a model_80
174 EXTRN WAS_INST:BYTE ; Error message for protect mode in use
175 Extrn Small_Parm:Byte ; Parm value < 64 and > 0 ;an000; dms;
176 Extrn No_Mem:Byte ; Parm value > memory available ;an000; dms;
177
178 ; These entries are located in external procedures
179
180 EXTRN SIDT_BLD:NEAR ; Build the interrupt descriptor table (IDT)
181 EXTRN GDT_BLD:NEAR ; Build the global descriptor table (GDT)
182
183; General equates
184
185DDSIZE EQU GDT_LOC ; Size of the device driver
186HIGH_SEG EQU 0FFF0H ; The segment we relocate to
187MEG_SUPPORTED EQU 24 ; Must be a multiple of 4
188XMA_PAGES_SEL EQU RSDA_PTR ; Selector for XMA pages
189DISPSTRG EQU 09H ; DOS display string function number D0A
190GET_VECT EQU 35H ; DOS get vector function number P7A
191SET_VECT EQU 25H ; DOS set vector function number P7A
192model_80 EQU 0F8H ; Model byte for the Wangler D0A
193XMA640KSTRT EQU 580H ; Start address of XMA block for D0A
194 ; 640K (16000:0 / 1K) D0A P3C
195
196; ASCII character equates
197
198TAB EQU 09H ; ASCII tab
199LF EQU 0AH ; ASCII line feed
200CR EQU 0DH ; ASCII carriage return
201
202SUBTTL Structure Definitions
203PAGE
204;------------------------------------------------------------------------------;
205; Request Header (Common portion) ;
206;------------------------------------------------------------------------------;
207
208RH EQU DS:[BX] ; The Request Header structure is based off
209 ; of DS:[BX]
210
211RHC STRUC ; Fields common to all request types
212 DB ? ; Length of Request Header (including data)
213 DB ? ; Unit code (subunit)
214RHC_CMD DB ? ; Command code
215RHC_STA DW ? ; Status
216 DQ ? ; Reserved for DOS
217RHC ENDS ; End of common portion
218
219; Status values for RHC_STA
220
221STAT_DONE EQU 0100H ; Function complete status (high order byte)@P3C
222STAT_CMDERR EQU 8003H ; Invalid command code error
223STAT_GEN EQU 800CH ; General error code D0A
224
225;------------------------------------------------------------------------------;
226; Request Header for INIT command ;
227;------------------------------------------------------------------------------;
228
229RH0 STRUC
230 DB (TYPE RHC) DUP (?) ; Reserve space for the header
231
232RH0_NUN DB ? ; Number of units
233 ; Set to 1 if installation succeeds,
234 ; Set to 0 to cause installation failure
235RH0_ENDO DW ? ; Offset of ending address
236RH0_ENDS DW ? ; Segment of ending address
237RH0_BPBO DW ? ; Offset of BPB array address
238RH0_BPBS DW ? ; Segment of BPB array address
239RH0_DRIV DB ? ; Drive code (DOS 3 only)
240RH0 ENDS
241
242RH0_BPBA EQU DWORD PTR RH0_BPBO ; Offset & segment of BPB array address.
243 ; On the INIT command the BPB points to
244 ; the characters following the "DEVICE="
245 ; in the CONFIG.SYS file.
246
247;---------------------------------------------------------------------------D2A;
248; Request Header for Generic IOCTL Request D2A;
249;---------------------------------------------------------------------------D2A;
250
251RH19 STRUC
252 DB (TYPE RHC) DUP (?) ; Reserve space for the header @D2A
253
254RH19_MAJF DB ? ; Major function @D2A
255RH19_MINF DB ? ; Minor function @D2A
256RH19_SI DW ? ; Contents of SI @D2A
257RH19_DI DW ? ; Contents of DI @D2A
258RH19_RQPK DD ? ; Pointer to Generic IOCTL request packet @D2A
259RH19 ENDS
260
261SUBTTL Device Driver Header
262PAGE
263POST PROC NEAR
264
265 ; Declare the device driver header
266
267 ORG 0 ; Device header must the very first thing in the
268 ; device driver
269 DD -1 ; Becomes pointer to next device header
270 DW 0C040H ; Character device, does IOCTL @P3C @D2C
271 DW OFFSET STRATEGY ; Pointer to device "strategy" routine
272 DW OFFSET IRPT ; Pointer to device "interrupt handler"
273 DB "386XMAEM" ; Device name @D0C
274
275 ; End of device driver header
276
277;------------------------------------------------------------------------------;
278; Request Header (RH) address, saved here by "strategy" routine ;
279;------------------------------------------------------------------------------;
280
281RH_PTRA LABEL DWORD
282RH_PTRO DW ? ; Offset of the request header
283RH_PTRS DW ? ; Segment of the request header
284 ; Character ID "386XMAEMULATOR10" deleted 2@D2D
285HI_XMA_BLK DW ? ; The highest XMA block number @D0A
286EXT_MEM DW ? ; Number of K of extended memory @P7A
287 ; D0A
288RBX DW ? ; Temporary save area for register BX @P1A
289ISmodel_80 DB -1 ; model_80 flag. Set to 1 if on a model_80 @P1A
290 ; Set to 0 if not on a model_80 @D1C
291
292SUBTTL Device Strategy
293PAGE
294;------------------------------------------------------------------------------;
295; Device "strategy" entry point ;
296; ;
297; Retain the Request Header address for use by Interrupt routine ;
298;------------------------------------------------------------------------------;
299
300STRATEGY PROC FAR
301
302 MOV CS:RH_PTRO,BX ; Save the offset of the request header
303 MOV CS:RH_PTRS,ES ; Save the segment of the request header
304 RET
305
306STRATEGY ENDP
307
308SUBTTL Device Interrupt Intry Point
309PAGE
310
311;------------------------------------------------------------------------------;
312; Table of command processing routine entry points ;
313;------------------------------------------------------------------------------;
314CMD_TABLE LABEL WORD
315 DW OFFSET INIT_P1 ; 0 - Initialization
316 DW OFFSET MEDIA_CHECK ; 1 - Media check
317 DW OFFSET BLD_BPB ; 2 - Build BPB
318 DW OFFSET INPUT_IOCTL ; 3 - IOCTL input
319 DW OFFSET INPUT ; 4 - Input
320 DW OFFSET INPUT_NOWAIT ; 5 - Non destructive input no wait
321 DW OFFSET INPUT_STATUS ; 6 - Input status
322 DW OFFSET INPUT_FLUSH ; 7 - Input flush
323 DW OFFSET OUTPUT ; 8 - Output
324 DW OFFSET OUTPUT_VERIFY ; 9 - Output with verify
325 DW OFFSET OUTPUT_STATUS ;10 - Output status
326 DW OFFSET OUTPUT_FLUSH ;11 - Output flush
327 DW OFFSET OUTPUT_IOCTL ;12 - IOCTL output
328 DW OFFSET DEVICE_OPEN ;13 - Device OPEN
329 DW OFFSET DEVICE_CLOSE ;14 - Device CLOSE
330 DW OFFSET REMOVABLE_MEDIA ;15 - Removable media
331 DW OFFSET INVALID_FCN ;16 - Invalid IOCTL function @D2A
332 DW OFFSET INVALID_FCN ;17 - Invalid IOCTL function @D2A
333 DW OFFSET INVALID_FCN ;18 - Invalid IOCTL function @D2A
334 DW OFFSET GENERIC_IOCTL ;19 - Generic IOCTL function @D2A
335 DW OFFSET INVALID_FCN ;20 - Invalid IOCTL function @D2A
336 DW OFFSET INVALID_FCN ;21 - Invalid IOCTL function @D2A
337 DW OFFSET INVALID_FCN ;22 - Invalid IOCTL function @D2A
338 DW OFFSET GET_LOG_DEVICE ;23 - Get Logical Device @D2A
339MAX_CMD EQU ($-CMD_TABLE)/2 ; Highest valid command follows
340 DW OFFSET SET_LOG_DEVICE ;24 - Set Logical Device @D2A
341
342;------------------------------------------------------------------------------;
343; Device "interrupt" entry point ;
344;------------------------------------------------------------------------------;
345IRPT PROC FAR ; Device interrupt entry point
346
347; First we must save all the registers that we use so that when we return to
348; DOS the registers are not changed.
349
350 PUSH DS ; Save the segment registers modified
351 PUSH ES
352
353 CMP CS:ISmodel_80,-1; Did we already check what machine we are @D2A
354 JNE DID_CHECK ; running on? @D2A
355
356 MOV CS:RBX,BX ; Save BX @P1A
357 MOV BX,0FFFFH ; Check the model byte at FFFF:000E @D0A @P1M
358 MOV ES,BX ; to see if we're running on a @D0A @P1M
359 MOV BX,0EH ; model_80 (PS/2 model 80). @D0A @P1M
360 CMP BYTE PTR ES:[BX],model_80 ; @P1A
361 MOV BX,CS:RBX ; Restore BX @P1A @D2M
362 JNE NO_model_80
363
364 MOV CS:ISmodel_80,1 ; Set the flag saying we're on a @P1A @D2M
365 JMP DID_CHECK ; model_80 @D2A
366
367NO_model_80:
368 MOV CS:ISmodel_80,0 ; Set the flag saying we're not on a @D2M
369 ; model_80
370
371DID_CHECK: ; D2A
372 CMP ISmodel_80,1 ; Are we on a model_80? @D2A
373 JE PUSH32 ; If so, go save the 32 bit registers @P1A
374
375; Push 16 bit registers onto the stack.
376
377 PUSH AX
378 PUSH BX
379 PUSH CX
380 PUSH DX
381 PUSH DI
382 PUSH SI
383 PUSH BP
384
385 JMP PUSHED ; @P1A
386
387; Push 32 bit registers onto the stack P1A
388 ; @D2D
389PUSH32: DATAOV ; Save all the 32 bit registers. The @P1A
390 PUSHA ; model_80's BIOS uses 32 bit registers, @P1A
391 ; so we must not trash the high order P1A
392 ; words as well as the low order words. P1A
393
394PUSHED: CLD ; All moves go forward
395
396 LDS BX,CS:RH_PTRA ; Get the request header address passed to the
397 ; "strategy" routine into DS:BX
398
399 MOV AL,RH.RHC_CMD ; Get the command code from the Request Header
400 CBW ; Zero AH (if AL > 7FH, next compare will
401 ; catch that error)
402
403 CMP AL,MAX_CMD ; If command code is too high
404 JA IRPT_CMD_HIGH ; Then jump to error routine
405
406 ADD AX,AX ; Double command code for table offset since
407 ; table entries are words
408 MOV DI,AX ; Put into index register for CALL
409 ; @D2D
410;
411; At entry to command processing routine:
412;
413; DS:BX = Request Header address
414; CS = 386XMAEM code segment address
415; AX = 0
416;
417 CALL CS:CMD_TABLE[DI] ; Call routine to handle the command
418 JMP IRPT_CMD_EXIT
419
420
421IRPT_CMD_HIGH: ; JMPed to if RHC_CMD > MAX_CMD
422 MOV AX,STAT_CMDERR ; Return "Invalid Command" error code
423 OR AX,STAT_DONE ; Add "done" bit to status word @P3C
424 MOV RH.RHC_STA,AX ; Store status into request header
425
426IRPT_CMD_EXIT: ; Return from command routine
427
428; Restore the registers before returning to DOS.
429
430 CMP CS:ISmodel_80,1 ; Are we on a model_80? @P1A
431 JE POP32 ; Yes. Then pop the 32 bit registers. @P1A
432
433; Pop 16 bit registers off of the stack.
434
435 POP BP
436 POP SI
437 POP DI
438 POP DX
439 POP CX
440 POP BX
441 POP AX
442
443 JMP POPPED ; @P1A
444
445; Pop 32 bit registers off of the stack. P1A
446 ; P1A
447POP32: DATAOV ; @P1A
448 POPA ; @P1A
449
450; Pop the segment registers off of the stack.
451
452POPPED: POP ES
453 POP DS
454
455 RET
456IRPT ENDP
457
458SUBTTL Command Routines
459PAGE
460
461MEDIA_CHECK: ;
462BLD_BPB: ;
463INPUT_IOCTL: ; IOCTL input
464INPUT: ;
465INPUT_NOWAIT: ; Non-destructive input no wait
466INPUT_STATUS: ; Input status
467INPUT_FLUSH: ; Input flush
468OUTPUT: ;
469OUTPUT_VERIFY: ;
470OUTPUT_IOCTL: ; IOCTL output
471OUTPUT_STATUS: ; Output status
472OUTPUT_FLUSH: ; Output flush
473DEVICE_OPEN: ;
474DEVICE_CLOSE: ;
475REMOVABLE_MEDIA: ;
476INVALID_FCN: ; @D2A
477GET_LOG_DEVICE: ; @D2A
478SET_LOG_DEVICE: ; @D2A
479
480 MOV AX,STAT_GEN ; Return general error code @D2A
481 OR AX,STAT_DONE ; Add "done" bit to status word @D2A
482 MOV RH.RHC_STA,AX ; Store status into request header @D2A
483
484 RET
485
486SUBTTL Generic IOCTL Service Routine
487PAGE
488
489;------------------------------------------------------------------------------;
490; This routine handles the Generic IOCTL call. The Emulator provides an D2A;
491; interface through the Generic IOCTL call to query the number of XMA D2A;
492; blocks available. When the function code in the parameter list is 0 the D2A;
493; Emulator will return the number of XMA blocks available. There are no D2A;
494; other functions uspported at this time. D2A;
495;------------------------------------------------------------------------------;
496
497GIP EQU ES:[DI] ; @D2A
498
499GEN_IOCTL_PARM STRUC ; @D2A
500
501GIOPLEN DW ? ; Length of the parameter list @D2A
502GIOPFCN DW ? ; Function code @D2A
503GIOPBLK DW ? ; Number of XMA blocks available @D2A
504
505GEN_IOCTL_PARM ENDS ; @D2A
506
507MAXFCN EQU 0 ; Highest function number allowed @D2A
508
509; Return codes D2A
510
511GOODRET EQU 0 ; Good return code @D2A
512BADLEN EQU 1 ; Bad parameter list length @D2A
513BADFCN EQU 2 ; Bad function number @D2A
514
515GENERIC_IOCTL: ; D2A
516
517 LES DI,RH.RH19_RQPK ; Point ES:DI to the Generic IOCTL @D2A
518 ; request packet D2A
519
520; First check to make sure the parameter list is long enough to return the D2A
521; number of XMA blocks. D2A
522
523 CMP GIP.GIOPLEN,4 ; Do we have at least four bytes? @D2A
524 JAE GIP_CHKFCN ; Yup. Go to check function number. @D2A
525
526 MOV GIP.GIOPFCN,BADLEN ; Nope. Sorry. Return the error @D2A
527 JMP GIP_DONE ; code and go to the end. @D2A
528
529; Check if the function number in the parameter list is a valid function. D2A
530
531GIP_CHKFCN: ; D2A
532 CMP GIP.GIOPFCN,MAXFCN ; Is the function code less than or @D2A
533 ; equal to the maximum supported? D2A
534 JLE GIP_CONT ; Yes. Good boy. You get to continue. @D2A
535
536 MOV GIP.GIOPFCN,BADFCN ; No. Shamey, shamey. Set the bad @D2A
537 JMP GIP_DONE ; return code and go to the end. @D2A
538
539; Parameter list is OK. Let's return the number of XMA blocks. D2A
540
541GIP_CONT: ; D2A
542 MOV GIP.GIOPFCN,GOODRET ; Set a good return code @D2A
543 MOV AX,CS:HI_XMA_BLK ; Get the number of XMA blox @D2A
544 MOV GIP.GIOPBLK,AX ; Put it in the paramter list @D2A
545
546
547GIP_DONE: ; D2A
548 MOV RH.RHC_STA,STAT_DONE ; Store done status and good return @D2A
549 ; code into request header D2A
550 RET ; @D2A
551
552INT15F88 PROC FAR ; P7A
553
554; The following is the interrupt chaining structure specified in the PC AT P7A
555; Technical Reference. P7A
556
557 JMP SHORT BEGIN ; P7A
558
559CHAINOFF DW 0 ; Offest of the previous INT 15 vect. @P7A
560CHAINSEG DW 0 ; Segment of the previous INT 15 vect.@P7A
561SIGNATURE DW 424BH ; Says we're doing chaining @P7A
562FLAGS DB 0 ; @P7A
563FIRST EQU 80H ; @P7A
564 JMP SHORT RESET ; @P7A
565RESERVED DB 7 DUP (0) ; @P7A
566
567; OK. Let's see if the user asked for function 88H, query memory size. P7A
568; The function number is specified in the AL register. If it's P7A
569; function88h, then put the memory size in AX and IRET to the caller. P7A
570; Else, just pass the interrupt on to the guy who was installed in the INT P7A
571; 15 vector before us. P7A
572
573BEGIN: CMP AH,88H ; Is it function 88H? @P7A
574 JNE NOT_MINE ; It's not ours to handle @P7A
575
576 MOV AX,CS:EXT_MEM ; Put the number of K into AX @P7A
577 IRET ; Return to the caller @P7A
578
579NOT_MINE: JMP CS:DWORD PTR CHAINOFF
580 ; Pass the interrupt on to the @P7A
581 ; previously installed vector @P7A
582
583RESET: RET ; This, too, is part of the interrupt@P7A
584 ; chaining structure. We will just@P7A
585 ; return on a call to reset. Note @P7A
586 ; that this is a far return. @P7A
587INT15F88 ENDP ; @P7A
588
589LEAVE_RES LABEL NEAR ; Leave code up to here resident.@D0A @D2M
590
591SUBTTL Initialize Routine
592PAGE
593INIT_P1:
594
595 PUSH ES ; Save our code segment at the @D0A
596 MOV DI,0 ; fixed location 0:4F4. This @P3C
597 MOV ES,DI ; gives us a quick way to find CS @P3C
598 MOV DI,4F4H ; and also enables us to break on @P3C
599 MOV ES:[DI],CS ; a write to 0:4F4 which helps us @P3C
600 POP ES ; find the code on the ICE386. @D0A
601 MOV AH,DISPSTRG ; Display the welcome message. @D0A
602 MOV DX,OFFSET WELCOME ; @D0A
603 PUSH DS ; Save DS since DS:BX points to the @D0A
604 PUSH CS ; request header @D0A
605 POP DS ; DS:DX points to the message @D0A
606 INT 21H ; Display the message @D0A
607 POP DS ; Restore DS @D0A
608 ; @P3D
609 MOV RH.RH0_ENDS,CS ; Set the segment and offset of the end
610 MOV RH.RH0_ENDO,OFFSET LEAVE_RES ; of code to leave resident
611 MOV RH.RHC_STA,STAT_DONE ; Store "done" status into request
612 ; header
613 CMP CS:ISmodel_80,1 ; Check if we're on a model_80 @D0A @P1C
614 JE CONT ; If so, then continue @D0A
615 ; D0A
616 MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A
617 MOV AX,STAT_GEN ; Return general error code @D0A
618 OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C
619 MOV RH.RHC_STA,AX ; Store status into request header @D0A
620 ; D0A
621 MOV AH,DISPSTRG ; Display the message that we are @D0A
622 MOV DX,OFFSET NO_80386 ; not on a model_80 @D0A
623 PUSH CS ; @D0A
624 POP DS ; @D0A
625 INT 21H ; @D0A
626 ; D0A
627 RET ; D0A
628 ; D0A
629CONT: ; @D0M
630 SMSW AX ; Get machine status register
631 TEST AL,1 ; Check if the processor is already in
632 ; protect mode. If so, then someone
633 ; else (maybe us) has already taken
634 ; over protect mode.
635 JZ STILLOK ; If not, keep going @D0C
636
637 MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A
638 MOV AX,STAT_GEN ; Return general error code @D0A
639 OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C
640 MOV RH.RHC_STA,AX ; Store status into request header @D0A
641 ; D0A
642 MOV AH,DISPSTRG ; Display the message that protect @D0A
643 MOV DX,OFFSET WAS_INST ; mode is taken. @D0A
644 PUSH CS ; DS:DX points to the message @D0A
645 POP DS ; @D0A
646 INT 21H ; @D0A
647
648 RET ;
649STILLOK: ; D0A
650 PUSH 0DEADH ; Push stack delimiter
651 ; Don't have to set character ID @D2D
652 CALL GET_PARMS ; Get the MOVEBLOCK buffer size if
653 jnc StillOK1
654 MOV RH.RH0_ENDO,0 ; Leave nothing resident @D0A
655 MOV AX,STAT_GEN ; Return general error code @D0A
656 OR AX,STAT_DONE ; Add "done" bit to status word@D0A @P3C
657 MOV RH.RHC_STA,AX ; Store status into request header @D0A
658 ; D0A
659 pop ax
660 ret ; exit program
661
662StillOK1:
663 ; one was specified
664 CLI ; Disable interrupts
665
666 PUSH CS ; Now we can point DS to our own @P3A
667 POP DS ; code segment @P3A
668 ; 2@D2D
669 MOV AX,CS
670 MOV REAL_CS,AX ; Save real CS for when we @P3C
671 MOV AX,SS ; switch to protect mode
672 MOV REAL_SS,AX ; Save real SS @P3C
673 MOV AX,SP
674 MOV REAL_SP,AX ; Save real SP @P3C
675
676;------------------------------------------------------------------------------;
677; Enable address line A20 ;
678;------------------------------------------------------------------------------;
679
680 ; 3@P4D
681 CALL GATE_A20
682
683 INT 11H ; Get the BIOS equipment flags
684 AND AL,30H ; Bits 5 and 6 on means it's a mono
685 CMP AL,30H
686 JE LEAVEBW
687 MOV CRT_SELECTOR,C_CCRT_PTR ; Set the CRT selector to color display
688LEAVEBW:
689 MOV AH,88H ; Get number of 1k blocks above 1M
690 INT 15H
691 ADD AX,1024 ; Add 640K for the memory below 640K @P7C
692 MOV MAXMEM,AX ; Save for later
693
694; Get the maximum XMA block number and save it in the header up front D0A
695; All memory is treated as XMA memory. D1C
696 ; D0A
697 SUB AX,BUFF_SIZE ; Can't use the MOVEBLOCK buffer for @D0A
698 ; XMA memory. AX = number of K D0A
699 ; available. D0A
700 SUB AX,(1024-640) +128 ; Subtract 128k for the Emulator code ;an000; dms;
701 SHR AX,2 ; Divide by four to get the number of @D0A
702 ; 4K blocks D0A
703 DEC AX ; Subtract 1. This converts the @P3A
704 ; number of blocks available to the P3A
705 ; highest block number available. P3A
706 ; Block numbers are zero based. P3A
707 MOV HI_XMA_BLK,AX ; Save it in the header D0A
708
709;------------------------------------------------------------------------------;
710; Now lets relocate ourselves to high memory. ;
711;------------------------------------------------------------------------------;
712
713 MOV AX,HIGH_SEG ; Set ES to the highest segment value
714 MOV ES,AX
715 MOV DI,0 ; ES:DI points to the place to relocate to
716 MOV AX,CS
717 MOV DS,AX
718 MOV SI,0 ; DS:SI points to our code to be moved
719 MOV CX,DDSIZE/2 ; Length of code / 2 since moving words
720 CLD
721 REP MOVSW ; Copy myself to high memory
722
723 JUMPFAR NEXT,HIGH_SEG ; Jump to my relocated code
724NEXT:
725
726 MOV AX,HIGH_SEG ; Set DS to be the same as CS
727 MOV DS,AX
728;------------------------------------------------------------------------------;
729; The machine is still in real mode. Zero out GDT and IDT ram. ;
730;------------------------------------------------------------------------------;
731
732 MOV DI,GDT_LOC ; DI points to GDT location
733
734 MOV CX,(GDT_LEN+SIDT_LEN)/2 ; Set GDT and IDT to zero
735 MOV AX,0 ; Store zeroes for now
736 REP STOSW
737
738;------------------------------------------------------------------------------;
739; Use good-old real-mode selectors to set up the page tables. The ;
740; page directory is a 4K block that is placed just before the ;
741; beginning of the GDT and on a 4K boundary. Note that the DATAOV ;
742; macro creates a prefix for the following instruction so that its ;
743; data references are 32 bits wide. ;
744;------------------------------------------------------------------------------;
745
746 DATAOV
747 SUB AX,AX ; Clear EAX (32 bit AX reg.)
748 MOV AX,HIGH_SEG ; Get the current code segment
749 DATAOV
750 SUB BX,BX ; Clear EBX (32 bit BX reg.)
751 MOV BX,GDT_LOC/16 ; Load the offset of the GDT, converted
752 ; to paragraphs
753 DATAOV ; Add it on to the current code segment
754 ADD AX,BX ; to get the segment address of the GDT.
755 ; This will be over 1M, so use 32 bits.
756 AND AX,0FF00H ; Round down to nice 4k boundary
757 DATAOV
758 SUB BX,BX ; Clear EBX
759 MOV BX,4096/16 ; Load with the size of the page directory
760 ; converted to paragraphs
761 DATAOV ; Subtract the number of paragraphs needed
762 SUB AX,BX ; for the page directory
763 DATAOV
764 SHL AX,4 ; Convert from paragraphs to bytes
765 CMOV CR3,EAX ; Load the address of the page directory
766 ; into CR3
767 DATAOV
768 SUB BX,BX ; Clear EBX
769 MOV BX,HIGH_SEG ; Load our current code segment
770 DATAOV
771 SHL BX,4 ; Convert from paragraphs to bytes
772 DATAOV
773 SUB AX,BX ; Subtract from the address of the page
774 ; directory to get the offset of the
775 ; directory in our code segment
776 MOV SGTBLOFF,AX ; Save for later
777
778; Now let's clear the page directory
779
780 MOV CX,2048 ; Length is 4K/2 since storing words
781 DATAOV
782 MOV DI,AX ; ES:EDI points to beginning of directory
783 MOV AX,0
784 REP STOSW ; Clear the page directory!
785
786;------------------------------------------------------------------------------;
787; Initialize the first directory entries to our page tables ;
788;------------------------------------------------------------------------------;
789
790 CMOV EAX,CR3 ; Get back CR3 - the address of the page dir.
791 DATAOV
792 MOV DI,SGTBLOFF ; Point ES:EDI to first entry in directory
793 DATAOV
794 SUB BX,BX ; Clear EBX
795 MOV BX,MEG_SUPPORTED/4*4096 ; Load the size of the page tables.
796 ; Each page table maps 4M of memory, so divide
797 ; the number of Meg supported by 4 to get the
798 ; number of page tables. Each page table is
799 ; 4K in size, so multiply by 4K.
800 DATAOV
801 SUB AX,BX ; Subtract the size needed for the page tables
802 ; from the address of the page directory to
803 ; get the address of the first page table.
804 ADD AX,7 ; Set the present bit and access rights.
805 ; This converts the address to a valid entry
806 ; for the page directory.
807 DATAOV
808 MOV NORMPAGE,AX ; Save for later
809 MOV CX,MEG_SUPPORTED/4 ; Load the number of page tables into CX
810 DATAOV
811 SUB BX,BX ; Clear EBX
812 MOV BX,1000H ; Set up 4k increment
813;
814; Now we load the page directory. EAX contains the address of the first
815; page table, EBX contains 4K, CX contains the number of page tables, and
816; ES:EDI (32 bit DI reg.) points to the first page directory entry. Now what
817; we do is stuff EAX into the 32bits pointed to by EDI. EDI is then auto-
818; incremented by four bytes, because of the 32 bit stuff, and points to the
819; next page directory entry. (Page directory and page table entries are four
820; bytes long.) Then we add the 4K in EBX to the address in EAX making EAX
821; the address of the next page table. This is done for the number of page
822; table entries in CX. Pretty slick, huh?
823;
824LPT:
825 DATAOV ; Stuff the page table address into the
826 STOSW ; page directory
827 DATAOV ; Add 4K to the page table address in EAX
828 ADD AX,BX ; so that it contains the address of the
829 ; next page table
830 LOOP LPT ; Do it again
831
832; Now calcuate the offset from our code segment of the page tables
833
834 DATAOV
835 SUB BX,BX ; Clear EBX
836 MOV BX,HIGH_SEG ; Load our current code segment
837 DATAOV
838 SHL BX,4 ; Convert paragraphs to bytes
839 DATAOV ; Load EAX with the address of the first
840 MOV AX,NORMPAGE ; page table
841 DATAOV
842 SUB AX,BX ; Convert EAX to an offset
843 AND AL,0F8H ; AND off the access rights
844 MOV PGTBLOFF,AX ; Save for later
845
846;------------------------------------------------------------------------------;
847; Initialize the page tables ;
848;------------------------------------------------------------------------------;
849
850 MOV DI,PGTBLOFF ; ES:DI points to the first page table
851 DATAOV
852 SUB AX,AX ; Zero EAX
853 ADD AX,7 ; Set the present and access rights
854 MOV CX,MEG_SUPPORTED/4*1024 ; Load CX with the number of page table
855 ; entries to initialize. As mentioned
856 ; above, the number of page tables =
857 ; number of Meg / 4. There are 1K
858 ; entries per table so multiply by 1K
859 DATAOV
860 SUB BX,BX ; Clear EBX
861 MOV BX,1000H ; Set up 4k increment
862;
863; As with the page directory, we use a tight loop to initialize the page tables.
864; EAX contains the address of the first page frame, which is 0000, plus the
865; access rights. EBX contains a 4K increment. ES:DI points to the first entry
866; in the first page table. CX contains the number of page table entries to
867; initialize. The stuff and increment works the same as for the page directory
868; with an added touch. Note that this does all the page tables in one fell
869; swoop. When we finish stuffing the last address into the first page table
870; the next place we stuff is into the first entry in the second page table.
871; Since our page tables are back to back we can just zoom up the page tables
872; incrementing by 4K as we go and thus initialize all the page tables in one
873; fell swoop.
874;
875BPT:
876 DATAOV ; Stuff the page frame address into the
877 STOSW ; page table
878 DATAOV
879 ADD AX,BX ; Next 4k page frame
880 LOOP BPT
881
882;------------------------------------------------------------------------------;
883; Now set up the first 64K over 1M to point to point to the first 64K ;
884; in low memory to simulate the segment wrap over 1M. ;
885; For now will set it up to point to itself and try to get DOS to load ;
886; the device driver up there. Will find out if anyone tries to alter ;
887; it because it will be marked for system use only. ;
888;------------------------------------------------------------------------------;
889
890 MOV DI,1024 ; 1M offset into page table
891 ADD DI,PGTBLOFF ; Page table offset
892 MOV AX,10H ; Set EAX to contain 1M address by loading
893 DATAOV ; it with 10H and shifting it 16 bits to
894 SHL AX,16 ; get 00100000. (Same as 10000:0)
895 ADD AX,5 ; Present, system use, read only
896 MOV CX,16 ; 16 entries = 64k
897BPT2:
898 DATAOV
899 STOSW ; Stuff the address in the page table
900 DATAOV
901 ADD AX,BX ; Next 4k page frame
902 LOOP BPT2
903
904PAGE
905;------------------------------------------------------------------------------;
906; Build the Global Descriptor Table and load the GDT register. ;
907;------------------------------------------------------------------------------;
908 CALL GDT_BLD
909
910 MOV DI,GDT_PTR ; Get the offset of the GDT descriptor
911 ADD DI,GDT_LOC ; located in the GDT
912 MOV BP,DI ; Transfer the offset to BP
913 LGDT ES:FWORD PTR[BP] ; Put the descriptor for the GDT into
914 ; the GDT register
915
916PAGE
917;------------------------------------------------------------------------------;
918; Build and initialize the system Interrupt Descriptor Table, ;
919; then load the IDT register. ;
920;------------------------------------------------------------------------------;
921 CALL SIDT_BLD
922
923 MOV DI,MON_IDT_PTR ; Get the offset of the IDT descriptor
924 ADD DI,GDT_LOC ; located in the GDT
925 MOV BP,DI ; Transfer the offset to BP
926
927 LIDT ES:FWORD PTR[BP] ; Put the descriptor for the IDT into
928 ; the IDT register
929
930PAGE
931;------------------------------------------------------------------------------;
932; At this point we prepare to switch to virtual mode. The first ;
933; instruction after the LMSW that causes the switch must be a ;
934; jump far to set a protected mode segment selector into CS. ;
935;------------------------------------------------------------------------------;
936
937 MOV AX,VIRTUAL_ENABLE ; Machine status word needed to
938 LMSW AX ; switch to virtual mode
939
940 JUMPFAR DONE,SYS_PATCH_CS ; Must purge pre-fetch queue
941 ; and set selector into CS
942DONE:
943PAGE
944;------------------------------------------------------------------------------;
945; Initialize all the segment registers ;
946;------------------------------------------------------------------------------;
947
948 MOV AX,SYS_PATCH_DS ; Load DS, ES, and SS with the selector
949 MOV DS,AX ; for our data area. This is the same
950 MOV ES,AX ; as our code area but has read/write
951 ; access.
952 MOV SS,AX
953 MOV SP,OFFSET SP_INIT
954
955 PUSH 0002H ; Clean up our flags. Turn off all bits
956 POPF ; except the one that is always on.
957
958;------------------------------------------------------------------------------;
959; Load the LDTR to avoid faults ;
960;------------------------------------------------------------------------------;
961
962 MOV AX,SCRUBBER.TSS_PTR ; Load DS with the data descriptor for
963 MOV DS,AX ; the virtual machine's TSS
964 MOV AX,SCRUBBER.VM_LDTR ; Get the LDTR for virtual machine
965 MOV DS:VM_LDT,AX ; Set LDTR in TSS
966 LLDT AX ; Set the LDTR. Temporary for now.
967
968; Have to always have space allocated for the dispatch task TSS
969
970 MOV AX,SCRUBBER.VM_TR ; Low mem gets clobbered without this @P5C
971 LTR AX ; Set current Task Register
972 ; This TSS is located right after the IDT
973
974PAGE
975;------------------------------------------------------------------------------;
976; Now we initialize the TSS (Task State Segment) for the one and only ;
977; virtual 8086 task. This task encompasses everything that runs in real ;
978; mode. First we clear the TSS and its I/O bit map. Then we initialize ;
979; the bit map for all the I/O ports we want to trap. Then we set up the ;
980; registers for the V86 task. These registers are given the same values ;
981; as we got on entry. IP is set to point to TEST_EXIT. ;
982;------------------------------------------------------------------------------;
983
984 MOV AX,SCRUBBER.TSS_PTR ; Load ES and DS with the descriptor
985 MOV DS,AX ; for the VM's TSS with read/write
986 MOV ES,AX ; access rights
987 CLD
988 MOV DI,0 ; Point ES:DI to the beginning of the TSS
989 MOV AX,0 ; Clear AX
990 MOV BX,0 ; Clear BX
991 MOV CX,TSS_386_LEN ; Load CX with the length of the TSS
992 REP STOSB ; Clear the TSS
993 MOV CX,TSS_BM_LEN ; Load CX with the length of the I/O bit
994 ; map. The bit map immediately follows
995 ; the TSS and is in the TSS segment.
996 REP STOSB ; Clear the bit map
997 MOV AL,0FFH ; Intel requires this byte
998 STOSB
999
1000;
1001; Now set up the bit map. Turn on bits for I/O ports that we want to trap.
1002;
1003
1004 MOV DI,0+TSS_386_LEN ; Set bits 0,2,4,6 to 1 - DMA ports
1005 MOV AL,055H
1006 STOSB
1007 MOV DI,1+TSS_386_LEN ; Set C to 1 - DMA port
1008 MOV AL,010H
1009 STOSB
1010 MOV DI,3+TSS_386_LEN ; Set 18,1A to 1 - DMA ports
1011 MOV AL,005H
1012 STOSB
1013 MOV DI,16+TSS_386_LEN ; Set 80-8f to 1s - DMA page ports
1014 MOV AL,0FFH ; + manufacturing port for ctl-alt-del
1015 STOSB
1016 STOSB
1017 MOV DI,0680H/8+TSS_386_LEN ; Set Roundup manuf. port to 1
1018 MOV AL,001H
1019 STOSB
1020 MOV DI,31A0H/8+TSS_386_LEN ; Set 31a0-31a7 to 1s (XMA)
1021 MOV AL,0FFH
1022 STOSB
1023
1024 MOV WORD PTR [BX].ETSS_BM_OFFSET,TSS_386_LEN
1025 ; Put the bit map offset in the TSS
1026 MOV WORD PTR [BX].ETSS_SP0,OFFSET SP_INIT
1027 ; Put our SP as the SP for privilege
1028 ; level 0
1029 MOV WORD PTR [BX].ETSS_SS0,SYS_PATCH_DS
1030 ; Put our SS as the SS for privilege
1031 ; level 0
1032
1033; Next we set up the segment registers
1034
1035 MOV WORD PTR [BX].ETSS_GS,SEG PROG ; GS - our code segment
1036 MOV WORD PTR [BX].ETSS_FS,SEG PROG ; FS - our code segment
1037 MOV WORD PTR [BX].ETSS_DS,SEG PROG ; DS - our code segment
1038 MOV WORD PTR [BX].ETSS_ES,SEG PROG ; ES - our code segment
1039
1040; Next the SS,SP
1041
1042 MOV AX,CS:REAL_SS ; Set the real mode SS as the SS for the task
1043 MOV WORD PTR [BX].ETSS_SS,AX
1044 MOV AX,CS:REAL_SP ; Set the real mode SP as the SP for the task
1045 MOV WORD PTR [BX].ETSS_SP,AX
1046
1047; The flags register
1048
1049 MOV WORD PTR [BX].ETSS_FL2,2 ; Set the VM flag. Task is a V86 task.
1050 MOV WORD PTR [BX].ETSS_FL,0202H ; Set interrupts enabled
1051
1052; Set up CS and IP
1053
1054 MOV AX,CS:REAL_CS ; Set the real mode CS as the CS for the task
1055 MOV WORD PTR [BX].ETSS_CS,AX ; This is the CS we got when we loaded
1056 ; in low memory, before relocating
1057 MOV AX,OFFSET PROG:TEST_EXIT ; Set IP to the label TEST_EXIT below.
1058 MOV WORD PTR [BX].ETSS_IP,AX
1059
1060; The LDTR
1061
1062 MOV WORD PTR [BX].ETSS_LDT,SCRUBBER.VM_LDTR
1063
1064; And finally, CR3, the page directory base register
1065
1066 CMOV EAX,CR3 ; Get CR3
1067 DATAOV
1068 MOV WORD PTR [BX].ETSS_CR3,AX ; Save it in the TSS
1069
1070PAGE
1071;------------------------------------------------------------------------------;
1072; Now initialize our wonderful XMA page tables. Each table maps 4M. ;
1073; There is one table for each XMA bank since 4M is enough to map the ;
1074; 1M address space. All the XMA tables are initialized to point to ;
1075; the real memory at 0 to 4M. This is done by just copying the page ;
1076; table entry for 0 to 4M that was initialized above. ;
1077;------------------------------------------------------------------------------;
1078
1079 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our data
1080 MOV DS,AX
1081 MOV SI,PGTBLOFF ; DS:SI point to the real page table for 0-4M
1082 MOV AX,XMA_PAGES_SEL ; Load ES with the selector for the XMA pages
1083 MOV ES,AX
1084 SUB DI,DI ; ES:DI point to the first XMA page table
1085 MOV CX,2048 ; Copy 4K / 2 since we're copying words
1086 REP MOVSW ; Copy the first XMA page table
1087;
1088; Now ES:DI points to the second XMA page table. Set DS:SI to point to the
1089; first XMA page table as the source for the copy. Now we can put a count
1090; of 15 page tables in CX. After each page is copied it is used as the source
1091; for the next page. This method lets us zip up the page tables initializing
1092; them all to be the same as the original page table for 0 - 4M.
1093;
1094 MOV AX,XMA_PAGES_SEL ; Load DS with the selector for the XMA page
1095 MOV DS,AX ; tables
1096 SUB SI,SI ; DS:SI points to the first XMA page table
1097 MOV CX,2048*15 ; Copy 15 more page tables
1098 REP MOVSW ; Copy to the other 15 XMA ID'S page tables
1099
1100; D1A
1101; Set the first page directory entry to point to the page table for bank 0. D1A
1102; This is another way of saying, "Let's make bank 0 the active bank." We D1A
1103; are now emulating the XMA 2 card along with its initialization device D1A
1104; driver, INDXMAA.SYS. When the device driver exits, it leaves the XMA 2 D1A
1105; card enabled and set to bank 0. Therefore, we must do the same. D1A
1106; D1A
1107 ; D1A
1108 MOV AX,SYS_PATCH_DS ; Load DS and ES with our data segment @D1A
1109 MOV DS,AX ; selector @D1A
1110 MOV ES,AX ; @D1A
1111 MOV DI,SGTBLOFF ; Point ES:DI to the first page @D1A
1112 ; directory entry D1A
1113 DATAOV ; Load AX with the page directory entry @D1A
1114 MOV AX,XMAPAGE ; for the first XMA page table @D1A
1115 DATAOV ; Stuff the address of the page table @D1A
1116 STOSW ; for bank 0 into the page directory @D1A
1117
1118PAGE
1119;------------------------------------------------------------------------------;
1120; And now, the moment you've all been waiting for -- TURN ON THE PAGING ;
1121; MECHANISM!!! ;
1122;------------------------------------------------------------------------------;
1123
1124 CMOV EAX,CR0 ; Get CR0 @P5A
1125 MOV BX,8000H ; Set up BX to OR on the Paging Enable bit @P5C
1126 DATAOV
1127 SHL BX,16 ; It's the one all the way on the left @P5C
1128 DATAOV ; @P5A
1129 OR AX,BX ; Set the paging enabled bit @P5A
1130 OR AL,02H ; Set co-processor bit on @P5A
1131 AND AL,0F7H ; Turn off Task Switch bit @P5C
1132 CMOV CR0,EAX ; Here we go...
1133
1134; Make sure high order bits of ESP are zero - a1 errata
1135
1136 MOV AX,SP ; Save SP in AX 'cause it changes when we do...
1137 PUSH 0 ; this PUSH. Push 0 for high 16 bits of ESP
1138 PUSH AX ; Push low 16 bits of SP
1139 DATAOV
1140 POP SP ; Pop 32 bit ESP!
1141
1142PAGE
1143;------------------------------------------------------------------------------;
1144; Now we give control back to the V86 task by setting up the stack P5C;
1145; for an IRET back to the V86 task. This requires putting the V86 P5C;
1146; task's segment registers, SS and ESP, and the EFLAGS, CS and IP on P5C;
1147; the stack. The 80386 puts all these values on the stack when it P5C;
1148; interrupts out of V86 mode, so it expects them there on an IRET P5C;
1149; back to V86 mode. But really we are giving control back to ;
1150; ourself. The CS:IP on the stack point to the label TEST_EXIT ;
1151; below, but it is in the copy of the emulator that was originally ;
1152; loaded, not the copy that was relocated to high memory and is now ;
1153; running in protect mode. This clever trick will result in the ;
1154; original copy of the emulator returning to DOS which will continue ;
1155; to load the rest of the system. The system will come up completely ;
1156; unaware that it is running in a small universe of a V86 task which ;
1157; is being monitored by the XMA emulator. ;
1158;------------------------------------------------------------------------------;
1159
1160
1161 MOV AX,SCRUBBER.TSS_PTR ; Load DS with the descriptor for the @P5A
1162 MOV DS,AX ; VM's TSS with read/write access @P5A
1163 MOV BX,0 ; VM's TSS with read/write access @P5A
1164; P5A
1165; Set up our stack for an IRET to the V86 task. This is an inter-level P5A
1166; IRET to a V86 task so we need the V86 task's SS, ESP, ES, DS, FS and GS P5A
1167; as well as his EFLAGS, EIP and CS. P5A
1168; P5A
1169 DATAOV ; @P5A
1170 PUSH WORD PTR [BX].ETSS_GS ; Put V86 task's GS on the stack @P5A
1171 DATAOV ; @P5A
1172 PUSH WORD PTR [BX].ETSS_FS ; Put V86 task's FS on the stack @P5A
1173 DATAOV ; @P5A
1174 PUSH WORD PTR [BX].ETSS_DS ; Put V86 task's DS on the stack @P5A
1175 DATAOV ; @P5A
1176 PUSH WORD PTR [BX].ETSS_ES ; Put V86 task's ES on the stack @P5A
1177 DATAOV ; @P5A
1178 PUSH WORD PTR [BX].ETSS_SS ; Put V86 task's SS on the stack @P5A
1179 DATAOV ; @P5A
1180 PUSH WORD PTR [BX].ETSS_SP ; Put V86 task's ESP on the stack @P5A
1181 DATAOV ; @P5A
1182 PUSH WORD PTR [BX].ETSS_FL ; Put V86 task's EFLAGS on the stack @P5A
1183 DATAOV ; @P5A
1184 PUSH WORD PTR [BX].ETSS_CS ; Put V86 task's CS on the stack @P5A
1185 DATAOV ; @P5A
1186 PUSH WORD PTR [BX].ETSS_IP ; Put V86 task's EIP on the stack @P5A
1187 DATAOV ; @P5A
1188 IRET ; @P5A
1189 ; @P5D
1190
1191TEST_EXIT: ; We are now running in V86 mode
1192 POP AX ; Pop the stack until our DEAD delimiter is
1193 CMP AX,0DEADH ; found
1194 JNE TEST_EXIT
1195
1196; Replace the interrupt 15 vector with our handler (INT15F88). P7A
1197
1198 MOV AH,GET_VECT ; Get the current vector at interrupt 15H @P7A
1199 MOV AL,15H ; @P7A
1200 INT 21H ; @P7A
1201
1202 MOV CS:CHAINSEG,ES ; Save it in the chaining header in @P7A
1203 MOV CS:CHAINOFF,BX ; INT15F88 @P7A
1204
1205 MOV AH,SET_VECT ; Set the entry point of INT15F88 as the @P7A
1206 MOV AL,15H ; new interrupt 15 vector @P7A
1207 PUSH CS ; @P7A
1208 POP DS ; @P7A
1209 MOV DX,OFFSET INT15F88 ; @P7A
1210 INT 21H ; @P7A
1211
1212; Copy the number of K for extended memory from BUFF_SIZE to EXT_MEM. This P7A
1213; is needed because BUFF_SIZE does not stay resident, EXT_MEM does. P7A
1214
1215 MOV AX,BUFF_SIZE ; @P7A
1216 MOV EXT_MEM,AX ; @P7A
1217
1218; Issue the message that says we installed successfully
1219
1220 MOV AH,DISPSTRG ; Set AH to DOS display string function @D0A
1221 MOV DX,OFFSET GOODLOAD ; @D0A
1222 PUSH CS ; @D0A
1223 POP DS ; DS:DX points to the message @D0A
1224 INT 21H ; Display the message @D0A
1225
1226 RET ; Return to IRPT which called INIT_P1
1227
1228SUBTTL Gate A20
1229PAGE
1230;------------------------------------------------------------------------------;
1231; GATE_A20 ;
1232; This routine controls a signal which gates address bit 20. ;
1233; Bit 2 of port 92H controls the enabling of A20. If bit 2 is on, P4C;
1234; then A20 is enabled. Conversely, if bit 2 is off, A20 is disabled. P4C;
1235; ;
1236;------------------------------------------------------------------------------;
1237
1238; Equates for the Gate A20 enable
1239
1240ENABLE_A20 EQU 02H ; Bit 2 of port 92H turns on A20 @P4C
1241
1242GATE_A20 PROC
1243
1244 IN AL,92H ; Get the current value of port 92 @P4A
1245 OR AL,ENABLE_A20 ; Turn on the bit to enable A20 @P4A
1246 OUT 92H,AL ; Send it back out to port 92 @P4A
1247 RET
1248 ; 15@P4D
1249GATE_A20 ENDP
1250
1251SUBTTL GET_PARMS parameter line scan
1252PAGE
1253;------------------------------------------------------------------------------;
1254; GET_PARMS ;
1255; This procedure converts the numeric parameter following the DEVICE statement ;
1256; in the CONFIG.SYS file to a binary number and saves it in BUFF_SIZE. The ;
1257; number is rounded up to the nearest 16K boundary. ;
1258; ;
1259; Register usage: ;
1260; DS:SI indexes parameter string ;
1261; AL contains character from parameter string ;
1262; CX value from GET_NUMBER ;
1263; ;
1264;------------------------------------------------------------------------------;
1265
1266 ASSUME DS:NOTHING ; DS:BX point to Request Header
1267
1268GET_PARMS PROC
1269
1270 PUSH DS ; Save DS
1271 push bx ; save bx ;an000; dms;
1272
1273 LDS SI,RH.RH0_BPBA ; DS:SI point to all text after "DEVICE="
1274 ; in CONFIG.SYS
1275 XOR AL,AL ; Start with a null character in AL.
1276
1277;------------------------------------------------------------------------------;
1278; Skip until first delimiter is found. There may be digits in the path string.;
1279; ;
1280; DS:SI points to \pathstring\386XMAEM.SYS nn nn nn ;
1281; The character following 386XMAEM.SYS may have been changed to a null (00H). ;
1282; All letters have been changed to uppercase. ;
1283;------------------------------------------------------------------------------;
1284
1285GET_PARMS_A:
1286 CALL GET_PCHAR ; Get a character from the parameter string
1287 JZ Get_Parms_Null ; The zero flag is set if the end of the line
1288 ; is found. If so, then exit.
1289
1290; Check for various delimeters
1291
1292 OR AL,AL ; Null
1293 JZ GET_PARMS_B
1294 CMP AL,' ' ; Blank
1295 JE GET_PARMS_B
1296 CMP AL,',' ; Comma
1297 JE GET_PARMS_B
1298 CMP AL,';' ; Semi-colon
1299 JE GET_PARMS_B
1300 CMP AL,'+' ; Plus sign
1301 JE GET_PARMS_B
1302 CMP AL,'=' ; Equals
1303 JE GET_PARMS_B
1304 CMP AL,TAB ; Tab
1305 JNE GET_PARMS_A ; Skip until delimiter or CR is found
1306
1307GET_PARMS_B: ; Now pointing to first delimiter
1308 CALL SKIP_TO_DIGIT ; Skip to first digit
1309 JZ Get_Parms_C ; Found EOL, no digits remain
1310
1311 CALL GET_NUMBER ; Extract the digits and convert to binary
1312 jmp Get_Parms_Found ; Parm found
1313
1314Get_Parms_Null:
1315
1316 xor cx,cx ; set cx to 0 ;an000; dms;
1317
1318Get_Parms_Found:
1319
1320 mov bx,cx ; put cx value in bx ;an000; dms;
1321
1322 cmp cx,0 ; 0 pages requested? ;an000; dms;
1323 jne Get_Parm_Max ; allocate maximum number ;an000; dms;
1324 MOV CS:BUFF_SIZE,0; Store buffer size
1325 jmp Get_Parms_C
1326
1327Get_Parm_Max:
1328
1329 cmp bx,64 ; >= 64 pages requested? ;an000; dms;
1330 jnb Get_Parms_64_Pg ; yes - continue ;an000; dms;
1331 mov dx,offset Small_Parm ; Parm < 64 and > 0 ;an000; dms;
1332 mov ah,Dispstrg ; Display the welcome message. ;an000; dms;
1333 push ds ; Save DS ;an000; dms;
1334 push cs ; ;an000; dms;
1335 pop ds ; DS:DX points to the message ;an000; dms;
1336 int 21h ; Display the message ;an000; dms;
1337 pop ds ; Restore DS ;an000; dms;
1338 stc ; flag an error occurred ;an000; dms;
1339 jmp Get_Parms_C ; exit routine ;an000; dms;
1340
1341Get_Parms_64_Pg:
1342
1343 mov ax,bx ; prepare to adjust to Kb value ;an000; dms;
1344 mov cx,10h ; 16Kb per page ;an000; dms;
1345 xor dx,dx ; clear high word ;an000; dms;
1346 mul cx ; get Kb value ;an000; dms;
1347
1348 mov bx,ax ; store page Kb value in bx ;an000; dms;
1349 add bx,128 ; adjust for emulator code
1350
1351 mov ah,88h ; get number of 1k blocks above 1Mb ;an000; dms;
1352 int 15h ;
1353
1354 sub ax,bx ; get number of blocks to allocate for extended ;an000; dms;
1355 jnc Get_Parms_Ext ; set extended memory value in buff size ;an000; dms;
1356 mov dx,offset No_Mem ; not enough memory for parm
1357 mov ah,Dispstrg ; Display the welcome message. ;an000; dms;
1358 push ds ; Save DS ;an000; dms;
1359 push cs ; ;an000; dms;
1360 pop ds ; DS:DX points to the message ;an000; dms;
1361 int 21h ; Display the message ;an000; dms;
1362 pop ds ; Restore DS ;an000; dms;
1363 stc ; flag an error ;an000; dms;
1364 jmp Get_Parms_C ; exit routine ;an000; dms;
1365
1366Get_Parms_Ext:
1367
1368 MOV CS:BUFF_SIZE,ax ; Store buffer size
1369 clc
1370
1371GET_PARMS_C:
1372 pop bx ; restore bx ;an000; dms;
1373 POP DS ; Restore DS
1374
1375 RET
1376
1377;------------------------------------------------------------------------------;
1378; GET_PCHAR -- Get a character from the parameter string into AL ;
1379;------------------------------------------------------------------------------;
1380
1381GET_PCHAR PROC
1382 CMP AL,CR ; Carriage return already encountered?
1383 JE GET_PCHAR_X ; Don't read past end of line
1384 LODSB ; Get character from DS:SI, increment SI
1385 CMP AL,CR ; Is the character a carriage return?
1386 JE GET_PCHAR_X ; Yes, leave the zero flag set to signal end
1387 ; of line
1388 CMP AL,LF ; No, is it a line feed? This will leave the
1389 ; zero flag set if a line feed was found.
1390GET_PCHAR_X:
1391 RET
1392
1393GET_PCHAR ENDP
1394
1395;------------------------------------------------------------------------------;
1396; CHECK_NUM -- Check if the character in AL is a numeric digit, ASCII for ;
1397; 0 - 9. The zero flag is set if the character is a digit, ;
1398; otherwise it is reset. ;
1399;------------------------------------------------------------------------------;
1400
1401CHECK_NUM PROC
1402 CMP AL,'0' ; If character is less than a "0" then it is not
1403 JB CHECK_NUM_X ; a number, so exit
1404
1405 CMP AL,'9' ; If character is greater than a "9" then it is
1406 JA CHECK_NUM_X ; not a number, so exit
1407
1408 CMP AL,AL ; Set the zero flag to show it is a number
1409CHECK_NUM_X:
1410 RET ; Zero flag is left reset if character is not
1411CHECK_NUM ENDP ; a number
1412
1413;------------------------------------------------------------------------------;
1414; SKIP_TO_DIGIT -- Scan the parameter string until a numeric character is ;
1415; found or the end of the line is encountered. If a numeric ;
1416; character is not found then the zero flag is set. Else if ;
1417; a character was found then the zero flag is reset. ;
1418;------------------------------------------------------------------------------;
1419
1420SKIP_TO_DIGIT PROC
1421 CALL CHECK_NUM ; Is the current character a digit?
1422 JZ SKIP_TO_DIGIT_X ; If zero flag is set then it is a number
1423
1424 CALL GET_PCHAR ; Get the next character from the line
1425 JNZ SKIP_TO_DIGIT ; Loop until first digit or CR or LF is found
1426 RET ; Fall through to here if digit not found
1427
1428SKIP_TO_DIGIT_X:
1429 CMP AL,0 ; Digit found, reset the zero flag to show digit
1430 RET ; was found
1431SKIP_TO_DIGIT ENDP
1432
1433;------------------------------------------------------------------------------;
1434; GET_NUMBER -- Convert the character digits in the parameter string to a ;
1435; binary value. The value is returned in CX, unless the ;
1436; calculation overflows, in which case return a 0. The next ;
1437; character after the digits is left in AL. ;
1438;------------------------------------------------------------------------------;
1439
1440C10 DW 10
1441GN_ERR DB ? ; Zero if no overflow in accumulation
1442
1443GET_NUMBER PROC ; Convert string of digits to binary value
1444 XOR CX,CX ; Clear CX, the resulting number
1445 MOV CS:GN_ERR,CL ; No overflow yet
1446
1447GET_NUMBER_A:
1448 SUB AL,'0' ; Convert the ASCII character in AL to binary
1449 CBW ; Clear AH
1450 XCHG AX,CX ; Previous accumulation in AX, new digit in CL
1451 MUL CS:C10 ; DX:AX = AX*10
1452 OR CS:GN_ERR,DL ; Any overflow from AX goes into DX. Any non-
1453 ; zero value in DL will signal an error
1454 ADD AX,CX ; Add the new digit to ten times the previous
1455 ; digits
1456 XCHG AX,CX ; New number now in CX
1457 CALL GET_PCHAR ; Get the next character
1458 CALL CHECK_NUM ; Check if it is numeric
1459 JZ GET_NUMBER_A ; If so, then go back and add this digit to the
1460 ; result
1461 CMP CS:GN_ERR,0 ; Did we overflow?
1462 JE GET_NUMBER_B ; If not, we're done
1463 XOR CX,CX ; Return a zero result if overflow
1464GET_NUMBER_B:
1465 RET
1466GET_NUMBER ENDP
1467
1468GET_PARMS ENDP
1469
1470POST ENDP
1471
1472PROG ENDS
1473 END
1474
diff --git a/v4.0/src/DEV/XMAEM/INDEINS.MAC b/v4.0/src/DEV/XMAEM/INDEINS.MAC
new file mode 100644
index 0000000..c4b13e5
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEINS.MAC
@@ -0,0 +1,923 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEINS *
5* *
6* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
7* *
8* DESCRIPTIVE NAME: Instructions for the 80386 *
9* *
10* STATUS (LEVEL) : Version (0) Level (1.0) *
11* *
12* FUNCTION : These macros define instructions that are recognized by *
13* the 80386 but that are not recognized by MASM 3.0. We *
14* have to create these instructions ourselves because the *
15* Macro Assembler won't. *
16* *
17* MODULE TYPE : MAC *
18* *
19* REGISTER USAGE : 80286 Standard *
20* *
21* CHANGE ACTIVITY : *
22* *
23* $MAC(INDEINS) COMP(LOAD) PROD(3270PC) : *
24* *
25* $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 *
26* $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" *
27* *
28* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29#
30
31; Some information about creating instructions
32
33; MODIFIER BYTE VALUES
34
35; MOD REG/OPX R/M
36; --- ------- ---
37; 11 111 111
38
39; EAX AX AL 000 DISP0 00
40; ECX CX CL 001 DISPB 01
41; EDX DX DL 010 DISPW 10
42; EBX BX BL 011 DISPR 11
43; ESP SP AH 100
44; EBP BP CH 101
45; ESI SI DH 110
46; EDI DI BH 111
47
48; ES:0
49; CS:1
50; SS:2
51; DS:3
52; FS:4
53; GS:5
54
55
56; OPX FIELD VALUES
57
58; 00F-000 OPCODE VALUES 00F-001 OPCODE VALUES
59; --------------------- ---------------------
60
61; SLDT 000 SGDT 000
62; STR 001 SIDT 001
63; LLDT 010 LIDT 010
64; LTR 011 LGDT 011
65; VERR 100 SMSW 100
66; VERW 101 ? 101
67; ? 110 LMSW 110
68; ? 111 ? 111
69
70
71PAGE
72
73; Macros to move to and from the 80386 system registers and to and from the
74; new segment registers FS and GS.
75
76
77; CMOV - Move to and From Control Registers
78;
79; Examples:
80;
81; CMOV CRx,EREG
82; CMOV EREG,CRx
83;
84
85CMOV MACRO REG1,REG2
86
87 _CREGFD = 0
88 _CRCNT = 0
89 IRP TREG,<CR3,CR2,CR1,CR0>
90 IFIDN <&REG1>,<&TREG>
91 _CREGFD = 1
92 _CRCNT = 0
93 ELSE
94 _CRCNT = _CRCNT + 1
95 ENDIF
96 ENDM
97 IFE _CREGFD-1
98 F_DREG <&REG2>
99 IF _DREGNUM LT 8
100 DB 0FH
101 DB 22H
102 DB 0C0H + _CRCNT*8 + _DREGNUM
103 ELSE
104 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
105 ENDIF
106 ELSE
107 _CREGFD = 0
108 _CRCNT = 0
109 IRP TREG,<CR3,CR2,CR1,CR0>
110 IFIDN <&REG2>,<&TREG>
111 _CREGFD = 1
112 _CRCNT = 0
113 ELSE
114 _CRCNT = _CRCNT + 1
115 ENDIF
116 ENDM
117 IFE _CREGFD-1
118 F_DREG <&REG1>
119 IF _DREGNUM LT 8
120 DB 0FH
121 DB 20H
122 DB 0C0H + _CRCNT*8 + _DREGNUM
123 ELSE
124 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
125 ENDIF
126 ELSE
127 SYNTAX ERROR - CONTROL REGISTER EXPECTED
128 ENDIF
129 ENDIF
130 ENDM
131
132
133; DMOV - Move to and From Debug Registers
134;
135; Examples:
136;
137; DMOV DRx,EREG
138; DMOV EREG,DRx
139;
140
141DMOV MACRO REG1,REG2
142
143 _DREGFD = 0
144 _DRCNT = 0
145 IRP TREG,<DR7,DR6,DRX,DRX,DR3,DR2,DR1,DR0>
146 IFIDN <&REG1>,<&TREG>
147 _DREGFD = 1
148 _DRCNT = 0
149 ELSE
150 _DRCNT = _DRCNT + 1
151 ENDIF
152 ENDM
153 IFE _DREGFD-1
154 F_DREG <&REG2>
155 IF _DREGNUM LT 8
156 DB 0FH
157 DB 23H
158 DB 0C0H + _DRCNT*8 + _DREGNUM
159 ELSE
160 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
161 ENDIF
162 ELSE
163 _DREGFD = 0
164 _DRCNT = 0
165 IRP TREG,<DR7,DR6,DRX,DRX,DR3,DR2,DR1,DR0>
166 IFIDN <&REG2>,<&TREG>
167 _DREGFD = 1
168 _DRCNT = 0
169 ELSE
170 _DRCNT = _DRCNT + 1
171 ENDIF
172 ENDM
173 IFE _DREGFD-1
174 F_DREG <&REG1>
175 IF _DREGNUM LT 8
176 DB 0FH
177 DB 21H
178 DB 0C0H + _DRCNT*8 + _DREGNUM
179 ELSE
180 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
181 ENDIF
182 ELSE
183 SYNTAX ERROR - DEBUG REGISTER EXPECTED
184 ENDIF
185 ENDIF
186 ENDM
187
188; TMOV - Move to and From Test Registers
189;
190; Examples:
191;
192; TMOV TRx,EREG
193; TMOV EREG,TRx
194;
195
196TMOV MACRO REG1,REG2
197
198 _TREGFD = 0
199 _TRCNT = 0
200 IRP TREG,<TR7,TR6>
201 IFIDN <&REG1>,<&TREG>
202 _TREGFD = 1
203 _TRCNT = 0
204 ELSE
205 _TRCNT = _TRCNT + 1
206 ENDIF
207 ENDM
208 _TRCNT = _TRCNT + 6
209 IFE _TREGFD-1
210 F_DREG <&REG2>
211 IF _DREGNUM LT 8
212 DB 0FH
213 DB 26H
214 DB 0C0H + _TRCNT*8 + _DREGNUM
215 ELSE
216 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
217 ENDIF
218 ELSE
219 _TREGFD = 0
220 _TRCNT = 0
221 IRP TREG,<TR7,TR6>
222 IFIDN <&REG2>,<&TREG>
223 _TREGFD = 1
224 _TRCNT = 0
225 ELSE
226 _TRCNT = _TRCNT + 1
227 ENDIF
228 ENDM
229 _TRCNT = _TRCNT + 6
230 IFE _TREGFD-1
231 F_DREG <&REG1>
232 IF _DREGNUM LT 8
233 DB 0FH
234 DB 24H
235 DB 0C0H + _TRCNT*8 + _DREGNUM
236 ELSE
237 SYNTAX ERROR - EXTENDED REGISTER EXPECTED
238 ENDIF
239 ELSE
240 SYNTAX ERROR - TEST REGISTER EXPECTED
241 ENDIF
242 ENDIF
243 ENDM
244
245; SMOV - Move to/from FS/GS segment registers from/to general registers
246;
247; Examples:
248;
249; SMOV SReg, REG16
250; SMOV REG16, SReg
251;
252
253SMOV MACRO REG1,REG2
254 _SREGNUM = 8
255 _SREG1 = 1
256 IFIDN <&REG1>,<FS>
257 _SREGNUM = 4
258 ELSE
259 IFIDN <&REG1>,<FS>
260 _SREGNUM = 4
261 ENDIF
262 ENDIF
263 IF _SREGNUM GT 7
264 IFIDN <&REG1>,<GS>
265 _SREGNUM = 5
266 ELSE
267 IFIDN <&REG1>,<GS>
268 _SREGNUM = 5
269 ENDIF
270 ENDIF
271 ENDIF
272 IF _SREGNUM GT 7
273 _SREG1 = 0
274 IFIDN <&REG2>,<FS>
275 _SREGNUM = 4
276 ELSE
277 IFIDN <&REG2>,<FS>
278 _SREGNUM = 4
279 ENDIF
280 ENDIF
281 IF _SREGNUM GT 7
282 IFIDN <&REG2>,<GS>
283 _SREGNUM = 5
284 ELSE
285 IFIDN <&REG2>,<GS>
286 _SREGNUM = 5
287 ENDIF
288 ENDIF
289 ENDIF
290 ENDIF
291 IF _SREGNUM GT 7
292 SYNTAX ERROR - FS OR GS SEGMENT REGISTER EXPECTED
293 ELSE
294 IF _SREG1 EQ 1
295 DB 8EH
296 F_WREG <&REG2>
297 ELSE
298 DB 8CH
299 F_WREG <&REG1>
300 ENDIF
301 IF _WREGNUM GT 7
302 SYNTAX ERROR - WORD REGISTER EXPECTED
303 ELSE
304 DB 0C0H + _SREGNUM*8 + _WREGNUM
305 ENDIF
306 ENDIF
307 ENDM
308
309F_MOD MACRO TYPE,DISP1,DISP2
310 _DISP = 2
311;; 1 0
312 IRP _TEST_,<DISP32, DISP8>
313 IFIDN <&TYPE>,<&_TEST_>
314 _DISP = 0
315 ELSE
316 _DISP = _DISP + 1
317 ENDIF
318 ENDM
319 IFE (_DISP LT 2)
320;; 1 0
321 IRP _TEST_,<DISP32, DISP8>
322 IFIDN <&TYPE>,<&_TEST_>
323 _DISP = 0
324 ELSE
325 _DISP = _DISP + 1
326 ENDIF
327 ENDM
328 ENDIF
329 IF _DISP LT 2
330 IFB <&DISP1>
331 SYNTAX ERROR - IMMEDIATE OPERAND EXPECTED
332 ELSE
333 IFE _DISP-1
334 _MOD = 2
335 ELSE
336 _MOD = 1
337 ENDIF
338 ENDIF
339 ELSE
340 _MOD = 0
341 ENDIF
342 ENDM
343
344MK_DISP MACRO P3,P4
345 IFE _DISP
346 DB &P3
347 ELSE
348 DW &P3
349 IFNB <&P4>
350 IFDIF <&P4>,<IMMD>
351 DW &P4
352 ENDIF
353 ELSE
354 DW 0H
355 ENDIF
356 ENDIF
357 ENDM
358
359MK_IMMD MACRO P2,P3,P4,P5
360 _IMMDCNT = 3
361 IRP _PARM,<&P2,&P3,&P4,&P5>
362 IFE _IMMDCNT
363 IF _SIZE EQ 1
364 DB &_PARM
365 ELSE
366 DW &_PARM
367 ENDIF
368 ELSE
369 IFE _IMMDCNT-1
370 IF _SIZE EQ 4
371 IFNB <&_PARM>
372 DW &_PARM
373 ELSE
374 DW 0H
375 ENDIF
376 ENDIF
377 ENDIF
378 ENDIF
379 _IMMDCNT = _IMMDCNT + 1
380 IFIDN <&_PARM>,<IMMD>
381 _IMMDCNT = 0
382 ENDIF
383 ENDM
384 ENDM
385
386F_BREG MACRO TBREG
387 _BREGNUM = 0
388 IRP TREG,<BH,DH,CH,AH,BL,DL,CL,AL>
389 IFIDN <&TBREG>,<&TREG>
390 _BREGNUM = 0
391 ELSE
392 _BREGNUM = _BREGNUM + 1
393 ENDIF
394 ENDM
395 IFE (_BREGNUM LT 8)
396 IRP TREG,<BH,DH,CH,AH,BL,DL,CL,AL>
397 IFIDN <&TDREG>,<&TREG>
398 _BREGNUM = 0
399 ELSE
400 _BREGNUM = _BREGNUM + 1
401 ENDIF
402 ENDM
403 ENDIF
404 ENDM
405
406F_WREG MACRO TWREG
407 _WREGNUM = 0
408 IRP TREG,<DI,SI,BP,SP,BX,DX,CX,AX>
409 IFIDN <&TWREG>,<&TREG>
410 _WREGNUM = 0
411 ELSE
412 _WREGNUM = _WREGNUM + 1
413 ENDIF
414 ENDM
415 IFE (_WREGNUM LT 8)
416 IRP TREG,<DI,SI,BP,SP,BX,DX,CX,AX>
417 IFIDN <&TWREG>,<&TREG>
418 _WREGNUM = 0
419 ELSE
420 _WREGNUM = _WREGNUM + 1
421 ENDIF
422 ENDM
423 ENDIF
424 ENDM
425
426F_DREG MACRO TDREG
427 _DREGNUM = 0
428 IRP TREG,<EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX>
429 IFIDN <&TDREG>,<&TREG>
430 _DREGNUM = 0
431 ELSE
432 _DREGNUM = _DREGNUM + 1
433 ENDIF
434 ENDM
435 IFE (_DREGNUM LT 8)
436 IRP TREG,<EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX>
437 IFIDN <&TDREG>,<&TREG>
438 _DREGNUM = 0
439 ELSE
440 _DREGNUM = _DREGNUM + 1
441 ENDIF
442 ENDM
443 ENDIF
444 ENDM
445
446F_BASE MACRO TBASE
447 _BASE = 0
448;; 7 6 5 4 3 2 1 0
449 IRP TREG,<[EDI],[ESI],[EBP],[ESP],[EBX],[EDX],[ECX],[EAX]>
450 IFIDN <&TBASE>,<&TREG>
451 _BASE = 0
452 ELSE
453 _BASE = _BASE + 1
454 ENDIF
455 ENDM
456 IFE (_BASE LT 8)
457;; 7 6 5 4 3 2 1 0
458 IRP TREG,<[EDI],[ESI],[EBP],[ESP],[EBX],[EDX],[ECX],[EAX]>
459 IFIDN <&TBASE>,<&TREG>
460 _BASE = 0
461 ELSE
462 _BASE = _BASE + 1
463 ENDIF
464 ENDM
465 ENDIF
466 ENDM
467
468F_INDEX MACRO INDX
469 _INDEX = 0
470;; 7 6 5 4 3 2 1 0
471 IRP TREG,<[EDI,[ESI,[EBP,_XX_,[EBX,[EDX,[ECX,[EAX>
472 IFIDN <&INDX>,<&TREG>
473 _INDEX = 0
474 ELSE
475 _INDEX = _INDEX + 1
476 ENDIF
477 ENDM
478 IFE (_INDEX LT 8)
479;; 7 6 5 4 3 2 1 0
480 IRP TREG,<[EDI,[ESI,[EBP,_XX_,[EBX,[EDX,[ECX,[EAX>
481 IFIDN <&INDX>,<&TREG>
482 _INDEX = 0
483 ELSE
484 _INDEX = _INDEX + 1
485 ENDIF
486 ENDM
487 ENDIF
488 ENDM
489
490F_SCALE MACRO TSCALE
491 _SCALE = 0
492;; 3 2 1 0
493 IRP TREG,<*8], *4], *2], *1]>
494 IFIDN <&TSCALE>,<&TREG>
495 _SCALE = 0
496 ELSE
497 _SCALE = _SCALE + 1
498 ENDIF
499 ENDM
500 ENDM
501
502PAGE
503
504; Macros to PUSH and POP the new segment registers FS and GS
505
506
507; PUSH_FS - PUSH FS segment register
508
509PUSH_FS MACRO
510 DB 00FH
511 DB 0A0H
512 ENDM
513
514
515; PUSH_GS - PUSH GS segment register
516
517PUSH_GS MACRO
518 DB 00FH
519 DB 0A8H
520 ENDM
521
522
523; POP_FS - POP FS segment register
524
525POP_FS MACRO
526 DB 00FH
527 DB 0A1H
528 ENDM
529
530
531; POP_GS - POP GS segment register
532
533POP_GS MACRO
534 DB 00FH
535 DB 0A9H
536 ENDM
537
538PAGE
539
540; Macros for multiplication instructions
541
542; RIMUL - Uncharacterized Signed Multiply (16-bit)
543; Syntax: RIMUL REG,REG/MEM
544
545RIMUL MACRO REG,OPND
546 LOCAL L1,L2
547 _2BYTEOP = 1
548 DB 0FH
549 .XLIST
550L1 LABEL BYTE
551 .LIST
552 CMP &REG,&OPND
553 .XLIST
554L2 LABEL BYTE
555 ORG OFFSET CS:L1
556 .LIST
557 DB 0AFH
558 .XLIST
559 ORG OFFSET CS:L2
560 .LIST
561 ENDM
562
563; ERIMUL - 32 bit Uncharacterized Signed Multiply
564; Systax: ERIMUL REG,REG/MEM
565
566ERIMUL MACRO REG,OPND
567 DB 66H
568 RIMUL &REG,<&OPND>
569 ENDM
570
571PAGE
572
573; Macros to load pointers with the segment in FS, GS or SS. That is, these are
574; just like the instructions LDS and LES but for the FS, GS and SS registers.
575
576NEWLS MACRO OP,REG,OPND
577 LOCAL L1,L2
578 DB 0FH
579 .XLIST
580L1 LABEL BYTE
581 .LIST
582 LDS &REG,DWORD PTR &OPND
583 .XLIST
584L2 LABEL BYTE
585 ORG OFFSET CS:L1
586 .LIST
587 DB &OP
588 .XLIST
589 ORG OFFSET CS:L2
590 .LIST
591 ENDM
592
593; LFS REG,OPND
594
595LFS MACRO REG,OPND
596 NEWLS 0B4H,&REG,<&OPND>
597 ENDM
598
599; LGS REG,OPND
600
601LGS MACRO REG,OPND
602 NEWLS 0B5H,&REG,<&OPND>
603 ENDM
604
605; LSS REG,OPND
606
607LSS MACRO REG,OPND
608 NEWLS 0B2H,&REG,<&OPND>
609 ENDM
610
611; Now we do 32 bit versions of the above
612
613; ELFS REG,OPND
614
615ELFS MACRO REG,OPND
616 DB 66H
617 NEWLS 0B4H,&REG,<&OPND>
618 ENDM
619
620; ELGS REG,OPND
621
622ELGS MACRO REG,OPND
623 DB 66H
624 NEWLS 0B5H,&REG,<&OPND>
625 ENDM
626
627; ELSS REG,OPND
628
629ELSS MACRO REG,OPND
630 DB 66H
631 NEWLS 0B2H,&REG,<&OPND>
632 ENDM
633
634PAGE
635
636; Macros for some shift instructions
637
638; Shift Left Double R/M, Reg [CL = COUNT] [16-bit Operand]
639; SHLD OPND,REG (Double left shift) [CL = COUNT]
640
641SHLD MACRO OPND,REG
642 SHDOP 0A5H,<&OPND>,&REG
643 ENDM
644
645
646; Shift Right Double R/M, Reg [CL = COUNT] [16-bit Operand]
647; SHRD OPND,REG (Double right shift) [CL = COUNT]
648
649SHRD MACRO OPND,REG
650 SHDOP 0ADH,<&OPND>,&REG
651 ENDM
652
653
654; Shift Left Double R/M, Reg, Immd (8-bit) [16-bit Operand]
655; SHLDI OPND,REG,IMMD-8
656
657SHLDI MACRO OPND,REG,IMMD
658 SHDOP 0A4H,<&OPND>,&REG
659 DB &IMMD
660 ENDM
661
662
663; Shift Right Double R/M, Reg, Immd (8-bit) [16-bit Operand]
664; SHRDI OPND,REG,IMMD-8
665
666SHRDI MACRO OPND,REG,IMMD
667 SHDOP 0ACH,<&OPND>,&REG
668 DB &IMMD
669 ENDM
670
671; Now 32 bit versions of the above
672
673; Shift Left Double R/M, Reg [CL = COUNT] [32-bit Operand]
674; ESHLD OPND,REG (Double left shift) [CL = COUNT]
675
676ESHLD MACRO OPND,REG
677 DB 66H
678 SHDOP 0A5H,<&OPND>,&REG
679 ENDM
680
681
682; Shift Right Double R/M, Reg [CL = COUNT] [32-bit Operand]
683; ESHRD OPND,REG (Double right shift) [CL = COUNT]
684
685ESHRD MACRO OPND,REG
686 DB 66H
687 SHDOP 0ADH,<&OPND>,&REG
688 ENDM
689
690
691; Shift Left Double R/M, Reg, Immd (8-bit) [32-bit Operand]
692; ESHLDI OPND,REG,IMMD-8 (Double left shift)
693
694ESHLDI MACRO OPND,REG,IMMD
695 DB 66H
696 SHDOP 0A4H,<&OPND>,&REG
697 DB &IMMD
698 ENDM
699
700
701; Shift Right Double R/M, Reg, Immd (8-bit) [32-bit Operand]
702; ESHRDI OPND,REG,IMMD-8 (Double right shift)
703
704ESHRDI MACRO OPND,REG,IMMD
705 DB 66H
706 SHDOP 0ACH,<&OPND>,&REG
707 DB &IMMD
708 ENDM
709
710
711SHDOP MACRO OP,OPND,REG
712 LOCAL L1,L2
713 _2BYTEOP = 1
714 DB 0FH
715 .XLIST
716L1 LABEL BYTE
717 .LIST
718 OR &REG,&OPND
719 .XLIST
720L2 LABEL BYTE
721 ORG OFFSET CS:L1
722 .LIST
723 DB &OP
724 .XLIST
725 ORG OFFSET CS:L2
726 .LIST
727 ENDM
728
729PAGE
730
731; The following two instructions, CALLFAR and JUMPFAR, work in the
732; MS Macro Assembler, but not for intersegment direct. The assembler
733; generates segments based on 8088 values, and we need them based
734; on protect-mode selector values. The assembler works just ducky for
735; jump and call far indirect, since you go pick up the offset and
736; segment at execution time.
737
738CALLFAR MACRO DISP,SEGMENT
739
740 DB 09AH ; Call far direct
741 DW (OFFSET &DISP) ; to this offset
742 DW &SEGMENT ; in this segment
743
744 ENDM
745
746
747JUMPFAR MACRO DISP,SEGMENT
748
749 DB 0EAH ; Jump far direct
750 DW (OFFSET &DISP) ; to this offset
751 DW &SEGMENT ; in this segment
752
753 ENDM
754
755PAGE
756
757; Macros for extended jump instructions
758
759LJCOND MACRO OP,DISPL
760 _2BYTEOP = 1
761TEMP = $ + 4
762 DB 0FH
763 DB &OP
764 DW (OFFSET &DISPL)-(&TEMP)
765 ENDM
766
767; LJO DISPL (Long Jump on Overflow)
768LJO MACRO DISPL
769 LJCOND 80H,<&DISPL>
770 ENDM
771
772
773; LJNO DISPL (Long Jump on NO Overflow)
774LJNO MACRO DISPL
775 LJCOND 81H,<&DISPL>
776 ENDM
777
778; LJB DISPL (Long Jump on Below)
779LJB MACRO DISPL
780 LJCOND 82H,<&DISPL>
781 ENDM
782
783; LJC DISPL (Long Jump on Carry)
784LJC MACRO DISPL
785 LJCOND 82H,<&DISPL>
786 ENDM
787
788; LNAE DISPL (Long Jump on Not Above or Equal)
789LNAE MACRO DISPL
790 LJCOND 82H,<&DISPL>
791 ENDM
792
793; LJNB DISPL (Long Jump on Not Below)
794LJNB MACRO DISPL
795 LJCOND 83H,<&DISPL>
796 ENDM
797
798; LJNC DISPL (Long Jump on No Carry)
799LJNC MACRO DISPL
800 LJCOND 83H,<&DISPL>
801 ENDM
802
803; LJAE DISPL (Long Jump on Above or Equal)
804LJAE MACRO DISPL
805 LJCOND 83H,<&DISPL>
806 ENDM
807
808; LJE DISPL (Long Jump on Equal)
809LJE MACRO DISPL
810 LJCOND 84H,<&DISPL>
811 ENDM
812
813; LJZ DISPL (Long Jump on Zero)
814LJZ MACRO DISPL
815 LJCOND 84H,<&DISPL>
816 ENDM
817
818; LJNE DISPL (Long Jump on Not Equal)
819LJNE MACRO DISPL
820 LJCOND 85H,<&DISPL>
821 ENDM
822
823; LJNZ DISPL (Long Jump on Not Zero)
824LJNZ MACRO DISPL
825 LJCOND 85H,<&DISPL>
826 ENDM
827
828; LJBE DISPL (Long Jump on Below or Equal)
829LJBE MACRO DISPL
830 LJCOND 86H,<&DISPL>
831 ENDM
832
833; LJNA DISPL (Long Jump on Not Above)
834LJNA MACRO DISPL
835 LJCOND 86H,<&DISPL>
836 ENDM
837
838; LJNBE DISPL (Long Jump on Not Below or Equal)
839LJNBE MACRO DISPL
840 LJCOND 87H,<&DISPL>
841 ENDM
842
843; LJA DISPL (Long Jump on Above)
844LJA MACRO DISPL
845 LJCOND 87H,<&DISPL>
846 ENDM
847
848; LJS DISPL (Long Jump on Sign)
849LJS MACRO DISPL
850 LJCOND 88H,<&DISPL>
851 ENDM
852
853; LJNS DISPL (Long Jump on No Sign)
854LJNS MACRO DISPL
855 LJCOND 89H,<&DISPL>
856 ENDM
857
858; LJP DISPL (Long Jump on Parity)
859LJP MACRO DISPL
860 LJCOND 8AH,<&DISPL>
861 ENDM
862
863; LJPE DISPL (Long Jump on Parity Even)
864LJPE MACRO DISPL
865 LJCOND 8AH,<&DISPL>
866 ENDM
867
868; LJNP DISPL (Long Jump on No Parity)
869LJNP MACRO DISPL
870 LJCOND 8BH,<&DISPL>
871 ENDM
872
873; LJPO DISPL (Long Jump on Parity Odd)
874LJPO MACRO DISPL
875 LJCOND 8BH,<&DISPL>
876 ENDM
877
878; LJL DISPL (Long Jump on Less)
879LJL MACRO DISPL
880 LJCOND 8CH,<&DISPL>
881 ENDM
882
883; LJNGE DISPL (Long Jump on Not Greater or Equal)
884LJNGE MACRO DISPL
885 LJCOND 8CH,<&DISPL>
886 ENDM
887
888; LJNL DISPL (Long Jump on Not Less)
889LJNL MACRO DISPL
890 LJCOND 8DH,<&DISPL>
891 ENDM
892
893; LJGE DISPL (Long Jump on Greater than or Equal)
894LJGE MACRO DISPL
895 LJCOND 8DH,<&DISPL>
896 ENDM
897
898; LJLE DISPL (Long Jump on Less than or Equal)
899LJLE MACRO DISPL
900 LJCOND 8EH,<&DISPL>
901 ENDM
902
903; LJNG DISPL (Long Jump on Not Greater than)
904LJNG MACRO DISPL
905 LJCOND 8EH,<&DISPL>
906 ENDM
907
908; LJNLE DISPL (Long Jump on Not Less than or Equal)
909LJNLE MACRO DISPL
910 LJCOND 8FH,<&DISPL>
911 ENDM
912
913; LJG DISPL (Long Jump on Greater than)
914LJG MACRO DISPL
915 LJCOND 8FH,<&DISPL>
916 ENDM
917
918; JECXZ DISPL (Jump short on ECX Zero)
919JECEXZ MACRO DISPL
920 DB 66H
921 JCXZ &DISPL
922 ENDM
923
diff --git a/v4.0/src/DEV/XMAEM/INDEMAUS.ASM b/v4.0/src/DEV/XMAEM/INDEMAUS.ASM
new file mode 100644
index 0000000..1174510
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEMAUS.ASM
@@ -0,0 +1,73 @@
1PAGE 60,132
2TITLE INDEMAUS - 386 XMA Emulator - Messages
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEMAUS *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. *
12* *
13* STATUS (LEVEL) : Version (0) Level (1.0) *
14* *
15* FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator *
16* *
17* MODULE TYPE : ASM *
18* *
19* REGISTER USAGE : N/A *
20* *
21* RESTRICTIONS : None *
22* *
23* DEPENDENCIES : None *
24* *
25* ENTRY POINT : None *
26* *
27* LINKAGE : The messages are made PUBLIC so that the initialization *
28* module, INDEINI, can access them. *
29* *
30* INPUT PARMS : None *
31* *
32* RETURN PARMS : None *
33* *
34* OTHER EFFECTS : None *
35* *
36* EXIT NORMAL : None *
37* *
38* EXIT ERROR : None *
39* *
40* EXTERNAL *
41* REFERENCES : None *
42* *
43* SUB-ROUTINES : None *
44* *
45* MACROS : None *
46* *
47* CONTROL BLOCKS : None *
48* *
49* CHANGE ACTIVITY : *
50* *
51* $MOD(INDEMAUS) COMP(LOAD) PROD(3270PC) : *
52* *
53* $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 *
54* *
55* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
56#
57
58SUBTTL Messages ; D0A
59PAGE ; D0A
60 ; D0A
61PROG SEGMENT PARA PUBLIC 'PROG' ; D0A
62 ; D0A
63 ASSUME CS:PROG ; D0A
64 ASSUME SS:NOTHING ; D0A
65 ASSUME DS:PROG ; D0A
66 ASSUME ES:NOTHING ; D0A
67 ; D0A
68INDEMAUS LABEL NEAR ; D0A
69 ; D0A
70 INCLUDE INDEMSUS.INC ; Use the US messages D0A
71 ; D0A
72PROG ENDS ; D0A
73 END ; D0A
diff --git a/v4.0/src/DEV/XMAEM/INDEMSG.ASM b/v4.0/src/DEV/XMAEM/INDEMSG.ASM
new file mode 100644
index 0000000..1adf363
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEMSG.ASM
@@ -0,0 +1,96 @@
1PAGE 60,132
2TITLE INDEMSG - 80386 XMA Emulator - Messages
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEMSG *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. *
12* *
13* STATUS (LEVEL) : Version (0) Level (1.10) *
14* *
15* FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator *
16* *
17* MODULE TYPE : ASM *
18* *
19* REGISTER USAGE : N/A *
20* *
21* RESTRICTIONS : None *
22* *
23* DEPENDENCIES : None *
24* *
25* ENTRY POINT : None *
26* *
27* LINKAGE : The messages are made PUBLIC so that the initialization *
28* module, INDEINI, can access them. *
29* *
30* INPUT PARMS : None *
31* *
32* RETURN PARMS : None *
33* *
34* OTHER EFFECTS : None *
35* *
36* EXIT NORMAL : None *
37* *
38* EXIT ERROR : None *
39* *
40* EXTERNAL *
41* REFERENCES : None *
42* *
43* SUB-ROUTINES : None *
44* *
45* MACROS : None *
46* *
47* CONTROL BLOCKS : None *
48* *
49* CHANGE ACTIVITY : *
50* *
51* $MOD(INDEMSG) COMP(LOAD) PROD(3270PC) : *
52* *
53* $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 *
54* $P1=P0000311 410 870805 D : RENAME MODULE TO INDEMSUS *
55* $P2=P0000489 410 871002 D : RENAME MODULE TO INDEMSG. DECLARE MESSAGES HERE.*
56* $P3=P0000649 411 880125 D : NEW VERSION OF THE EMULATOR *
57* $P4=P0000741 411 880203 D : UPDATE COPYRIGHT *
58* $D1=D0008700 120 880206 D : SUPPORT DOS 4.00 IOCTL CALL *
59* *
60* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
61#
62
63SUBTTL Messages ; D0A
64PAGE ; D0A
65 ; D0A
66PROG SEGMENT PARA PUBLIC 'PROG' ; D0A
67 ; D0A
68 ASSUME CS:PROG ; D0A
69 ASSUME SS:NOTHING ; D0A
70 ASSUME DS:PROG ; D0A
71 ASSUME ES:NOTHING ; D0A
72 ; D0A
73INDEMSG LABEL NEAR ; D0A
74 ; D0A
75;---------------------------------------------------------------------------P2A;
76; Declare messages that the emulator will display on the screen. These P2A;
77; messages are declared with line lengths of 80 bytes to allow for World P2A;
78; Trade translation. The messages are made public so that other modules P2A;
79; can access them. P2A;
80; Note that the messages are declared 80 bytes long to facilitate world trade translation. P2A;
81;---------------------------------------------------------------------------P2A;
82 ; P2A
83 PUBLIC WELCOME ; P2A
84 PUBLIC GOODLOAD ; P2A
85 PUBLIC NO_80386 ; P2A
86 PUBLIC WAS_INST ; P2A
87 Public Small_Parm ;an000; dms;
88 Public No_Mem ;an000; dms;
89 ; P2A
90CR EQU 13 ; ASCII for a carriage return ; @P2A
91LF EQU 10 ; ASCII for a line feed ; @P2A
92 ; P2A
93INCLUDE xmaem.cl1
94
95PROG ENDS ; D0A
96 END ; D0A
diff --git a/v4.0/src/DEV/XMAEM/INDEMSUS.ASM b/v4.0/src/DEV/XMAEM/INDEMSUS.ASM
new file mode 100644
index 0000000..d73d016
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEMSUS.ASM
@@ -0,0 +1,76 @@
1PAGE 60,132
2TITLE INDEMSG - 80386 XMA Emulator - Messages
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEMSUS *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. *
12* *
13* STATUS (LEVEL) : Version (0) Level (1.0) *
14* *
15* FUNCTION : Declare the U.S. messages for the 80386 XMA Emulator *
16* *
17* MODULE TYPE : ASM *
18* *
19* REGISTER USAGE : N/A *
20* *
21* RESTRICTIONS : None *
22* *
23* DEPENDENCIES : None *
24* *
25* ENTRY POINT : None *
26* *
27* LINKAGE : The messages are made PUBLIC so that the initialization *
28* module, INDEINI, can access them. *
29* *
30* INPUT PARMS : None *
31* *
32* RETURN PARMS : None *
33* *
34* OTHER EFFECTS : None *
35* *
36* EXIT NORMAL : None *
37* *
38* EXIT ERROR : None *
39* *
40* EXTERNAL *
41* REFERENCES : None *
42* *
43* SUB-ROUTINES : None *
44* *
45* MACROS : None *
46* *
47* CONTROL BLOCKS : None *
48* *
49* CHANGE ACTIVITY : *
50* *
51* $MOD(INDEMSUS) COMP(LOAD) PROD(3270PC) : *
52* *
53* $D0=D0004700 410 870629 D : NEW FOR RELEASE 1.1 *
54* $P1=P0000311 410 870805 D : RENAME MODULE TO INDEMSUS *
55* *
56* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
57#
58
59SUBTTL Messages ; D0A
60PAGE ; D0A
61 ; D0A
62PROG SEGMENT PARA PUBLIC 'PROG' ; D0A
63 ; D0A
64 ASSUME CS:PROG ; D0A
65 ASSUME SS:NOTHING ; D0A
66 ASSUME DS:PROG ; D0A
67 ASSUME ES:NOTHING ; D0A
68 ; D0A
69INDEMSG LABEL NEAR ; D0A
70 ; D0A
71 INCLUDE INDEMSUS.INC ; Use the US messages D0A
72 ; D0A
73 include copyrigh.inc ; DCL p1821
74 ;
75PROG ENDS ; D0A
76 END ; D0A
diff --git a/v4.0/src/DEV/XMAEM/INDEMSUS.INC b/v4.0/src/DEV/XMAEM/INDEMSUS.INC
new file mode 100644
index 0000000..e352729
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEMSUS.INC
@@ -0,0 +1,64 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEMSUS *
5* *
6* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
7* *
8* DESCRIPTIVE NAME: 80386 XMA Emulator messages -- U.S. *
9* *
10* STATUS (LEVEL) : Version (0) Level (1.0) *
11* *
12* FUNCTION : Include file for U.S. messages for the 80386 XMA Emulator.*
13* The messages are made PUBLIC so that the initialization *
14* module, INDEINI, can access them. *
15* *
16* MODULE TYPE : INC *
17* *
18* MACROS : None *
19* *
20* CONTROL BLOCKS : None *
21* *
22* CHANGE ACTIVITY : *
23* *
24* $MAC(INDEMSUS) COMP(LOAD) PROD(3270PC) : *
25* *
26* $D0=D0004700 410 870722 D : NEW FOR RELEASE 1.1 *
27* $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "INC" *
28* $P2=P0036900 110 870826 D : CHG MSG NO. INDXE003 *
29* *
30* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
31#
32
33;---------------------------------------------------------------------------D0A;
34; Declare messages that the emulator will display on the screen. These D0A;
35; messages are declared with line lengths of 80 bytes to allow for World D0A;
36; Trade translation. The messages are made public so that other modules D0A;
37; can access them. D0A;
38; Note that the messages are declared 80 bytes long to facilitate world trade translation. D0A;
39;---------------------------------------------------------------------------D0A;
40 ; D0A
41 PUBLIC WELCOME ; D0A
42 PUBLIC GOODLOAD ; D0A
43 PUBLIC NO_80386 ; D0A
44 PUBLIC WAS_INST ; D0A
45 ; D0A
46CR EQU 13 ; ASCII for a carriage return ; @D0A
47LF EQU 10 ; ASCII for a line feed ; @D0A
48 ; D0A
49WELCOME DB "INDXE001 80386 XMA Emulator Version 1.00 " ; @D0A
50 DB " (C) Copyright 1988 Microsoft Corporation All rights reserved " ; @D0A
51 DB CR,LF,"$" ; @D0A
52 ; D0A
53GOODLOAD DB "INDXE002 80386 XMA Emulator installed " ; @D0A
54 DB CR,LF,"$" ; @D0A
55 ; D0A
56NO_80386 DB "INDXE003 80386 XMA Emulator not installed. This system unit " ; @D0A
57 DB " is not supported. The 80386 XMA Emulator requires " ; @D0A
58 DB " an IBM Personal System/2 Model 80. " ; @D0A
59 DB CR,LF,"$" ; @D0A
60 ; D0A
61WAS_INST DB "INDXE004 80386 XMA Emulator not installed. " ; @D0A
62 DB " Protected mode already in use. " ; @D0A
63 DB CR,LF,"$" ; @D0A
64 ; D0A
diff --git a/v4.0/src/DEV/XMAEM/INDEOVP.MAC b/v4.0/src/DEV/XMAEM/INDEOVP.MAC
new file mode 100644
index 0000000..3f2e213
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEOVP.MAC
@@ -0,0 +1,111 @@
1COMMENT #
2* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3* *
4* MODULE NAME : INDEOVP *
5* *
6* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
7* *
8* DESCRIPTIVE NAME: Override prefix macros *
9* *
10* STATUS (LEVEL) : Version (0) Level (1.0) *
11* *
12* FUNCTION : DATAOV - Creates a prefix so that the next instruction *
13* accesses data twice as wide as it normally would.*
14* Bytes go to words, and words go to double words. *
15* ADDROV - Creates a prefix so that the next instruction *
16* uses 32 bit addresses instead of 16 bit. *
17* SEGOV - Creates a segment override prefix for the next *
18* instruction. *
19* *
20* MODULE TYPE : MAC *
21* *
22* REGISTER USAGE : 80286 Standard *
23* *
24* CHANGE ACTIVITY : *
25* *
26* $MAC(INDEOVP) COMP(LOAD) PROD(3270PC) : *
27* *
28* $D0=D0004700 410 870604 D : NEW FOR RELEASE 1.1 *
29* $P1=P0000311 410 870804 D : RENAME MODULE'S LIBRARY FILE TYPE TO "MAC" *
30* *
31* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32#
33
34PAGE
35; DATAOV - Create a prefix for an instruction so that it accesses data twice
36; as wide as it normally would have. If the instruction was to access
37; bytes then it will access words. If it was to access words then it
38; will access double words (32 bits).
39
40DATAOV MACRO
41 DB 066H
42 ENDM
43
44PAGE
45; ADDROV - Create a prefix for an instruction so that it uses 32 bit addresses
46; instead of 16 bit addresses.
47
48ADDROV MACRO
49 DB 067H
50 ENDM
51
52PAGE
53; SEGOV - Segment Prefix Overrides
54; This macro will create segment prefix overrides for all the segment registers
55; on the 80386. It will also create prefixes for the data override and address
56; override as listed in the DATOV and ADDROV macros above.
57;
58; Syntax: SEGOV ES | CS | SS | DS | FS | GS | DATA | ADDRESS
59;
60
61SEGOV MACRO SR
62 IFIDN <&SR>,<ES>
63 DB 026H
64 ENDIF
65 IFIDN <&SR>,<es>
66 DB 026H
67 ENDIF
68 IFIDN <&SR>,<CS>
69 DB 02EH
70 ENDIF
71 IFIDN <&SR>,<cs>
72 DB 02EH
73 ENDIF
74 IFIDN <&SR>,<SS>
75 DB 036H
76 ENDIF
77 IFIDN <&SR>,<ss>
78 DB 036H
79 ENDIF
80 IFIDN <&SR>,<DS>
81 DB 03EH
82 ENDIF
83 IFIDN <&SR>,<ds>
84 DB 03EH
85 ENDIF
86 IFIDN <&SR>,<FS>
87 DB 064H
88 ENDIF
89 IFIDN <&SR>,<fs>
90 DB 064H
91 ENDIF
92 IFIDN <&SR>,<GS>
93 DB 065H
94 ENDIF
95 IFIDN <&SR>,<gs>
96 DB 065H
97 ENDIF
98 IFIDN <&SR>,<DATA>
99 DB 066H
100 ENDIF
101 IFIDN <&SR>,<data>
102 DB 066H
103 ENDIF
104 IFIDN <&SR>,<ADDRESS>
105 DB 067H
106 ENDIF
107 IFIDN <&SR>,<address>
108 DB 067H
109 ENDIF
110 ENDM
111
diff --git a/v4.0/src/DEV/XMAEM/INDEPAT.ASM b/v4.0/src/DEV/XMAEM/INDEPAT.ASM
new file mode 100644
index 0000000..e14d1d8
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEPAT.ASM
@@ -0,0 +1,74 @@
1PAGE 60,132
2TITLE INDEPAT - 80386 XMA Emulator - Patch area
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEPAT *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: 80386 XMA Emulator patch area *
12* *
13* STATUS (LEVEL) : Version (0) Level (1.0) *
14* *
15* FUNCTION : Declare a patch area for the 80386 XMA Emulator *
16* *
17* MODULE TYPE : ASM *
18* *
19* REGISTER USAGE : N/A *
20* *
21* RESTRICTIONS : None *
22* *
23* DEPENDENCIES : None *
24* *
25* ENTRY POINT : None *
26* *
27* LINKAGE : None *
28* *
29* INPUT PARMS : None *
30* *
31* RETURN PARMS : None *
32* *
33* OTHER EFFECTS : None *
34* *
35* EXIT NORMAL : None *
36* *
37* EXIT ERROR : None *
38* *
39* EXTERNAL *
40* REFERENCES : None *
41* *
42* SUB-ROUTINES : None *
43* *
44* MACROS : None *
45* *
46* CONTROL BLOCKS : None *
47* *
48* CHANGE ACTIVITY : *
49* *
50* $MOD(INDEPAT) COMP(LOAD) PROD(3270PC) : *
51* *
52* $P0=P0000489 410 871002 D : NEW FOR WSP VERSION 1.1 *
53* *
54* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55#
56
57SUBTTL Patch Area
58PAGE
59
60PROG SEGMENT PARA PUBLIC 'PROG'
61
62 ASSUME CS:PROG
63 ASSUME SS:NOTHING
64 ASSUME DS:PROG
65 ASSUME ES:NOTHING
66
67 PUBLIC INDEPAT
68
69INDEPAT LABEL NEAR
70
71 DB 512 DUP(0EEH)
72
73PROG ENDS
74 END
diff --git a/v4.0/src/DEV/XMAEM/INDEXMA.ASM b/v4.0/src/DEV/XMAEM/INDEXMA.ASM
new file mode 100644
index 0000000..c35dd24
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEXMA.ASM
@@ -0,0 +1,781 @@
1PAGE 60,132
2TITLE INDEXMA - 386 XMA Emulator - XMA Emulation
3
4COMMENT #
5* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6* *
7* MODULE NAME : INDEXMA *
8* *
9* 5669-196 (C) COPYRIGHT 1988 Microsoft Corp. *
10* *
11* DESCRIPTIVE NAME: Do the XMA emulation for the 80386 XMA Emulator *
12* *
13* STATUS (LEVEL) : Version (0) Level (1.0) *
14* *
15* FUNCTION : This module does the actual manipulation of the page *
16* tables to emulate the XMA card. Using the 80386 *
17* paging mechanism we let the 4K page frames represent *
18* the 4K XMA blocks on the XMA card. We let the page *
19* tables represent the translate table. *
20* *
21* The XMA "blocks" start at address 12000:0. The D1C*
22* Emulator emulates the XMA 2 card with the INDXMAA D1C*
23* device driver. On initial power up, the XMA 2 card is D1C*
24* disabled. The INDXMAA device driver then disables the D1C*
25* memory from 0K to 640K and backs it with memory from D1C*
26* 0K to 640K on the XMA 2 card. The Emulator looks like D1C*
27* it does the same thing. The XMA blocks for 0K to 640K D1C*
28* are taken from the system board memory from 0K to D1C*
29* 640K. This memory on the motherboard is treated as D1C*
30* XMA memory. This emulates the INDXMAA device driver's D1C*
31* mapping of 0K to 640K on the XMA card to real memory. D1C*
32* The XMA "blocks" for 640K and up are located in high D1C*
33* memory starting at 12000:0. These "blocks" run up to D1C*
34* the start of the MOVEBLOCK buffer. The MOVEBLOCK D1C*
35* buffer is a chunk of storage (in 16K multiples) at the D1C*
36* end of available memory that is reserved for the D1C*
37* MOVEBLOCK functions. D1C*
38* *
39* The page tables are used to emulate the translate *
40* table. By setting the address of the XMA "block" into *
41* the page table entry for a specific page frame we can *
42* make that address access that particular XMA page *
43* frame. To the user this looks just like the translate *
44* table is active. *
45* *
46* The tricky part comes in disabling pages (blocks). On D1C*
47* the XMA 2 card, when a translate table entry is D1C*
48* disabled the addresses for that address range go to D1C*
49* real memory. If the address is between 0K and 640K D1C*
50* then any access of that storage gets nothing because D1C*
51* there is no memory backed from 0K to 640K on the real D1C*
52* system. All other addresses go to real memory. So D1C*
53* when the user disables translation of a translate D1C*
54* table entry we need to check what range that entry D1C*
55* covers. If the entry points to somewhere between 0K D1C*
56* and 640K then we will set the page table entry that D1C*
57* corresponds to the translate table entry to point to D1C*
58* non-existent memory. For all other addresses we will D1C*
59* just point the page table entry back to the real D1C*
60* memory at that address. D1C*
61* *
62* This module receives control on all "IN"s and "OUT"s *
63* done by the user. If the "IN" or "OUT" is not to an *
64* XMA port then it passes the I/O on to INDEDMA. If it *
65* is for an XMA port then the request is handled here. *
66* *
67* This module keeps its own copies of the XMA registers *
68* and the translate table. When any I/O comes for the *
69* XMA card it updates its copies of the registers and *
70* the translate table. Then it does any needed *
71* modifications on the page tables to emulate the XMA *
72* request. *
73* *
74* MODULE TYPE : ASM *
75* *
76* REGISTER USAGE : 80386 Standard *
77* *
78* RESTRICTIONS : None *
79* *
80* DEPENDENCIES : None *
81* *
82* ENTRY POINTS : INW - Emulate "IN" for a word with port number *
83* in DX *
84* INWIMMED - Emulate "IN" for a word with an immediate *
85* port number *
86* INIMMED - Emulate "IN" for a byte with an immediate *
87* port number *
88* XMAIN - Emulate "OUT" for a byte with port number *
89* in DX *
90* OUTW - Emulate "OUT" for a word with port number *
91* in DX *
92* OUTWIMMED - Emulate "OUT" for a word with an immediate *
93* port number *
94* XMAOUTIMMED - Emulate "OUT" for a byte with an immediate *
95* port number *
96* XMAOUT - Emulate "OUT" for a byte with port number *
97* in DX *
98* *
99* LINKAGE : Jumped to by INDEEXC *
100* *
101* INPUT PARMS : None *
102* *
103* RETURN PARMS : None *
104* *
105* OTHER EFFECTS : None *
106* *
107* EXIT NORMAL : Go to POPIO in INDEEMU to IRET to the V86 task *
108* *
109* EXIT ERROR : None *
110* *
111* EXTERNAL *
112* REFERENCES : POPIO:NEAR - Entry in INDEEMU to return to V86 task *
113* HEXW:NEAR - Entry in INDEEXC to display word in AX *
114* DMAIN:NEAR - Entry in INDEDMA to "IN" from DMA port *
115* DMAOUT:NEAR - Entry in INDEDMA to "OUT" to DMA port *
116* PGTBLOFF:WORD - Offset of the normal page tables *
117* SGTBLOFF:WORD - Offset of the page directory *
118* NORMPAGE:WORD - Entry for the 1st page directory entry *
119* so that it points to the normal *
120* page tables *
121* XMAPAGE:WORD - Entry for the 1st page directory entry *
122* that points to the XMA page tables *
123* TTTABLE:WORD - The translate table *
124* BUFF_SIZE:WORD - Size of the MOVEBLOCK buffer *
125* MAXMEM:WORD - Number of kilobytes on this machine *
126* *
127* SUB-ROUTINES : TTARCHANGED - Put the block number at the translate table *
128* entry in 31A0H into "ports" 31A2H and 31A4H *
129* UPDATETT - Update the translate table and page tables *
130* to reflect the new block number written to *
131* either 31A2H or 31A4H *
132* *
133* MACROS : DATAOV - Add prefix for the next instruction so that it *
134* accesses data as 32 bits wide *
135* ADDROV - Add prefix for the next instruction so that it *
136* uses addresses that are 32 bits wide *
137* CMOV - Move to and from control registers *
138* *
139* CONTROL BLOCKS : INDEDAT.INC - system data structures *
140* *
141* CHANGE ACTIVITY : *
142* *
143* $MOD(INDEXMA) COMP(LOAD) PROD(3270PC) : *
144* *
145* $D0=D0004700 410 870530 D : NEW FOR RELEASE 1.1 *
146* $P1=P0000293 410 870731 D : LIMIT LINES TO 80 CHARACTERS *
147* $P2=P0000312 410 870804 D : CHANGE COMPONENT FROM MISC TO LOAD *
148* $D1=D0007100 410 870810 D : CHANGE TO EMULATE XMA 2 *
149* *
150* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
151#
152
153 .286P ; Enable recognition of 286 privileged instructs.
154
155 .XLIST ; Turn off the listing
156 INCLUDE INDEDAT.INC ; Include system data structures
157
158 IF1 ; Only include macros on the first pass
159 INCLUDE INDEOVP.MAC
160 INCLUDE INDEINS.MAC
161 ENDIF
162 .LIST ; Turn on the listing
163
164CRT_SELECTOR EQU 00030H ; Selector for mono display buffer
165SEX_ATTR EQU 04B00H ; Attribute for turquoise on red
166STACK_ATTR EQU 00700H ; Attribute for white o black
167BLANK EQU 00020H ; ASCII for a blank
168XMA_PAGES_SEL EQU RSDA_PTR ; Selector for the XMA pages
169HIMEM EQU 120H ; Adjustment for XMA pages >= 640K. @D1C
170 ; They start at address 12000:0.
171 ; It's the block number corresponding
172 ; to address 12000:0.
173 ; @D1D
174
175PROG SEGMENT PARA PUBLIC 'PROG'
176
177 ASSUME CS:PROG
178 ASSUME DS:PROG
179 ASSUME ES:NOTHING
180 ASSUME SS:NOTHING
181
182INDEXMA LABEL NEAR
183
184; The following entry points are in other modules
185
186 EXTRN POPIO:NEAR ; Return to V86 task - in INDEEMU
187 EXTRN HEXW:NEAR ; Display word in AX - in INDEEXC
188 EXTRN DMAIN:NEAR ; "IN" from DMA port - in INDEDMA
189 EXTRN DMAOUT:NEAR ; "OUT" to DMA port - in INDEDMA
190
191; The following data are in INDEI15.ASM
192
193 EXTRN PGTBLOFF:WORD ; Offset of the normal page tables
194 EXTRN SGTBLOFF:WORD ; Offset of the page directory
195 EXTRN NORMPAGE:WORD ; Entry for the 1st page directory entry
196 ; so that it points to the normal
197 ; page tables
198 EXTRN XMAPAGE:WORD ; Entry for the 1st page directory entry
199 ; that points to the XMA page tables
200 EXTRN TTTABLE:WORD ; The translate table
201 EXTRN BUFF_SIZE:WORD ; Size of the MOVEBLOCK buffer
202 EXTRN MAXMEM:WORD ; Number of kilobytes on this machine
203
204; Let the following entries be known to other modules
205
206 PUBLIC INDEXMA
207 PUBLIC INW
208 PUBLIC INWIMMED
209 PUBLIC INIMMED
210 PUBLIC XMAIN
211 PUBLIC OUTW
212 PUBLIC OUTWIMMED
213 PUBLIC XMAOUTIMMED
214 PUBLIC XMAOUT
215 PUBLIC NOTXMAOUT
216
217; Let the following data be known to other modules
218
219 PUBLIC WORD_FLAG
220 PUBLIC XMATTAR
221 PUBLIC XMATTIO
222 PUBLIC XMATTII
223 PUBLIC XMATID
224 PUBLIC XMACTL
225
226; The following XMA labels represent the XMA ports starting at 31A0H.
227; THEY MUST BE KEPT IN THE FOLLOWING ORDER.
228
229XMATTAR DW 0 ; Port 31A0H - Translate table index
230XMATTIO DW 0 ; Port 31A2H - XMA block number
231XMATTII DW 0 ; Port 31A4H - Block number with auto-increment
232XMATID DB 0 ; Port 31A6H - Bank ID
233XMACTL DB 02H ; Port 31A7H - Control flags. Virtual @D1C
234 ; enable bit is initially on.
235
236; How about some flags?
237
238WORD_FLAG DB 0 ; If set to 1 then I/O is for a word.
239 ; Else, it's for a byte
240
241PAGE
242
243; Control comes here for an "IN" for a word with the port value in DX
244
245INW:
246 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our
247 MOV DS,AX ; data segment so we can set WORD_FLAG
248 MOV WORD_FLAG,1 ; Flag this as a word operation
249 JMP XMAIN ; Go do the "IN"
250
251; Control comes here for an "IN" for a word with an immediate port value
252
253INWIMMED:
254 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our
255 MOV DS,AX ; data segment so we can set WORD_FLAG
256 MOV WORD_FLAG,1 ; Flag this as a word operation
257
258; Control comes here for an "IN" for a byte with an immediate port value
259
260INIMMED:
261
262 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "IN" instruction
263
264; Get the port address from the instruction. The port address is in the byte
265; immediately following the "IN" op-code. We will load the port address into
266; DX. This way when we join the code below it will look like the port address
267; was in DX all along.
268
269 MOV AX,HUGE_PTR ; Load DS with a selector that accesses
270 MOV DS,AX ; all of memory as data
271
272 MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86
273 MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP
274
275 DATAOV ; Load ESI (32 bit SI) with the V86
276 MOV SI,SS:[BP+BP_IP] ; task's IP
277 DATAOV
278 MOV AX,SS:[BP+BP_CS] ; Load EAX with the V86 task's CS
279 DATAOV ; and then shift left four bits to
280 SHL AX,4 ; convert it to an offset
281 DATAOV ; Add the CS offset to "IP" in SI
282 ADD SI,AX ; SI now contains CS:IP as a 32 bit
283 ; offset from 0
284 ADDROV ; Get the byte after the "IN" instruc-
285 LODSB ; tion. This is the port address.
286
287 ADDROV ; Intel bug # A0-119
288 NOP ; Intel bug # A0-119
289
290 SUB DX,DX ; Clear DX to prepare for one byte move
291 MOV DL,AL ; DX now has the port address
292
293; Control comes here for an "IN" for a byte with the port value in DX
294
295XMAIN PROC NEAR
296
297 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our
298 MOV DS,AX ; data segment
299
300 CMP DX,31A0H ; Is the port address below 31A0H?
301 JB NOTXMAIN ; Yup. Then it's not XMA.
302
303 CMP DX,31A7H ; Is the port address above 31A7H?
304 JA NOTXMAIN ; Yup. Then it's not XMA.
305
306; It's an XMA port so lets do the "IN" for the guy.
307
308 AND XMATTAR,0FFFH ; First lets clear the high nibbles of
309 AND XMATID,0FH ; our ports. This insures that we
310 AND XMACTL,0FH ; have valid values in our ports.
311
312 LEA SI,XMATTAR ; Point SI to the port requested by
313 ADD SI,DX ; first pointing it to port 31A0H
314 SUB SI,31A0H ; and then adding on the difference
315 ; between 31A0H and the requested port
316 CMP WORD_FLAG,0 ; Is this a word operation?
317 JNE GETWORD ; Yes. Then go get a word.
318
319 LODSB ; Else get a byte from the "port"
320 MOV BYTE PTR SS:[BP+BP_AX],AL ; Put it in the V86 task's AL register
321 JMP INEXIT ; Th-th-that's all folks!
322
323; For non-XMA ports we just pass the "IN" on to INDEDMA
324
325NOTXMAIN:
326 JMP DMAIN
327
328; The "IN" is for a word
329
330GETWORD:
331 LODSW ; Get a word from the "port"
332 MOV WORD PTR SS:[BP+BP_AX],AX ; Put it in the V86 task's AX register
333
334 MOV WORD_FLAG,0 ; Reset the word flag
335
336 CMP DX,31A4H ; Is this an "IN" from the auto-
337 ; increment port?
338 JNE INEXIT ; Nope. Then just leave.
339
340 INC XMATTAR ; The "IN" is from the auto-increment
341 ; port so increment the translate
342 CALL TTARCHANGED ; table index and call TTARCHANGED
343 ; to update the status of the "card"
344INEXIT:
345 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the instruction (past
346 ; the port value for immediate insts.)
347 JMP POPIO ; Go return to the V86 task
348
349PAGE
350
351; Control comes here for an "OUT" for a word with the port value in DX
352
353OUTW:
354 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our
355 MOV DS,AX ; data segment so we can set WORD_FLAG
356 MOV WORD_FLAG,1 ; Flag this as a word operation
357 JMP XMAOUT ; Go do the "OUT"
358
359; Control comes here for an "OUT" for a word with an immediate port value
360
361OUTWIMMED:
362 MOV AX,SYS_PATCH_DS ; Load DS with the selector for our
363 MOV DS,AX ; data segment so we can set WORD_FLAG
364 MOV WORD_FLAG,1 ; Flag this as a word operation
365
366; Control comes here for an "OUT" for a byte with an immediate port value
367
368XMAOUTIMMED:
369
370 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "OUT" instruction
371
372; Get the port address from the instruction. The port address is in the byte
373; immediately following the "OUT" op-code. We will load the port address into
374; DX. This way when we join the code below it will look like the port address
375; was in DX all along.
376
377 MOV AX,HUGE_PTR ; Load DS with a selector that accesses
378 MOV DS,AX ; all of memory as data
379
380 MOV SS:WORD PTR [BP+BP_IP2],0 ; Clear the high words of the V86
381 MOV SS:WORD PTR [BP+BP_CS2],0 ; task's CS and IP
382
383 DATAOV ; Load ESI (32 bit SI) with the V86
384 MOV SI,SS:[BP+BP_IP] ; task's IP
385 DATAOV
386 MOV AX,SS:[BP+BP_CS] ; Load EAX with the V86 task's CS
387 DATAOV ; and then shift left four bits to
388 SHL AX,4 ; convert it to an offset
389 DATAOV ; Add the CS offset to "IP" in SI
390 ADD SI,AX ; SI now contains CS:IP as a 32 bit
391 ; offset from 0
392 ADDROV ; Get the byte after the "OUT" instruc-
393 LODSB ; tion. This is the port address.
394
395 ADDROV ; Intel bug # A0-119
396 NOP ; Intel bug # A0-119
397
398 SUB DX,DX ; Clear DX to prepare for one byte move
399 MOV DL,AL ; DX now has the port address
400
401; Control comes here for an "OUT" for a byte with the port value in DX
402
403XMAOUT:
404 MOV AX,SYS_PATCH_DS ; Load DS and ES with the selector for
405 MOV DS,AX ; our data area
406 MOV ES,AX
407
408 CMP DX,31A0H ; Is the port address below 31A0H?
409 JB NOTXMAOUT ; Yes. Then it's not XMA.
410
411 CMP DX,31A7H ; Is the port address above 31A7H?
412 JA NOTXMAOUT ; Yes. Then it's not XMA.
413
414 LEA DI,XMATTAR ; Point SI to the port requested by
415 ADD DI,DX ; first pointing it to port 31A0H
416 SUB DI,31A0H ; and then adding on the difference
417 ; between 31A0H and the requested port
418 CMP WORD_FLAG,0 ; Is this a word operation?
419 JNE PUTWORD ; Yes. Then go put a word.
420
421 MOV AL,BYTE PTR SS:[BP+BP_AX] ; Put the value in the V86 task's AL
422 STOSB ; register into the "port"
423
424 CMP DX,31A6H ; Is this "OUT" to the bank ID port?
425 JE CHKCNTRL ; If so, go set the new bank
426
427 CMP DX,31A7H ; Is the "OUT" to the control port?
428 JE CHKCNTRL ; Affirmative. Go handle control bits.
429
430 CMP DX,31A1H ; Is this "OUT" to the TT index?
431 ; (high byte)
432 JBE TTAROUT ; Yup. Go update dependent fields.
433
434 JMP OUTEXIT ; Any other ports just exit.
435
436; The "OUT" is for a word
437
438PUTWORD:
439 MOV AX,WORD PTR SS:[BP+BP_AX] ; Put the value in the V86 task's AX
440 STOSW ; register into the "port"
441
442 MOV WORD_FLAG,0 ; Reset the word flag
443
444 CMP DX,31A0H ; Is the "OUT" to the TT index port?
445 JE TTAROUT ; Si. Go update the dependent fields.
446
447 CMP DX,31A2H ; Is the "OUT" to set a block number?
448 JNE CHKA4 ; No. Go do some more checks.
449
450 MOV XMATTII,AX ; The "OUT" is to 31A2H. Set the auto-
451 ; increment port to the same value.
452 ; The two ports should always be in
453 ; sync.
454 CALL UPDATETT ; Update the "translate table" with the
455 ; new block number
456 JMP OUTEXIT ; That's it. Let's leave.
457
458CHKA4:
459 CMP DX,31A4H ; Is "OUT" to the auto-increment port
460 JNE CHKCNTRL ; No. Then it must be to the bank ID/
461 ; control byte port (31A6H).
462 MOV XMATTIO,AX ; The "OUT is to the auto-increment port
463 CALL UPDATETT ; Update the "translate table"
464 INC XMATTAR ; Increment the translate table index
465 CALL TTARCHANGED ; Update fields that depend on the
466 ; translate table index
467 JMP OUTEXIT ; And return to the V86 task
468
469; The translate table index was changed
470
471TTAROUT:
472 CALL TTARCHANGED ; Update fields that depend on the
473 ; setting of the translate table index
474 JMP OUTEXITDMA ; Skip flushing the page-translation
475 ; cache since the page tables have
476 ; not changed.
477
478; It's not an XMA "OUT" so pass it on to INDEDMA
479
480NOTXMAOUT:
481 JMP DMAOUT
482
483; The "OUT" is to the bank ID port (31A6H), the control port (31A7H) or both
484
485CHKCNTRL:
486
487 TEST XMACTL,02H ; Is the virtual enable bit on?
488 JNZ SETXMA ; Aye. Go make the specified XMA bank
489 ; active.
490 DATAOV ; Nay. We simulate disabling the XMA
491 MOV AX,NORMPAGE ; card by making the normal page
492 ; tables active.
493 MOV DI,SGTBLOFF ; This is done by setting the first
494 DATAOV ; entry in the page directory to
495 STOSW ; point to the page table for normal
496 ; memory.
497 JMP OUTEXIT ; Return to the V86 task
498
499SETXMA:
500 AND XMATID,0FH ; Wipe out the high nibble of the bank
501 MOV AL,XMATID ; ID. XMA only has 16 banks.
502 DATAOV ; Now multiply by 4K (shift left 12 ;P1C
503 SHL AX,28 ; bits) to get the offset from the
504 DATAOV ; base of the XMA page tables of the
505 SHR AX,28-12 ; page table for the requested bank.
506 ; Page tables are 4K in length. In
507 ; the process of shifting we shift the
508 ; high order 16 bits off the left end
509 ; of EAX so that they are 0 when we
510 ; shift back.
511 DATAOV ; Add on the offset of the base of the
512 ADD AX,XMAPAGE ; page tables. EAX now has the offset
513 ; of the page table for the XMA bank.
514 MOV DI,SGTBLOFF ; Point to the first entry in the page
515 ; directory.
516 DATAOV ; Set the first entry in the page
517 STOSW ; directory to point to the XMA page
518 ; table
519
520; Since the page tables have changed we need to purge the page-translation
521; cache. "For greatest efficiency in address translation, the processor
522; stores the most recently used page-table data in an on-chip cache... The
523; existence of the page-translation cache is invisible to applications
524; programmers but not to systems programmers; operating-system programmers
525; must flush the cache whenever the page tables are changed."
526; -- 80386 Programmer's Reference Manual (C) Intel 1986
527
528OUTEXIT:
529 CMOV EAX,CR3 ; Get the page directory base register
530 NOP ; 386 errata B0-110
531 CMOV CR3,EAX ; Write it back to reset the cache
532 NOP ; 386 errata B0-110
533
534OUTEXITDMA:
535 ADD WORD PTR SS:[BP+BP_IP],1 ; Step IP past the "OUT" instruction
536 JMP POPIO ; Return to the V86 task
537
538PAGE
539
540; TTARCHANGED updates all the fields that depend on the translate table index
541; in port 31A0H. This is mainly getting the translate table entries for the
542; specified index and putting them in the block number ports 31A2H and 31A4H.
543
544TTARCHANGED PROC
545
546 MOV AX,XMATTAR ; Get the new translate table index
547 AND AX,0FFFH ; The high nibble is not used
548 SHL AX,1 ; Change it to a word index. The
549 ; translate table entries are words.
550 LEA SI,TTTABLE ; Point SI to the translate table base
551 ADD SI,AX ; Add on the offset into the table
552 LODSW ; Get the XMA block number for the
553 ; specified translate table entry
554 MOV XMATTIO,AX ; Put it into "port" 31A2H
555 MOV XMATTII,AX ; Put it into "port" 31A4H
556
557 RET
558
559TTARCHANGED ENDP
560
561PAGE
562
563; UPDATETT will update the "translate table" and the corresponding page
564; tables when an XMA block number is written to either port 31A2H or the
565; auto-increment port 31A4H. A write to either of these ports means to set
566; the XMA block specified at the translate table entry indicated in port
567; 31A0H.
568;
569; The Emulator is set up to look like an XMA 2 card with the INDXMAA device D1C
570; driver. When the system comes up the XMA card is initially disabled. D1C
571; INDXMAA then backs memory from 0K to 640K on the system board with memory D1C
572; from 0K to 640K on the XMA card. To emulate this, the Emulator treats D1C
573; real memory from 0K to 640K as XMA blocks from 0K to 640K on the XMA card. D1C
574; This both saves memory and requires no code to back the real memory from D1C
575; 0K to 640K with XMA memory on initialization. The Emulator therefore only D1C
576; needs to allocate XMA memory for the XMA blocks over 640K. The XMA memory D1C
577; for over 640K starts at 12000:0. The XMA blocks 00H to 9FH will be mapped D1C
578; to the motherboard memory at 0K to 640K. The XMA blocks A0H and up will D1C
579; be mapped to the memory at 12000:0 and up. D1C
580;
581; Bits 15 (IBM bit 0) and 11 (IBM bit 4) of the XMA block number have
582; special meanings. When bit 15 is on it means that the block number is a
583; 15 bit number. This is in anticipation of larger block numbers in the
584; future. Current block numbers are 11 bits. When bit 11 is on it means
585; that the XMA translation for this translation table entry should be
586; disabled. The memory for this 4K block should be mapped back to real
587; memory.
588;
589; We also check to make sure that the XMA block is not above the XMA memory
590; limit. XMA memory ends where the MOVEBLOCK buffer starts. If the XMA
591; block is above the end of XMA memory then the page table entry for that
592; address is set to point to non-existent memory.
593;
594; When address translation is disabled for addresses above 640K then the D1C
595; page table entry for that address is set to point back to real memory. D1C
596; For disabled pages in the range 0K to 640K the page table entry is set to D1C
597; point to non-existent memory. D1C
598
599UPDATETT PROC
600
601 MOV AX,XMATTAR ; Get the index of the TT entry that
602 ; is to be changed
603 AND AX,0FFFH ; Clear the high four bits. They are
604 ; not used.
605 SHL AX,1 ; Change to a word offset since the TT
606 ; entries are words.
607 LEA DI,TTTABLE ; Point DI to the translate table base
608 ADD DI,AX ; Add on the offset of the entry that
609 ; is to be changed
610 MOV AX,XMATTIO ; Get the block number to be written
611 STOSW ; Store the block number in the TT
612
613; Convert bank number to a page address.
614; The following code works only with paging enabled at 256k boundary.
615; It is intended to support up to 128M at 4k granularity.
616; It interprets the high order bits as a superset of XMA.
617; Following is a truth table for bits 11 (XMA inhibit bit) and 15 ("enable-hi").
618; 15 11
619; 0 0 = enabled 11 bit address
620; 0 1 = disabled address
621; 1 x = enabled 15 bit address
622
623 TEST AH,80H ; Is this a 15 bit block number?
624 JZ SMALL ; Far from it. Go do stuff for 11 bit
625 ; block numbers.
626
627; We have a 15 bit address
628
629 CMP AX,0FFFFH ; If it's FFFFH then we treat it the
630 ; the same as 0FFFH which means
631 JE DISABLEPAGE ; disable the page
632
633 AND AX,7FFFH ; Turn off the 15 bit address bit
634 JMP BOTH ; leaving a valid block number for
635 ; our calculations later
636
637SMALL:
638 TEST AH,08H ; Is the disable bit on?
639 JNZ DISABLEPAGE ; Yes. Go disable the page.
640
641 AND AX,07FFH ; No. Turn off the high nibble and the
642 ; disable bit leaving a valid block
643 ; number for our upcoming calculations
644BOTH:
645 CMP AX,640/4 ; Is this block number for 640K or over?
646 JB NOADJUST ; Yup. There's no adjustment @D1C
647 ; needed for blocks between 0K and
648 ; 640K since we use real memory for
649 ; these blocks.
650 ; XMA 1 emulation code deleted 3@D1D
651 ADD AX,HIMEM-(640/4) ; Add on the adjustment needed for @D1C
652 ; blocks above 640K to point to
653 ; the XMA blocks starting at 12000:0.
654 ; But don't forget to subtract the
655 ; block number for 640K. This makes
656 ; the block number 0 based before we
657 ; add on the block number for 12000:0.
658NOADJUST:
659 DATAOV ; Shift the high order 16 bits of EAX
660 SHL AX,16 ; off the left end of the register.
661 DATAOV ; Now shift the block number back four
662 SHR AX,16-12 ; bits. This results in a net shift
663 ; left of 12 bits which converts the
664 ; block number to an offset, and it
665 ; clears the high four bits.
666 OR AL,7 ; Set the access and present bits. This
667 ; converts our offset to a valid page
668 ; table entry.
669 DATAOV ; Save the page table entry in EBX for
670 MOV BX,AX ; now
671
672; Now we must make sure the offset of our XMA page frame is within the address
673; space of the XMA pages, that is, it is below the start of the MOVEBLOCK
674; buffer.
675
676 DATAOV ; Clear all 32 bits of EAX
677 SUB AX,AX
678 MOV AX,MAXMEM ; Load up the number of K on the box
679 SUB AX,BUFF_SIZE ; Subtract the number of K reserved
680 ; for the MOVEBLOCK buffer
681 DATAOV ; Multiply by 1K (shift left 10) to
682 SHL AX,10 ; convert it to an offset
683 DATAOV ; Is the XMA page address below the
684 CMP BX,AX ; MOVEBLOCK buffer address?
685 JB ENABLED ; Yup. Whew! Let's go set up the page
686 ; table entry for this XMA block.
687 JMP EMPTY ; Nope. Rats! Well, we'll just have
688 ; to point this TT entry to unbacked
689 ; memory.
690
691; We come here when we want to disable translation for this translate table
692; entry. For TT entries for 640K and over we just point the translate table
693; entry back to real memory. For TT entries between 0K and 640K we point
694; the translate table to unbacked memory. This memory on the motherboard
695; was disabled under real XMA so we emulate it by pointing to unbacked
696; memory.
697
698DISABLEPAGE:
699 ; XMA 1 emulation code deleted 2@D1D
700 CMP BYTE PTR XMATTAR,640/4 ; Is the address at 640K or above?
701 JNB SPECIAL ; Aye. Go point back to real memory.
702
703; The address is between 256K and 640K. Let's set the page table entry to
704; point to non-exiatent memory.
705
706EMPTY:
707 DATAOV ; Clear EAX
708 SUB AX,AX
709 MOV AX,MAXMEM ; Get the total number of K on the box
710 DATAOV ; Multiply by 1024 to convert to an
711 SHL AX,10 ; offset. AX now points to the 4K
712 ; page frame after the end of memory.
713 OR AL,7 ; Turn on the accessed and present bits
714 ; to avoid page faults
715 DATAOV ; Save the page table entry in EBX
716 MOV BX,AX
717 JMP ENABLED ; Go set up the page table
718
719; If the address is above 640K then the translate table (page table) entry D1C
720; is set to point back to real memory.
721SPECIAL:
722 MOV AX,XMATTAR ; Get the index of the TT entry that is
723 ; to be disabled
724 DATAOV ; Dump the high 24 bits off the left end
725 SHL AX,24 ; of the register
726 DATAOV ; Now shift it back 12 bits. This
727 SHR AX,24-12 ; results in a net shift left of 12
728 ; bits which multiplies the TT index
729 ; by 4K while at the same time clear-
730 ; ing the high order bits. EAX is now
731 ; the offset of the memory pointed to
732 ; by the TT entry.
733 OR AL,7 ; Turn on the accessed and present bits
734 ; to make this a page table entry
735 DATAOV ; Save the page table entry in EBX
736 MOV BX,AX
737
738; Now let's put the new page table entry in EBX, which represents the XMA block,
739; into the page table.
740ENABLED:
741 MOV AX,XMATTAR ; Get the index of the TT entry
742
743; Now we want ot convert the index of the TT entry to an offset into our XMA
744; page tables. The bank number is now in AH and the 4K block number of the
745; bank is in AL. To point to the right page table we need to multiply the bank
746; number by 4K (shift left 12 bits) since page tables are 4K in length. The
747; bank number is already shifted left 8 bits by virtue of it being in AH. It
748; needs to be shifted left four more bits. In order to access the right entry
749; in the page table, the block number in AL must be multiplied by 4 (shifted
750; left two bits) because the page table entries are 4 bytes in length. So,
751; first we shift AH left two bits and then shift AX left two bits. In the end
752; this shifts AH, the bank ID, left four bits and shifts AL, the block number,
753; two bits, which is what we wanted. A long explanation for two instructions,
754; but they're pretty efficient, don't you think?
755
756 SHL AH,2 ; Shift the bank ID left two bits
757 SHL AX,2 ; Shift the bank ID and the block number
758 ; left two bits
759 MOV DI,AX ; Load DI with the offset of the page
760 ; table entry that is to be changed
761 PUSH ES ; Save ES
762 MOV AX,XMA_PAGES_SEL ; Load ES with the selector for our
763 MOV ES,AX ; XMA page tables. Now ES:DI points
764 ; to the page table entry to be
765 ; changed
766 DATAOV ; Get the new value for the page table
767 MOV AX,BX ; entry which was saved in EBX.
768 DATAOV ; Stuff it into the page table - all
769 STOSW ; 32 bits of it.
770
771 POP ES ; Restore ES
772
773 RET ; And return
774
775UPDATETT ENDP
776
777XMAIN ENDP
778
779PROG ENDS
780
781 END
diff --git a/v4.0/src/DEV/XMAEM/INDEXMAE.SYS b/v4.0/src/DEV/XMAEM/INDEXMAE.SYS
new file mode 100644
index 0000000..d0fd31a
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/INDEXMAE.SYS
@@ -0,0 +1,8 @@
1MZ% 
2+V386XMAEM#86XMAEMULATOR11...(û&?t.(PSQRWVU.*.(f`.G<w3.6
3G.>*t
4]^_ZY[Xfaû& PD!G OG(G.>*tG G FE!tG G 9F!ð3.h.Ok.A.?.=5$0<0tS8Q+O-&Ȏؾhؿѹ f+f+ۻ f%f+ۻf+f"f+ۻff+ãEf f>Ef+ۻ`f+fGf+ۻfff+ۻffGf+$C>Cf+f+ۻff>Cfff@ы&VO<ы&^`h؎м=6jظ*иظ؎h󪹗hUikx8GfhG=6GhG\GXGTGH.?GP.=G8G&G$.AGL|G G` fGh؋6C++x󥸀f"jPf\X=u D!u du`Q+d$Yw24t0
5t< t<,t<;t <+t<=t< u*t6.O< t< t<
6<0r<9w:tu<
73.,0.& .t.>t3f`F4t~$ u~$uF4t &F$.>S3 3 Kh޾+.f FFK<t譋Ѓu fFp
8F⼋F4t" f+v6f+F:fff
diff --git a/v4.0/src/DEV/XMAEM/MAKEFILE b/v4.0/src/DEV/XMAEM/MAKEFILE
new file mode 100644
index 0000000..8aa4237
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/MAKEFILE
@@ -0,0 +1,57 @@
1#************************ makefile for dev\xmaem************************
2
3msg =..\..\messages
4dos =..\..\dos
5inc =..\..\inc
6hinc =..\..\h
7
8#
9####################### dependencies begin here. #########################
10#
11
12all: xmaem.sys
13
14xmaem.ctl: xmaem.skl $(msg)\$(COUNTRY).msg makefile
15 nosrvbld xmaem.skl $(msg)\$(COUNTRY).msg
16
17INDEINI.obj: INDEINI.ASM
18
19INDEEMU.obj: INDEEMU.ASM
20
21INDEEXC.obj: INDEEXC.ASM
22
23INDEXMA.obj: INDEXMA.ASM
24
25INDEDMA.obj: INDEDMA.ASM
26
27INDEIDT.obj: INDEIDT.ASM
28
29INDEGDT.obj: INDEGDT.ASM
30
31INDEI15.obj: INDEI15.ASM
32
33INDEmsg.obj: INDEmsg.ASM xmaem.ctl
34
35INDEpat.obj: INDEpat.ASM
36
37xmaem.sys: makefile \
38 xmaem.ctl \
39 INDEINI.obj \
40 INDEEMU.obj \
41 INDEEXC.obj \
42 INDEXMA.obj \
43 INDEDMA.obj \
44 INDEIDT.obj \
45 INDEGDT.obj \
46 INDEI15.obj \
47 indemaus.obj \
48 indemsus.inc \
49 indeovp.mac \
50 indeins.mac \
51 indedes.mac \
52 indemsg.obj \
53 indepat.obj \
54 indedat.inc \
55 indeacc.inc \
56 xmaem.lnk
57 link @xmaem.lnk
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.ARF b/v4.0/src/DEV/XMAEM/XMAEM.ARF
new file mode 100644
index 0000000..acbb2e7
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/XMAEM.ARF
@@ -0,0 +1,13 @@
1INDEINI+
2INDEEXC+
3INDEEMU+
4INDEXMA+
5INDEDMA+
6INDEI15+
7INDEIDT+
8INDEGDT+
9INDEMSG+
10INDEPAT
11xmaem.sys
12nul;
13 \ No newline at end of file
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.LC b/v4.0/src/DEV/XMAEM/XMAEM.LC
new file mode 100644
index 0000000..37c45f4
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/XMAEM.LC
@@ -0,0 +1,19 @@
1INDEINI.ASM
2INDEEMU.ASM
3INDEEXC.ASM
4INDEXMA.ASM
5INDEDMA.ASM
6INDEIDT.ASM
7INDEGDT.ASM
8INDEI15.ASM
9INDEMAUS.ASM
10INDEMSUS.INC
11INDEDAT.INC
12INDEACC.INC
13INDEOVP.MAC
14INDEINS.MAC
15INDEDES.MAC
16INDEMSUS.ASM
17INDEMSG.ASM
18INDEPAT.ASM
19 \ No newline at end of file
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.LNK b/v4.0/src/DEV/XMAEM/XMAEM.LNK
new file mode 100644
index 0000000..acbb2e7
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/XMAEM.LNK
@@ -0,0 +1,13 @@
1INDEINI+
2INDEEXC+
3INDEEMU+
4INDEXMA+
5INDEDMA+
6INDEI15+
7INDEIDT+
8INDEGDT+
9INDEMSG+
10INDEPAT
11xmaem.sys
12nul;
13 \ No newline at end of file
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.MAK b/v4.0/src/DEV/XMAEM/XMAEM.MAK
new file mode 100644
index 0000000..35e6b1b
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/XMAEM.MAK
@@ -0,0 +1,66 @@
1COM=G:\COMMON
2MSG=G:\MESSAGES
3
4#
5
6xmaem.cl1: xmaem.skl \
7 $(MSG)\$(country).MSG \
8 xmaem.mak
9 nosrvbld xmaem.skl $(MSG)\$(country).msg
10
11INDEINI.obj: INDEINI.ASM
12 asm87 INDEINI
13
14INDEEMU.obj: INDEEMU.ASM
15 asm87 INDEEMU
16
17INDEEXC.obj: INDEEXC.ASM
18 asm87 INDEEXC
19
20INDEXMA.obj: INDEXMA.ASM
21 asm87 INDEXMA
22
23INDEDMA.obj: INDEDMA.ASM
24 asm87 INDEDMA
25
26INDEIDT.obj: INDEIDT.ASM
27 asm87 INDEIDT
28
29INDEGDT.obj: INDEGDT.ASM
30 asm87 INDEGDT
31
32INDEI15.obj: INDEI15.ASM
33 asm87 INDEI15
34
35INDEmsg.obj: INDEmsg.ASM \
36 xmaem.cl1
37 asm87 INDEmsg
38
39INDEpat.obj: INDEpat.ASM
40 asm87 INDEpat
41
42
43xmaem.sys: g:\common\setver.bat \
44 XMAEM.MAK \
45 INDEINI.asm \
46 INDEEMU.asm \
47 INDEEXC.asm \
48 INDEXMA.asm \
49 INDEDMA.asm \
50 INDEIDT.asm \
51 INDEGDT.asm \
52 INDEI15.asm \
53 indemaus.asm \
54 indemsus.inc \
55 indeovp.mac \
56 indeins.mac \
57 indedes.mac \
58 indemsus.asm \
59 indemsg.asm \
60 indepat.asm \
61 indedat.inc \
62 indeacc.inc \
63 xmaem.arf
64 link @xmaem.arf
65 tag xmaem.sys
66 \ No newline at end of file
diff --git a/v4.0/src/DEV/XMAEM/XMAEM.SKL b/v4.0/src/DEV/XMAEM/XMAEM.SKL
new file mode 100644
index 0000000..6275a6c
--- /dev/null
+++ b/v4.0/src/DEV/XMAEM/XMAEM.SKL
@@ -0,0 +1,16 @@
1:class 1
2
3:use 1 xmaem Welcome
4:use 2 xmaem GoodLoad
5:use 3 xmaem No_80386
6:use 4 xmaem Was_Inst
7:use 5 xmaem Small_Parm
8:use 6 xmaem No_Mem
9
10:end
11
12
13
14
15
16 \ No newline at end of file