Subversion Repositories SvarDOS

Rev

Rev 1870 | Rev 1872 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
349 mateuszvis 1
;
537 mateuszvis 2
; rmod - resident module of the SvarCOM command interpreter (NASM code)
349 mateuszvis 3
;
1730 mateusz.vi 4
; Copyright (C) 2021-2024 Mateusz Viste
349 mateuszvis 5
; MIT license
6
;
7
; this is installed in memory by the transient part of SvarCOM. it has only
8
; two jobs: providing a resident buffer for command history, environment, etc
9
; and respawning COMMAND.COM whenever necessary.
10
 
11
CPU 8086
459 mateuszvis 12
org 0x100
349 mateuszvis 13
 
459 mateuszvis 14
PSP_ENVSEG equ 0x2C
15
 
349 mateuszvis 16
section .text    ; all goes into code segment
17
 
350 mateuszvis 18
                 ; offset
19
SIG1 dw 0x1983   ;  +0
20
SIG2 dw 0x1985   ;  +2
21
SIG3 dw 0x2017   ;  +4
983 mateusz.vi 22
SIG4 dw 0x2019   ;  +6  acts also as a guardval to detect severe stack overflows
349 mateuszvis 23
 
983 mateusz.vi 24
; Buffer used to remember previous command, when SvarCOM calls the buffered
25
; input service at INT 21h,AH=0x0A.
26
; This buffer is right before the stack, so in case of a stack overflow event
27
; (for example because of a "too ambitious" TSR) only this buffer is damaged,
987 mateusz.vi 28
; and can be invalidated without much harm. To detect such damage, SvarCOM's
29
; transient part is appending a signature at the end of the buffer.
30
INPUTBUF: times 132 db 0 ; 130 bytes for the input buffer + 2 for signature
983 mateusz.vi 31
 
490 mateuszvis 32
; DOS int 21h functions that I use require at least 40 bytes of stack under
33
; DOS-C (FreeDOS) kernel, so here I reserve 64 bytes juste to be sure
34
STACKBUF db "XXX  SVARCOM RMOD BY MATEUSZ VISTE  XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
35
STACKPTR dw 0
349 mateuszvis 36
 
366 mateuszvis 37
; offset of the COMSPEC variable in the environment block, 0 means "use
38
; boot drive". this value is patched by the transient part of COMMAND.COM
1178 mateusz.vi 39
COMSPECPTR dw 0  ; +CEh
349 mateuszvis 40
 
1849 mateusz.vi 41
; fallback COMSPEC string used if no COMSPEC is present in the environment.
42
; drive is patched by the transient part of COMMAND.COM
1178 mateusz.vi 43
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +D0h
350 mateuszvis 44
 
529 mateuszvis 45
; exit code of last application
1178 mateusz.vi 46
LEXCODE  db 0    ; +DFh
529 mateuszvis 47
 
460 mateuszvis 48
; ExecParamRec used by INT 21h, AX=4b00 (load and execute program), 14 bytes:
49
;  offset  size  content
50
;     +0     2   segment of environment for child (0 = current)
51
;     +2     4   address of command line to place at PSP:0080
52
;     +6     4   address of an FCB to be placed at PSP:005c
53
;    +0Ah    4   address of an FCB to be placed at PSP:006c
1178 mateusz.vi 54
EXEC_PARAM_REC db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   ; +E0h
366 mateuszvis 55
 
548 mateuszvis 56
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
1178 mateusz.vi 57
EXECPROG: times 128 db 0                                     ; +EEh
460 mateuszvis 58
 
548 mateuszvis 59
; File where stdin and stdout should be redirected (0 = no redirection)
1178 mateusz.vi 60
REDIR_INFIL:     times 128 db 0     ; +16Eh
61
REDIR_OUTFIL:    times 128 db 0     ; +1EEh
62
REDIR_OUTAPPEND: dw 0               ; +26Eh
63
REDIR_DEL_STDIN: db 0               ; +270h  indicates that the stdin file
576 mateuszvis 64
                                    ;        should be deleted (pipes). This
65
                                    ;        MUST contain the 1st char of
66
                                    ;        REDIR_INFIL!
461 mateuszvis 67
 
