Subversion Repositories SvarDOS

Rev

Rev 547 | Rev 576 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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