Subversion Repositories SvarDOS

Rev

Rev 1875 | 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
 
1872 mateusz.vi 474
; Get the segment to the original process PSP. Using int 21h,ah=62h should be
475
; safe, RBIL says: "This function does not use any of the DOS-internal stacks
476
; and may thus be called at any time, even during another INT 21h call"
1869 mateusz.vi 477
mov ah, 0x62
1872 mateusz.vi 478
int 0x21        ; segment of the original PSP is in BX now
1869 mateusz.vi 479
 
1872 mateusz.vi 480
; set DS to the original PSP
481
mov ds, bx
482
 
1875 mateusz.vi 483
; load the pointer to the original JFT, set DS to the JFT seg and BX to offset
484
lds bx, [0x34]  ; same as "mov bx, [0x34]" + "mov ds, [0x36]", but smaller
485
 
486
; save the original process stdin and stdout (at [BX]) on stack, as well as a
487
; dword pointer to the original JFT
488
push word [bx]  ; original stdin and stdout (from the JFT at DS:BX)
1873 mateusz.vi 489
push ds
1869 mateusz.vi 490
push bx
491
 
492
; overwrite the original process stdin and stdout with stderr, in case stdout
493
; or stdin was redirected.
1872 mateusz.vi 494
mov dl, [bx+2]   ; the process stderr (3rd entry of the JFT in original PSP)
1873 mateusz.vi 495
mov dh, dl       ; dup DL so I can overwrite stdin and stdout with one write
1872 mateusz.vi 496
mov [bx], dx
1869 mateusz.vi 497
 
498
; set DS to myself so I can reach (and display) my messages
1863 mateusz.vi 499
push cs
500
pop ds
501
 
502
; is this a DISK error?
1869 mateusz.vi 503
test ch, 0x80
1864 mateusz.vi 504
jz DISKERROR
1863 mateusz.vi 505
; non-disk error: output "CRITICAL ERROR #XXX SYSTEM HALTED" and freeze
506
; update the crit string so it contains the proper error code
1881 mateusz.vi 507
mov bx, CRITERRSYST+2
1863 mateusz.vi 508
mov ax, di
509
xor ah, ah
510
mov cl, 100
511
div cl ; AL = AX / cl     AH = remainder
512
add al, '0'
1864 mateusz.vi 513
mov [bx], al
514
inc bx
1863 mateusz.vi 515
 
516
mov al, ah
517
xor ah, ah
518
mov cl, 10
519
div cl
520
add al, '0'
521
add ah, '0'
1864 mateusz.vi 522
mov [bx], al
523
inc bx
524
mov [bx], ah
1863 mateusz.vi 525
 
526
; display the string
527
mov ah, 0x09
528
mov dx, CRITERR
529
int 0x21
1864 mateusz.vi 530
mov dx, CRITERRSYST
531
int 0x21
1863 mateusz.vi 532
; freeze the system
533
HALT:
534
sti
535
hlt;
536
jmp HALT
537
 
538
DISKERROR:
1864 mateusz.vi 539
; disk errors produce this message:
1866 mateusz.vi 540
; A: - READ|WRITE FAILURE
541
; (A)bort, (R)etry, (I)gnore, (F)ail
1864 mateusz.vi 542
add al, 'A'
1866 mateusz.vi 543
mov [CRITERRDISK], al
1864 mateusz.vi 544
mov ah, 0x09
545
mov dx, CRITERRDISK
546
int 0x21
547
; READ / WRITE (test flag 0x01, set = write, read otherwise)
548
mov dx, CRITERRDSK_WRITE
549
test ch, 1
550
jnz WRITE
551
mov dx, CRITERRDSK_READ
552
WRITE:
553
int 0x21
1866 mateusz.vi 554
mov dx, CRLF
1864 mateusz.vi 555
int 0x21
1866 mateusz.vi 556
; print available options (abort=always, 0x10=retry, 0x20=ignore, 0x08=fail)
557
CRITERR_ASKCHOICE:
558
mov dx, CRITERR_ABORT
559
int 0x21
560
; retry?
561
test ch, 0x10
562
jz NORETRY
563
mov dx, CRITERR_COMMA
564
int 0x21
565
mov dx, CRITERR_RETRY
566
int 0x21
567
NORETRY:
568
; ignore?
569
test ch, 0x20
570
jz NOIGNORE
571
mov dx, CRITERR_COMMA
572
int 0x21
573
mov dx, CRITERR_IGNOR
574
int 0x21
575
NOIGNORE:
576
; fail?
577
test ch, 0x08
578
jz NOFAIL
579
mov dx, CRITERR_COMMA
580
int 0x21
581
mov dx, CRITERR_FAIL
582
int 0x21
583
NOFAIL:
584
; output "? "
585
mov ah, 0x06
586
mov dl, '?'
587
int 0x21
588
mov dl, ' '
589
int 0x21
1863 mateusz.vi 590
 
