Subversion Repositories SvarDOS

Rev

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