Subversion Repositories SvarDOS

Rev

Rev 1881 | 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?
1986 mateusz.vi 199
test [COMSPECPTR], word 0xffff
366 mateuszvis 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
 
1986 mateusz.vi 212
mov si, dx             ; preset si to command in case I will display it in the
213
                       ; err message (DX might be destroyed by int 21h,AH=4Bh)
214
 
349 mateuszvis 215
; execute command.com
216
mov ax, 0x4B00         ; DOS 2+ - load & execute program
366 mateuszvis 217
push es                ;
218
pop ds                 ;
219
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
220
push cs
221
pop es
349 mateuszvis 222
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
223
int 0x21
224
 
225
; if all went well, jump back to start
226
jnc skipsig
227
 
1851 mateusz.vi 228
; save error code into cl
229
mov cl, al
230
 
231
; display program name (in DS:DX), but first replace its nul terminator by a $
1986 mateusz.vi 232
;mov si, dx           ; done already before the exec attempt
1851 mateusz.vi 233
PARSENEXTBYTE:
234
lodsb ; load byte at DS:SI into AL and inc SI (direction flag is clear already)
235
test al, al  ; is zero yet?
236
jnz PARSENEXTBYTE
237
mov [si], byte '$'   ; replace the nul terminator by a $ and display it
238
mov ah, 0x09
239
int 0x21
240
mov [si], byte 0     ; revert the nul terminator back to its place
241
 
366 mateuszvis 242
; restore DS=CS
243
mov bx, cs
244
mov ds, bx
245
 
349 mateuszvis 246
; update error string so it contains the error number
1851 mateusz.vi 247
mov al, '0'
248
add al, cl    ; the exec error code
249
mov [ERRLOAD + 6], al
349 mateuszvis 250
 
366 mateuszvis 251
; display error message
349 mateuszvis 252
mov ah, 0x09
253
mov dx, ERRLOAD
254
int 0x21
255
 
256
; wait for keypress
1853 mateusz.vi 257
mov ah, 0x07    ; use INT 21h,AH=7 instead of AH=8 for CTRL+C immunity
349 mateuszvis 258
int 0x21
259
 
260
; back to program start
261
jmp skipsig
262
 
460 mateuszvis 263
; command.com tail arguments, in PSP format: length byte followed by args and
465 mateuszvis 264
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
265
; called as respawn (as opposed to being invoked as a normal application)
266
; this allows multiple copies of SvarCOM to stack upon each other.
267
CMDTAIL db 0x01, 0x0A, 0x0D
442 mateuszvis 268
 
1851 mateusz.vi 269
ERRLOAD db ": ERR x, LOAD FAILED", 0x0A, 0x0D, '$'
517 mateuszvis 270
 
271
; variables used to revert stdin/stdout to their initial state
272
OLD_STDOUT dw 0xffff
273
OLD_STDIN  dw 0xffff
274
 
275
 
520 mateuszvis 276
; ****************************************************************************
517 mateuszvis 277
; *** ROUTINES ***************************************************************
520 mateuszvis 278
; ****************************************************************************
517 mateuszvis 279
 
520 mateuszvis 280
; ----------------------------------------------------------------------------
517 mateuszvis 281
; revert stdin/stdout redirections (if any) to their initial state
282
REVERT_REDIR_IF_ANY:
283
; is stdout redirected?
284
mov bx, [OLD_STDOUT]
285
cmp bx, 0xffff
286
je STDOUT_DONE
519 mateuszvis 287
; revert the stdout handle (dst in BX already)
517 mateuszvis 288
mov cx, 1        ; src handle (1=stdout)
289
mov ah, 0x46     ; redirect a handle
290
int 0x21
519 mateuszvis 291
; close the old handle (still in bx)
292
mov ah, 0x3e
293
int 0x21
517 mateuszvis 294
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
295
STDOUT_DONE:
543 mateuszvis 296
 
297
; is stdin redirected?
298
mov bx, [OLD_STDIN]
299
cmp bx, 0xffff
300
je STDIN_DONE
547 mateuszvis 301
; revert the stdin handle (dst in BX already)
543 mateuszvis 302
xor cx, cx       ; src handle (0=stdin)
303
mov ah, 0x46     ; redirect a handle
304
int 0x21
305
; close the old handle (still in bx)
306
mov ah, 0x3e
307
int 0x21
308
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
576 mateuszvis 309
 