1730 mateusz.vi 68
EXEC_LH: db 0                       ; +271h  EXECPROG to be loaded high?
69
ORIG_UMBLINKSTATE: db 0             ; +272h
70
ORIG_ALLOCSTRAT: db 0               ; +273h
1846 mateusz.vi 71
CTRLC_FLAG: db 0                    ; +274h  flag that says "aborted by CTRL+C"
1730 mateusz.vi 72
 
537 mateuszvis 73
; CTRL+BREAK (int 23h) handler
74
; According to the TechHelp! Manual: "If you want to abort (exit to the parent
75
; process), then set the carry flag and return via a FAR RET. This causes DOS
76
; to perform normal cleanup and exit to the parent." (otherwise use iret)
1846 mateusz.vi 77
BREAK_HANDLER:            ; +275h
78
mov [CTRLC_FLAG], byte 1  ; checked by SvarCOM to abort BAT files
537 mateuszvis 79
stc
80
retf
517 mateuszvis 81
 
1178 mateusz.vi 82
; INT 0x2E handler
83
INT2E:
84
xor ax, ax
85
iret
537 mateuszvis 86
 
1846 mateusz.vi 87
skipsig:                  ; +27Fh
537 mateuszvis 88
 
349 mateuszvis 89
; set up CS=DS=SS and point SP to my private stack buffer
90
mov ax, cs
91
mov ds, ax
92
mov es, ax
93
mov ss, ax
94
mov sp, STACKPTR
95
 
1178 mateusz.vi 96
; set up myself as break handler (int 0x23)
537 mateuszvis 97
mov ax, 0x2523  ; set int vector 23h
98
mov dx, BREAK_HANDLER
99
int 0x21
100
 
1863 mateusz.vi 101
; set up myself as criterr handler (int 0x24)
102
mov ax, 0x2524
103
mov dx, HANDLER_24H
104
int 0x21
105
 
1178 mateusz.vi 106
; set up myself as int 0x2E handler ("pass command to shell")
107
mov ax, 0x252E
108
mov dx, INT2E ; TODO do something meaningful instead of a no-op
109
int 0x21
110
 
517 mateuszvis 111
; revert stdin/stdout redirections (if any) to their initial state
112
call REVERT_REDIR_IF_ANY
113
 
576 mateuszvis 114
; redirect stdin and/or stdout if required
543 mateuszvis 115
call REDIR_INOUTFILE_IF_REQUIRED
517 mateuszvis 116
 
1593 mateusz.vi 117
; should I execute command.com or a pre-set application?
118
cmp [EXECPROG], byte 0
460 mateuszvis 119
jz EXEC_COMMAND_COM
120
 
461 mateuszvis 121
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
122
;       int 21h, ah=50h call freezes...
123
;mov ah, 0x50           ; DOS 2+ -- Set PSP
124
;mov bx, cs
125
;int 0x21
460 mateuszvis 126
 
1730 mateusz.vi 127
 
128
; LOADHIGH?
129
cmp [EXEC_LH], byte 0
130
je NO_LOADHIGH
131
; SAVE CURRENT UMB LINK STATE
132
mov ax, 0x5802  ; GET UMB LINK STATE
133
int 0x21
134
mov [ORIG_UMBLINKSTATE], al
135
; SAVE CURRENT ALLOCATION STRATEGY
136
mov ax, 0x5800
137
int 0x21
138
mov [ORIG_ALLOCSTRAT], al
139
 
140
; LOADHIGH: link in the UMB memory chain for enabling high-memory allocation
141
;           (and save initial status on stack)
142
mov ax, 0x5803  ; SET UMB LINK STATE */
143
mov bx, 1
144
int 0x21
145
; set strategy to 'last fit, try high then low memory'
146
mov ax, 0x5801
147
mov bx, 0x0082
148
int 0x21
149
NO_LOADHIGH:
150
 
460 mateuszvis 151
; exec an application preset (by SvarCOM) in the ExecParamRec
152
mov ax, 0x4B00         ; DOS 2+ - load & execute program
461 mateuszvis 153
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
460 mateuszvis 154
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
155
int 0x21
465 mateuszvis 156
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
460 mateuszvis 157
 
1730 mateusz.vi 158
; go to start if nothing else to do (this will enforce valid ds/ss/etc)
159
cmp [cs:EXEC_LH], byte 0
160
je skipsig
463 mateuszvis 161
 
