source: vendor/emx/current/src/dos/signal.asm

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 36.2 KB
Line 
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
44LSTACKS = 2 ; Number of local stacks
45LSTACK_SIZE = 512 ; Size of a local stack (bytes)
46
47LSTACK SEGMENT
48 DB LSTACKS DUP (LSTACK_SIZE DUP (?))
49LSTACK ENDS
50
51
52SV_DATA SEGMENT
53
54;
55; Original interrupt 1BH vector
56;
57OLD_BREAK LABEL DWORD
58OLD_BREAK_OFF DW 0
59OLD_BREAK_SEG DW 0
60
61;
62; This flag is set when cleaning up while executing the critical
63; error handler
64;
65CRIT_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
81EMERGENCY_TIMER DB 0
82EMERGENCY_COUNTER DB 0
83EMERGENCY_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
118SIG_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;
131SIG_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
145SIG_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;
159SIG_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;
173SIG_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;
187SIG_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
196SV_DATA ENDS
197
198
199SV_CODE SEGMENT
200
201;
202; Check for pending signals
203;
204 ASSUME DS:SV_DATA
205 ASSUME BP:PTR ISTACKFRAME
206SIG_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
248SDP_RET_STI: STI ; End of critical section
249SDP_RET: RET
250
251;
252; SIG_IGN
253;
254SDP_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
261SDP_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
271SDP_TERM_2:
272;
273; Default signal handler for SIGTERM
274;
275SDP_SIGTERM: MOV AX, 4C03H ; exit(3)
276 INT 21H
277
278;
279; Call user specified signal handler
280;
281SDP_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
287SIG_DELIVER_PENDING ENDP
288
289;
290; Display "Stopped by" message
291;
292; In: EAX Signal number
293;
294 ASSUME DS:SV_DATA
295SIG_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]
305SIG_MSG_1: CALL OTEXT
306 CALL OCRLF
307 RET
308SIG_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;
326SUC_TRAP EQU (DWORD PTR [BP-1*4])
327SUC_SIGNO EQU (DWORD PTR [BP-2*4])
328SUC_HANDLER EQU (DWORD PTR [BP-3*4])
329SUC_MASK EQU (DWORD PTR [BP-4*4])
330SUC_FLAGS EQU (DWORD PTR [BP-5*4])
331
332 ASSUME DS:SV_DATA
333 ASSUME BX:PTR PROCESS
334 ASSUME BP:PTR ISTACKFRAME
335SIG_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
360SUC_SYSV: MOV [BX].P_SIG_HANDLERS[SI], SIG_DFL
361 JMP SHORT SUC_1
362
363SUC_SETMASK: MOV [BX].P_SIG_BLOCKED, EAX
364SUC_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
373SUC_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
464SIG_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
478SIG_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
492SIGRET_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
497SIGRET_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
514SIGRET_TERMINATE:
515 RET ; Continue exception handler
516 ASSUME BX:NOTHING
517 ASSUME BP:NOTHING
518SIG_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;
531ISA EQU (SIGACTION PTR [BP-1*SIZE SIGACTION])
532OSA EQU (SIGACTION PTR [BP-2*SIZE SIGACTION])
533
534 ASSUME DS:SV_DATA
535 ASSUME DI:PTR PROCESS
536 TALIGN 4
537DO_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
555SIGNAL_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
568SIGNAL_RET: MOV SP, BP
569 POP BP
570 RET
571 ASSUME DI:NOTHING
572DO_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;
584SIGA_O_HANDLER EQU (DWORD PTR [BP-1*4])
585SIGA_O_MASK EQU (DWORD PTR [BP-2*4])
586SIGA_O_FLAGS EQU (DWORD PTR [BP-3*4])
587SIGA_OACT EQU (DWORD PTR [BP-4*4])
588SIGA_SIGNO EQU (DWORD PTR [BP-5*4])
589
590 ASSUME DS:SV_DATA
591 TALIGN 4
592 ASSUME DI:PTR PROCESS
593DO_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
640SIGACT_DISCARD: MOV EAX, SIGA_SIGNO
641 BTR [DI].P_SIG_PENDING, EAX
642SIGACT_NO_DISCARD:
643;
644; Store the previous action if OACT is not NULL
645;
646SIGACT_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
659SIGACT_NO_OUTPUT:
660 XOR EAX, EAX
661SIGACT_RET: MOV SP, BP
662 POP BP
663 RET
664
665SIGACT_ERROR_STI:
666 STI
667SIGACT_ERROR: MOV EAX, EINVAL
668 JMP SIGACT_RET
669 ASSUME DI:NOTHING
670DO_SIGACTION ENDP
671
672
673SV_CODE ENDS
674
675
676INIT_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
685HOOK_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
700HOOK_INT ENDP
701
702;
703; Remove interrupt hooks
704;
705 ASSUME DS:SV_DATA
706CLEANUP_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
713CS_1: RET
714CLEANUP_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
727CNTRL_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
745CB_EMGCY_START: MOV EMERGENCY_COUNTER, 0 ; Initialize counter
746 MOV EMERGENCY_TIMER, 18 ; Set timer to one second
747CB_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
756CB_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
762CNTRL_BREAK ENDP
763
764;
765; Ctrl-C interrupt
766;
767 ASSUME DS:NOTHING
768CNTRL_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
795CC_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
806CNTRL_C ENDP
807
808
809
810OLD_CRIT LABEL DWORD
811OLD_CRIT_OFF DW ?
812OLD_CRIT_SEG DW ?
813
814;
815; Critical error handler
816;
817 ASSUME DS:NOTHING
818CRIT_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
840CRIT_RET: IRET ; Return
841CRIT_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
848LSTACK_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
856LOCAL_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
868LSTACK1: 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
895LOCAL_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
905RESTORE_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
924RESTORE_STACK ENDP
925
926
927INIT_CODE ENDS
928
929 END
Note: See TracBrowser for help on using the repository browser.