Subversion Repositories SvarDOS

Rev

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

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