Subversion Repositories SvarDOS

Rev

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