1730 mateusz.vi 162
; restore UMB link state and alloc strategy to original values (but make sure
163
; to base it on CS since DS might have been trashed by the program)
164
mov ax, 0x5803
165
xor bx, bx
166
mov bl, [cs:ORIG_UMBLINKSTATE]
167
int 0x21
168
; restore original memory allocation strategy
169
mov ax, 0x5801
170
mov bl, [cs:ORIG_ALLOCSTRAT]
171
int 0x21
172
; turn off the LH flag
173
mov [cs:EXEC_LH], byte 0
174
 
175
 
176
jmp skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
177
 
460 mateuszvis 178
EXEC_COMMAND_COM:
179
 
353 mateuszvis 180
; collect the exit code of previous application
181
mov ah, 0x4D
182
int 0x21
529 mateuszvis 183
mov [LEXCODE], al
353 mateuszvis 184
 
460 mateuszvis 185
; zero out the exec param block (14 bytes)
186
mov al, 0              ; byte to write
187
mov cx, 14             ; how many times
188
mov di, EXEC_PARAM_REC ; ES:DI = destination
189
cld                    ; stosb must move forward
190
rep stosb              ; repeat cx times
191
 
1730 mateusz.vi 192
; zero out the LH flag
193
mov [EXEC_LH], byte 0
194
 
366 mateuszvis 195
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
196
mov dx, COMSPECBOOT
197
 
198
; do I have a valid COMSPEC?
199
or [COMSPECPTR], word 0
200
jz USEDEFAULTCOMSPEC
459 mateuszvis 201
; set ES:DX to actual COMSPEC (in env segment)
202
mov es, [PSP_ENVSEG]
366 mateuszvis 203
mov dx, [COMSPECPTR]
204
USEDEFAULTCOMSPEC:
205
 
349 mateuszvis 206
; prepare the exec param block
459 mateuszvis 207
mov ax, [PSP_ENVSEG]
350 mateuszvis 208
mov [EXEC_PARAM_REC], ax
465 mateuszvis 209
mov [EXEC_PARAM_REC+2], word CMDTAIL
442 mateuszvis 210
mov [EXEC_PARAM_REC+4], cs
349 mateuszvis 211
 
212
; execute command.com
213
mov ax, 0x4B00         ; DOS 2+ - load & execute program
366 mateuszvis 214
push es                ;
215
pop ds                 ;
216
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
217
push cs
218
pop es
349 mateuszvis 219
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
220
int 0x21
221
 
222
; if all went well, jump back to start
223
jnc skipsig
224
 
1851 mateusz.vi 225
; save error code into cl
226
mov cl, al
227
 
228
; display program name (in DS:DX), but first replace its nul terminator by a $
229
mov si, dx
230
PARSENEXTBYTE:
231
lodsb ; load byte at DS:SI into AL and inc SI (direction flag is clear already)
232
test al, al  ; is zero yet?
233
jnz PARSENEXTBYTE
234
mov [si], byte '$'   ; replace the nul terminator by a $ and display it
235
mov ah, 0x09
236
int 0x21
237
mov [si], byte 0     ; revert the nul terminator back to its place
238
 
366 mateuszvis 239
; restore DS=CS
240
mov bx, cs
241
mov ds, bx
242
 
349 mateuszvis 243
; update error string so it contains the error number
1851 mateusz.vi 244
mov al, '0'
245
add al, cl    ; the exec error code
246
mov [ERRLOAD + 6], al
349 mateuszvis 247
 
366 mateuszvis 248
; display error message
349 mateuszvis 249
mov ah, 0x09
250
mov dx, ERRLOAD
251
int 0x21
252
 
253
; wait for keypress
1853 mateusz.vi 254
mov ah, 0x07    ; use INT 21h,AH=7 instead of AH=8 for CTRL+C immunity
349 mateuszvis 255
int 0x21
256
 
257
; back to program start
258
jmp skipsig
259
 
460 mateuszvis 260
; command.com tail arguments, in PSP format: length byte followed by args and
465 mateuszvis 261
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
262
; called as respawn (as opposed to being invoked as a normal application)
263
; this allows multiple copies of SvarCOM to stack upon each other.
264
CMDTAIL db 0x01, 0x0A, 0x0D
442 mateuszvis 265
 
