Subversion Repositories SvarDOS

Rev

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