[SNDVOL32] Create small speaker icons from the default sndvol32 icon
[reactos.git] / subsystems / mvdm / dos / command.S
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: command.S
5 * PURPOSE: DOS32 command.com for NTVDM
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 */
8
9 //
10 // See http://www.ganino.com/games/scripts/dos-6.0%20source%20code%3F/dev/smartdrv/umbload.asm
11 // and https://books.google.fr/books?id=rtmJgtfaxz8C&pg=PA256&lpg=PA256&dq=int+21+4b+program+exec+block&source=bl&ots=OfAF7qFwfl&sig=PrW73CE1dzFm3rwrTsYZkC77U4Y&hl=en&sa=X&redir_esc=y#v=onepage&q=int%2021%204b%20program%20exec%20block&f=false
12 //
13
14 /* INCLUDES *******************************************************************/
15
16 #include <asm.inc>
17 #include "asmxtras.inc"
18 #include <isvbop.inc>
19
20 #define NDEBUG
21
22 /* DEFINES ********************************************************************/
23
24 #define MAX_PATH 260
25 #define DOS_CMDLINE_LENGTH 127
26
27 #define DOS_VERSION HEX(0005) // MAKEWORD(5, 00)
28 #define NTDOS_VERSION HEX(3205) // MAKEWORD(5, 50)
29
30 #define SYSTEM_PSP HEX(08)
31
32 #define BOP .byte HEX(C4), HEX(C4),
33 // #define BOP_START_DOS HEX(2C)
34 #define BOP_CMD HEX(54)
35
36 /**** PSP MEMBERS ****/
37 #define PSP_VAR(x) es:[x]
38 #define PSP HEX(0000)
39 #define ParentPsp HEX(0016) // word
40 #define EnvBlock HEX(002C) // word
41 #define CmdLineLen HEX(0080) // byte
42 #define CmdLineStr HEX(0081) // byte[DOS_CMDLINE_LENGTH]
43
44 /**** DATA stored inside the stack ****/
45 #define CmdLine BaseStack // Command line for the program to be started
46 #define PgmName [CmdLine + (1 + DOS_CMDLINE_LENGTH)]
47
48
49 // WARNING! Using the VAL(x) macro doesn't work with GCC/GAS (because it inserts
50 // a spurious space in front of the parameter when the macro is expanded).
51 // So that: 'VAL(foo)' is expanded to: '\ foo', instead of '\foo' as one would expect.
52
53 /* NEXT_CMD structure */
54 STRUCT(NEXT_CMD, 2)
55 FIELD_DECL(EnvBlockSeg, word, 0)
56 FIELD_DECL(EnvBlockLen, word, 0)
57 FIELD_DECL(CurDrive , word, 0)
58 FIELD_DECL(NumDrives , word, 1)
59 FIELD_DECL(CmdLineSeg , word, 0)
60 FIELD_DECL(CmdLineOff , word, 0)
61 FIELD_DECL(Unknown0 , word, 2)
62 FIELD_DECL(ExitCode , word, 3)
63 FIELD_DECL(Unknown1 , word, 4)
64 FIELD_DECL(Unknown2 , long, 5)
65 FIELD_DECL(CodePage , word, 6)
66 FIELD_DECL(Unknown3 , word, 7)
67 FIELD_DECL(Unknown4 , word, 8)
68 FIELD_DECL(AppNameSeg , word, 0)
69 FIELD_DECL(AppNameOff , word, 0)
70 FIELD_DECL(AppNameLen , word, 0)
71 FIELD_DECL(Flags , word, 0)
72 ENDS(NEXT_CMD)
73
74 /* DOS_EXEC_PARAM_BLOCK structure */
75 STRUCT(DOS_EXEC_PARAM_BLOCK, 2)
76 FIELD_DECL(EnvSeg, word, 0) // Use parent's environment (ours)
77 FIELD_DECL(CmdLineOff, word, OFF(CmdLine))
78 FIELD_DECL(CmdLineSeg, word, 0)
79 FIELD_DECL(Fcb1Off, word, OFF(Fcb1))
80 FIELD_DECL(Fcb1Seg, word, 0)
81 FIELD_DECL(Fcb2Off, word, OFF(Fcb2))
82 FIELD_DECL(Fcb2Seg, word, 0)
83 ENDS(DOS_EXEC_PARAM_BLOCK)
84
85
86
87 /* RESIDENT CODE AND DATA *****************************************************/
88
89 .code16
90 // .org HEX(0100)
91 ASSUME CS:.text, DS:.text, ES:.text
92
93
94 /* CODE *******************************/
95
96 EntryPoint:
97 jmp Main
98 .align 2
99
100 ResidentMain:
101 /*
102 * Relocate our stack.
103 * Our local stack is big enough for holding the command line and the path
104 * to the executable to start, plus a full DOS_REGISTER_STATE and for one pusha 16-bit.
105 *
106 * FIXME: enlarge it for pushing the needed Load&Exec data.
107 */
108 cli
109 mov ax, ds
110 mov ss, ax
111 mov bp, offset BaseStack
112 lea sp, [bp + (1 + DOS_CMDLINE_LENGTH) + MAX_PATH + 255]
113 sti
114
115 /* Resize ourselves */
116 mov bx, sp // Get size in bytes...
117 // sub bx, offset PSP_VAR(PSP)
118 add bx, HEX(0F) // (for rounding to the next paragraph)
119 shr bx, 4 // ... then the number of paragraphs
120 mov ah, HEX(4A)
121 int HEX(21)
122
123 /* Check whether we need to start the 32-bit command interpreter */
124 BOP BOP_CMD, HEX(10) // Check whether we were started from a new console (SessionId != 0)
125 test al, al // and we are not reentering (32-bit process starting a 16-bit process).
126 jz Run
127 cmp word ptr OldParentPsp, SYSTEM_PSP // Check whether our parent is SYSTEM
128 je Run
129
130 #ifndef NDEBUG
131 /********************************/
132 mov dx, offset Msg1
133 mov ah, HEX(09)
134 int HEX(21)
135 /********************************/
136 #endif
137
138 BOP BOP_CMD, HEX(0A) // Start 32-bit COMSPEC
139 jnc Quit
140
141 /* Loop for new commands to run */
142 Run:
143 /* Initialize the NextCmd structure */
144 mov word ptr FIELD(NextCmd, EnvBlockSeg), ds
145 mov word ptr FIELD(NextCmd, EnvBlockLen), 0 // FIXME
146 mov word ptr FIELD(NextCmd, CmdLineSeg), ds
147 mov word ptr FIELD(NextCmd, CmdLineOff), offset CmdLine
148 mov word ptr FIELD(NextCmd, AppNameSeg), ds
149 mov word ptr FIELD(NextCmd, AppNameOff), offset PgmName
150
151 /* Wait for the next command */
152 #ifndef NDEBUG
153 /********************************/
154 mov dx, offset Msg2
155 mov ah, HEX(09)
156 int HEX(21)
157 /********************************/
158 #endif
159
160 // FIXME: Initialize memory with structure for holding CmdLine etc...
161 // mov ds, seg NextCmd
162 mov dx, offset NextCmd
163 BOP BOP_CMD, HEX(01)
164 /* Quit if we shell-out */
165 jc Quit
166
167 /* Initialize the DosLoadExec structure */
168 // mov word ptr FIELD(DosLoadExec, EnvSeg), 0
169 mov word ptr FIELD(DosLoadExec, CmdLineSeg), ds
170 mov word ptr FIELD(DosLoadExec, Fcb1Seg), ds
171 mov word ptr FIELD(DosLoadExec, Fcb2Seg), ds
172
173 /* Run the command */
174 mov ds, word ptr FIELD(NextCmd, AppNameSeg)
175 mov dx, word ptr FIELD(NextCmd, AppNameOff)
176 // mov es, seg DosLoadExec
177 mov bx, offset DosLoadExec
178 pusha // Save the registers in case stuff go wrong
179 // FIXME: Save also SS !!
180 mov ax, HEX(4B00)
181 int HEX(21)
182 popa // Restore the registers
183 // FIXME: Restore also SS !!
184
185 /* Retrieve and set its exit code. Also detect whether
186 * we need to continue or whether we need to quit. */
187 // xor ax, ax
188 // mov ah, HEX(4D)
189 mov ax, HEX(4D00)
190 int HEX(21)
191 /* Send exit code back to NTVDM */
192 mov dx, ax
193 BOP BOP_CMD, HEX(0B)
194
195 /* If we don't shell-out, go and get a new app! */
196 jc Run
197
198 mov al, HEX(00) // ERROR_SUCCESS
199
200 Quit:
201 mov bl, al // Save AL in BL
202
203 #ifndef NDEBUG
204 /********************************/
205 cmp al, HEX(0A)
206 jne XXXX
207 mov dx, offset Msg3
208 mov ah, HEX(09)
209 int HEX(21)
210 XXXX:
211 /********************************/
212 #endif
213
214 #ifndef NDEBUG
215 /* Say bye-bye */
216 // mov ds, seg QuitMsg
217 mov dx, offset QuitMsg
218 mov ah, HEX(09)
219 int HEX(21)
220 #endif
221
222 /* Restore our old parent PSP */
223 mov ax, word ptr OldParentPsp
224 mov PSP_VAR(ParentPsp), ax
225
226 mov al, bl // Restore AL from BL
227
228 Exit:
229 /* Return to caller (with possible error code in AL) */
230 mov ah, HEX(4C)
231 int HEX(21)
232 int 3
233
234 /* Does not return */
235
236 /* DATA *******************************/
237
238 #ifndef NDEBUG
239 QuitMsg:
240 .ascii "Bye bye!", CR, LF, "$"
241
242 /********************************/
243 Msg1: .ascii "Starting COMSPEC...", CR, LF, "$"
244 Msg2: .ascii "Waiting for new command...", CR, LF, "$"
245 Msg3: .ascii "Bad environment!", CR, LF, "$"
246 /********************************/
247 #endif
248
249 OldParentPsp: .word 0
250 CurrentPsp: .word 0
251
252 // BOP_CMD, HEX(01) "Get a new app to start" structure
253 VAR_STRUCT(NextCmd, NEXT_CMD)
254
255 // DOS INT 21h, AH=4Bh "Load and Execute" structure
256 VAR_STRUCT(DosLoadExec, DOS_EXEC_PARAM_BLOCK)
257
258 // Blank FCB blocks needed for DOS INT 21h, AH=4Bh
259 Fcb1:
260 .byte 0
261 .space 11, ' '
262 .space 25, 0
263 Fcb2:
264 .byte 0
265 .space 11, ' '
266 .space 25, 0
267
268 // The stack resides at the end of the resident code+data
269 // and it overwrites the transient part.
270 BaseStack:
271
272
273 /* TRANSIENT CODE AND DATA ****************************************************/
274
275 /* DATA *******************************/
276
277 #ifndef NDEBUG
278 WelcomeMsg:
279 .ascii "ReactOS DOS32 Command", CR, LF, \
280 "Copyright (C) ReactOS Team 2015" , CR, LF, "$"
281 #endif
282
283 VerErrMsg:
284 .ascii "Incorrect DOS version", CR, LF, "$"
285
286 /* CODE *******************************/
287
288 .align 2
289
290 Main:
291 /* Setup segment registers */
292 mov ax, cs // cs contains the PSP segment on entry
293 mov ds, ax
294 mov es, ax
295 // mov fs, ax
296 // mov gs, ax
297 /* Stack is set to cs:FFFE down to cs:09xx by the DOS.
298 * We will need to relocate it before we resize ourselves. */
299
300 /*
301 * Verify DOS version:
302 * - Check whether we are on DOS 5+ (subject to SETVER);
303 * - If so, check our real DOS version and see
304 * whether we are running on NTVDM (version 5.50).
305 */
306 mov ax, HEX(3000)
307 int HEX(21)
308 cmp ax, DOS_VERSION // AH:AL contains minor:major version number
309 jne VerErr
310
311 mov ax, HEX(3306)
312 int HEX(21)
313 cmp bx, NTDOS_VERSION // BH:BL contains minor:major version number
314 je Continue
315
316 VerErr:
317 /* Display wrong version error message and exit */
318 // mov ds, seg VerErrMsg
319 mov dx, offset VerErrMsg
320 mov ah, HEX(09)
321 int HEX(21)
322 jmp Exit
323
324 Continue:
325 /* Save our PSP */
326 mov word ptr CurrentPsp, cs
327 /*
328 * The DOS way:
329 *
330 * mov ah, HEX(51) // DOS 2+ internal, or HEX(62) since DOS 3+
331 * int HEX(21)
332 * mov word ptr CurrentPsp, bx
333 */
334
335 /* Save our old parent PSP */
336 mov ax, PSP_VAR(ParentPsp)
337 mov word ptr OldParentPsp, ax
338
339 /* Give us shell privileges: set our PSP as our new parent */
340 mov ax, word ptr CurrentPsp
341 mov PSP_VAR(ParentPsp), ax
342
343 #ifndef NDEBUG
344 /* Say hello */
345 // mov ds, seg WelcomeMsg
346 mov dx, offset WelcomeMsg
347 mov ah, HEX(09)
348 int HEX(21)
349 #endif
350
351 /* Jump to resident code */
352 jmp ResidentMain
353
354 .endcode16
355 END
356
357 /* EOF */