; MSStack.inc ; ; Interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - AT level) ; should follow the standard Interrupt Sharing Scheme which has ; a standard header structure. ; Fyi, the following shows the relations between ; the interrupt vector and interrupt level. ; VEC(Hex) 2 8 9 A B C D E 70 72 73 74 76 77 ; LVL(Deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15 ; MSSTACK module modifies the following interrupt vectors ; to meet the standard Interrupt Sharing standard; ; A, B, C, D, E, 72, 73, 74, 76, 77. ; Also, for interrupt level 7 and 15, the FirstFlag in a standard header ; should be initialized to indicat whether this interrupt handler is ; the first (= 80h) or not. The FirstFlag entry of INT77h's ; program header is initialized in STKINIT.INC module. ; FirstFlag is only meaningful for interrupt level 7 and 15. ; ; User specifies the number of stack elements - default = 9 ; minimum = 8 ; maximum = 64 ; ; Intercepts Asynchronous Hardware Interrupts only ; ; Picks a stack from pool of stacks and switches to it ; ; Calls the previously saved interrupt vector after pushing flags ; ; On return, returns the stack to the stack pool ; ; This is a modification of STACKS: ; 1. To fix a bug which was causing the program to take up too much space. ; 2. To dispense stack space from hi-mem first rather than low-mem first. ; . Clobbers the stack that got too big instead of innocent stack ; . Allows system to work if the only stack that got too big was the most ; deeply nested one ; 3. Disables NMI interrupts while setting the NMI vector. ; 4. Does not intercept any interupts on a PCjr. ; 5. Double checks that a nested interrupt didn't get the same stack. ; 6. Intercepts Ints 70, 72-77 for PC-ATs and other future products ;The following variables are for MSSTACK.inc EVEN dw 0 ; SPARE FIELD BUT LEAVE THESE IN ORDER StackCount dw 0 StackAt dw 0 StackSize dw 0 Stacks dw 0 dw 0 FirstEntry dw Stacks LastEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize NextEntry dw Stacks+(DefaultCount*EntrySize)-EntrySize ;End of variables defined for MSSTACK. ;******************************************************************* ;Macro Interrupt handler for the ordinary interrupt vectors and ;the shared interrupt vectors. ;***************************** Stack_Main MACRO AA ASSUME DS:NOTHING ASSUME ES:NOTHING ASSUME SS:NOTHING PUBLIC Int&AA PUBLIC Old&AA ;----------------------------- ife IntSharingFlag ;if not IntSharingFlag ;----------------------------- Old&AA DD 0 Int&AA PROC FAR ;----------------------------- else ;for shared interrupt. A Header exists. PUBLIC FirstFlag&AA Int&AA PROC FAR jmp short Entry_Int&AA&_Stk Old&AA dd 0 ;Forward pointer dw 424Bh ;compatible signature for Int. Sharing FirstFlag&AA db 0 ;the firstly hooked. jmp short Intret_&AA ;Reset routine. We don't care this. db 7 dup (0) ;Reserved for future. Entry_Int&AA&_Stk: ;----------------------------- endif ;----------------------------- ; ; Keyboard interrupt must have a three byte jump, a NOP and a zero byte ; as its first instruction for compatibility reasons ifidn <&aa>,<09> jmp Keyboard_lbl nop db 0 Keyboard_lbl label near endif ; This patches INTERRUPT 75h to be "unhooked". We do this Wierdness, ; rather than never hooking INT 75h, to maintain maximum compat. with IBMs ; post production patch. push ax ifidn <&aa>,<02> ; ********************************************************************* ; ; This is special support for the P12 / NMI handler ; ; On the P12, there is a situation where an NMI can be caused by ; using the "OUT" instructions to certain ports. When this ; occurs, the P12 hardware *GUARANTEES* that **NOTHING** can stop ; the NMI or interfere with getting to the NMI handler. This ; includes other type of interrupts (hardware and software), and ; also includes other type of NMI's. When any NMI has occured, ; no other interrtupt (hardware, software or NMI) can occur until ; the software takes specific steps to allow further interrupting. ; ; For P12, the situation where the NMI is generated by the "OUT" ; to a control port requires "fixing-up" and re-attempting. In ; otherwords, it is actually a "restartable exception". In this ; case, the software handler must be able to get to the stack in ; order to figure out what instruction caused the problem, where ; it was "OUT"ing to and what value it was "OUT"ing. Therefore, ; we will not switch stacks in this situation. This situation is ; detected by interrogating port 62h, and checking for a bit value ; of 80h. If set, *****DO NOT SWITCH STACKS*****. ; ; ********************************************************************* push es mov ax,0f000h mov es,ax cmp byte ptr es:[0fffeh],0f9h ;check if P12 pop es jne Normal&aa in al,62h test al,80h jz Normal&aa Special&aa: pop ax jmp dword ptr Old&aa Normal&aa: ; ********************************************************************* endif push bp push es mov es, cs:[STACKS+2] ; Get segment of stacks mov bp,NextEntry ; get most likely candidate mov al,Allocated xchg AllocByte,al ; grab the entry cmp al,Free ; still avail? jne NotFree&aa sub NextEntry,EntrySize ; set for next interrupt Found&aa: mov SavedSP,sp ; save sp value mov SavedSS,ss ; save ss also ; mov IntLevel,aa&h ; save the int level mov ax,bp ; temp save of table offset mov bp,NewSP ; get new SP value cmp es:[bp],ax ; check for offset into table jne FoundBad&aa mov ax,es ; point ss,sp to the new stack mov ss,ax mov sp,bp pushf ; go execute the real interrupt handler call dword ptr old&aa ; which will iret back to here mov bp,sp ; retrieve the table offset for us mov bp,es:[bp] ; but leave it on the stack mov ss,SavedSS ; get old stack back mov sp,SavedSP ; cmp AllocByte,Allocated ; If an error occured, ; jne NewError&aa ; do not free us mov AllocByte,Free ; free the entry mov NextEntry,bp ; setup to use next time NewError&aa: pop es pop bp ; saved on entry pop ax ; saved on entry INTRET_&AA: ;3.30 iret ; done with this interrupt NotFree&aa: cmp al,Allocated ; error flag je findnext&aa ; no, continue xchg AllocByte,al ; yes, restore error value FindNext&aa: call LongPath jmp Found&aa FoundBad&aa: cmp bp,FirstEntry jc findnext&aa mov bp,ax ; flag this entry mov AllocByte,Clobbered ; add bp,EntrySize ; and previous entry ; mov AllocByte,Overflowed ; sub bp,EntrySize jmp findnext&aa ; keep looking int&aa endp endm ;***************************** ;3.30 ;End of Macro definition ;3.30 ;******************************************************************** ;3.30 ; THESE ARE THE INDIVIDUAL INTERRUPT HANDLERS ;3.30 ;3.30 IRP A,<02,08,09,70> ;3.30 IntSharingFlag=0 ;3.30 Stack_Main &A ;3.30 ENDM ;3.30 ;3.30 IRP A,<0A,0B,0C,0D,0E,72,73,74,76,77> ;3.30 IntSharingFlag=1 ;3.30 Stack_Main &A ;3.30 ENDM ;3.30 ;3.30 ;******************************************************************** ;3.30 ;Common routines ;3.30 longpath: mov bp,LastEntry ; start with last entry in table LPLOOPP: ;3.30 cmp AllocByte,Free ; is entry free? jne inuse ; no, try next one mov al,Allocated xchg AllocByte,al ; allocate entry cmp al,Free ; is it still free? je found ; yes, go use it cmp al,Allocated ; is it other than Allocated or Free? je inuse ; no, check the next one mov AllocByte,al ; yes, put back the error state inuse: cmp bp,FirstEntry je Fatal sub bp,EntrySize JMP LPLOOPP ;3.30 found: ret page fatal proc near push ds ;3.30 mov ax, 0f000h ;loook at the model byte ;3.30 mov ds, ax ;3.30 cmp ds:byte ptr [0fffeh], 0f9h ;convertible ;3.30 pop ds ;3.30 jne Skip_NMIS ;3.30 ;3.30 mov al,07h ; disable p12 NMIs out 72h,al Skip_NMIS: ;3.30 cli ; disable and mask mov al,0ffh ; all other ints out 021h,al out 0a1h,al mov si,cs mov ds,si mov si,offset fatal_msg fatal_loop: lodsb cmp al,'$' je fatal_done mov bl,7 ;3.30* mov ah,14 ;3.30* int 010h ; whoops, this enables ints ;3.30* jmp fatal_loop fatal_done: jmp fatal_done fatal endp