Subversion Repositories SvarDOS

Rev

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