summaryrefslogtreecommitdiff
path: root/v4.0/src/BIOS/MSSTACK.INC
blob: 21a2095b50e990ee956211822303486e6015dcc6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
;	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 PC Convertible / NMI handler
;
;	On the PC Convertible, there is a situation where an NMI can be 
;	caused by using the "OUT" instructions to certain ports.  When this
;	occurs, the PC Convertible 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 PC Convertible, 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],mdl_convert	;check if convertible
	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], mdl_convert	;convertible?	  ;3.30
	pop	ds							  ;3.30
	jne	Skip_NMIS						  ;3.30
									  ;3.30
	mov	al,07h				; disable PC Convertible 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