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