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