1851 mateusz.vi 266
ERRLOAD db ": ERR x, LOAD FAILED", 0x0A, 0x0D, '$'
517 mateuszvis 267
 
268
; variables used to revert stdin/stdout to their initial state
269
OLD_STDOUT dw 0xffff
270
OLD_STDIN  dw 0xffff
271
 
272
 
520 mateuszvis 273
; ****************************************************************************
517 mateuszvis 274
; *** ROUTINES ***************************************************************
520 mateuszvis 275
; ****************************************************************************
517 mateuszvis 276
 
520 mateuszvis 277
; ----------------------------------------------------------------------------
517 mateuszvis 278
; revert stdin/stdout redirections (if any) to their initial state
279
REVERT_REDIR_IF_ANY:
280
; is stdout redirected?
281
mov bx, [OLD_STDOUT]
282
cmp bx, 0xffff
283
je STDOUT_DONE
519 mateuszvis 284
; revert the stdout handle (dst in BX already)
517 mateuszvis 285
mov cx, 1        ; src handle (1=stdout)
286
mov ah, 0x46     ; redirect a handle
287
int 0x21
519 mateuszvis 288
; close the old handle (still in bx)
289
mov ah, 0x3e
290
int 0x21
517 mateuszvis 291
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
292
STDOUT_DONE:
543 mateuszvis 293
 
294
; is stdin redirected?
295
mov bx, [OLD_STDIN]
296
cmp bx, 0xffff
297
je STDIN_DONE
547 mateuszvis 298
; revert the stdin handle (dst in BX already)
543 mateuszvis 299
xor cx, cx       ; src handle (0=stdin)
300
mov ah, 0x46     ; redirect a handle
301
int 0x21
302
; close the old handle (still in bx)
303
mov ah, 0x3e
304
int 0x21
305
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
576 mateuszvis 306
 
307
; delete stdin file if required
308
cmp [REDIR_DEL_STDIN], byte 0
309
je STDIN_DONE
310
; revert the original file and delete it
311
mov ah, [REDIR_DEL_STDIN]
312
mov [REDIR_INFIL], ah
313
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
314
mov dx, REDIR_INFIL
315
int 0x21
316
mov [REDIR_INFIL], byte 0
317
mov [REDIR_DEL_STDIN], byte 0
318
 
543 mateuszvis 319
STDIN_DONE:
320
 
517 mateuszvis 321
ret
520 mateuszvis 322
; ----------------------------------------------------------------------------
517 mateuszvis 323
 
324
 
520 mateuszvis 325
; ----------------------------------------------------------------------------
517 mateuszvis 326
; redirect stdout if REDIR_OUTFIL points to something
543 mateuszvis 327
REDIR_INOUTFILE_IF_REQUIRED:
548 mateuszvis 328
cmp [REDIR_OUTFIL], byte 0
517 mateuszvis 329
je NO_STDOUT_REDIR
548 mateuszvis 330
mov si, REDIR_OUTFIL   ; si = output file
517 mateuszvis 331
mov ax, 0x6c00         ; Extended Open/Create
332
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
333
xor cx, cx             ; file attribs when(if) file is created (0=normal)
334
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
335
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 336
mov [REDIR_OUTFIL], byte 0
517 mateuszvis 337
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
520 mateuszvis 338
 
339
; jump to end of file if flag was 0x11 (required for >> redirections)
340
cmp [REDIR_OUTAPPEND], word 0x11
341
jne SKIP_JMPEOF
342
mov bx, ax
343
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
344
xor cx, cx
345
xor dx, dx
346
int 0x21
347
mov ax, bx             ; put my handle back in ax, as expected by later code
348
SKIP_JMPEOF:
349
 
517 mateuszvis 350
; duplicate current stdout so I can revert it later
351
push ax                ; save my file handle in stack
352
mov ah, 0x45           ; duplicate file handle BX
548 mateuszvis 353
mov bx, 1              ; 1 = stdout
517 mateuszvis 354
int 0x21               ; ax=new (duplicated) file handle
355
mov [OLD_STDOUT], ax   ; save the old handle in memory
520 mateuszvis 356
 
517 mateuszvis 357
; redirect stdout to my file
358
pop bx                 ; dst handle
359
mov cx, 1              ; src handle (1=stdout)
360
mov ah, 0x46           ; "redirect a handle"
361
int 0x21
520 mateuszvis 362
 