310
; delete stdin file if required
311
cmp [REDIR_DEL_STDIN], byte 0
312
je STDIN_DONE
313
; revert the original file and delete it
314
mov ah, [REDIR_DEL_STDIN]
315
mov [REDIR_INFIL], ah
316
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
317
mov dx, REDIR_INFIL
318
int 0x21
319
mov [REDIR_INFIL], byte 0
320
mov [REDIR_DEL_STDIN], byte 0
321
 
543 mateuszvis 322
STDIN_DONE:
323
 
517 mateuszvis 324
ret
520 mateuszvis 325
; ----------------------------------------------------------------------------
517 mateuszvis 326
 
327
 
520 mateuszvis 328
; ----------------------------------------------------------------------------
517 mateuszvis 329
; redirect stdout if REDIR_OUTFIL points to something
543 mateuszvis 330
REDIR_INOUTFILE_IF_REQUIRED:
548 mateuszvis 331
cmp [REDIR_OUTFIL], byte 0
517 mateuszvis 332
je NO_STDOUT_REDIR
548 mateuszvis 333
mov si, REDIR_OUTFIL   ; si = output file
517 mateuszvis 334
mov ax, 0x6c00         ; Extended Open/Create
335
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
336
xor cx, cx             ; file attribs when(if) file is created (0=normal)
337
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
338
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 339
mov [REDIR_OUTFIL], byte 0
517 mateuszvis 340
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
520 mateuszvis 341
 
342
; jump to end of file if flag was 0x11 (required for >> redirections)
343
cmp [REDIR_OUTAPPEND], word 0x11
344
jne SKIP_JMPEOF
345
mov bx, ax
346
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
347
xor cx, cx
348
xor dx, dx
349
int 0x21
350
mov ax, bx             ; put my handle back in ax, as expected by later code
351
SKIP_JMPEOF:
352
 
517 mateuszvis 353
; duplicate current stdout so I can revert it later
354
push ax                ; save my file handle in stack
355
mov ah, 0x45           ; duplicate file handle BX
548 mateuszvis 356
mov bx, 1              ; 1 = stdout
517 mateuszvis 357
int 0x21               ; ax=new (duplicated) file handle
358
mov [OLD_STDOUT], ax   ; save the old handle in memory
520 mateuszvis 359
 
517 mateuszvis 360
; redirect stdout to my file
361
pop bx                 ; dst handle
362
mov cx, 1              ; src handle (1=stdout)
363
mov ah, 0x46           ; "redirect a handle"
364
int 0x21
520 mateuszvis 365
 
517 mateuszvis 366
; close the original file handle, I no longer need it
367
mov ah, 0x3e           ; close a file handle (handle in BX)
519 mateuszvis 368
int 0x21
517 mateuszvis 369
NO_STDOUT_REDIR:
543 mateuszvis 370
 
371
; *** redirect stdin if REDIR_INFIL points to something ***
548 mateuszvis 372
cmp [REDIR_INFIL], byte 0
543 mateuszvis 373
je NO_STDIN_REDIR
548 mateuszvis 374
mov dx, REDIR_INFIL    ; dx:dx = file
543 mateuszvis 375
mov ax, 0x3d00         ; open file for read
376
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 377
mov [REDIR_INFIL], byte 0
543 mateuszvis 378
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
379
 
380
; duplicate current stdin so I can revert it later
381
push ax                ; save my file handle in stack
382
mov ah, 0x45           ; duplicate file handle BX
383
xor bx, bx             ; 0=stdin
384
int 0x21               ; ax=new (duplicated) file handle
385
mov [OLD_STDIN], ax    ; save the old handle in memory
386
 
387
; redirect stdout to my file
388
pop bx                 ; dst handle
389
xor cx, cx             ; src handle (0=stdin)
390
mov ah, 0x46           ; "redirect a handle"
391
int 0x21
392
 
