1 ; SCCSID = @(#)ctrlc.asm 1.4 85/08/16
2 ; Low level routines for detecting special characters on CON input,
3 ; the ^C exit/int code, the Hard error INT 24 code, the
4 ; process termination code, and the INT 0 divide overflow handler.
19 ; AN000 version 4.0 Jan 1988
20 ; A002 PTM -- dir >lpt3 hangs
21 ; A003 PTM 3957- fake version for IBMCAHE.COM
24 ; get the appropriate segment definitions
29 CODE SEGMENT BYTE PUBLIC 'CODE'
30 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
54 i_need User_In_AX
,WORD
56 i_need ConC_spsave
,WORD
64 i_need CurrentPDB
,WORD
70 i_need ERR_TABLE_24
,BYTE
72 I_need ErrMap24End
,BYTE
76 I_need EXTOPEN_ON
,BYTE ;AN000; DOS 4.0
77 I_need InterCon
,BYTE ;AN000; DOS 4.0
78 I_need DOS34_FLAG
,WORD ;AN000; DOS 4.0
79 I_need ACT_PAGE
,WORD ;AN000; DOS 4.0
80 I_need Special_Version
,WORD ;AN007; DOS 4.0
87 extrn restore_user_map
:near
90 Break <Checks for ^C
in CON I
/O
>
92 ASSUME
DS:NOTHING
,ES:NOTHING
94 procedure DSKSTATCHK
,NEAR ; Check for ^C if only one level in
95 CMP BYTE PTR [INDOS
],1
105 DOSAssume
CS,<DS>,"DskStatChk"
106 MOV BYTE PTR [DSKSTCOM
],DEVRDND
107 MOV BYTE PTR [DSKSTCALL
],DRDNDHL
110 MOV AL, [InterCon
] ;AN000;get type of status read 2/13/KK
111 MOV BYTE PTR [DSKCHRET
],AL ;AN000; load interim flag into packet
113 MOV BX,OFFSET DOSGROUP
:DSKSTCALL
118 JZ GotCh
; No characters available
129 MOV AL,BYTE PTR [DSKCHRET
]
133 MOV BYTE PTR [DSKSTCOM
],DEVRD
134 MOV BYTE PTR [DSKSTCALL
],DRDWRHL
135 MOV BYTE PTR [DSKCHRET
],CL
138 invoke DEVIOCALL2
; Eat the ^C
149 CMP BYTE PTR [SCAN_FLAG
],0 ; ALT_Q ?
169 ; SpoolInt - signal processes that the DOS is truly idle. We are allowed to
170 ; do this ONLY if we are working on a 1-12 system call AND if we are not in
171 ; the middle of an INT 24.
173 procedure SPOOLINT
,NEAR
180 ; Note that we are going to allow an external program to issue system calls
181 ; at this time. We MUST preserve IdleInt across this.
183 PUSH WORD PTR IdleInt
191 procedure STATCHK
,NEAR
193 invoke DSKSTATCHK
; Allows ^C to be detected under
206 CMP BYTE PTR [SCAN_FLAG
],0 ;AN000; ALT_R ?
207 JNZ check_end
;AN000; yes
209 invoke IOFUNC
; Eat Cntrl-S
223 MOV DI,SI ; ES:DI -> SFT
224 TEST ES:[DI.sf_flags
],sf_net_spool
225 JZ NORM_PR
; Not redirected, echo is OK
226 Callinstall NetSpoolEchoCheck
,MultNet
,38,<AX>,<AX> ; See if allowed
227 JNC NORM_PR
; Echo is OK
228 MOV BYTE PTR [PFLAG
],0 ; If not allowed, disable echo
229 Callinstall NetSpoolClose
,MultNet
,36,<AX>,<AX> ; and close
233 CMP BYTE PTR [PFLAG
],0
260 ;;;;; 7/14/86 ALT_Q key fix
262 JZ PRINTON
; no! must be CTRL_P
265 ;;;;; 7/14/86 ALT_Q key fix
274 procedure CNTCHAND
,NEAR
276 ; "^C" and CR/LF is printed. Then the user registers are restored and the
277 ; user CTRL-C handler is executed. At this point the top of the stack has 1)
278 ; the interrupt return address should the user CTRL-C handler wish to allow
279 ; processing to continue; 2) the original interrupt return address to the code
280 ; that performed the function call in the first place. If the user CTRL-C
281 ; handler wishes to continue, it must leave all registers unchanged and RET
282 ; (not IRET) with carry CLEAR. If carry is SET then an terminate system call
284 TEST [DOS34_FLAG
],CTRL_BREAK_FLAG
;AN002; from RAWOUT
285 JNZ around_deadlock
;AN002;
286 MOV AL,3 ; Display "^C"
289 around_deadlock: ;AN002;
291 CMP BYTE PTR [CONSWAP
],0
295 CLI ; Prepare to play with stack
296 MOV SS,[user_SS
] ; User stack now restored
299 invoke restore_world
; User registers now restored
301 MOV BYTE PTR [INDOS
],0 ; Go to known state
302 MOV BYTE PTR [ERRORMODE
],0
303 MOV [ConC_spsave
],SP ; save his SP
305 INT int_ctrl_c
; Execute user Ctrl-C handler
307 ; The user has returned to us. The circumstances we allow are:
309 ; IRET We retry the operation by redispatching the system call
310 ; CLC/RETF POP the stack and retry
311 ; ... Exit the current process with ^C exit
313 ; User's may RETURN to us and leave interrupts on. Turn 'em off just to be
317 MOV [user_IN_AX
],ax ; save the AX
318 PUSHF ; and the flags (maybe new call)
321 ; See if the input stack is identical to the output stack
324 JNZ ctrlc_try_new
; current SP not the same as saved SP
326 ; Repeat the operation by redispatching the system call.
332 ; The current SP is NOT the same as the input SP. Presume that he RETF'd
333 ; leaving some flags on the stack and examine the input
336 ADD SP,2 ; pop those flags
337 TEST AX,f_carry
; did he return with carry?
338 JZ Ctrlc_Repeat
; no carry set, just retry
340 ; Well... time to abort the user. Signal a ^C exit and use the EXIT system
344 MOV AX,(EXIT
SHL 8) + 0
346 transfer COMMAND
; give up by faking $EXIT
350 Break <DIVISION OVERFLOW INTERRUPT
>
352 ; Default handler for division overflow trap
354 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:NOTHING
355 MOV SI,OFFSET DOSGROUP
:DIVMES
359 MOV SP,OFFSET DOSGROUP
:AUXSTACK
; Enough stack for interrupts
361 JMP ctrlc_abort
; Use Ctrl-C abort on divide overflow
365 ; OutMes: perform message output
366 ; Inputs: SS:SI points to message
367 ; BX has message length
368 ; Outputs: message to BCON
370 procedure OutMes
,NEAR
372 Context
ES ; get ES addressability
373 Context
DS ; get DS addressability
375 MOV BYTE PTR [DskStCom
],DevWrt
376 MOV BYTE PTR [DskStCall
],DRdWrHL
379 MOV BX,OFFSET DOSGROUP
:DskStCall
380 MOV WORD PTR [DskChRet
+1],SI ; transfer address (need an EQU)
384 MOV WORD PTR [DskChRet
+1],OFFSET DOSGROUP
:DevIOBuf
389 Break <CHARHRD
,HARDERR
,ERROR
-- HANDLE DISK ERRORS
AND RETURN TO USER
>
391 procedure CHARHARD
,NEAR
392 ASSUME
DS:NOTHING
,ES:NOTHING
,SS:DOSGROUP
394 ; Character device error handler
395 ; Same function as HARDERR
397 OR AH,allowed_FAIL
+ allowed_IGNORE
+ allowed_RETRY
399 MOV WORD PTR [EXITHOLD
+2],ES
400 MOV WORD PTR [EXITHOLD
],BP
403 MOV BP,DS ; Device pointer is BP:SI
409 ; Hard disk error handler. Entry conditions:
410 ; DS:BX = Original disk transfer address
411 ; DX = Original logical sector number
412 ; CX = Number of sectors to go (first one gave the error)
413 ; AX = Hardware error code
414 ; DI = Original sector transfer count
415 ; ES:BP = Base of drive parameters
416 ; [READOP] = 0 for read, 1 for write
417 ; [ALLOWED] Set with allowed responses to this error (other bits MUST BE 0)
419 ; [FAILERR] will be set if user responded FAIL
421 procedure HardErr
,NEAR
422 ASSUME
DS:NOTHING
,ES:NOTHING
424 XCHG AX,DI ; Error code in DI, count in AX
425 AND DI,STECODE
; And off status bits
426 CMP DI,error_I24_write_protect
; Write Protect Error?
429 MOV AL,ES:[BP.dpb_drive
]
430 MOV BYTE PTR [WPERR
],AL ; Flag drive with WP error
433 SUB AX,CX ; Number of sectors successfully transferred
434 ADD DX,AX ; First sector number to retry
436 MUL ES:[BP.dpb_sector_size
] ; Number of bytes transferred
438 ADD BX,AX ; First address for retry
439 XOR AH,AH ; Flag disk section in error
440 CMP DX,ES:[BP.dpb_first_FAT
] ; In reserved area?
442 INC AH ; Flag for FAT
443 CMP DX,ES:[BP.dpb_dir_sector
] ; In FAT?
445 MOV ES:[BP.dpb_free_cnt
],-1 ; Err in FAT must force recomp of freespace
450 CMP DX,ES:[BP.dpb_first_sector
] ; In directory?
452 INC AH ; Must be in data area
454 SHL AH,1 ; Make room for read/write bit
455 OR AH,BYTE PTR [READOP
] ; Set bit 0
456 ; If we have a write protect error when writing on a critical area on disk,
457 ; do not allow a retry as this may write out garbage on any subsequent disk.
462 ;and [ALLOWED],NOT Allowed_RETRY
464 OR AH,[ALLOWED
] ; Set the allowed_ bits
466 MOV AL,ES:[BP.dpb_drive
] ; Get drive number
468 MOV WORD PTR [EXITHOLD
+2],ES
469 MOV WORD PTR [EXITHOLD
],BP ; The only things we preserve
470 LES SI,ES:[BP.dpb_driver_addr
]
471 MOV BP,ES ; BP:SI points to the device involved
473 ; DI has the INT-24-style extended error. We now map the error code for this
474 ; into the normalized get extended error set by using the ErrMap24 table as an
475 ; translate table. Note that we translate ONLY the device returned codes and
476 ; leave all others beyond the look up table alone.
479 call SET_I24_EXTENDED_ERROR
480 CMP DI,error_I24_gen_failure
481 JBE GOT_RIGHT_CODE
; Error codes above gen_failure get
482 MOV DI,error_I24_gen_failure
; mapped to gen_failure. Real codes
483 ; Only come via GetExtendedError
486 ; Entry point used by REDIRector on Network I 24 errors.
488 ; ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
490 ; ALL I 24 regs set up. ALL Extended error info SET. ALLOWED Set.
491 ; EXITHOLD set for restore of ES:BP.
494 CMP BYTE PTR [ERRORMODE
],0 ; No INT 24s if already INT 24
500 invoke RESTORE_USER_MAP
;AN000;LB. restore user's EMS map
504 fmt TypINT24
,LevLog
,<"INT 24: AX = $x DI = $x\n">,<AX,DI>
506 ; Wango!!! We may need to free some user state info... In particular, we
507 ; may have locked down a JFN for a user and he may NEVER return to us. Thus,
508 ; we need to free it here and then reallocate it when we come back.
514 MOV BYTE PTR [SI],0FFH
517 CLI ; Prepare to play with stack
518 INC BYTE PTR [ERRORMODE
] ; Flag INT 24 in progress
519 DEC BYTE PTR [INDOS
] ; INT 24 handler might not return
520 ;; Extneded Open hooks
521 TEST [DOS34_FLAG
],Force_I24_Fail
;AN000;IFS. form IFS Call Back ;AN000;
522 JNZ faili24
;AN000;IFS. ;AN000;
523 TEST [EXTOPEN_ON
],EXT_OPEN_I24_OFF
;AN000;IFS.I24 error disabled ;AN000;
524 JZ i24yes
;AN000;IFS.no ;AN000;
526 MOV AL,3 ;AN000;IFS.fake fail ;AN000;
527 JMP passi24
;AN000;IFS.exit ;AN000;
530 ;; Extended Open hooks
533 MOV SP,ES:[user_SP
] ; User stack pointer restored
534 INT int_fatal_abort
; Fatal error interrupt vector, must preserve ES
535 MOV ES:[user_SP
],SP ; restore our stack
542 INC BYTE PTR [INDOS
] ; Back in the DOS
543 MOV BYTE PTR [ERRORMODE
],0 ; Back from INT 24
545 ;; MOV [ACT_PAGE],-1 ;LB. invalidate DOS active page ;AN000;
546 ;; invoke SAVE_MAP ;LB. save user's EMS map ;AN000;
547 fmt TypINT24
,LevLog
,<"INT 24: User reply = $x\n">,<AX>
552 ; Triage the user's reply.
555 JB CheckIgnore
; 0 => ignore
556 JZ CheckRetry
; 1 => retry
558 JNZ DoAbort
; 2, invalid => abort
560 ; The reply was fail. See if we are allowed to fail.
562 TEST [ALLOWED
],allowed_FAIL
; Can we?
563 JZ DoAbort
; No, do abort
565 MOV AL,3 ; just in case...
566 TEST [EXTOPEN_ON
],EXT_OPEN_I24_OFF
;AN000;EO. I24 error disabled
567 JNZ cleanup
;AN000;EO. no
568 INC [FAILERR
] ; Tell everybody
577 RestoreReg
<AX,SI,DS>
580 ; The reply was IGNORE. See if we are allowed to ignore.
583 TEST [ALLOWED
],allowed_IGNORE
; Can we?
584 JZ DoFail
; No, do fail
587 ; The reply was RETRY. See if we are allowed to retry.
590 TEST [ALLOWED
],allowed_RETRY
; Can we?
591 JZ DoFail
; No, do fail
594 ; The reply was ABORT.
598 CMP BYTE PTR [CONSWAP
],0
603 ; See if we are to truly abort. If we are in the process of aborting, turn
604 ; this abort into a fail.
611 MOV BYTE PTR [exit_Type
],Exit_hard_error
614 ; we are truly aborting the process. Go restore information from the PDB as
619 ; reset_environment checks the DS value against the CurrentPDB. If they are
620 ; different, then an old-style return is performed. If they are the same,
621 ; then we release jfns and restore to parent. We still use the PDB at DS:0 as
622 ; the source of the terminate addresses.
624 ; Some subtlety: We are about to issue a bunch of calls that *may* generate
625 ; INT 24s. We *cannot* allow the user to restart the abort process; we may
626 ; end up aborting the wrong process or turn a terminate/stay/resident into a
627 ; normal abort and leave interrupt handlers around. What we do is to set a
628 ; flag that will indicate that if any abort code is seen, we just continue the
629 ; operation. In essence, we dis-allow the abort response.
633 entry reset_environment
634 ASSUME
DS:NOTHING
,ES:NOTHING
636 invoke Reset_Version
;AN007;MS. reset version number
637 PUSH DS ; save PDB of process
640 ; There are no critical sections in force. Although we may enter here with
641 ; critical sections locked down, they are no longer relevant. We may safely
642 ; free all allocated resources.
647 MOV fAborting
,-1 ; signal abort in progress
649 CallInstall NetResetEnvironment
, multNet
, 34 ;DOS 4.00 doesn't need it
650 ; Allow REDIR to clear some stuff
653 invoke $Get_interrupt_vector
; and who to go to
656 SaveReg
<ES,BX> ; save return address
658 MOV BX,[CurrentPDB
] ; get currentPDB
660 MOV AX,DS:[PDB_Parent_PID
] ; get parentPDB
663 ; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB
664 ; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not
668 JZ reset_return
; parentPDB = CurrentPDB
670 JNZ reset_return
; CurrentPDB <> ThisPDB
671 PUSH AX ; save parent
672 CMP BYTE PTR [exit_type
],Exit_keep_process
673 JZ reset_to_parent
; keeping this process
675 ; We are truly removing a process. Free all allocation blocks belonging to
678 invoke arena_free_process
680 ; Kill off remainder of this process. Close file handles and signal to
681 ; relevant network folks that this process is dead. Remember that CurrentPDB
682 ; is STILL the current process!
687 POP [CurrentPDB
] ; set up process as parent
689 reset_return: ; come here for normal return
695 ; make sure that everything is clean In this case ignore any errors, we cannot
696 ; "FAIL" the abort, the program being aborted is dead.
702 ; Decrement open ref. count if we had done a virtual open earlier.
704 invoke CHECK_VIRT_OPEN
706 invoke RESTORE_USER_MAP
;AN000;LB. restore user's EMS map
709 MOV BYTE PTR [INDOS
],0 ; Go to known state
710 MOV BYTE PTR [WPERR
],-1 ; Forget about WP error
711 MOV fAborting
,0 ; let aborts occur
712 POP WORD PTR ExitHold
713 POP WORD PTR ExitHold
+2
715 ; Snake into multitasking... Get stack from CurrentPDB person
719 MOV SS,WORD PTR DS:[PDB_user_stack
+2]
720 MOV SP,WORD PTR DS:[PDB_user_stack
]
726 POP AX ; suck off CS:IP of interrupt...
731 PUSH WORD PTR [EXITHOLD
+2]
732 PUSH WORD PTR [EXITHOLD
]
734 IRET ; Long return back to user terminate address
738 ; This routine handles extended error codes.
739 ; Input : DI = error code from device
740 ; Output: All EXTERR fields are set
742 Procedure SET_I24_EXTENDED_ERROR
,NEAR
744 MOV AX,OFFSET DOSGroup
:ErrMap24End
745 SUB AX,OFFSET DOSGroup
:ErrMap24
747 ; AX is the index of the first unavailable error. Do not translate if
748 ; greater or equal to AX.
759 ; Now Extended error is set correctly. Translate it to get correct error
760 ; locus class and recommended action.
763 MOV SI,OFFSET DOSGROUP
:ERR_TABLE_24
764 invoke CAL_LK
; Set other extended error fields
767 EndProc SET_I24_EXTENDED_ERROR