Subversion Repositories SvarDOS

Rev

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

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