1 | ;
|
---|
2 | ; SIGNAL.ASM -- Signal processing
|
---|
3 | ;
|
---|
4 | ; Copyright (c) 1991-1998 by Eberhard Mattes
|
---|
5 | ;
|
---|
6 | ; This file is part of emx.
|
---|
7 | ;
|
---|
8 | ; emx is free software; you can redistribute it and/or modify it
|
---|
9 | ; under the terms of the GNU General Public License as published by
|
---|
10 | ; the Free Software Foundation; either version 2, or (at your option)
|
---|
11 | ; any later version.
|
---|
12 | ;
|
---|
13 | ; emx is distributed in the hope that it will be useful,
|
---|
14 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | ; GNU General Public License for more details.
|
---|
17 | ;
|
---|
18 | ; You should have received a copy of the GNU General Public License
|
---|
19 | ; along with emx; see the file COPYING. If not, write to
|
---|
20 | ; the Free Software Foundation, 59 Temple Place - Suite 330,
|
---|
21 | ; Boston, MA 02111-1307, USA.
|
---|
22 | ;
|
---|
23 | ; See emx.asm for a special exception.
|
---|
24 | ;
|
---|
25 |
|
---|
26 | __SIGNAL = 1
|
---|
27 | INCLUDE EMX.INC
|
---|
28 | INCLUDE EXCEPT.INC
|
---|
29 | INCLUDE PMINT.INC
|
---|
30 | INCLUDE RMINT.INC
|
---|
31 | INCLUDE MISC.INC
|
---|
32 | INCLUDE SIGNAL.INC
|
---|
33 | INCLUDE PROCESS.INC
|
---|
34 | INCLUDE CORE.INC
|
---|
35 | INCLUDE OPRINT.INC
|
---|
36 | INCLUDE ERRORS.INC
|
---|
37 |
|
---|
38 | PUBLIC SIG_DELIVER_PENDING, SIG_USER_CALL, SIG_RETURN, SIG_MSG
|
---|
39 | PUBLIC CRIT_ERR_FLAG, SIG_CORE, SIG_VALID, EMERGENCY_TIMER
|
---|
40 | PUBLIC EMERGENCY_FLAG
|
---|
41 | PUBLIC HOOK_INT
|
---|
42 | PUBLIC CLEANUP_SIGNAL
|
---|
43 |
|
---|
44 | LSTACKS = 2 ; Number of local stacks
|
---|
45 | LSTACK_SIZE = 512 ; Size of a local stack (bytes)
|
---|
46 |
|
---|
47 | LSTACK SEGMENT
|
---|
48 | DB LSTACKS DUP (LSTACK_SIZE DUP (?))
|
---|
49 | LSTACK ENDS
|
---|
50 |
|
---|
51 |
|
---|
52 | SV_DATA SEGMENT
|
---|
53 |
|
---|
54 | ;
|
---|
55 | ; Original interrupt 1BH vector
|
---|
56 | ;
|
---|
57 | OLD_BREAK LABEL DWORD
|
---|
58 | OLD_BREAK_OFF DW 0
|
---|
59 | OLD_BREAK_SEG DW 0
|
---|
60 |
|
---|
61 | ;
|
---|
62 | ; This flag is set when cleaning up while executing the critical
|
---|
63 | ; error handler
|
---|
64 | ;
|
---|
65 | CRIT_ERR_FLAG DB FALSE
|
---|
66 |
|
---|
67 | ;
|
---|
68 | ; Timer and counter for emergency exit. EMERGENCY_TIMER set to 18 if
|
---|
69 | ; it is zero when Ctrl-Break is hit. Each timer tick decrements
|
---|
70 | ; EMERGENCY_TIMER. If Ctrl-Break is hit four times while EMERGENCY_TIMER
|
---|
71 | ; is non-zero, EMERGENCY_FLAG will be set to make emx abort.
|
---|
72 | ; EMERGENCY_COUNTER is used for counting Ctrl-Break interrupts after
|
---|
73 | ; setting EMERGENCY_TIMER.
|
---|
74 | ;
|
---|
75 | ; This implementation is simple but does not work correctly if Ctrl-Break
|
---|
76 | ; is hit less than five times in a second, followed by more Ctrl-Break
|
---|
77 | ; interrupts in the next second. A perfect solution involves keeping
|
---|
78 | ; time stamps for the last 4 Ctrl-Break interrupts.
|
---|
79 | ;
|
---|
80 |
|
---|
81 | EMERGENCY_TIMER DB 0
|
---|
82 | EMERGENCY_COUNTER DB 0
|
---|
83 | EMERGENCY_FLAG DB FALSE
|
---|
84 |
|
---|
85 | ;
|
---|
86 | ; Don't use RTEXT, as only function calls 01H..0CH, 59H are allowed.
|
---|
87 | ;
|
---|
88 | $ABORTED DB "Program aborted", CR, LF, "$"
|
---|
89 | $STACKS DB "Out of stacks", CR, LF, "$"
|
---|
90 |
|
---|
91 | $STOPPED_BY BYTE CR, LF, "Process terminated by ", 0
|
---|
92 | $ABNORMAL BYTE CR, LF, "Abnormal program termination", CR, LF, 0
|
---|
93 |
|
---|
94 | $SIG_UNKNOWN BYTE "unknown signal", 0
|
---|
95 |
|
---|
96 | $SIGHUP BYTE "SIGHUP", 0
|
---|
97 | $SIGINT BYTE "SIGINT", 0
|
---|
98 | $SIGQUIT BYTE "SIGQUIT", 0
|
---|
99 | $SIGILL BYTE "SIGILL", 0
|
---|
100 | $SIGTRAP BYTE "SIGTRAP", 0
|
---|
101 | $SIGABRT BYTE "SIGABRT", 0
|
---|
102 | $SIGEMT BYTE "SIGEMT", 0
|
---|
103 | $SIGFPE BYTE "SIGFPE", 0
|
---|
104 | $SIGKILL BYTE "SIGKILL", 0
|
---|
105 | $SIGBUS BYTE "SIGBUS", 0
|
---|
106 | $SIGSEGV BYTE "SIGSEGV", 0
|
---|
107 | $SIGSYS BYTE "SIGSYS", 0
|
---|
108 | $SIGPIPE BYTE "SIGPIPE", 0
|
---|
109 | $SIGALRM BYTE "SIGALRM", 0
|
---|
110 | $SIGTERM BYTE "SIGTERM", 0
|
---|
111 | $SIGUSR1 BYTE "SIGUSR1", 0
|
---|
112 | $SIGUSR2 BYTE "SIGUSR2", 0
|
---|
113 | $SIGCLD BYTE "SIGCLD", 0
|
---|
114 | $SIGBREAK BYTE "SIGBREAK", 0
|
---|
115 | $SIGWINCH BYTE "SIGWINCH", 0
|
---|
116 |
|
---|
117 | TALIGN 2
|
---|
118 | SIG_NAMES WORD $SIG_UNKNOWN, $SIGHUP, $SIGINT, $SIGQUIT ; 0..3
|
---|
119 | WORD $SIGILL, $SIGTRAP, $SIGABRT, $SIGEMT ; 4..7
|
---|
120 | WORD $SIGFPE, $SIGKILL, $SIGBUS, $SIGSEGV ; 8..11
|
---|
121 | WORD $SIGSYS, $SIGPIPE, $SIGALRM, $SIGTERM ; 12..15
|
---|
122 | WORD $SIGUSR1, $SIGUSR2, $SIGCLD ; 16..18
|
---|
123 | WORD $SIG_UNKNOWN, $SIG_UNKNOWN, $SIGBREAK ; 19..21
|
---|
124 | WORD $SIG_UNKNOWN, $SIG_UNKNOWN, $SIG_UNKNOWN ; 22..24
|
---|
125 | WORD $SIG_UNKNOWN, $SIG_UNKNOWN, $SIG_UNKNOWN ; 25..27
|
---|
126 | WORD $SIGWINCH ; 28
|
---|
127 |
|
---|
128 | ;
|
---|
129 | ; Valid signal numbers have a non-FALSE entry in this table.
|
---|
130 | ;
|
---|
131 | SIG_VALID BYTE FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 0..3
|
---|
132 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 4..7
|
---|
133 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 8..11
|
---|
134 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 12..15
|
---|
135 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, FALSE ; 16..19
|
---|
136 | BYTE FALSE, NOT FALSE, FALSE, FALSE ; 20..23
|
---|
137 | BYTE FALSE, FALSE, FALSE, FALSE ; 24..27
|
---|
138 | BYTE NOT FALSE ; 28
|
---|
139 |
|
---|
140 | ;
|
---|
141 | ; If SIG_CORE[signo] is FALSE, no core dump file will be written for
|
---|
142 | ; the signal signo.
|
---|
143 | ;
|
---|
144 |
|
---|
145 | SIG_CORE BYTE FALSE, FALSE, FALSE, NOT FALSE ; 0..3
|
---|
146 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 4..7
|
---|
147 | BYTE NOT FALSE, FALSE, NOT FALSE, NOT FALSE ; 8..11
|
---|
148 | BYTE NOT FALSE, FALSE, FALSE, FALSE ; 12..15
|
---|
149 | BYTE FALSE, FALSE, FALSE, FALSE ; 16..19
|
---|
150 | BYTE FALSE, FALSE, FALSE, FALSE ; 20..23
|
---|
151 | BYTE FALSE, FALSE, FALSE, FALSE ; 24..27
|
---|
152 | BYTE FALSE ; 28
|
---|
153 |
|
---|
154 | ;
|
---|
155 | ; If SIG_DFL_ACTION[signo] is FALSE, the program will be terminated
|
---|
156 | ; for signal signo if SIG_DFL is set. If the table entry is not FALSE,
|
---|
157 | ; the signal will be ignored.
|
---|
158 | ;
|
---|
159 | SIG_DFL_ACTION BYTE FALSE, FALSE, FALSE, FALSE ; 0..3
|
---|
160 | BYTE FALSE, FALSE, FALSE, FALSE ; 4..7
|
---|
161 | BYTE FALSE, FALSE, FALSE, FALSE ; 8..11
|
---|
162 | BYTE FALSE, FALSE, FALSE, FALSE ; 12..15
|
---|
163 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, FALSE ; 16..19
|
---|
164 | BYTE FALSE, FALSE, FALSE, FALSE ; 20..23
|
---|
165 | BYTE FALSE, FALSE, FALSE, FALSE ; 24..27
|
---|
166 | BYTE NOT FALSE ; 28
|
---|
167 |
|
---|
168 | ;
|
---|
169 | ; If SIG_IGN_ACTION[signo] is FALSE, the program will be terminated
|
---|
170 | ; for signal signo if SIG_IGN is set. If the entry is not FALSE, the
|
---|
171 | ; signal will be ignored.
|
---|
172 | ;
|
---|
173 | SIG_IGN_ACTION BYTE FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 0..3
|
---|
174 | BYTE FALSE, FALSE, FALSE, FALSE ; 4..7
|
---|
175 | BYTE FALSE, FALSE, FALSE, FALSE ; 8..11
|
---|
176 | BYTE FALSE, NOT FALSE, NOT FALSE, FALSE ; 12..15
|
---|
177 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, FALSE ; 16..19
|
---|
178 | BYTE FALSE, NOT FALSE, FALSE, FALSE ; 20..23
|
---|
179 | BYTE FALSE, FALSE, FALSE, FALSE ; 24..27
|
---|
180 | BYTE NOT FALSE ; 28
|
---|
181 |
|
---|
182 | ;
|
---|
183 | ; If SIG_FUN_ACTION[signo] is FALSE, the program will be terminated
|
---|
184 | ; for after calling the signal handler for signal signo. If the entry
|
---|
185 | ; is not FALSE, the program will be continued.
|
---|
186 | ;
|
---|
187 | SIG_FUN_ACTION BYTE FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 0..3
|
---|
188 | BYTE FALSE, FALSE, FALSE, FALSE ; 4..7
|
---|
189 | BYTE FALSE, FALSE, FALSE, FALSE ; 8..11
|
---|
190 | BYTE FALSE, NOT FALSE, NOT FALSE, NOT FALSE ; 12..15
|
---|
191 | BYTE NOT FALSE, NOT FALSE, NOT FALSE, FALSE ; 16..19
|
---|
192 | BYTE FALSE, NOT FALSE, FALSE, FALSE ; 20..23
|
---|
193 | BYTE FALSE, FALSE, FALSE, FALSE ; 24..27
|
---|
194 | BYTE NOT FALSE ; 28
|
---|
195 |
|
---|
196 | SV_DATA ENDS
|
---|
197 |
|
---|
198 |
|
---|
199 | SV_CODE SEGMENT
|
---|
200 |
|
---|
201 | ;
|
---|
202 | ; Check for pending signals
|
---|
203 | ;
|
---|
204 | ASSUME DS:SV_DATA
|
---|
205 | ASSUME BP:PTR ISTACKFRAME
|
---|
206 | SIG_DELIVER_PENDING PROC NEAR
|
---|
207 | MOV BX, PROCESS_PTR ; Current process
|
---|
208 | CMP BX, NO_PROCESS ; In user code?
|
---|
209 | JE SHORT SDP_RET ; No -> no signals
|
---|
210 | ASSUME BX:PTR PROCESS
|
---|
211 | ;
|
---|
212 | ; Check signals only if called from user code [0.8b]
|
---|
213 | ;
|
---|
214 | TEST I_CS, 3 ; Called from user code?
|
---|
215 | JZ SHORT SDP_RET ; No -> no signals
|
---|
216 | ;
|
---|
217 | ; Start of Critical section
|
---|
218 | ;
|
---|
219 | CLI
|
---|
220 | MOV EAX, [BX].P_SIG_BLOCKED ; Get set of pending,
|
---|
221 | NOT EAX ; unblocked signals
|
---|
222 | AND EAX, [BX].P_SIG_PENDING
|
---|
223 | JZ SHORT SDP_RET_STI ; No signals -> just return
|
---|
224 | ;
|
---|
225 | ; Find a pending signal, reset its `signal pending' bit and
|
---|
226 | ; fetch the signal handler
|
---|
227 | ;
|
---|
228 | BSF EDX, EAX ; Find first bit
|
---|
229 | JZ SHORT SDP_RET_STI ; Cannot happen
|
---|
230 | BTR [BX].P_SIG_PENDING, EDX ; Reset `signal pending' bit
|
---|
231 | MOV SI, DX
|
---|
232 | SHL SI, 2
|
---|
233 | MOV EAX, [BX].P_SIG_HANDLERS[SI] ; Get address
|
---|
234 | CMP EAX, SIG_IGN ; Ignore signal?
|
---|
235 | JE SHORT SDP_IGNORE ; Yes -> see table
|
---|
236 | CMP EAX, SIG_DFL ; Default handler?
|
---|
237 | JNE SDP_USER ; No -> call signal handler
|
---|
238 | ;
|
---|
239 | ; SIG_DFL
|
---|
240 | ;
|
---|
241 | STI ; End of critical section
|
---|
242 | CMP EDX, SIGTERM ; SIGTERM?
|
---|
243 | JE SHORT SDP_SIGTERM ; Yes -> terminate program
|
---|
244 | CMP SIG_DFL_ACTION[EDX], FALSE ; Ingore signal?
|
---|
245 | JNE SHORT SDP_RET ; Yes -> ignore
|
---|
246 | JMP SHORT SDP_TERM ; No -> terminate process
|
---|
247 |
|
---|
248 | SDP_RET_STI: STI ; End of critical section
|
---|
249 | SDP_RET: RET
|
---|
250 |
|
---|
251 | ;
|
---|
252 | ; SIG_IGN
|
---|
253 | ;
|
---|
254 | SDP_IGNORE: STI ; End of critical section
|
---|
255 | CMP SIG_IGN_ACTION[EDX], FALSE ; Ignore signal?
|
---|
256 | JNE SHORT SDP_RET
|
---|
257 | ;
|
---|
258 | ; Terminate / abort process due to signal EDX
|
---|
259 | ;
|
---|
260 | ASSUME BX:PTR PROCESS
|
---|
261 | SDP_TERM: MOV EAX, EDX
|
---|
262 | CALL SIG_MSG
|
---|
263 | TEST [BX].P_FLAGS, PF_NO_CORE
|
---|
264 | JNZ SHORT SDP_TERM_2
|
---|
265 | CMP EAX, SIGNALS
|
---|
266 | JAE SHORT SDP_TERM_2
|
---|
267 | CMP SIG_CORE[EAX], FALSE
|
---|
268 | JE SHORT SDP_TERM_2
|
---|
269 | CALL CORE_REGS_I
|
---|
270 | CALL CORE_DUMP
|
---|
271 | SDP_TERM_2:
|
---|
272 | ;
|
---|
273 | ; Default signal handler for SIGTERM
|
---|
274 | ;
|
---|
275 | SDP_SIGTERM: MOV AX, 4C03H ; exit(3)
|
---|
276 | INT 21H
|
---|
277 |
|
---|
278 | ;
|
---|
279 | ; Call user specified signal handler
|
---|
280 | ;
|
---|
281 | SDP_USER: MOV ECX, FALSE ; Not a trap
|
---|
282 | CALL SIG_USER_CALL
|
---|
283 | JMP SDP_RET
|
---|
284 |
|
---|
285 | ASSUME BX:NOTHING
|
---|
286 | ASSUME BP:NOTHING
|
---|
287 | SIG_DELIVER_PENDING ENDP
|
---|
288 |
|
---|
289 | ;
|
---|
290 | ; Display "Stopped by" message
|
---|
291 | ;
|
---|
292 | ; In: EAX Signal number
|
---|
293 | ;
|
---|
294 | ASSUME DS:SV_DATA
|
---|
295 | SIG_MSG PROC NEAR
|
---|
296 | LEA EDX, $ABNORMAL
|
---|
297 | CMP EAX, SIGABRT
|
---|
298 | JE SHORT SIG_MSG_1
|
---|
299 | LEA EDX, $STOPPED_BY
|
---|
300 | CALL OTEXT
|
---|
301 | LEA EDX, $SIG_UNKNOWN
|
---|
302 | CMP EAX, SIGNALS
|
---|
303 | JAE SHORT SIG_MSG_1
|
---|
304 | MOVZX EDX, SIG_NAMES[EAX*2]
|
---|
305 | SIG_MSG_1: CALL OTEXT
|
---|
306 | CALL OCRLF
|
---|
307 | RET
|
---|
308 | SIG_MSG ENDP
|
---|
309 |
|
---|
310 |
|
---|
311 | ;
|
---|
312 | ; Call user specified signal handler on return from interrupt or exception.
|
---|
313 | ;
|
---|
314 | ; In: EAX Address of signal handler
|
---|
315 | ; EDX Signal number
|
---|
316 | ; ECX Non-FALSE if signal generated by an exception
|
---|
317 | ; BX Pointer to process table entry
|
---|
318 | ;
|
---|
319 | ; We copy the saved registers to the interrupted program's stack
|
---|
320 | ; to save supervisor stack space and to enable the program to reclaim
|
---|
321 | ; the stack space by resetting the stack pointer: setjmp/longjmp.
|
---|
322 | ;
|
---|
323 | ; This function reenables interrupts as soon as possible. It is
|
---|
324 | ; assumed that interrupts are disabled when entering this function.
|
---|
325 | ;
|
---|
326 | SUC_TRAP EQU (DWORD PTR [BP-1*4])
|
---|
327 | SUC_SIGNO EQU (DWORD PTR [BP-2*4])
|
---|
328 | SUC_HANDLER EQU (DWORD PTR [BP-3*4])
|
---|
329 | SUC_MASK EQU (DWORD PTR [BP-4*4])
|
---|
330 | SUC_FLAGS EQU (DWORD PTR [BP-5*4])
|
---|
331 |
|
---|
332 | ASSUME DS:SV_DATA
|
---|
333 | ASSUME BX:PTR PROCESS
|
---|
334 | ASSUME BP:PTR ISTACKFRAME
|
---|
335 | SIG_USER_CALL PROC NEAR
|
---|
336 | MOV DI, BP
|
---|
337 | ASSUME DI:PTR ISTACKFRAME
|
---|
338 | PUSH BP
|
---|
339 | MOV BP, SP
|
---|
340 | ASSUME BP:NOTHING
|
---|
341 | SUB SP, 5 * 4
|
---|
342 | MOV SUC_HANDLER, EAX
|
---|
343 | MOV SUC_TRAP, ECX
|
---|
344 | MOV SUC_SIGNO, EDX
|
---|
345 | ;
|
---|
346 | ; Compute and set new signal mask
|
---|
347 | ;
|
---|
348 | MOV SI, DX ; Signal number
|
---|
349 | SHL SI, 2
|
---|
350 | MOV EAX, [BX].P_SIG_BLOCKED
|
---|
351 | MOV SUC_MASK, EAX ; Previous signal mask
|
---|
352 | TEST [BX].P_SA_FLAGS[SI], SA_SYSV
|
---|
353 | JNZ SHORT SUC_SYSV
|
---|
354 | BTS EAX, EDX ; Block the signal
|
---|
355 | TEST [BX].P_SA_FLAGS[SI], SA_ACK
|
---|
356 | JNZ SHORT SUC_SETMASK
|
---|
357 | OR EAX, [BX].P_SA_MASK[SI] ; Block signals in sa_mask
|
---|
358 | JMP SHORT SUC_SETMASK
|
---|
359 |
|
---|
360 | SUC_SYSV: MOV [BX].P_SIG_HANDLERS[SI], SIG_DFL
|
---|
361 | JMP SHORT SUC_1
|
---|
362 |
|
---|
363 | SUC_SETMASK: MOV [BX].P_SIG_BLOCKED, EAX
|
---|
364 | SUC_1: MOV EAX, [BX].P_SA_FLAGS[SI]
|
---|
365 | STI ; Enable interrupts
|
---|
366 | ;
|
---|
367 | ; Compute sa_flags (set SA_TRAP if signal generated by an exception)
|
---|
368 | ;
|
---|
369 | AND EAX, NOT SA_TRAP
|
---|
370 | CMP SUC_TRAP, FALSE
|
---|
371 | JE SHORT SUC_2
|
---|
372 | OR EAX, SA_TRAP
|
---|
373 | SUC_2: MOV SUC_FLAGS, EAX
|
---|
374 | ;
|
---|
375 | ; Copy registers to the stack
|
---|
376 | ;
|
---|
377 | MOV EAX, SS:[DI].IS_ESP ; User stack
|
---|
378 | SUB EAX, I_REG_DWORDS * 4 ; Allocate stack frame
|
---|
379 | MOV SS:[DI].IS_ESP, EAX ; and adjust ESP
|
---|
380 | PUSH DS ; Save DS
|
---|
381 | PUSH EDI ; Save EDI
|
---|
382 | MOV ECX, I_REG_DWORDS ; Copy saved registers
|
---|
383 | PUSH SS ; Copy from supervisor stack
|
---|
384 | POP DS
|
---|
385 | ASSUME DS:NOTHING
|
---|
386 | MOVZX ESI, DI ; Pointer to stack frame
|
---|
387 | MOV ES, SS:[DI].IS_SS ; Access program's stack
|
---|
388 | MOV EDI, EAX
|
---|
389 | CLD
|
---|
390 | REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]
|
---|
391 | POP EDI ; Restore EDI
|
---|
392 | POP DS ; Restore DS
|
---|
393 | ASSUME DS:SV_DATA
|
---|
394 | ;
|
---|
395 | ; Then, build a stack frame for the signal handler and return.
|
---|
396 | ; Problem: on return from the signal handler, it should restore all
|
---|
397 | ; registers from the stack. Where shall we put that code?
|
---|
398 | ;
|
---|
399 | ; 1. put it into the startup code (at a fixed location or introduce
|
---|
400 | ; a system function called by startup code for telling the supervisor
|
---|
401 | ; where that code resides)
|
---|
402 | ;
|
---|
403 | ; 2. put it into the application's stack
|
---|
404 | ;
|
---|
405 | ; 3. put it into the supervisor. The signal handler must return to the
|
---|
406 | ; supervisor. This is tricky, as the signal handler normally returns
|
---|
407 | ; with a *near* `RET', which doesn't change privilege levels. Here's
|
---|
408 | ; the trick: The `RET' instruction must generate an exception. There's
|
---|
409 | ; little choice: Either a segmentation fault (EIP beyond CS limit)
|
---|
410 | ; or a page fault (page not present). For the second alternative,
|
---|
411 | ; we would have to reserve a page *inside* the code segment for
|
---|
412 | ; that purpose to avoid a segmentation fault and we wouldn't know why
|
---|
413 | ; and from where we got to that address. Therefore, we'll return
|
---|
414 | ; to an address outside the code segment. CS:EIP will point to the
|
---|
415 | ; offending instruction (`RET') and SS:ESP will pointer to the address
|
---|
416 | ; we chose for that purpose. We assume that all signal handlers return
|
---|
417 | ; by means of `RET', not by `RET n' or `JMP'. For additional security,
|
---|
418 | ; we put a signature word onto the stack.
|
---|
419 | ;
|
---|
420 | ; This is the stack frame we need:
|
---|
421 | ;
|
---|
422 | ; +-------------------------------------------+
|
---|
423 | ; | |
|
---|
424 | ; | Saved registers of interrupted program |
|
---|
425 | ; | (see PMINT.INC for details) |
|
---|
426 | ; | |
|
---|
427 | ; +-------------------------------------------+
|
---|
428 | ; | |
|
---|
429 | ; | SIGFRAME: |
|
---|
430 | ; | - Old signal mask |
|
---|
431 | ; | - sa_flags |
|
---|
432 | ; | - Signal number |
|
---|
433 | ; | - Signature word |
|
---|
434 | ; | - Signal number (signal handler argument) |
|
---|
435 | ; | - Our special EIP |
|
---|
436 | ; | |
|
---|
437 | ; ESP-> +-------------------------------------------+
|
---|
438 | ;
|
---|
439 | ; The signal number is stored twice as the signal handler may
|
---|
440 | ; change its argument.
|
---|
441 | ;
|
---|
442 | MOV ESI, SS:[DI].IS_ESP ; Now points to saved regs
|
---|
443 | SUB ESI, SIZE SIGFRAME ; Push SIGFRAME
|
---|
444 | MOV SS:[DI].IS_ESP, ESI ; Adjust ESP
|
---|
445 | ASSUME ESI:NEAR32 PTR SIGFRAME
|
---|
446 | MOV ES:[ESI].SF_EIP, SIG_EIP ; Our special EIP
|
---|
447 | MOV EAX, SUC_SIGNO
|
---|
448 | MOV ES:[ESI].SF_ARG, EAX ; Signal number (arg)
|
---|
449 | MOV ES:[ESI].SF_SIGNO, EAX ; Signal number
|
---|
450 | MOV ES:[ESI].SF_SIGNATURE, SIG_SIGNATURE ; Signature
|
---|
451 | MOV EAX, SUC_MASK
|
---|
452 | MOV ES:[ESI].SF_MASK, EAX ; Old signal mask
|
---|
453 | MOV EAX, SUC_FLAGS
|
---|
454 | MOV ES:[ESI].SF_FLAGS, EAX ; sa_flags
|
---|
455 | ASSUME ESI:NOTHING
|
---|
456 | MOV EAX, SUC_HANDLER
|
---|
457 | MOV SS:[DI].IS_EIP, EAX ; Address of signal handler
|
---|
458 | CALL BREAK_AFTER_IRET ; Allow debugging signals
|
---|
459 | MOV SP, BP
|
---|
460 | POP BP
|
---|
461 | RET ; Done
|
---|
462 | ASSUME BX:NOTHING
|
---|
463 | ASSUME DI:NOTHING
|
---|
464 | SIG_USER_CALL ENDP
|
---|
465 |
|
---|
466 |
|
---|
467 | ;
|
---|
468 | ; Return from signal handler
|
---|
469 | ;
|
---|
470 | ; Remove our special stack frame and restore registers from user program's
|
---|
471 | ; stack
|
---|
472 | ;
|
---|
473 | ; In: ES:ESI Pointer to special stack frame
|
---|
474 | ;
|
---|
475 | ASSUME DS:SV_DATA
|
---|
476 | ASSUME BP:PTR ISTACKFRAME
|
---|
477 | ASSUME ESI:NEAR32 PTR SIGFRAME
|
---|
478 | SIG_RETURN PROC NEAR
|
---|
479 | MOV BX, PROCESS_PTR ; Current process
|
---|
480 | CMP BX, NO_PROCESS ; No process?
|
---|
481 | JE SIGRET_TERMINATE ; Yes -> cannot happen
|
---|
482 | ASSUME BX:PTR PROCESS
|
---|
483 |
|
---|
484 | MOV EAX, ES:[ESI].SF_SIGNO ; Get the signal number
|
---|
485 | CMP EAX, SIGNALS ; Signal number out of range?
|
---|
486 | JAE SHORT SIGRET_TERMINATE ; Yes -> terminate process
|
---|
487 | MOV ECX, ES:[ESI].SF_FLAGS ; Saved sa_flags
|
---|
488 | TEST ECX, SA_TRAP ; Generated by exception?
|
---|
489 | JZ SHORT SIGRET_1 ; No -> continue
|
---|
490 | CMP SIG_FUN_ACTION[EAX], FALSE ; Continue program?
|
---|
491 | JE SHORT SIGRET_TERMINATE ; No -> terminate process
|
---|
492 | SIGRET_1: TEST ECX, SA_SYSV OR SA_ACK
|
---|
493 | JNZ SHORT SIGRET_REGS ; Don't restore signal mask
|
---|
494 | MOV EAX, ES:[ESI].SF_MASK ; Restore signal mask
|
---|
495 | MOV [BX].P_SIG_BLOCKED, EAX
|
---|
496 |
|
---|
497 | SIGRET_REGS: PUSH DS ; Save DS
|
---|
498 | ADD ESI, SIZE SIGFRAME ; Skip special stack frame
|
---|
499 | ASSUME ESI:NOTHING
|
---|
500 | MOV EDI, EBP ; Copy to supervisor stack
|
---|
501 | PUSH SS
|
---|
502 | POP ES
|
---|
503 | MOV DS, I_SS ; Copy from user stack segment
|
---|
504 | ASSUME DS:NOTHING
|
---|
505 | CLD
|
---|
506 | MOV ECX, I_REG_DWORDS ; Copy saved registers
|
---|
507 | REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]
|
---|
508 | POP DS
|
---|
509 | ASSUME DS:SV_DATA
|
---|
510 | MOV I_ESP, ESI ; Adjust stack pointer
|
---|
511 | CALL BREAK_AFTER_IRET ; Continue debugging
|
---|
512 | JMP EXCEPT_RET ; Return to interrupted program
|
---|
513 |
|
---|
514 | SIGRET_TERMINATE:
|
---|
515 | RET ; Continue exception handler
|
---|
516 | ASSUME BX:NOTHING
|
---|
517 | ASSUME BP:NOTHING
|
---|
518 | SIG_RETURN ENDP
|
---|
519 |
|
---|
520 |
|
---|
521 |
|
---|
522 | ;
|
---|
523 | ; Implementation of __signal()
|
---|
524 | ;
|
---|
525 | ; In: EAX Signal number
|
---|
526 | ; EDX Signal handler
|
---|
527 | ; DI Pointer to process table entry
|
---|
528 | ;
|
---|
529 | ; Out: EAX Previous handler or SIG_ERR
|
---|
530 | ;
|
---|
531 | ISA EQU (SIGACTION PTR [BP-1*SIZE SIGACTION])
|
---|
532 | OSA EQU (SIGACTION PTR [BP-2*SIZE SIGACTION])
|
---|
533 |
|
---|
534 | ASSUME DS:SV_DATA
|
---|
535 | ASSUME DI:PTR PROCESS
|
---|
536 | TALIGN 4
|
---|
537 | DO_SIGNAL PROC NEAR
|
---|
538 | PUSH BP
|
---|
539 | MOV BP, SP
|
---|
540 | SUB SP, 2 * SIZE SIGACTION
|
---|
541 | MOV ISA.SA_MASK, 0
|
---|
542 | MOV ISA.SA_HANDLER, EDX
|
---|
543 | ;
|
---|
544 | ; Set sa_flags according to __uflags()
|
---|
545 | ;
|
---|
546 | MOV EDX, [DI].P_UFLAGS
|
---|
547 | AND EDX, UF_SIG_MODEL
|
---|
548 | MOV ECX, SA_ACK
|
---|
549 | CMP EDX, UF_SIG_EMX
|
---|
550 | JE SHORT SIGNAL_1
|
---|
551 | MOV ECX, SA_SYSV
|
---|
552 | CMP EDX, UF_SIG_SYSV
|
---|
553 | JE SHORT SIGNAL_1
|
---|
554 | MOV ECX, 0
|
---|
555 | SIGNAL_1: MOV ISA.SA_FLAGS, ECX
|
---|
556 | ;
|
---|
557 | ; Call __sigaction()
|
---|
558 | ;
|
---|
559 | PUSH SS
|
---|
560 | POP ES
|
---|
561 | LEA EDX, ISA
|
---|
562 | LEA EBX, OSA
|
---|
563 | CALL DO_SIGACTION
|
---|
564 | OR EAX, EAX
|
---|
565 | MOV EAX, SIG_ERR
|
---|
566 | JNZ SHORT SIGNAL_RET
|
---|
567 | MOV EAX, OSA.SA_HANDLER
|
---|
568 | SIGNAL_RET: MOV SP, BP
|
---|
569 | POP BP
|
---|
570 | RET
|
---|
571 | ASSUME DI:NOTHING
|
---|
572 | DO_SIGNAL ENDP
|
---|
573 |
|
---|
574 |
|
---|
575 | ;
|
---|
576 | ; This function implements __sigaction()
|
---|
577 | ;
|
---|
578 | ; In: EAX Signal number
|
---|
579 | ; ES:EDX Pointer to sigaction structure (input)
|
---|
580 | ; ES:EBX Pointer to sigaction structure (output)
|
---|
581 | ;
|
---|
582 | ; Out: EAX errno (0 if no error)
|
---|
583 | ;
|
---|
584 | SIGA_O_HANDLER EQU (DWORD PTR [BP-1*4])
|
---|
585 | SIGA_O_MASK EQU (DWORD PTR [BP-2*4])
|
---|
586 | SIGA_O_FLAGS EQU (DWORD PTR [BP-3*4])
|
---|
587 | SIGA_OACT EQU (DWORD PTR [BP-4*4])
|
---|
588 | SIGA_SIGNO EQU (DWORD PTR [BP-5*4])
|
---|
589 |
|
---|
590 | ASSUME DS:SV_DATA
|
---|
591 | TALIGN 4
|
---|
592 | ASSUME DI:PTR PROCESS
|
---|
593 | DO_SIGACTION PROC NEAR
|
---|
594 | PUSH BP
|
---|
595 | MOV BP, SP
|
---|
596 | SUB SP, 5 * 4
|
---|
597 | MOV SIGA_SIGNO, EAX
|
---|
598 | MOV SIGA_OACT, EBX
|
---|
599 | CMP EAX, SIGNALS ; Valid signal number?
|
---|
600 | JAE SIGACT_ERROR ; No -> failure
|
---|
601 | CMP SIG_VALID[EAX], FALSE
|
---|
602 | JE SIGACT_ERROR ; No -> failure
|
---|
603 | MOV BX, AX
|
---|
604 | SHL BX, 2
|
---|
605 | ;
|
---|
606 | ; Save the current action (in case both pointers point to the same object).
|
---|
607 | ;
|
---|
608 | CLI ; Start of critical section
|
---|
609 | MOV EAX, [DI].P_SIG_HANDLERS[BX]
|
---|
610 | MOV SIGA_O_HANDLER, EAX
|
---|
611 | MOV EAX, [DI].P_SA_MASK[BX]
|
---|
612 | MOV SIGA_O_MASK, EAX
|
---|
613 | MOV EAX, [DI].P_SA_FLAGS[BX]
|
---|
614 | MOV SIGA_O_FLAGS, EAX
|
---|
615 | ;
|
---|
616 | ; Set the new action if present
|
---|
617 | ;
|
---|
618 | TEST EDX, EDX
|
---|
619 | JZ SHORT SIGACT_NO_INPUT
|
---|
620 | CMP SIGA_SIGNO, SIGKILL ; Cannot modify SIGKILL
|
---|
621 | JE SIGACT_ERROR_STI
|
---|
622 | ASSUME EDX:NEAR32 PTR SIGACTION
|
---|
623 | MOV EAX, ES:[EDX].SA_MASK
|
---|
624 | SHL EAX, 1
|
---|
625 | AND EAX, SIG_BLOCK_MASK
|
---|
626 | MOV [DI].P_SA_MASK[BX], EAX
|
---|
627 | MOV ECX, ES:[EDX].SA_FLAGS
|
---|
628 | MOV [DI].P_SA_FLAGS[BX], ECX
|
---|
629 | MOV EAX, ES:[EDX].SA_HANDLER
|
---|
630 | MOV [DI].P_SIG_HANDLERS[BX], EAX
|
---|
631 | ASSUME EDX:NOTHING
|
---|
632 | ;
|
---|
633 | ; Discard a pending signal when setting the handler to SIG_IGN or,
|
---|
634 | ; if the default action is ignoring the signal, to SIG_DFL.
|
---|
635 | ;
|
---|
636 | CMP EAX, SIG_DFL
|
---|
637 | JE SHORT SIGACT_DISCARD
|
---|
638 | CMP EAX, SIG_IGN
|
---|
639 | JE SHORT SIGACT_NO_DISCARD
|
---|
640 | SIGACT_DISCARD: MOV EAX, SIGA_SIGNO
|
---|
641 | BTR [DI].P_SIG_PENDING, EAX
|
---|
642 | SIGACT_NO_DISCARD:
|
---|
643 | ;
|
---|
644 | ; Store the previous action if OACT is not NULL
|
---|
645 | ;
|
---|
646 | SIGACT_NO_INPUT:STI ; End of critical section
|
---|
647 | MOV ESI, SIGA_OACT
|
---|
648 | TEST ESI, ESI
|
---|
649 | JZ SHORT SIGACT_NO_OUTPUT
|
---|
650 | ASSUME ESI:NEAR32 PTR SIGACTION
|
---|
651 | MOV EAX, SIGA_O_HANDLER
|
---|
652 | MOV ES:[ESI].SA_HANDLER, EAX
|
---|
653 | MOV EAX, SIGA_O_MASK
|
---|
654 | SHR EAX, 1
|
---|
655 | MOV ES:[ESI].SA_MASK, EAX
|
---|
656 | MOV EAX, SIGA_O_FLAGS
|
---|
657 | MOV ES:[ESI].SA_FLAGS, EAX
|
---|
658 | ASSUME ESI:NOTHING
|
---|
659 | SIGACT_NO_OUTPUT:
|
---|
660 | XOR EAX, EAX
|
---|
661 | SIGACT_RET: MOV SP, BP
|
---|
662 | POP BP
|
---|
663 | RET
|
---|
664 |
|
---|
665 | SIGACT_ERROR_STI:
|
---|
666 | STI
|
---|
667 | SIGACT_ERROR: MOV EAX, EINVAL
|
---|
668 | JMP SIGACT_RET
|
---|
669 | ASSUME DI:NOTHING
|
---|
670 | DO_SIGACTION ENDP
|
---|
671 |
|
---|
672 |
|
---|
673 | SV_CODE ENDS
|
---|
674 |
|
---|
675 |
|
---|
676 | INIT_CODE SEGMENT
|
---|
677 |
|
---|
678 | ASSUME CS:INIT_CODE, DS:NOTHING
|
---|
679 |
|
---|
680 | ;
|
---|
681 | ; Hook BIOS interrupt: 1BH (Ctrl-Break)
|
---|
682 | ; Hook DOS interrupts: 23H (Ctrl-C) and 24H (critical error)
|
---|
683 | ;
|
---|
684 | ASSUME DS:SV_DATA
|
---|
685 | HOOK_INT PROC NEAR
|
---|
686 | MOV AL, 1BH ; Hook interrupt 1BH
|
---|
687 | LEA DX, CNTRL_BREAK ; (Ctrl-Break)
|
---|
688 | CALL SET_RM_INT
|
---|
689 | MOV OLD_BREAK_OFF, DX ; Save old Ctrl-Break
|
---|
690 | MOV OLD_BREAK_SEG, AX ; handler vector
|
---|
691 | MOV AL, 23H ; Hook interrupt 23H
|
---|
692 | LEA DX, CNTRL_C ; (Ctrl-C)
|
---|
693 | CALL SET_RM_INT
|
---|
694 | MOV AL, 24H ; Hook interrupt 24H
|
---|
695 | LEA DX, CRIT_ERROR ; (critical error)
|
---|
696 | CALL SET_RM_INT
|
---|
697 | MOV CS:OLD_CRIT_OFF, DX ; Save old critical error
|
---|
698 | MOV CS:OLD_CRIT_SEG, AX ; handler vector
|
---|
699 | RET
|
---|
700 | HOOK_INT ENDP
|
---|
701 |
|
---|
702 | ;
|
---|
703 | ; Remove interrupt hooks
|
---|
704 | ;
|
---|
705 | ASSUME DS:SV_DATA
|
---|
706 | CLEANUP_SIGNAL PROC NEAR
|
---|
707 | MOV DX, OLD_BREAK_OFF
|
---|
708 | MOV BX, OLD_BREAK_SEG
|
---|
709 | OR BX, BX
|
---|
710 | JZ SHORT CS_1
|
---|
711 | MOV AL, 1BH
|
---|
712 | CALL RESTORE_RM_INT
|
---|
713 | CS_1: RET
|
---|
714 | CLEANUP_SIGNAL ENDP
|
---|
715 |
|
---|
716 |
|
---|
717 | ;
|
---|
718 | ; Ctrl-Break interrupt
|
---|
719 | ;
|
---|
720 | ; This interrupt is issued by BIOS when Ctrl-Break is pressed.
|
---|
721 | ;
|
---|
722 | ; Note: INT 23H also raises SIGINT. To avoid SIGINT being raised twice,
|
---|
723 | ; CNTRL_BREAK returns instead of jumping to the original vector.
|
---|
724 | ; This way, DOS doesn't get informed about Ctrl-Break.
|
---|
725 | ;
|
---|
726 | ASSUME DS:NOTHING
|
---|
727 | CNTRL_BREAK PROC FAR
|
---|
728 | CALL LOCAL_STACK
|
---|
729 | PUSHAD
|
---|
730 | PUSH DS ; Save all registers
|
---|
731 | MOV AX, SV_DATA
|
---|
732 | MOV DS, AX
|
---|
733 | ASSUME DS:SV_DATA
|
---|
734 | ;
|
---|
735 | ; Check for emergency exit (Ctrl-Break five times in one second)
|
---|
736 | ;
|
---|
737 | CMP EMERGENCY_TIMER, 0 ; Timer running?
|
---|
738 | JE SHORT CB_EMGCY_START ; No -> start timer
|
---|
739 | INC EMERGENCY_COUNTER ; Increment counter
|
---|
740 | CMP EMERGENCY_COUNTER, 4 ; 5 Ctrl-Break in one second?
|
---|
741 | JNE SHORT CB_EMGCY_DONE ; No -> skip
|
---|
742 | MOV EMERGENCY_FLAG, NOT FALSE ; Yes -> set flag
|
---|
743 | JMP SHORT CB_EMGCY_DONE
|
---|
744 |
|
---|
745 | CB_EMGCY_START: MOV EMERGENCY_COUNTER, 0 ; Initialize counter
|
---|
746 | MOV EMERGENCY_TIMER, 18 ; Set timer to one second
|
---|
747 | CB_EMGCY_DONE:
|
---|
748 | ;
|
---|
749 | ; Generate SIGINT if appropriate
|
---|
750 | ;
|
---|
751 | MOV BX, PROCESS_SIG ; Get current process
|
---|
752 | CMP BX, NO_PROCESS ; In supervisor?
|
---|
753 | JE SHORT CB_DONE ; Yes -> ignore
|
---|
754 | ASSUME BX:PTR PROCESS
|
---|
755 | BTS [BX].P_SIG_PENDING, SIGINT ; Generate SIGINT
|
---|
756 | CB_DONE: POP DS ; Restore registers
|
---|
757 | ASSUME DS:NOTHING
|
---|
758 | POPAD
|
---|
759 | ASSUME BX:NOTHING
|
---|
760 | CALL RESTORE_STACK ; Switch back to original stack
|
---|
761 | IRET ; Return
|
---|
762 | CNTRL_BREAK ENDP
|
---|
763 |
|
---|
764 | ;
|
---|
765 | ; Ctrl-C interrupt
|
---|
766 | ;
|
---|
767 | ASSUME DS:NOTHING
|
---|
768 | CNTRL_C PROC FAR
|
---|
769 | CALL LOCAL_STACK ; Switch to local stack
|
---|
770 | PUSHAD
|
---|
771 | PUSH DS ; Save all registers
|
---|
772 | PUSH ES
|
---|
773 | PUSH FS
|
---|
774 | PUSH GS
|
---|
775 | MOV AX, SV_DATA
|
---|
776 | MOV DS, AX
|
---|
777 | ASSUME DS:SV_DATA
|
---|
778 | CMP CRIT_ERR_FLAG, FALSE ; Critical error?
|
---|
779 | JNE SHORT CC_QUIT ; Yes -> just quit
|
---|
780 | MOV BX, PROCESS_SIG ; Get current process
|
---|
781 | CMP BX, NO_PROCESS ; In supervisor?
|
---|
782 | JE SHORT CC_QUIT ; Yes -> just quit
|
---|
783 | ASSUME BX:PTR PROCESS
|
---|
784 | BTS [BX].P_SIG_PENDING, SIGINT ; Generate SIGINT
|
---|
785 | ASSUME BX:NOTHING
|
---|
786 | POP GS
|
---|
787 | POP FS
|
---|
788 | POP ES
|
---|
789 | POP DS ; Restore registers
|
---|
790 | POPAD
|
---|
791 | NOP ; Avoid 386 bug
|
---|
792 | CALL RESTORE_STACK ; Switch back to original stack
|
---|
793 | IRET
|
---|
794 |
|
---|
795 | CC_QUIT: CALL CLEANUP ; Cleanup for exit
|
---|
796 | POP GS
|
---|
797 | POP FS
|
---|
798 | POP ES
|
---|
799 | POP DS ; Restore registers
|
---|
800 | POPAD
|
---|
801 | NOP ; Avoid 386 bug
|
---|
802 | CALL RESTORE_STACK ; Switch back to original stack
|
---|
803 | MOV AX, 4C03H ; End program, errorlevel 3
|
---|
804 | INT 21H
|
---|
805 | JMP SHORT $ ; Never reached
|
---|
806 | CNTRL_C ENDP
|
---|
807 |
|
---|
808 |
|
---|
809 |
|
---|
810 | OLD_CRIT LABEL DWORD
|
---|
811 | OLD_CRIT_OFF DW ?
|
---|
812 | OLD_CRIT_SEG DW ?
|
---|
813 |
|
---|
814 | ;
|
---|
815 | ; Critical error handler
|
---|
816 | ;
|
---|
817 | ASSUME DS:NOTHING
|
---|
818 | CRIT_ERROR PROC FAR
|
---|
819 | PUSHF ; Call original handler
|
---|
820 | CALL OLD_CRIT ; (it's an interrupt routine)
|
---|
821 | CMP AL, 2 ; Abort the program?
|
---|
822 | JNE SHORT CRIT_RET ; No -> skip
|
---|
823 | CALL LOCAL_STACK ; Switch to local stack
|
---|
824 | PUSHAD ; Save registers
|
---|
825 | PUSH DS
|
---|
826 | PUSH ES
|
---|
827 | MOV AX, SV_DATA
|
---|
828 | MOV DS, AX ; Setup DS
|
---|
829 | ASSUME DS:SV_DATA
|
---|
830 | MOV CRIT_ERR_FLAG, NOT FALSE ; Avoid some DOS calls
|
---|
831 | CALL CLEANUP ; Cleanup before return to DOS
|
---|
832 | LEA DX, $ABORTED
|
---|
833 | MOV AH, 09H ; Display message
|
---|
834 | INT 21H
|
---|
835 | POP ES ; Restore registers
|
---|
836 | POP DS
|
---|
837 | ASSUME DS:NOTHING
|
---|
838 | POPAD
|
---|
839 | CALL RESTORE_STACK ; Switch to original stack
|
---|
840 | CRIT_RET: IRET ; Return
|
---|
841 | CRIT_ERROR ENDP
|
---|
842 |
|
---|
843 | ;
|
---|
844 | ; This variable is located in the code segment to avoid having to
|
---|
845 | ; load segment registers
|
---|
846 | ;
|
---|
847 | TALIGN 2
|
---|
848 | LSTACK_NO DW 0 ; No local stacks in use
|
---|
849 |
|
---|
850 | ;
|
---|
851 | ; Switch to local stack
|
---|
852 | ;
|
---|
853 | ; Only flags altered
|
---|
854 | ;
|
---|
855 | ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING
|
---|
856 | LOCAL_STACK PROC NEAR
|
---|
857 | CMP LSTACK_NO, LSTACKS ; Any stacks left?
|
---|
858 | JB SHORT LSTACK1 ; Yes -> continue
|
---|
859 | MOV AX, SV_DATA
|
---|
860 | MOV DS, AX
|
---|
861 | ASSUME DS:SV_DATA
|
---|
862 | LEA DX, $STACKS ; We're out of stacks
|
---|
863 | MOV AH, 09H ; Display message
|
---|
864 | INT 21H
|
---|
865 | JMP SHORT $ ; Stop
|
---|
866 | ASSUME DS:NOTHING
|
---|
867 |
|
---|
868 | LSTACK1: PUSH BX ; Save registers on original
|
---|
869 | PUSH AX ; stack (will be moved to
|
---|
870 | PUSH DS ; new stack)
|
---|
871 | PUSH DX ; Save DX
|
---|
872 | INC LSTACK_NO ; One more used stack
|
---|
873 | MOV AX, LSTACK_NO ; Get stack number
|
---|
874 | MOV DX, LSTACK_SIZE ; Size of one stack
|
---|
875 | MUL DX ; DX:AX := top of stack
|
---|
876 | MOV BX, AX ; BX := top of stack
|
---|
877 | MOV AX, LSTACK
|
---|
878 | MOV DS, AX ; DS:BX points to top of stack
|
---|
879 | ASSUME DS:LSTACK
|
---|
880 | POP DX ; Restore DX
|
---|
881 | SUB BX, 12 ; Build stack frame
|
---|
882 | POP WORD PTR [BX+0] ; Move DS to new stack
|
---|
883 | POP WORD PTR [BX+2] ; Move AX to new stack
|
---|
884 | POP WORD PTR [BX+4] ; Move BX to new stack
|
---|
885 | POP WORD PTR [BX+6] ; Move return address
|
---|
886 | MOV [BX+8], SP ; Copy original SS:SP
|
---|
887 | MOV [BX+10], SS ; to new stack
|
---|
888 | MOV SS, AX ; (Disables interrupts for:)
|
---|
889 | MOV SP, BX ; Switch to new stack
|
---|
890 | POP DS ; Restore registers
|
---|
891 | ASSUME DS:NOTHING ; from new stack
|
---|
892 | POP AX
|
---|
893 | POP BX
|
---|
894 | RET ; Return address from new stack
|
---|
895 | LOCAL_STACK ENDP
|
---|
896 |
|
---|
897 |
|
---|
898 | ;
|
---|
899 | ; Switch back to original stack
|
---|
900 | ;
|
---|
901 | ; Only flags altered
|
---|
902 | ;
|
---|
903 |
|
---|
904 | ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING
|
---|
905 | RESTORE_STACK PROC NEAR
|
---|
906 | PUSH BP ; Save registers on local
|
---|
907 | PUSH DS ; stack (will be moved to
|
---|
908 | PUSH BX ; original stack)
|
---|
909 | DEC LSTACK_NO ; Adjust number of used stacks
|
---|
910 | MOV BP, SP ; SS:SP points to local stack
|
---|
911 | LDS BX, [BP+8] ; Original stack
|
---|
912 | SUB BX, 8 ; Build stack frame
|
---|
913 | POP WORD PTR [BX+0] ; Move BX to original stack
|
---|
914 | POP WORD PTR [BX+2] ; Move DS to original stack
|
---|
915 | POP WORD PTR [BX+4] ; Move BP to original stack
|
---|
916 | POP WORD PTR [BX+6] ; Move return address
|
---|
917 | MOV BP, DS ; Copy DS to SS
|
---|
918 | MOV SS, BP ; (Disables interrupts for:)
|
---|
919 | MOV SP, BX ; Switch to original stack
|
---|
920 | POP BX ; Restore registers from
|
---|
921 | POP DS ; original stack
|
---|
922 | POP BP
|
---|
923 | RET
|
---|
924 | RESTORE_STACK ENDP
|
---|
925 |
|
---|
926 |
|
---|
927 | INIT_CODE ENDS
|
---|
928 |
|
---|
929 | END
|
---|