Subversion Repositories SvarDOS

Rev

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

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