393
; close the original file handle, I no longer need it
394
mov ah, 0x3e           ; close a file handle (handle in BX)
395
int 0x21
396
NO_STDIN_REDIR:
517 mateuszvis 397
ret
1863 mateusz.vi 398
 
399
 
400
; ****************************************************************************
401
; *                                                                          *
402
; * INT 24H HANDLER                                                          *
403
; *                                                                          *
404
; ****************************************************************************
405
;
406
; this is an executable image that can be set up as the critical error handler
1867 mateusz.vi 407
; interrupt (int 24h). It displays the usual "Abort, Retry, Fail..." prompt.
1863 mateusz.vi 408
;
409
; documentation:
410
; http://www.techhelpmanual.com/564-int_24h__critical_error_handler.html
411
;
412
; === CRIT HANDLER DETAILS ====================================================
413
;
414
; *** ON ENTRY ***
415
;
416
; upon entry to the INT 24h handler, the registers are as follows:
417
;  BP:SI = addr of a "device header" that identifies the failing device
418
;     DI = error code in lower 8 bits (only for non-disk errors)
419
;     AL = drive number, but only if AH bit 7 is reset
420
;     AH = error flags
421
;        0x80 = reset if device is a disk, set otherwise
422
;           all the following are valid ONLY for disks (0x80 reset):
423
;        0x20 = set if "ignore" action allowed
424
;        0x10 = set if "retry" action allowed
425
;        0x08 = set if "fail" action allowed
426
;        0x06 = disk area, 0=sys files, 1=fat, 10=directory, 11=data
427
;        0x01 = set if failure is a write, reset if read
428
;
429
; within the int 24h handler, only these DOS functions are allowed:
430
;   01H-0CH (DOS character I/O)
431
;   33H (all subfns are OK, including 3306H get DOS version)
432
;   50H (set PSP address)
433
;   51H and 62H (query PSP address)
434
;   59H (get extended error information)
435
;
436
; *** ON EXIT ***
437
;
438
; After handling the error, AL should be set with an action code and get back
439
; to DOS. Available actions are defined in AH at entry (see above). Possible
440
; values on exit are:
441
;   AL=0  ignore error (pretend nothing happened)
442
;   AL=1  retry operation
443
;   AL=2  abort (terminates the failed program via int 23h, like ctrl+break)
444
;   AL=3  return to application indicating a failure of the DOS function
445
;
446
; A very basic "always fail" handler would be as simple as this:
447
;   mov al, 3
448
;   iret
449
;
450
; *** DOS CALLS ***
451
;
452
; Warning! Be careful about using DOS fns in your Critical Error handler.
453
;          With DOS 5.0+, ONLY the following fns can be called safely:
454
;
455
;          01H-0CH (DOS character I/O)
456
;          33H (all subfns are OK, including 3306H get DOS version)
457
;          50H (set PSP address)
458
;          51H and 62H (query PSP address)
459
;          59H (get extended error information)
460
;
461
; =============================================================================
1986 mateusz.vi 462
HANDLER_24H:    ; +46Dh
1863 mateusz.vi 463
 
1868 mateusz.vi 464
; save registers so I can restore them later. AX does not require saving.
465
; Microsoft documentation says:
466
;  "When it is desired to ignore an error, the same registers must be preserved
467
;   as when it is desired to retry the operation (SS,SP,DS,BX,CX,DX)."
468
; source: INT24.DOC from MS-DOS 2.0
469
push bx
470
push cx
471
push dx
472
push ds
473
pushf
1863 mateusz.vi 474
 
1869 mateusz.vi 475
mov ch, ah      ; backup AH flags into CH
476
 
1872 mateusz.vi 477
; Get the segment to the original process PSP. Using int 21h,ah=62h should be
478
; safe, RBIL says: "This function does not use any of the DOS-internal stacks
479
; and may thus be called at any time, even during another INT 21h call"
1869 mateusz.vi 480
mov ah, 0x62
1872 mateusz.vi 481
int 0x21        ; segment of the original PSP is in BX now
1869 mateusz.vi 482
 
1872 mateusz.vi 483
; set DS to the original PSP
484
mov ds, bx
485
 
