summaryrefslogtreecommitdiff
path: root/v4.0/src/DEV/XMAEM/INDEIDT.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/DEV/XMAEM/INDEIDT.ASM')
-rw-r--r--v4.0/src/DEV/XMAEM/INDEIDT.ASM512
1 files changed, 512 insertions, 0 deletions
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