Subversion Repositories SvarDOS

Rev

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