Subversion Repositories SvarDOS

Rev

Rev 1730 | Rev 1849 | 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
 
1713 bttr 41
; fallback COMSPEC string used if no COMSPEC is present in the environment
366 mateuszvis 42
; drive. 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
 
1178 mateusz.vi 101
; set up myself as int 0x2E handler ("pass command to shell")
102
mov ax, 0x252E
103
mov dx, INT2E ; TODO do something meaningful instead of a no-op
104
int 0x21
105
 
517 mateuszvis 106
; revert stdin/stdout redirections (if any) to their initial state
107
call REVERT_REDIR_IF_ANY
108
 
576 mateuszvis 109
; redirect stdin and/or stdout if required
543 mateuszvis 110
call REDIR_INOUTFILE_IF_REQUIRED
517 mateuszvis 111
 
1593 mateusz.vi 112
; should I execute command.com or a pre-set application?
113
cmp [EXECPROG], byte 0
460 mateuszvis 114
jz EXEC_COMMAND_COM
115
 
461 mateuszvis 116
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
117
;       int 21h, ah=50h call freezes...
118
;mov ah, 0x50           ; DOS 2+ -- Set PSP
119
;mov bx, cs
120
;int 0x21
460 mateuszvis 121
 
1730 mateusz.vi 122
 
123
; LOADHIGH?
124
cmp [EXEC_LH], byte 0
125
je NO_LOADHIGH
126
; SAVE CURRENT UMB LINK STATE
127
mov ax, 0x5802  ; GET UMB LINK STATE
128
int 0x21
129
mov [ORIG_UMBLINKSTATE], al
130
; SAVE CURRENT ALLOCATION STRATEGY
131
mov ax, 0x5800
132
int 0x21
133
mov [ORIG_ALLOCSTRAT], al
134
 
135
; LOADHIGH: link in the UMB memory chain for enabling high-memory allocation
136
;           (and save initial status on stack)
137
mov ax, 0x5803  ; SET UMB LINK STATE */
138
mov bx, 1
139
int 0x21
140
; set strategy to 'last fit, try high then low memory'
141
mov ax, 0x5801
142
mov bx, 0x0082
143
int 0x21
144
NO_LOADHIGH:
145
 