517 mateuszvis 363
; close the original file handle, I no longer need it
364
mov ah, 0x3e           ; close a file handle (handle in BX)
519 mateuszvis 365
int 0x21
517 mateuszvis 366
NO_STDOUT_REDIR:
543 mateuszvis 367
 
368
; *** redirect stdin if REDIR_INFIL points to something ***
548 mateuszvis 369
cmp [REDIR_INFIL], byte 0
543 mateuszvis 370
je NO_STDIN_REDIR
548 mateuszvis 371
mov dx, REDIR_INFIL    ; dx:dx = file
543 mateuszvis 372
mov ax, 0x3d00         ; open file for read
373
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 374
mov [REDIR_INFIL], byte 0
543 mateuszvis 375
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
376
 
377
; duplicate current stdin so I can revert it later
378
push ax                ; save my file handle in stack
379
mov ah, 0x45           ; duplicate file handle BX
380
xor bx, bx             ; 0=stdin
381
int 0x21               ; ax=new (duplicated) file handle
382
mov [OLD_STDIN], ax    ; save the old handle in memory
383
 
384
; redirect stdout to my file
385
pop bx                 ; dst handle
386
xor cx, cx             ; src handle (0=stdin)
387
mov ah, 0x46           ; "redirect a handle"
388
int 0x21
389
 
390
; close the original file handle, I no longer need it
391
mov ah, 0x3e           ; close a file handle (handle in BX)
392
int 0x21
393
NO_STDIN_REDIR:
517 mateuszvis 394
ret
1863 mateusz.vi 395
 
396
 
397
; ****************************************************************************
398
; *                                                                          *
399
; * INT 24H HANDLER                                                          *
400
; *                                                                          *
401
; ****************************************************************************
402
;
403
; this is an executable image that can be set up as the critical error handler
1867 mateusz.vi 404
; interrupt (int 24h). It displays the usual "Abort, Retry, Fail..." prompt.
1863 mateusz.vi 405
;
406
; documentation:
407
; http://www.techhelpmanual.com/564-int_24h__critical_error_handler.html
408
;
409
; === CRIT HANDLER DETAILS ====================================================
410
;
411
; *** ON ENTRY ***
412
;
413
; upon entry to the INT 24h handler, the registers are as follows:
414
;  BP:SI = addr of a "device header" that identifies the failing device
415
;     DI = error code in lower 8 bits (only for non-disk errors)
416
;     AL = drive number, but only if AH bit 7 is reset
417
;     AH = error flags
418
;        0x80 = reset if device is a disk, set otherwise
419
;           all the following are valid ONLY for disks (0x80 reset):
420
;        0x20 = set if "ignore" action allowed
421
;        0x10 = set if "retry" action allowed
422
;        0x08 = set if "fail" action allowed
423
;        0x06 = disk area, 0=sys files, 1=fat, 10=directory, 11=data
424
;        0x01 = set if failure is a write, reset if read
425
;
426
; within the int 24h handler, only these DOS functions are allowed:
427
;   01H-0CH (DOS character I/O)
428
;   33H (all subfns are OK, including 3306H get DOS version)
429
;   50H (set PSP address)
430
;   51H and 62H (query PSP address)
431
;   59H (get extended error information)
432
;
433
; *** ON EXIT ***
434
;
435
; After handling the error, AL should be set with an action code and get back
436
; to DOS. Available actions are defined in AH at entry (see above). Possible
437
; values on exit are:
438
;   AL=0  ignore error (pretend nothing happened)
439
;   AL=1  retry operation
440
;   AL=2  abort (terminates the failed program via int 23h, like ctrl+break)
441
;   AL=3  return to application indicating a failure of the DOS function
442
;
443
; A very basic "always fail" handler would be as simple as this:
444
;   mov al, 3
445
;   iret
446
;
447
; *** DOS CALLS ***
448
;
449
; Warning! Be careful about using DOS fns in your Critical Error handler.
450
;          With DOS 5.0+, ONLY the following fns can be called safely:
451
;
452
;          01H-0CH (DOS character I/O)
453
;          33H (all subfns are OK, including 3306H get DOS version)
454
;          50H (set PSP address)
455
;          51H and 62H (query PSP address)
456
;          59H (get extended error information)
457
;
458
; =============================================================================
459
HANDLER_24H:    ; +46Ch
460
 
