#include "dos.h"
#include "bios.h"
+#include "bop.h"
#include "int32.h"
#include "registers.h"
static BOOLEAN DosUmbLinked = FALSE;
static WORD DosErrorLevel = 0x0000;
+/* BOP Identifiers */
+#define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
+#define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
+
/* PRIVATE FUNCTIONS **********************************************************/
/* Taken from base/shell/cmd/console.c */
{
WORD InfoWord = 0;
+ /*
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
+ * for a list of possible flags.
+ */
+
if (Handle == DosSystemFileTable[0])
{
/* Console input */
InfoWord |= 1 << 1;
}
- /* It is a character device */
+ /* It is a device */
InfoWord |= 1 << 7;
/* Return the device information word */
}
}
+VOID WINAPI DosSystemBop(LPWORD Stack)
+{
+ /* Get the Function Number and skip it */
+ BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+ setIP(getIP() + 1);
+
+ DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
+}
+
+VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
+{
+ /* Get the Function Number and skip it */
+ BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+ setIP(getIP() + 1);
+
+ switch (FuncNum)
+ {
+ case 0x08: // Launch external command
+ {
+#define CMDLINE_LENGTH 1024
+
+ BOOL Result;
+ DWORD dwExitCode;
+
+ LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI());
+ CHAR CommandLine[CMDLINE_LENGTH] = "";
+ STARTUPINFOA StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ DPRINT1("CMD Run Command '%s'\n", Command);
+
+ Command[strlen(Command)-1] = 0;
+
+ strcpy(CommandLine, "cmd.exe /c ");
+ strcat(CommandLine, Command);
+
+ ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+ ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
+
+ StartupInfo.cb = sizeof(StartupInfo);
+
+ DosPrintCharacter('\n');
+
+ Result = CreateProcessA(NULL,
+ CommandLine,
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+ if (Result)
+ {
+ DPRINT1("Command '%s' launched successfully\n");
+
+ /* Wait for process termination */
+ WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+
+ /* Get the exit code */
+ GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
+
+ /* Close handles */
+ CloseHandle(ProcessInformation.hThread);
+ CloseHandle(ProcessInformation.hProcess);
+ }
+ else
+ {
+ DPRINT1("Failed when launched command '%s'\n");
+ dwExitCode = GetLastError();
+ }
+
+ DosPrintCharacter('\n');
+
+ setAL((UCHAR)dwExitCode);
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
+ // setCF(1); // Disable, otherwise we enter an infinite loop
+ break;
+ }
+ }
+}
+
VOID WINAPI DosInt20h(LPWORD Stack)
{
/* This is the exit interrupt */
PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
/*
+ * DOS 2+ - GET DOS VERSION
* See Ralf Brown: http://www.ctyme.com/intr/rb-2711.htm
* for more information.
*/
setBL(0x00);
setCX(0x0000);
- /* Return DOS version: Minor:Major in AH:AL */
+ /*
+ * Return DOS version: Minor:Major in AH:AL
+ * The Windows NT DOS box returns version 5.00, subject to SETVER.
+ */
setAX(PspBlock->DosVersion);
break;
}
+ /* Extended functionalities */
+ case 0x33:
+ {
+ if (getAL() == 0x06)
+ {
+ /*
+ * DOS 5+ - GET TRUE VERSION NUMBER
+ * This function always returns the true version number, unlike
+ * AH=30h, whose return value may be changed with SETVER.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-2730.htm
+ * for more information.
+ */
+
+ /*
+ * Return the true DOS version: Minor:Major in BH:BL
+ * The Windows NT DOS box returns BX=3205h (version 5.50).
+ */
+ setBX(NTDOS_VERSION);
+
+ /* DOS revision 0 */
+ setDL(0x00);
+
+ /* Unpatched DOS */
+ setDH(0x00);
+ }
+ // else
+ // {
+ // /* Invalid subfunction */
+ // setAL(0xFF);
+ // }
+
+ break;
+ }
+
/* Get Interrupt Vector */
case 0x35:
{
}
else
{
+ /* Invalid subfunction */
setAL(0xFF);
}
- break;
+ break;
}
/* Create Directory */
if (getCF()) break;
// FIXME: Security checks!
+ DosPrintCharacter(Character);
Buffer[Stack[STACK_COUNTER]++] = Character;
if (Character == '\r')
{
/* Stop on first carriage return */
+ DosPrintCharacter('\n');
break;
}
}
{
UNREFERENCED_PARAMETER(Stack);
+ /* Stop the VDM */
VdmRunning = FALSE;
}
+VOID WINAPI DosFastConOut(LPWORD Stack)
+{
+ /*
+ * This is the DOS 2+ Fast Console Output Interrupt.
+ * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
+ * for more information.
+ */
+ UNREFERENCED_PARAMETER(Stack);
+
+ /*
+ * The default handler under DOS 2.x and 3.x simply calls INT 10/AH=0Eh.
+ * Do better and call directly BiosPrintCharacter: it's what INT 10/AH=0Eh
+ * does. Otherwise we would have to set BL to DOS_CHAR_ATTRIBUTE and
+ * BH to Bda->VideoPage.
+ */
+ BiosPrintCharacter(getAL(), DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
+}
+
VOID WINAPI DosInt2Fh(LPWORD Stack)
{
DPRINT1("DOS System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
+ /* Register the DOS BOPs */
+ RegisterBop(BOP_DOS, DosSystemBop );
+ RegisterBop(BOP_CMD, DosCmdInterpreterBop);
+
/* Register the DOS 32-bit Interrupts */
RegisterInt32(0x20, DosInt20h );
RegisterInt32(0x21, DosInt21h );
// RegisterInt32(0x22, DosInt22h ); // Termination
RegisterInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break
// RegisterInt32(0x24, DosInt24h ); // Critical Error
+ RegisterInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output
RegisterInt32(0x2F, DosInt2Fh );
return TRUE;