2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: DOS32 command.com for NTVDM
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
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
14 /* INCLUDES *******************************************************************/
17 #include "asmxtras.inc"
22 /* DEFINES ********************************************************************/
25 #define DOS_CMDLINE_LENGTH 127
27 #define DOS_VERSION HEX(0005) // MAKEWORD(5, 00)
28 #define NTDOS_VERSION HEX(3205) // MAKEWORD(5, 50)
30 #define SYSTEM_PSP HEX(08)
32 #define BOP .byte HEX(C4), HEX(C4),
33 // #define BOP_START_DOS HEX(2C)
34 #define BOP_CMD HEX(54)
36 /**** PSP MEMBERS ****/
37 #define PSP_VAR(x) es:[x]
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]
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)]
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.
53 /* NEXT_CMD structure */
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)
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)
87 /* RESIDENT CODE AND DATA *****************************************************/
91 ASSUME CS:.text, DS:.text, ES:.text
94 /* CODE *******************************/
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.
106 * FIXME: enlarge it for pushing the needed Load&Exec data.
111 mov bp, offset BaseStack
112 lea sp, [bp + (1 + DOS_CMDLINE_LENGTH) + MAX_PATH + 255]
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
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).
127 cmp word ptr OldParentPsp, SYSTEM_PSP // Check whether our parent is SYSTEM
131 /********************************/
135 /********************************/
138 BOP BOP_CMD, HEX(0A) // Start 32-bit COMSPEC
141 /* Loop for new commands to 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
151 /* Wait for the next command */
153 /********************************/
157 /********************************/
160 // FIXME: Initialize memory with structure for holding CmdLine etc...
161 // mov ds, seg NextCmd
162 mov dx, offset NextCmd
164 /* Quit if we shell-out */
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
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 !!
182 popa // Restore the registers
183 // FIXME: Restore also SS !!
185 /* Retrieve and set its exit code. Also detect whether
186 * we need to continue or whether we need to quit. */
191 /* Send exit code back to NTVDM */
195 /* If we don't shell-out, go and get a new app! */
198 mov al, HEX(00) // ERROR_SUCCESS
201 mov bl, al // Save AL in BL
204 /********************************/
211 /********************************/
216 // mov ds, seg QuitMsg
217 mov dx, offset QuitMsg
222 /* Restore our old parent PSP */
223 mov ax, word ptr OldParentPsp
224 mov PSP_VAR(ParentPsp), ax
226 mov al, bl // Restore AL from BL
229 /* Return to caller (with possible error code in AL) */
234 /* Does not return */
236 /* DATA *******************************/
240 .ascii "Bye bye!", CR, LF, "$"
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 /********************************/
249 OldParentPsp: .word 0
252 // BOP_CMD, HEX(01) "Get a new app to start" structure
253 VAR_STRUCT(NextCmd, NEXT_CMD)
255 // DOS INT 21h, AH=4Bh "Load and Execute" structure
256 VAR_STRUCT(DosLoadExec, DOS_EXEC_PARAM_BLOCK)
258 // Blank FCB blocks needed for DOS INT 21h, AH=4Bh
268 // The stack resides at the end of the resident code+data
269 // and it overwrites the transient part.
273 /* TRANSIENT CODE AND DATA ****************************************************/
275 /* DATA *******************************/
279 .ascii "ReactOS DOS32 Command", CR, LF, \
280 "Copyright (C) ReactOS Team 2015" , CR, LF, "$"
284 .ascii "Incorrect DOS version", CR, LF, "$"
286 /* CODE *******************************/
291 /* Setup segment registers */
292 mov ax, cs // cs contains the PSP segment on entry
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. */
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).
308 cmp ax, DOS_VERSION // AH:AL contains minor:major version number
313 cmp bx, NTDOS_VERSION // BH:BL contains minor:major version number
317 /* Display wrong version error message and exit */
318 // mov ds, seg VerErrMsg
319 mov dx, offset VerErrMsg
326 mov word ptr CurrentPsp, cs
330 * mov ah, HEX(51) // DOS 2+ internal, or HEX(62) since DOS 3+
332 * mov word ptr CurrentPsp, bx
335 /* Save our old parent PSP */
336 mov ax, PSP_VAR(ParentPsp)
337 mov word ptr OldParentPsp, ax
339 /* Give us shell privileges: set our PSP as our new parent */
340 mov ax, word ptr CurrentPsp
341 mov PSP_VAR(ParentPsp), ax
345 // mov ds, seg WelcomeMsg
346 mov dx, offset WelcomeMsg
351 /* Jump to resident code */