1868 mateusz.vi 461
; save registers so I can restore them later. AX does not require saving.
462
; Microsoft documentation says:
463
;  "When it is desired to ignore an error, the same registers must be preserved
464
;   as when it is desired to retry the operation (SS,SP,DS,BX,CX,DX)."
465
; source: INT24.DOC from MS-DOS 2.0
466
push bx
467
push cx
468
push dx
469
push ds
470
pushf
1863 mateusz.vi 471
 
1869 mateusz.vi 472
mov ch, ah      ; backup AH flags into CH
473
 
474
; get the segment to the original process PSP and save it on stack
475
; using int 21h,ah=62h should be safe, RBIL says: "This function does not use
476
; any of the DOS-internal stacks and may thus be called at any time, even
477
; during another INT 21h call."
478
mov ah, 0x62
479
int 0x21
480
push bx
481
 
482
; set DS to original PSP
483
push bx
484
pop ds
485
 
486
; save the original process stdin and stdout on stack
1870 mateusz.vi 487
mov dx, [0x18]   ; original stdin and stdout (from the JFT)
1869 mateusz.vi 488
push dx
489
 
490
; overwrite the original process stdin and stdout with stderr, in case stdout
491
; or stdin was redirected.
1871 mateusz.vi 492
mov dl, [0x1a]   ; the process stderr (3rd entry of the JFT in original PSP)
1870 mateusz.vi 493
mov dh, dl
494
mov [0x18], dx
1869 mateusz.vi 495
 
496
; set DS to myself so I can reach (and display) my messages
1863 mateusz.vi 497
push cs
498
pop ds
499
 
500
; is this a DISK error?
1869 mateusz.vi 501
test ch, 0x80
1864 mateusz.vi 502
jz DISKERROR
1863 mateusz.vi 503
; non-disk error: output "CRITICAL ERROR #XXX SYSTEM HALTED" and freeze
504
; update the crit string so it contains the proper error code
1864 mateusz.vi 505
mov bx, CRITERRSYST+1
1863 mateusz.vi 506
mov ax, di
507
xor ah, ah
508
mov cl, 100
509
div cl ; AL = AX / cl     AH = remainder
510
add al, '0'
1864 mateusz.vi 511
mov [bx], al
512
inc bx
1863 mateusz.vi 513
 
514
mov al, ah
515
xor ah, ah
516
mov cl, 10
517
div cl
518
add al, '0'
519
add ah, '0'
1864 mateusz.vi 520
mov [bx], al
521
inc bx
522
mov [bx], ah
1863 mateusz.vi 523
 
524
; display the string
525
mov ah, 0x09
526
mov dx, CRITERR
527
int 0x21
1864 mateusz.vi 528
mov dx, CRITERRSYST
529
int 0x21
1863 mateusz.vi 530
; freeze the system
531
HALT:
532
sti
533
hlt;
534
jmp HALT
535
 
536
DISKERROR:
1864 mateusz.vi 537
; disk errors produce this message:
1866 mateusz.vi 538
; A: - READ|WRITE FAILURE
539
; (A)bort, (R)etry, (I)gnore, (F)ail
1864 mateusz.vi 540
add al, 'A'
1866 mateusz.vi 541
mov [CRITERRDISK], al
1864 mateusz.vi 542
mov ah, 0x09
543
mov dx, CRITERRDISK
544
int 0x21
545
; READ / WRITE (test flag 0x01, set = write, read otherwise)
546
mov dx, CRITERRDSK_WRITE
547
test ch, 1
548
jnz WRITE
549
mov dx, CRITERRDSK_READ
550
WRITE:
551
int 0x21
1866 mateusz.vi 552
mov dx, CRLF
1864 mateusz.vi 553
int 0x21
1866 mateusz.vi 554
; print available options (abort=always, 0x10=retry, 0x20=ignore, 0x08=fail)
555
CRITERR_ASKCHOICE:
556
mov dx, CRITERR_ABORT
557
int 0x21
558
; retry?
559
test ch, 0x10
560
jz NORETRY
561
mov dx, CRITERR_COMMA
562
int 0x21
563
mov dx, CRITERR_RETRY
564
int 0x21
565
NORETRY:
566
; ignore?
567
test ch, 0x20
568
jz NOIGNORE
569
mov dx, CRITERR_COMMA
570
int 0x21
571
mov dx, CRITERR_IGNOR
572
int 0x21
573
NOIGNORE:
574
; fail?
575
test ch, 0x08
576
jz NOFAIL
577
mov dx, CRITERR_COMMA
578
int 0x21
579
mov dx, CRITERR_FAIL
580
int 0x21
581
NOFAIL:
582
; output "? "
583
mov ah, 0x06
584
mov dl, '?'
585
int 0x21
586
mov dl, ' '
587
int 0x21
1863 mateusz.vi 588
 
