Subversion Repositories SvarDOS

Rev

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