1875 mateusz.vi 486
; load the pointer to the original JFT, set DS to the JFT seg and BX to offset
487
lds bx, [0x34]  ; same as "mov bx, [0x34]" + "mov ds, [0x36]", but smaller
488
 
489
; save the original process stdin and stdout (at [BX]) on stack, as well as a
490
; dword pointer to the original JFT
491
push word [bx]  ; original stdin and stdout (from the JFT at DS:BX)
1873 mateusz.vi 492
push ds
1869 mateusz.vi 493
push bx
494
 
495
; overwrite the original process stdin and stdout with stderr, in case stdout
496
; or stdin was redirected.
1872 mateusz.vi 497
mov dl, [bx+2]   ; the process stderr (3rd entry of the JFT in original PSP)
1873 mateusz.vi 498
mov dh, dl       ; dup DL so I can overwrite stdin and stdout with one write
1872 mateusz.vi 499
mov [bx], dx
1869 mateusz.vi 500
 
501
; set DS to myself so I can reach (and display) my messages
1863 mateusz.vi 502
push cs
503
pop ds
504
 
505
; is this a DISK error?
1869 mateusz.vi 506
test ch, 0x80
1864 mateusz.vi 507
jz DISKERROR
1863 mateusz.vi 508
; non-disk error: output "CRITICAL ERROR #XXX SYSTEM HALTED" and freeze
509
; update the crit string so it contains the proper error code
1881 mateusz.vi 510
mov bx, CRITERRSYST+2
1863 mateusz.vi 511
mov ax, di
512
xor ah, ah
513
mov cl, 100
514
div cl ; AL = AX / cl     AH = remainder
515
add al, '0'
1864 mateusz.vi 516
mov [bx], al
517
inc bx
1863 mateusz.vi 518
 
519
mov al, ah
520
xor ah, ah
521
mov cl, 10
522
div cl
523
add al, '0'
524
add ah, '0'
1864 mateusz.vi 525
mov [bx], al
526
inc bx
527
mov [bx], ah
1863 mateusz.vi 528
 
529
; display the string
530
mov ah, 0x09
531
mov dx, CRITERR
532
int 0x21
1864 mateusz.vi 533
mov dx, CRITERRSYST
534
int 0x21
1863 mateusz.vi 535
; freeze the system
536
HALT:
537
sti
538
hlt;
539
jmp HALT
540
 
541
DISKERROR:
1864 mateusz.vi 542
; disk errors produce this message:
1866 mateusz.vi 543
; A: - READ|WRITE FAILURE
544
; (A)bort, (R)etry, (I)gnore, (F)ail
1864 mateusz.vi 545
add al, 'A'
1866 mateusz.vi 546
mov [CRITERRDISK], al
1864 mateusz.vi 547
mov ah, 0x09
548
mov dx, CRITERRDISK
549
int 0x21
550
; READ / WRITE (test flag 0x01, set = write, read otherwise)
551
mov dx, CRITERRDSK_WRITE
552
test ch, 1
553
jnz WRITE
554
mov dx, CRITERRDSK_READ
555
WRITE:
556
int 0x21
1866 mateusz.vi 557
mov dx, CRLF
1864 mateusz.vi 558
int 0x21
1866 mateusz.vi 559
; print available options (abort=always, 0x10=retry, 0x20=ignore, 0x08=fail)
560
CRITERR_ASKCHOICE:
561
mov dx, CRITERR_ABORT
562
int 0x21
563
; retry?
564
test ch, 0x10
565
jz NORETRY
566
mov dx, CRITERR_COMMA
567
int 0x21
568
mov dx, CRITERR_RETRY
569
int 0x21
570
NORETRY:
571
; ignore?
572
test ch, 0x20
573
jz NOIGNORE
574
mov dx, CRITERR_COMMA
575
int 0x21
576
mov dx, CRITERR_IGNOR
577
int 0x21
578
NOIGNORE:
579
; fail?
580
test ch, 0x08
581
jz NOFAIL
582
mov dx, CRITERR_COMMA
583
int 0x21
584
mov dx, CRITERR_FAIL
585
int 0x21
586
NOFAIL:
587
; output "? "
588
mov ah, 0x06
589
mov dl, '?'
590
int 0x21
591
mov dl, ' '
592
int 0x21
1863 mateusz.vi 593
 