1866 mateusz.vi 589
; wait for user key press and return (iret) with AL set accordingly:
590
;   AL=0  ignore
591
;   AL=1  retry
592
;   AL=2  abort
593
;   AL=3  fail
1863 mateusz.vi 594
 
1866 mateusz.vi 595
mov ah, 0x07  ; key input, no ctrl+c check
596
int 0x21
597
and al, 0xdf   ; switch AL to upper-case so key check is case-insensitive
598
mov cl, al     ; save pressed key in CL (AL is easily overwritten by DOS calls)
599
; print the pressed key
600
mov ah, 0x06
601
mov dl, cl
602
int 0x21
603
mov ah, 0x09
604
mov dx, CRLF
605
int 0x21
606
 
607
; was it abort?
608
cmp cl, [CRITERR_KEYS]
609
jne SKIP_ABORT
610
mov al, 2     ; AL=2 -> "abort"
1868 mateusz.vi 611
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 612
SKIP_ABORT:
613
; if retry is allowed - was it retry?
614
test ch, 0x10
615
jz SKIP_RETRY
616
cmp cl, [CRITERR_KEYS+1]
617
jne SKIP_RETRY
618
mov al, 1     ; AL=1 -> "retry"
1868 mateusz.vi 619
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 620
SKIP_RETRY:
621
; if ignore is allowed - was it ignore?
622
test ch, 0x20
623
jz SKIP_IGN
624
cmp cl, [CRITERR_KEYS+2]
625
jne SKIP_IGN
626
xor al, al    ; AL=0 -> "ignore"
1868 mateusz.vi 627
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 628
SKIP_IGN:
629
; if fail is allowed - was it fail?
630
test ch, 0x08
631
;jz SKIP_FAIL
632
cmp cl, [CRITERR_KEYS+3]
633
jne SKIP_FAIL
634
mov al, 3     ; AL=3 -> "fail"
1868 mateusz.vi 635
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 636
SKIP_FAIL:
1863 mateusz.vi 637
 
1866 mateusz.vi 638
jmp CRITERR_ASKCHOICE   ; invalid answer -> ask again
639
 
1868 mateusz.vi 640
QUIT_WITH_AL_SET:
641
 
1869 mateusz.vi 642
; restore original stdin/stdout handlers in the original PSP
643
; (saved on stack as STDINSTDOUT PSPSEG"
644
pop dx    ; original process' stdin and stdout handlers (dh=stdin / dl=stdout)
645
pop bx    ; original process' PSP
646
push bx
647
pop ds    ; set DS to the original process so I can access its PSP
1870 mateusz.vi 648
mov [0x18], dx
1869 mateusz.vi 649
 
1866 mateusz.vi 650
; restore registers and quit the handler
1868 mateusz.vi 651
popf
652
pop ds
653
pop dx
654
pop cx
655
pop bx
656
iret
1866 mateusz.vi 657
 
658
 
659
CRITERR db "CRITICAL ERROR $"
660
CRITERRSYST db "#XXX - SYSTEM HALTED$"
661
CRITERRDISK db "@: - $"
662
CRITERRDSK_READ db "READ FAILURE$"
663
CRITERRDSK_WRITE db "WRITE FAILURE$"
664
CRLF db 0x0A, 0x0D, "$"
665
CRITERR_ABORT db "(A)bort$"
666
CRITERR_RETRY db "(R)etry$"
667
CRITERR_IGNOR db "(I)gnore$"
668
CRITERR_FAIL  db "(F)ail$"
669
CRITERR_KEYS  db "ARIF"
670
CRITERR_COMMA db ", $"