| 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
|
|---|