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