]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/DEV/XMAEM/INDEIDT.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / DEV / XMAEM / INDEIDT.ASM
1 PAGE 60,132
2 TITLE INDEIDT - 386 XMA Emulator - Build Interrupt Descriptor Table
3
4 COMMENT #
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
73 PAGE
74
75 PROG SEGMENT PARA PUBLIC 'PROG'
76
77 ASSUME CS:PROG
78 ASSUME SS:NOTHING
79 ASSUME DS:NOTHING
80 ASSUME ES:NOTHING
81
82 INDEIDT 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
93 PAGE
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
102 SPSTACK STRUC
103
104 SP_SI DW 0 ; Saved ESI (32 bit SI)
105 DW 0
106 SP_DI DW 0 ; Saved EDI (32 bit DI)
107 DW 0
108 SP_AX DW 0 ; Saved EAX
109 DW 0
110 SP_BP DW 0 ; Saved BP (only 16 bits)
111 SP_EX DW 0 ; Interrupt vector offset (interrupt number * 4)
112
113 ; The following information is saved by the 80386
114
115 SP_IP DW 0 ; Interruptee's EIP (32 bit IP)
116 SP_IP2 DW 0
117 SP_CS DW 0 ; Interruptee's CS (16 bit CS and 16 bit junk)
118 SP_CS2 DW 0
119 SP_FL DW 0 ; Interruptee's Eflags (32 bit flags)
120 SP_FL2 DW 0
121 SP_SP DW 0 ; Interruptee's ESP
122 SP_SP2 DW 0
123 SP_SS DW 0 ; Interruptee's SS
124 SP_SS2 DW 0
125 SP_VMES DW 0 ; Interruptee's ES
126 DW 0
127 SP_VMDS DW 0 ; Interruptee's DS
128 DW 0
129 SP_VMFS DW 0 ; Interruptee's FS
130 DW 0
131 SP_VMGS DW 0 ; Interruptee's GS
132 DW 0
133 SP_STK DW 0 ; The rest of the stack
134
135 SPSTACK ENDS
136
137 SP_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
140 PAGE
141
142 SIDTBLD 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>
166 VEC&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.
212 SKIP&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
226 PAGE
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>
232 VEC&V:
233 PUSH 0 ; Push a dummy error code of 0
234 PUSH 0 ; 32 bits wide
235 SKIP&V:
236 PUSH 0&V&H ; Push the interrupt number
237 JMP VEXCPT13 ; Go to the exception handler
238 ENDM
239
240 PAGE
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>
251 VEC&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>
256 VEC&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>
261 VEC&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>
266 VEC&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>
271 VEC&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>
276 VEC&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>
281 VEC&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>
286 VEC&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>
291 VEC&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>
296 VEC&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>
301 VEC&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>
306 VEC&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>
311 VEC&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>
316 VEC&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>
321 VEC&V:
322 PUSH 0&V&H*4 ; Push the interrupt vector offset
323 JMP FASTPATH ; Go to the fastpath routine
324 ENDM
325
326 VEC10:
327 PUSH 010H*4 ; Push the interrupt vector offset
328
329 PAGE
330 FASTPATH:
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
340 PASS_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
406 PAGE
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
411 SIDT_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
461 PAGE
462 SIDT_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
488 PAGE
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
495 BLD_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
508 SIDTBLD ENDP
509
510 PROG ENDS
511
512 END