1866 mateusz.vi 591
; wait for user key press and return (iret) with AL set accordingly:
592
;   AL=0  ignore
593
;   AL=1  retry
594
;   AL=2  abort
595
;   AL=3  fail
1863 mateusz.vi 596
 
1866 mateusz.vi 597
mov ah, 0x07  ; key input, no ctrl+c check
598
int 0x21
599
and al, 0xdf   ; switch AL to upper-case so key check is case-insensitive
600
mov cl, al     ; save pressed key in CL (AL is easily overwritten by DOS calls)
601
; print the pressed key
602
mov ah, 0x06
603
mov dl, cl
604
int 0x21
605
mov ah, 0x09
606
mov dx, CRLF
607
int 0x21
608
 
609
; was it abort?
610
cmp cl, [CRITERR_KEYS]
611
jne SKIP_ABORT
612
mov al, 2     ; AL=2 -> "abort"
1868 mateusz.vi 613
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 614
SKIP_ABORT:
615
; if retry is allowed - was it retry?
616
test ch, 0x10
617
jz SKIP_RETRY
618
cmp cl, [CRITERR_KEYS+1]
619
jne SKIP_RETRY
620
mov al, 1     ; AL=1 -> "retry"
1868 mateusz.vi 621
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 622
SKIP_RETRY:
623
; if ignore is allowed - was it ignore?
624
test ch, 0x20
625
jz SKIP_IGN
626
cmp cl, [CRITERR_KEYS+2]
627
jne SKIP_IGN
628
xor al, al    ; AL=0 -> "ignore"
1868 mateusz.vi 629
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 630
SKIP_IGN:
631
; if fail is allowed - was it fail?
632
test ch, 0x08
633
;jz SKIP_FAIL
634
cmp cl, [CRITERR_KEYS+3]
635
jne SKIP_FAIL
636
mov al, 3     ; AL=3 -> "fail"
1868 mateusz.vi 637
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 638
SKIP_FAIL:
1863 mateusz.vi 639
 
1866 mateusz.vi 640
jmp CRITERR_ASKCHOICE   ; invalid answer -> ask again
641
 
1868 mateusz.vi 642
QUIT_WITH_AL_SET:
643
 
1872 mateusz.vi 644
; restore original stdin/stdout handlers in the original JFT
1875 mateusz.vi 645
pop bx        ; original process' JFT offset
646
pop ds        ; original process' JFT segment
647
pop word [bx] ; original process' stdin and stdout handlers
1869 mateusz.vi 648
 
1872 mateusz.vi 649
; restore registers to their original values and quit the handler (AL is
650
; already set to a proper action value and AH does not matter since it was
651
; changed by the kernel's int 24h calling routine anyway)
1868 mateusz.vi 652
popf
653
pop ds
654
pop dx
655
pop cx
656
pop bx
657
iret
1866 mateusz.vi 658
 
1881 mateusz.vi 659
; translatable messages, each message is stored inside a 16-bytes field.
660
; SvarCOM relies on the position and length of these fields to update messages
661
; accordingly to the selected language.
662
CRITERR db          "CRITICAL ERROR$ "
663
CRITERRDSK_READ db  "READ FAILURE$   "
664
CRITERRDSK_WRITE db "WRITE FAILURE$  "
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"        ; upcase keys for Abort, Retry, Ignore, Fail
670
CRITERRSYST db      " #XXX$"
1866 mateusz.vi 671
CRITERRDISK db "@: - $"
1881 mateusz.vi 672
CRITERR_COMMA db ", $"
1866 mateusz.vi 673
CRLF db 0x0A, 0x0D, "$"