1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
|
;
; ^C status routines for MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
i_need DevIOBuf,BYTE
i_need DidCTRLC,BYTE
i_need INDOS,BYTE
i_need DSKSTCOM,BYTE
i_need DSKSTCALL,BYTE
i_need DSKSTST,WORD
i_need BCON,DWORD
i_need DSKCHRET,BYTE
i_need DSKSTCNT,WORD
i_need IDLEINT,BYTE
i_need CONSWAP,BYTE
i_need user_SS,WORD
i_need user_SP,WORD
i_need ERRORMODE,BYTE
i_need ConC_spSave,WORD
i_need Exit_type,BYTE
i_need PFLAG,BYTE
i_need ExitHold,DWORD
i_need WPErr,BYTE
i_need ReadOp,BYTE
i_need CONTSTK,WORD
i_need Exit_Code,WORD
i_need CurrentPDB,WORD
i_need DIVMES,BYTE
i_need DivMesLen,BYTE
SUBTTL Checks for ^C in CON I/O
PAGE
ASSUME DS:NOTHING,ES:NOTHING
procedure DSKSTATCHK,NEAR ; Check for ^C if only one level in
CMP BYTE PTR [INDOS],1
retnz ; Do NOTHING
PUSH CX
PUSH ES
PUSH BX
PUSH DS
PUSH SI
PUSH CS
POP ES
PUSH CS
POP DS
ASSUME DS:DOSGROUP
XOR CX,CX
MOV BYTE PTR [DSKSTCOM],DEVRDND
MOV BYTE PTR [DSKSTCALL],DRDNDHL
MOV [DSKSTST],CX
MOV BX,OFFSET DOSGROUP:DSKSTCALL
LDS SI,[BCON]
ASSUME DS:NOTHING
invoke DEVIOCALL2
TEST [DSKSTST],STBUI
JNZ ZRET ; No characters available
MOV AL,BYTE PTR [DSKCHRET]
DSK1:
CMP AL,"C"-"@"
JNZ RET36
MOV BYTE PTR [DSKSTCOM],DEVRD
MOV BYTE PTR [DSKSTCALL],DRDWRHL
MOV BYTE PTR [DSKCHRET],CL
MOV [DSKSTST],CX
INC CX
MOV [DSKSTCNT],CX
invoke DEVIOCALL2 ; Eat the ^C
POP SI
POP DS
POP BX ; Clean stack
POP ES
POP CX
JMP SHORT CNTCHAND
ZRET:
XOR AL,AL ; Set zero
RET36:
POP SI
POP DS
POP BX
POP ES
POP CX
return
NOSTOP:
CMP AL,"P"-"@"
JZ INCHK
IF NOT TOGLPRN
CMP AL,"N"-"@"
JZ INCHK
ENDIF
CMP AL,"C"-"@"
JZ INCHK
return
DSKSTATCHK ENDP
procedure SPOOLINT,NEAR
PUSHF
CMP BYTE PTR [IDLEINT],0
JZ POPFRET
CMP BYTE PTR [ERRORMODE],0
JNZ POPFRET ;No spool ints in error mode
INT int_spooler
POPFRET:
POPF
RET18: return
SPOOLINT ENDP
procedure STATCHK,NEAR
invoke DSKSTATCHK ; Allows ^C to be detected under
; input redirection
PUSH BX
XOR BX,BX
invoke GET_IO_FCB
POP BX
JC RET18
MOV AH,1
invoke IOFUNC
JZ SPOOLINT
CMP AL,'S'-'@'
JNZ NOSTOP
XOR AH,AH
invoke IOFUNC ; Eat Cntrl-S
JMP SHORT PAUSOSTRT
PRINTOFF:
PRINTON:
NOT BYTE PTR [PFLAG]
return
PAUSOLP:
CALL SPOOLINT
PAUSOSTRT:
MOV AH,1
invoke IOFUNC
JZ PAUSOLP
INCHK:
PUSH BX
XOR BX,BX
invoke GET_IO_FCB
POP BX
JC RET18
XOR AH,AH
invoke IOFUNC
CMP AL,'P'-'@'
JZ PRINTON
IF NOT TOGLPRN
CMP AL,'N'-'@'
JZ PRINTOFF
ENDIF
CMP AL,'C'-'@'
retnz
STATCHK ENDP
procedure CNTCHAND,NEAR
; Ctrl-C handler.
; "^C" and CR/LF is printed. Then the user registers are restored and
; the user CTRL-C handler is executed. At this point the top of the stack
; has 1) the interrupt return address should the user CTRL-C handler wish
; to allow processing to continue; 2) the original interrupt return address
; to the code that performed the function call in the first place. If
; the user CTRL-C handler wishes to continue, it must leave all registers
; unchanged and RET (not IRET) with carry CLEAR. If carry is SET then
; an terminate system call is simulated.
MOV AL,3 ; Display "^C"
invoke BUFOUT
invoke CRLF
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP BYTE PTR [CONSWAP],0
JZ NOSWAP
invoke SWAPBACK
NOSWAP:
CLI ; Prepare to play with stack
MOV SP,[user_SP]
MOV SS,[user_SS] ; User stack now restored
ASSUME SS:NOTHING
invoke restore_world ; User registers now restored
ASSUME DS:NOTHING
MOV BYTE PTR [INDOS],0 ; Go to known state
MOV BYTE PTR [ERRORMODE],0
MOV [ConC_spsave],SP ; save his SP
INT int_ctrl_c ; Execute user Ctrl-C handler
MOV [user_SS],AX ; save the AX
PUSHF ; and the flags (maybe new call)
POP AX
CMP SP,[ConC_spsave]
JNZ ctrlc_try_new ; new syscall maybe?
ctrlc_repeat:
MOV AX,[user_SS] ; no...
transfer COMMAND ; Repeat command otherwise
ctrlc_try_new:
SUB [ConC_spsave],2 ; Are there flags on the stack?
CMP SP,[ConC_spsave]
JZ ctrlc_new ; yes, new system call
ctrlc_abort:
MOV AX,(EXIT SHL 8) + 0
MOV BYTE PTR [DidCTRLC],0FFh
transfer COMMAND ; give up by faking $EXIT
ctrlc_new:
PUSH AX
POPF
POP [user_SS]
JNC ctrlc_repeat ; repeat operation
JMP ctrlc_abort ; indicate ^ced
CNTCHAND ENDP
SUBTTL DIVISION OVERFLOW INTERRUPT
PAGE
; Default handler for division overflow trap
procedure DIVOV,NEAR
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
MOV SI,OFFSET DOSGROUP:DIVMES
CALL RealDivOv
JMP ctrlc_abort ; Use Ctrl-C abort on divide overflow
DIVOV ENDP
;
; RealDivOv: perform actual divide overflow stuff.
; Inputs: none
; Outputs: message to BCON
;
procedure RealDivOv,NEAR ; Do divide overflow and clock process
PUSH CS ; get ES addressability
POP ES
PUSH CS ; get DS addressability
POP DS
ASSUME DS:DOSGROUP
MOV BYTE PTR [DskStCom],DevWrt
MOV BYTE PTR [DskStCall],DRdWrHL
MOV [DskSTST],0
MOV BL,[DivMesLen]
XOR BH,BH
MOV [DskStCnt],BX
MOV BX,OFFSET DOSGROUP:DskStCall
MOV WORD PTR [DskChRet+1],SI ; transfer address (need an EQU)
LDS SI,[BCON]
ASSUME DS:NOTHING
invoke DEVIOCALL2
MOV WORD PTR [DskChRet+1],OFFSET DOSGROUP:DevIOBuf
MOV [DskStCnt],1
return
RealDivOv ENDP
SUBTTL CHARHRD,HARDERR,ERROR -- HANDLE DISK ERRORS AND RETURN TO USER
PAGE
procedure CHARHARD,NEAR
ASSUME DS:NOTHING,ES:NOTHING,SS:DOSGROUP
; Character device error handler
; Same function as HARDERR
MOV WORD PTR [EXITHOLD+2],ES
MOV WORD PTR [EXITHOLD],BP
PUSH SI
AND DI,STECODE
MOV BP,DS ;Device pointer is BP:SI
CALL FATALC
POP SI
return
CHARHARD ENDP
procedure HardErr,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Hard disk error handler. Entry conditions:
; DS:BX = Original disk transfer address
; DX = Original logical sector number
; CX = Number of sectors to go (first one gave the error)
; AX = Hardware error code
; DI = Original sector transfer count
; ES:BP = Base of drive parameters
; [READOP] = 0 for read, 1 for write
;
XCHG AX,DI ; Error code in DI, count in AX
AND DI,STECODE ; And off status bits
CMP DI,WRECODE ; Write Protect Error?
JNZ NOSETWRPERR
PUSH AX
MOV AL,ES:[BP.dpb_drive]
MOV BYTE PTR [WPERR],AL ; Flag drive with WP error
POP AX
NOSETWRPERR:
SUB AX,CX ; Number of sectors successfully transferred
ADD DX,AX ; First sector number to retry
PUSH DX
MUL ES:[BP.dpb_sector_size] ; Number of bytes transferred
POP DX
ADD BX,AX ; First address for retry
XOR AH,AH ; Flag disk section in error
CMP DX,ES:[BP.dpb_first_FAT] ; In reserved area?
JB ERRINT
INC AH ; Flag for FAT
CMP DX,ES:[BP.dpb_dir_sector] ; In FAT?
JB ERRINT
INC AH
CMP DX,ES:[BP.dpb_first_sector] ; In directory?
JB ERRINT
INC AH ; Must be in data area
ERRINT:
SHL AH,1 ; Make room for read/write bit
OR AH,BYTE PTR [READOP]
entry FATAL
MOV AL,ES:[BP.dpb_drive] ; Get drive number
entry FATAL1
MOV WORD PTR [EXITHOLD+2],ES
MOV WORD PTR [EXITHOLD],BP ; The only things we preserve
LES SI,ES:[BP.dpb_driver_addr]
MOV BP,ES ; BP:SI points to the device involved
FATALC:
CMP BYTE PTR [ERRORMODE],0
JNZ SETIGN ; No INT 24s if already INT 24
MOV [CONTSTK],SP
PUSH SS
POP ES
ASSUME ES:DOSGROUP
CLI ; Prepare to play with stack
INC BYTE PTR [ERRORMODE] ; Flag INT 24 in progress
DEC BYTE PTR [INDOS] ; INT 24 handler might not return
MOV SS,[user_SS]
ASSUME SS:NOTHING
MOV SP,ES:[user_SP] ; User stack pointer restored
INT int_fatal_abort ; Fatal error interrupt vector, must preserve ES
MOV ES:[user_SP],SP ; restore our stack
MOV ES:[user_SS],SS
MOV SP,ES
MOV SS,SP
ASSUME SS:DOSGROUP
MOV SP,[CONTSTK]
INC BYTE PTR [INDOS] ; Back in the DOS
MOV BYTE PTR [ERRORMODE],0 ; Back from INT 24
STI
IGNRET:
LES BP,[EXITHOLD]
ASSUME ES:NOTHING
CMP AL,2
JZ error_abort
MOV BYTE PTR [WPERR],-1 ;Forget about WP error
return
SETIGN:
XOR AL,AL ;Flag ignore
JMP SHORT IGNRET
error_abort:
PUSH SS
POP DS
ASSUME DS:DOSGROUP
CMP BYTE PTR [CONSWAP],0
JZ NOSWAP2
invoke SWAPBACK
NOSWAP2:
MOV BYTE PTR [exit_Type],Exit_hard_error
MOV DS,[CurrentPDB]
ASSUME DS:NOTHING
;
; reset_environment checks the DS value against the CurrentPDB. If they
; are different, then an old-style return is performed. If they are
; the same, then we release jfns and restore to parent. We still use
; the PDB at DS:0 as the source of the terminate addresses.
;
; output: none.
;
entry reset_environment
ASSUME DS:NOTHING,ES:NOTHING
PUSH DS ; save PDB of process
MOV AL,int_Terminate
invoke $Get_interrupt_vector ; and who to go to
MOV WORD PTR [EXITHOLD+2],ES ; save return address
MOV WORD PTR [EXITHOLD],BX
MOV BX,[CurrentPDB] ; get current process
MOV DS,BX ;
MOV AX,DS:[PDB_Parent_PID] ; get parent to return to
POP CX
;
; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB
; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not
; Exit_keep_process
;
CMP AX,BX
JZ reset_return ; parentPDB = CurrentPDB
CMP BX,CX
JNZ reset_return ; CurrentPDB <> ThisPDB
PUSH AX ; save parent
CMP BYTE PTR [exit_type],Exit_keep_process
JZ reset_to_parent ; keeping this process
invoke arena_free_process
; reset environment at [CurrentPDB]; close those handles
MOV CX,FilPerProc
reset_free_jfn:
MOV BX,CX
PUSH CX
DEC BX ; get jfn
invoke $CLOSE ; close it, ignore return
POP CX
LOOP reset_free_jfn ; and do 'em all
reset_to_parent:
POP [CurrentPDB] ; set up process as parent
reset_return: ; come here for normal return
PUSH CS
POP DS
ASSUME DS:DOSGROUP
MOV AL,-1
invoke FLUSHBUF ; make sure that everything is clean
CLI
MOV BYTE PTR [INDOS],0 ;Go to known state
MOV BYTE PTR [WPERR],-1 ;Forget about WP error
;
; Snake into multitasking... Get stack from CurrentPDB person
;
MOV DS,[CurrentPDB]
ASSUME DS:NOTHING
MOV SS,WORD PTR DS:[PDB_user_stack+2]
MOV SP,WORD PTR DS:[PDB_user_stack]
ASSUME SS:NOTHING
invoke restore_world
ASSUME ES:NOTHING
POP AX ; suck off CS:IP of interrupt...
POP AX
POP AX
MOV AX,0F202h ; STI
PUSH AX
PUSH WORD PTR [EXITHOLD+2]
PUSH WORD PTR [EXITHOLD]
STI
IRET ; Long return back to user terminate address
HardErr ENDP
ASSUME SS:DOSGROUP
do_ext
CODE ENDS
END
|