Subversion Repositories SvarDOS

Rev

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