Something went wrong. Try again.
Reactos
Something went wrong. Try again.
9.3 kB · 351 lines
at listview
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352/* * PROJECT: ReactOS Virtual DOS Machine * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: DOS32 command.com for NTVDM * COPYRIGHT: Copyright 2015-2018 Hermes Belusca-Maito *//* INCLUDES *******************************************************************/#include <asm.inc>#include "asmxtras.inc"#include <isvbop.inc>#define NDEBUG/* DEFINES ********************************************************************/#define MAX_PATH 260#define DOS_CMDLINE_LENGTH 127#define DOS_VERSION HEX(0005) // MAKEWORD(5, 00)#define NTDOS_VERSION HEX(3205) // MAKEWORD(5, 50)#define SYSTEM_PSP HEX(08)#define BOP .byte HEX(C4), HEX(C4),// #define BOP_START_DOS HEX(2C)#define BOP_CMD HEX(54)/**** PSP MEMBERS ****/#define PSP_VAR(x) es:[x]#define PSP HEX(0000)#define ParentPsp HEX(0016) // word#define EnvBlock HEX(002C) // word#define CmdLineLen HEX(0080) // byte#define CmdLineStr HEX(0081) // byte[DOS_CMDLINE_LENGTH]/**** DATA stored inside the stack ****/#define CmdLine BaseStack // Command line for the program to be started#define PgmName [CmdLine + (1 + DOS_CMDLINE_LENGTH)]// WARNING! Using the VAL(x) macro doesn't work with GCC/GAS (because it inserts// a spurious space in front of the parameter when the macro is expanded).// So that: 'VAL(foo)' is expanded to: '\ foo', instead of '\foo' as one would expect./* NEXT_CMD structure */STRUCT(NEXT_CMD, 2) FIELD_DECL(EnvBlockSeg, word, 0) FIELD_DECL(EnvBlockLen, word, 0) FIELD_DECL(CurDrive , word, 0) FIELD_DECL(NumDrives , word, 1) FIELD_DECL(CmdLineSeg , word, 0) FIELD_DECL(CmdLineOff , word, 0) FIELD_DECL(Unknown0 , word, 2) FIELD_DECL(ExitCode , word, 3) FIELD_DECL(Unknown1 , word, 4) FIELD_DECL(Unknown2 , long, 5) FIELD_DECL(CodePage , word, 6) FIELD_DECL(Unknown3 , word, 7) FIELD_DECL(Unknown4 , word, 8) FIELD_DECL(AppNameSeg , word, 0) FIELD_DECL(AppNameOff , word, 0) FIELD_DECL(AppNameLen , word, 0) FIELD_DECL(Flags , word, 0)ENDS(NEXT_CMD)/* DOS_EXEC_PARAM_BLOCK structure */STRUCT(DOS_EXEC_PARAM_BLOCK, 2) FIELD_DECL(EnvSeg, word, 0) // Use parent's environment (ours) FIELD_DECL(CmdLineOff, word, OFF(CmdLine)) FIELD_DECL(CmdLineSeg, word, 0) FIELD_DECL(Fcb1Off, word, OFF(Fcb1)) FIELD_DECL(Fcb1Seg, word, 0) FIELD_DECL(Fcb2Off, word, OFF(Fcb2)) FIELD_DECL(Fcb2Seg, word, 0)ENDS(DOS_EXEC_PARAM_BLOCK)/* RESIDENT CODE AND DATA *****************************************************/.code16// .org HEX(0100)ASSUME CS:.text, DS:.text, ES:.text/* CODE *******************************/EntryPoint: jmp Main.align 2ResidentMain: /* * Relocate our stack. * Our local stack is big enough for holding the command line and the path * to the executable to start, plus a full DOS_REGISTER_STATE and for one pusha 16-bit. * * FIXME: enlarge it for pushing the needed Load&Exec data. */ cli mov ax, ds mov ss, ax mov bp, offset BaseStack lea sp, [bp + (1 + DOS_CMDLINE_LENGTH) + MAX_PATH + 255] sti /* Resize ourselves */ mov bx, sp // Get size in bytes...// sub bx, offset PSP_VAR(PSP) add bx, HEX(0F) // (for rounding to the next paragraph) shr bx, 4 // ... then the number of paragraphs mov ah, HEX(4A) int HEX(21) /* Check whether we need to start the 32-bit command interpreter */ BOP BOP_CMD, HEX(10) // Check whether we were started from a new console (SessionId != 0) test al, al // and we are not reentering (32-bit process starting a 16-bit process). jz Run cmp word ptr OldParentPsp, SYSTEM_PSP // Check whether our parent is SYSTEM je Run#ifndef NDEBUG/********************************/ mov dx, offset Msg1 mov ah, HEX(09) int HEX(21)/********************************/#endif BOP BOP_CMD, HEX(0A) // Start 32-bit COMSPEC jnc Quit /* Loop for new commands to run */Run: /* Initialize the NextCmd structure */ mov word ptr FIELD(NextCmd, EnvBlockSeg), ds mov word ptr FIELD(NextCmd, EnvBlockLen), 0 // FIXME mov word ptr FIELD(NextCmd, CmdLineSeg), ds mov word ptr FIELD(NextCmd, CmdLineOff), offset CmdLine mov word ptr FIELD(NextCmd, AppNameSeg), ds mov word ptr FIELD(NextCmd, AppNameOff), offset PgmName /* Wait for the next command */#ifndef NDEBUG/********************************/ mov dx, offset Msg2 mov ah, HEX(09) int HEX(21)/********************************/#endif // FIXME: Initialize memory with structure for holding CmdLine etc...// mov ds, seg NextCmd mov dx, offset NextCmd BOP BOP_CMD, HEX(01) /* Quit if we shell-out */ jc Quit /* Initialize the DosLoadExec structure */// mov word ptr FIELD(DosLoadExec, EnvSeg), 0 mov word ptr FIELD(DosLoadExec, CmdLineSeg), ds mov word ptr FIELD(DosLoadExec, Fcb1Seg), ds mov word ptr FIELD(DosLoadExec, Fcb2Seg), ds /* Run the command */ mov ds, word ptr FIELD(NextCmd, AppNameSeg) mov dx, word ptr FIELD(NextCmd, AppNameOff)// mov es, seg DosLoadExec mov bx, offset DosLoadExec pusha // Save the registers in case stuff go wrong // FIXME: Save also SS !! mov ax, HEX(4B00) int HEX(21) popa // Restore the registers // FIXME: Restore also SS !! /* Retrieve and set its exit code. Also detect whether * we need to continue or whether we need to quit. */ // xor ax, ax // mov ah, HEX(4D) mov ax, HEX(4D00) int HEX(21) /* Send exit code back to NTVDM */ mov dx, ax BOP BOP_CMD, HEX(0B) /* If we don't shell-out, go and get a new app! */ jc Run mov al, HEX(00) // ERROR_SUCCESSQuit: mov bl, al // Save AL in BL#ifndef NDEBUG/********************************/ cmp al, HEX(0A) jne XXXX mov dx, offset Msg3 mov ah, HEX(09) int HEX(21)XXXX:/********************************/#endif#ifndef NDEBUG /* Say bye-bye */// mov ds, seg QuitMsg mov dx, offset QuitMsg mov ah, HEX(09) int HEX(21)#endif /* Restore our old parent PSP */ mov ax, word ptr OldParentPsp mov PSP_VAR(ParentPsp), ax mov al, bl // Restore AL from BLExit: /* Return to caller (with possible error code in AL) */ mov ah, HEX(4C) int HEX(21) int 3 /* Does not return *//* DATA *******************************/#ifndef NDEBUGQuitMsg: .ascii "Bye bye!", CR, LF, "$"/********************************/Msg1: .ascii "Starting COMSPEC...", CR, LF, "$"Msg2: .ascii "Waiting for new command...", CR, LF, "$"Msg3: .ascii "Bad environment!", CR, LF, "$"/********************************/#endifOldParentPsp: .word 0CurrentPsp: .word 0// BOP_CMD, HEX(01) "Get a new app to start" structureVAR_STRUCT(NextCmd, NEXT_CMD)// DOS INT 21h, AH=4Bh "Load and Execute" structureVAR_STRUCT(DosLoadExec, DOS_EXEC_PARAM_BLOCK)// Blank FCB blocks needed for DOS INT 21h, AH=4BhFcb1: .byte 0 .space 11, ' ' .space 25, 0Fcb2: .byte 0 .space 11, ' ' .space 25, 0// The stack resides at the end of the resident code+data// and it overwrites the transient part.BaseStack:/* TRANSIENT CODE AND DATA ****************************************************//* DATA *******************************/#ifndef NDEBUGWelcomeMsg: .ascii "ReactOS DOS32 Command", CR, LF, \ "Copyright (C) ReactOS Team 2015" , CR, LF, "$"#endifVerErrMsg: .ascii "Incorrect DOS version", CR, LF, "$"/* CODE *******************************/.align 2Main: /* Setup segment registers */ mov ax, cs // cs contains the PSP segment on entry mov ds, ax mov es, ax// mov fs, ax// mov gs, ax /* Stack is set to cs:FFFE down to cs:09xx by the DOS. * We will need to relocate it before we resize ourselves. */ /* * Verify DOS version: * - Check whether we are on DOS 5+ (subject to SETVER); * - If so, check our real DOS version and see * whether we are running on NTVDM (version 5.50). */ mov ax, HEX(3000) int HEX(21) cmp ax, DOS_VERSION // AH:AL contains minor:major version number jne VerErr mov ax, HEX(3306) int HEX(21) cmp bx, NTDOS_VERSION // BH:BL contains minor:major version number je ContinueVerErr: /* Display wrong version error message and exit */// mov ds, seg VerErrMsg mov dx, offset VerErrMsg mov ah, HEX(09) int HEX(21) jmp ExitContinue: /* Save our PSP */ mov word ptr CurrentPsp, cs/* * The DOS way: * * mov ah, HEX(51) // DOS 2+ internal, or HEX(62) since DOS 3+ * int HEX(21) * mov word ptr CurrentPsp, bx */ /* Save our old parent PSP */ mov ax, PSP_VAR(ParentPsp) mov word ptr OldParentPsp, ax /* Give us shell privileges: set our PSP as our new parent */ mov ax, word ptr CurrentPsp mov PSP_VAR(ParentPsp), ax#ifndef NDEBUG /* Say hello */// mov ds, seg WelcomeMsg mov dx, offset WelcomeMsg mov ah, HEX(09) int HEX(21)#endif /* Jump to resident code */ jmp ResidentMain.endcode16END/* EOF */