460 mateuszvis 146
; exec an application preset (by SvarCOM) in the ExecParamRec
147
mov ax, 0x4B00         ; DOS 2+ - load & execute program
461 mateuszvis 148
mov dx, EXECPROG       ; DS:DX  - ASCIZ program name (preset at PSP[already)
460 mateuszvis 149
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
150
int 0x21
465 mateuszvis 151
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
460 mateuszvis 152
 
1730 mateusz.vi 153
; go to start if nothing else to do (this will enforce valid ds/ss/etc)
154
cmp [cs:EXEC_LH], byte 0
155
je skipsig
463 mateuszvis 156
 
1730 mateusz.vi 157
; restore UMB link state and alloc strategy to original values (but make sure
158
; to base it on CS since DS might have been trashed by the program)
159
mov ax, 0x5803
160
xor bx, bx
161
mov bl, [cs:ORIG_UMBLINKSTATE]
162
int 0x21
163
; restore original memory allocation strategy
164
mov ax, 0x5801
165
mov bl, [cs:ORIG_ALLOCSTRAT]
166
int 0x21
167
; turn off the LH flag
168
mov [cs:EXEC_LH], byte 0
169
 
170
 
171
jmp skipsig      ; enforce valid ds/ss/etc (can be lost after int 21,4b)
172
 
460 mateuszvis 173
EXEC_COMMAND_COM:
174
 
353 mateuszvis 175
; collect the exit code of previous application
176
mov ah, 0x4D
177
int 0x21
529 mateuszvis 178
mov [LEXCODE], al
353 mateuszvis 179
 
460 mateuszvis 180
; zero out the exec param block (14 bytes)
181
mov al, 0              ; byte to write
182
mov cx, 14             ; how many times
183
mov di, EXEC_PARAM_REC ; ES:DI = destination
184
cld                    ; stosb must move forward
185
rep stosb              ; repeat cx times
186
 
1730 mateusz.vi 187
; zero out the LH flag
188
mov [EXEC_LH], byte 0
189
 
366 mateuszvis 190
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
191
mov dx, COMSPECBOOT
192
 
193
; do I have a valid COMSPEC?
194
or [COMSPECPTR], word 0
195
jz USEDEFAULTCOMSPEC
459 mateuszvis 196
; set ES:DX to actual COMSPEC (in env segment)
197
mov es, [PSP_ENVSEG]
366 mateuszvis 198
mov dx, [COMSPECPTR]
199
USEDEFAULTCOMSPEC:
200
 
349 mateuszvis 201
; prepare the exec param block
459 mateuszvis 202
mov ax, [PSP_ENVSEG]
350 mateuszvis 203
mov [EXEC_PARAM_REC], ax
465 mateuszvis 204
mov [EXEC_PARAM_REC+2], word CMDTAIL
442 mateuszvis 205
mov [EXEC_PARAM_REC+4], cs
349 mateuszvis 206
 
207
; execute command.com
208
mov ax, 0x4B00         ; DOS 2+ - load & execute program
366 mateuszvis 209
push es                ;
210
pop ds                 ;
211
;mov dx, COMSPEC       ; DS:DX  - ASCIZ program name (preset already)
212
push cs
213
pop es
349 mateuszvis 214
mov bx, EXEC_PARAM_REC ; ES:BX  - parameter block pointer
215
int 0x21
216
 
217
; if all went well, jump back to start
218
jnc skipsig
219
 
366 mateuszvis 220
; restore DS=CS
221
mov bx, cs
222
mov ds, bx
223
 
349 mateuszvis 224
; update error string so it contains the error number
225
add al, '0'
226
mov [ERRLOAD + 4], al
227
 
366 mateuszvis 228
; display error message
349 mateuszvis 229
mov ah, 0x09
230
mov dx, ERRLOAD
231
int 0x21
232
 
233
; wait for keypress
234
mov ah, 0x08
235
int 0x21
236
 
237
; back to program start
238
jmp skipsig
239
 
460 mateuszvis 240
; command.com tail arguments, in PSP format: length byte followed by args and
465 mateuszvis 241
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
242
; called as respawn (as opposed to being invoked as a normal application)
243
; this allows multiple copies of SvarCOM to stack upon each other.
244
CMDTAIL db 0x01, 0x0A, 0x0D
442 mateuszvis 245
 
366 mateuszvis 246
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
517 mateuszvis 247
 
248
; variables used to revert stdin/stdout to their initial state
249
OLD_STDOUT dw 0xffff
250
OLD_STDIN  dw 0xffff
251
 
252
 
520 mateuszvis 253
; ****************************************************************************
517 mateuszvis 254
; *** ROUTINES ***************************************************************
520 mateuszvis 255
; ****************************************************************************
517 mateuszvis 256
 
520 mateuszvis 257
; ----------------------------------------------------------------------------
517 mateuszvis 258
; revert stdin/stdout redirections (if any) to their initial state
259
REVERT_REDIR_IF_ANY:
260
; is stdout redirected?
261
mov bx, [OLD_STDOUT]
262
cmp bx, 0xffff
263
je STDOUT_DONE
519 mateuszvis 264
; revert the stdout handle (dst in BX already)
517 mateuszvis 265
mov cx, 1        ; src handle (1=stdout)
266
mov ah, 0x46     ; redirect a handle
267
int 0x21
519 mateuszvis 268
; close the old handle (still in bx)
269
mov ah, 0x3e
270
int 0x21
517 mateuszvis 271
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
272
STDOUT_DONE:
543 mateuszvis 273
 
274
; is stdin redirected?
275
mov bx, [OLD_STDIN]
276
cmp bx, 0xffff
277
je STDIN_DONE
547 mateuszvis 278
; revert the stdin handle (dst in BX already)
543 mateuszvis 279
xor cx, cx       ; src handle (0=stdin)
280
mov ah, 0x46     ; redirect a handle
281
int 0x21
282
; close the old handle (still in bx)
283
mov ah, 0x3e
284
int 0x21
285
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
576 mateuszvis 286
 
287
; delete stdin file if required
288
cmp [REDIR_DEL_STDIN], byte 0
289
je STDIN_DONE
290
; revert the original file and delete it
291
mov ah, [REDIR_DEL_STDIN]
292
mov [REDIR_INFIL], ah
293
mov ah, 0x41     ; DOS 2+ - delete file pointed at by DS:DX
294
mov dx, REDIR_INFIL
295
int 0x21
296
mov [REDIR_INFIL], byte 0
297
mov [REDIR_DEL_STDIN], byte 0
298
 
543 mateuszvis 299
STDIN_DONE:
300
 
517 mateuszvis 301
ret
520 mateuszvis 302
; ----------------------------------------------------------------------------
517 mateuszvis 303
 
304
 
520 mateuszvis 305
; ----------------------------------------------------------------------------
517 mateuszvis 306
; redirect stdout if REDIR_OUTFIL points to something
543 mateuszvis 307
REDIR_INOUTFILE_IF_REQUIRED:
548 mateuszvis 308
cmp [REDIR_OUTFIL], byte 0
517 mateuszvis 309
je NO_STDOUT_REDIR
548 mateuszvis 310
mov si, REDIR_OUTFIL   ; si = output file
517 mateuszvis 311
mov ax, 0x6c00         ; Extended Open/Create
312
mov bx, 1              ; access mode (0=read, 1=write, 2=r+w)
313
xor cx, cx             ; file attribs when(if) file is created (0=normal)
314
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
315
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 316
mov [REDIR_OUTFIL], byte 0
517 mateuszvis 317
jc NO_STDOUT_REDIR     ; TODO: abort with an error message instead
520 mateuszvis 318
 
319
; jump to end of file if flag was 0x11 (required for >> redirections)
320
cmp [REDIR_OUTAPPEND], word 0x11
321
jne SKIP_JMPEOF
322
mov bx, ax
323
mov ax, 0x4202         ; jump to position EOF - CX:DX in handle BX
324
xor cx, cx
325
xor dx, dx
326
int 0x21
327
mov ax, bx             ; put my handle back in ax, as expected by later code
328
SKIP_JMPEOF:
329
 
517 mateuszvis 330
; duplicate current stdout so I can revert it later
331
push ax                ; save my file handle in stack
332
mov ah, 0x45           ; duplicate file handle BX
548 mateuszvis 333
mov bx, 1              ; 1 = stdout
517 mateuszvis 334
int 0x21               ; ax=new (duplicated) file handle
335
mov [OLD_STDOUT], ax   ; save the old handle in memory
520 mateuszvis 336
 
517 mateuszvis 337
; redirect stdout to my file
338
pop bx                 ; dst handle
339
mov cx, 1              ; src handle (1=stdout)
340
mov ah, 0x46           ; "redirect a handle"
341
int 0x21
520 mateuszvis 342
 
517 mateuszvis 343
; close the original file handle, I no longer need it
344
mov ah, 0x3e           ; close a file handle (handle in BX)
519 mateuszvis 345
int 0x21
517 mateuszvis 346
NO_STDOUT_REDIR:
543 mateuszvis 347
 
348
; *** redirect stdin if REDIR_INFIL points to something ***
548 mateuszvis 349
cmp [REDIR_INFIL], byte 0
543 mateuszvis 350
je NO_STDIN_REDIR
548 mateuszvis 351
mov dx, REDIR_INFIL    ; dx:dx = file
543 mateuszvis 352
mov ax, 0x3d00         ; open file for read
353
int 0x21               ; ax=handle on success (CF clear)
548 mateuszvis 354
mov [REDIR_INFIL], byte 0
543 mateuszvis 355
jc NO_STDIN_REDIR      ; TODO: abort with an error message instead
356
 
357
; duplicate current stdin so I can revert it later
358
push ax                ; save my file handle in stack
359
mov ah, 0x45           ; duplicate file handle BX
360
xor bx, bx             ; 0=stdin
361
int 0x21               ; ax=new (duplicated) file handle
362
mov [OLD_STDIN], ax    ; save the old handle in memory
363
 
364
; redirect stdout to my file
365
pop bx                 ; dst handle
366
xor cx, cx             ; src handle (0=stdin)
367
mov ah, 0x46           ; "redirect a handle"
368
int 0x21
369
 
370
; close the original file handle, I no longer need it
371
mov ah, 0x3e           ; close a file handle (handle in BX)
372
int 0x21
373
NO_STDIN_REDIR:
517 mateuszvis 374
ret
520 mateuszvis 375
; ----------------------------------------------------------------------------