1866 mateusz.vi 594
; wait for user key press and return (iret) with AL set accordingly:
595
;   AL=0  ignore
596
;   AL=1  retry
597
;   AL=2  abort
598
;   AL=3  fail
1863 mateusz.vi 599
 
1866 mateusz.vi 600
mov ah, 0x07  ; key input, no ctrl+c check
601
int 0x21
602
and al, 0xdf   ; switch AL to upper-case so key check is case-insensitive
603
mov cl, al     ; save pressed key in CL (AL is easily overwritten by DOS calls)
604
; print the pressed key
605
mov ah, 0x06
606
mov dl, cl
607
int 0x21
608
mov ah, 0x09
609
mov dx, CRLF
610
int 0x21
611
 
612
; was it abort?
613
cmp cl, [CRITERR_KEYS]
614
jne SKIP_ABORT
615
mov al, 2     ; AL=2 -> "abort"
1868 mateusz.vi 616
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 617
SKIP_ABORT:
618
; if retry is allowed - was it retry?
619
test ch, 0x10
620
jz SKIP_RETRY
621
cmp cl, [CRITERR_KEYS+1]
622
jne SKIP_RETRY
623
mov al, 1     ; AL=1 -> "retry"
1868 mateusz.vi 624
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 625
SKIP_RETRY:
626
; if ignore is allowed - was it ignore?
627
test ch, 0x20
628
jz SKIP_IGN
629
cmp cl, [CRITERR_KEYS+2]
630
jne SKIP_IGN
631
xor al, al    ; AL=0 -> "ignore"
1868 mateusz.vi 632
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 633
SKIP_IGN:
634
; if fail is allowed - was it fail?
635
test ch, 0x08
636
;jz SKIP_FAIL
637
cmp cl, [CRITERR_KEYS+3]
638
jne SKIP_FAIL
639
mov al, 3     ; AL=3 -> "fail"
1868 mateusz.vi 640
jmp short QUIT_WITH_AL_SET
1866 mateusz.vi 641
SKIP_FAIL:
1863 mateusz.vi 642
 
1866 mateusz.vi 643
jmp CRITERR_ASKCHOICE   ; invalid answer -> ask again
644
 
1868 mateusz.vi 645
QUIT_WITH_AL_SET:
646
 
1872 mateusz.vi 647
; restore original stdin/stdout handlers in the original JFT
1875 mateusz.vi 648
pop bx        ; original process' JFT offset
649
pop ds        ; original process' JFT segment
650
pop word [bx] ; original process' stdin and stdout handlers
1869 mateusz.vi 651
 
1872 mateusz.vi 652
; restore registers to their original values and quit the handler (AL is
653
; already set to a proper action value and AH does not matter since it was
654
; changed by the kernel's int 24h calling routine anyway)
1868 mateusz.vi 655
popf
656
pop ds
657
pop dx
658
pop cx
659
pop bx
660
iret
1866 mateusz.vi 661
 
1881 mateusz.vi 662
; translatable messages, each message is stored inside a 16-bytes field.
663
; SvarCOM relies on the position and length of these fields to update messages
664
; accordingly to the selected language.
665
CRITERR db          "CRITICAL ERROR$ "
666
CRITERRDSK_READ db  "READ FAILURE$   "
667
CRITERRDSK_WRITE db "WRITE FAILURE$  "
668
CRITERR_ABORT db    "(A)bort$        "
669
CRITERR_RETRY db    "(R)etry$        "
670
CRITERR_IGNOR db    "(I)gnore$       "
671
CRITERR_FAIL  db    "(F)ail$         "
672
CRITERR_KEYS  db    "ARIF"        ; upcase keys for Abort, Retry, Ignore, Fail
673
CRITERRSYST db      " #XXX$"
1866 mateusz.vi 674
CRITERRDISK db "@: - $"
1881 mateusz.vi 675
CRITERR_COMMA db ", $"
1866 mateusz.vi 676
CRLF db 0x0A, 0x0D, "$"