#include "handle.h"
#include "dosfiles.h"
#include "memory.h"
+#include "process.h"
#include "himem.h"
#include "bios/bios.h"
CALLBACK16 DosContext;
-static DWORD DiskTransferArea;
/*static*/ BYTE CurrentDrive;
static CHAR LastDrive = 'E';
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
-static WORD DosErrorLevel = 0x0000;
static PBYTE InDos;
/* PUBLIC VARIABLES ***********************************************************/
/* Echo state for INT 21h, AH = 01h and AH = 3Fh */
BOOLEAN DoEcho = FALSE;
-WORD CurrentPsp = SYSTEM_PSP;
+
+DWORD DiskTransferArea;
+WORD DosErrorLevel = 0x0000;
WORD DosLastError = 0;
/* PRIVATE FUNCTIONS **********************************************************/
-static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
- LPCSTR ProgramName)
-{
- PCHAR Ptr, DestBuffer = NULL;
- ULONG TotalSize = 0;
- WORD DestSegment;
-
- /* If we have an environment strings list, compute its size */
- if (Environment)
- {
- /* Calculate the size of the environment block */
- Ptr = (PCHAR)Environment;
- while (*Ptr) Ptr += strlen(Ptr) + 1;
- TotalSize = (ULONG_PTR)Ptr - (ULONG_PTR)Environment;
- }
- else
- {
- /* Empty environment string */
- TotalSize = 1;
- }
- /* Add the final environment block NULL-terminator */
- TotalSize++;
-
- /* Add the two bytes for the program name tag */
- TotalSize += 2;
-
- /* Add the string buffer size */
- TotalSize += strlen(ProgramName) + 1;
-
- /* Allocate the memory for the environment block */
- DestSegment = DosAllocateMemory((WORD)((TotalSize + 0x0F) >> 4), NULL);
- if (!DestSegment) return 0;
-
- DestBuffer = (PCHAR)SEG_OFF_TO_PTR(DestSegment, 0);
-
- /* If we have an environment strings list, copy it */
- if (Environment)
- {
- Ptr = (PCHAR)Environment;
- while (*Ptr)
- {
- /* Copy the string and NULL-terminate it */
- strcpy(DestBuffer, Ptr);
- DestBuffer += strlen(Ptr);
- *(DestBuffer++) = '\0';
-
- /* Move to the next string */
- Ptr += strlen(Ptr) + 1;
- }
- }
- else
- {
- /* Empty environment string */
- *(DestBuffer++) = '\0';
- }
- /* NULL-terminate the environment block */
- *(DestBuffer++) = '\0';
-
- /* Store the special program name tag */
- *(DestBuffer++) = LOBYTE(DOS_PROGRAM_NAME_TAG);
- *(DestBuffer++) = HIBYTE(DOS_PROGRAM_NAME_TAG);
-
- /* Copy the program name after the environment block */
- strcpy(DestBuffer, ProgramName);
-
- return DestSegment;
-}
-
static BOOLEAN DosChangeDrive(BYTE Drive)
{
WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
/* PUBLIC FUNCTIONS ***********************************************************/
-VOID DosInitializePsp(WORD PspSegment,
- LPCSTR CommandLine,
- WORD ProgramSize,
- WORD Environment,
- DWORD ReturnAddress)
-{
- PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment);
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
-
- RtlZeroMemory(PspBlock, sizeof(*PspBlock));
-
- /* Set the exit interrupt */
- PspBlock->Exit[0] = 0xCD; // int 0x20
- PspBlock->Exit[1] = 0x20;
-
- /* Set the number of the last paragraph */
- PspBlock->LastParagraph = PspSegment + ProgramSize - 1;
-
- /* Save the interrupt vectors */
- PspBlock->TerminateAddress = ReturnAddress;
- PspBlock->BreakAddress = IntVecTable[0x23];
- PspBlock->CriticalAddress = IntVecTable[0x24];
-
- /* Set the parent PSP */
- PspBlock->ParentPsp = CurrentPsp;
-
- /* Copy the parent handle table */
- DosCopyHandleTable(PspBlock->HandleTable);
-
- /* Set the environment block */
- PspBlock->EnvBlock = Environment;
-
- /* Set the handle table pointers to the internal handle table */
- PspBlock->HandleTableSize = 20;
- PspBlock->HandleTablePtr = MAKELONG(0x18, PspSegment);
-
- /* Set the DOS version */
- PspBlock->DosVersion = DOS_VERSION;
-
- /* Set the far call opcodes */
- PspBlock->FarCall[0] = 0xCD; // int 0x21
- PspBlock->FarCall[1] = 0x21;
- PspBlock->FarCall[2] = 0xCB; // retf
-
- /* Set the command line */
- PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH - 1);
- RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
- PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
-}
-
-DWORD DosLoadExecutable(IN DOS_EXEC_TYPE LoadType,
- IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL,
- IN DWORD ReturnAddress OPTIONAL,
- OUT PDWORD StackLocation OPTIONAL,
- OUT PDWORD EntryPoint OPTIONAL)
-{
- DWORD Result = ERROR_SUCCESS;
- HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
- LPBYTE Address = NULL;
- WORD Segment = 0;
- WORD EnvBlock = 0;
- WORD MaxAllocSize;
- DWORD i, FileSize, ExeSize;
- PIMAGE_DOS_HEADER Header;
- PDWORD RelocationTable;
- PWORD RelocWord;
- LPSTR CmdLinePtr = (LPSTR)CommandLine;
-
- DPRINT1("DosLoadExecutable(%d, %s, %s, %s, 0x%08X, 0x%08X)\n",
- LoadType,
- ExecutablePath,
- CommandLine,
- Environment ? Environment : "n/a",
- StackLocation,
- EntryPoint);
-
- if (LoadType == DOS_LOAD_OVERLAY)
- {
- DPRINT1("Overlay loading is not supported yet.\n");
- return ERROR_NOT_SUPPORTED;
- }
-
- /* NULL-terminate the command line by removing the return carriage character */
- while (*CmdLinePtr && *CmdLinePtr != '\r') CmdLinePtr++;
- *CmdLinePtr = '\0';
-
- /* Open a handle to the executable */
- FileHandle = CreateFileA(ExecutablePath,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (FileHandle == INVALID_HANDLE_VALUE)
- {
- Result = GetLastError();
- goto Cleanup;
- }
-
- /* Get the file size */
- FileSize = GetFileSize(FileHandle, NULL);
-
- /* Create a mapping object for the file */
- FileMapping = CreateFileMapping(FileHandle,
- NULL,
- PAGE_READONLY,
- 0,
- 0,
- NULL);
- if (FileMapping == NULL)
- {
- Result = GetLastError();
- goto Cleanup;
- }
-
- /* Map the file into memory */
- Address = (LPBYTE)MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
- if (Address == NULL)
- {
- Result = GetLastError();
- goto Cleanup;
- }
-
- /* Copy the environment block to DOS memory */
- EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath);
- if (EnvBlock == 0)
- {
- Result = ERROR_NOT_ENOUGH_MEMORY;
- goto Cleanup;
- }
-
- /* Check if this is an EXE file or a COM file */
- if (Address[0] == 'M' && Address[1] == 'Z')
- {
- /* EXE file */
-
- /* Get the MZ header */
- Header = (PIMAGE_DOS_HEADER)Address;
-
- /* Get the base size of the file, in paragraphs (rounded up) */
- ExeSize = (((Header->e_cp - 1) * 512) + Header->e_cblp + 0x0F) >> 4;
-
- /* Add the PSP size, in paragraphs */
- ExeSize += sizeof(DOS_PSP) >> 4;
-
- /* Add the maximum size that should be allocated */
- ExeSize += Header->e_maxalloc;
-
- /* Make sure it does not pass 0xFFFF */
- if (ExeSize > 0xFFFF) ExeSize = 0xFFFF;
-
- /* Try to allocate that much memory */
- Segment = DosAllocateMemory((WORD)ExeSize, &MaxAllocSize);
-
- if (Segment == 0)
- {
- /* Check if there's at least enough memory for the minimum size */
- if (MaxAllocSize < (ExeSize - Header->e_maxalloc + Header->e_minalloc))
- {
- Result = DosLastError;
- goto Cleanup;
- }
-
- /* Allocate that minimum amount */
- ExeSize = MaxAllocSize;
- Segment = DosAllocateMemory((WORD)ExeSize, NULL);
- ASSERT(Segment != 0);
- }
-
- /* Initialize the PSP */
- DosInitializePsp(Segment,
- CommandLine,
- (WORD)ExeSize,
- EnvBlock,
- ReturnAddress);
-
- /* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
- DosChangeMemoryOwner(EnvBlock, Segment);
-
- /* Copy the program to Segment:0100 */
- RtlCopyMemory(SEG_OFF_TO_PTR(Segment, 0x100),
- Address + (Header->e_cparhdr << 4),
- min(FileSize - (Header->e_cparhdr << 4),
- (ExeSize << 4) - sizeof(DOS_PSP)));
-
- /* Get the relocation table */
- RelocationTable = (PDWORD)(Address + Header->e_lfarlc);
-
- /* Perform relocations */
- for (i = 0; i < Header->e_crlc; i++)
- {
- /* Get a pointer to the word that needs to be patched */
- RelocWord = (PWORD)SEG_OFF_TO_PTR(Segment + HIWORD(RelocationTable[i]),
- 0x100 + LOWORD(RelocationTable[i]));
-
- /* Add the number of the EXE segment to it */
- *RelocWord += Segment + (sizeof(DOS_PSP) >> 4);
- }
-
- if (LoadType == DOS_LOAD_AND_EXECUTE)
- {
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the location from the header */
- setSS(Segment + (sizeof(DOS_PSP) >> 4) + Header->e_ss);
- setSP(Header->e_sp);
-
- /* Execute */
- CurrentPsp = Segment;
- DiskTransferArea = MAKELONG(0x80, Segment);
- CpuExecute(Segment + Header->e_cs + (sizeof(DOS_PSP) >> 4),
- Header->e_ip);
- }
- }
- else
- {
- /* COM file */
-
- /* Find the maximum amount of memory that can be allocated */
- DosAllocateMemory(0xFFFF, &MaxAllocSize);
-
- /* Make sure it's enough for the whole program and the PSP */
- if (((DWORD)MaxAllocSize << 4) < (FileSize + sizeof(DOS_PSP)))
- {
- Result = ERROR_NOT_ENOUGH_MEMORY;
- goto Cleanup;
- }
-
- /* Allocate all of it */
- Segment = DosAllocateMemory(MaxAllocSize, NULL);
- if (Segment == 0)
- {
- Result = DosLastError;
- goto Cleanup;
- }
-
- /* The process owns its own memory */
- DosChangeMemoryOwner(Segment, Segment);
- DosChangeMemoryOwner(EnvBlock, Segment);
-
- /* Copy the program to Segment:0100 */
- RtlCopyMemory(SEG_OFF_TO_PTR(Segment, 0x100),
- Address,
- FileSize);
-
- /* Initialize the PSP */
- DosInitializePsp(Segment,
- CommandLine,
- MaxAllocSize,
- EnvBlock,
- ReturnAddress);
-
- if (LoadType == DOS_LOAD_AND_EXECUTE)
- {
- /* Set the initial segment registers */
- setDS(Segment);
- setES(Segment);
-
- /* Set the stack to the last word of the segment */
- setSS(Segment);
- setSP(0xFFFE);
-
- /*
- * Set the value on the stack to 0, so that a near return
- * jumps to PSP:0000 which has the exit code.
- */
- *((LPWORD)SEG_OFF_TO_PTR(Segment, 0xFFFE)) = 0;
-
- /* Execute */
- CurrentPsp = Segment;
- DiskTransferArea = MAKELONG(0x80, Segment);
- CpuExecute(Segment, 0x100);
- }
- }
-
-Cleanup:
- if (Result != ERROR_SUCCESS)
- {
- /* It was not successful, cleanup the DOS memory */
- if (EnvBlock) DosFreeMemory(EnvBlock);
- if (Segment) DosFreeMemory(Segment);
- }
-
- /* Unmap the file*/
- if (Address != NULL) UnmapViewOfFile(Address);
-
- /* Close the file mapping object */
- if (FileMapping != NULL) CloseHandle(FileMapping);
-
- /* Close the file handle */
- if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
-
- return Result;
-}
-
-DWORD DosStartProcess(IN LPCSTR ExecutablePath,
- IN LPCSTR CommandLine,
- IN LPCSTR Environment OPTIONAL)
-{
- DWORD Result;
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
-
- Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
- ExecutablePath,
- CommandLine,
- Environment,
- IntVecTable[0x20], // Use INT 20h
- NULL,
- NULL);
-
- if (Result != ERROR_SUCCESS) goto Quit;
-
- /* Attach to the console */
- ConsoleAttach();
- VidBiosAttachToConsole();
-
- // HACK: Simulate a ENTER key release scancode on the PS/2 port because
- // some apps expect to read a key release scancode (> 0x80) when they
- // are started.
- IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port
- IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release
-
- /* Start simulation */
- SetEvent(VdmTaskEvent);
- CpuSimulate();
-
- /* Detach from the console */
- VidBiosDetachFromConsole();
- ConsoleDetach();
-
-Quit:
- return Result;
-}
-
-#ifndef STANDALONE
-WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
- LPCSTR ProgramName,
- PDOS_EXEC_PARAM_BLOCK Parameters,
- DWORD ReturnAddress)
-{
- DWORD Result;
- DWORD BinaryType;
- LPVOID Environment = NULL;
- VDM_COMMAND_INFO CommandInfo;
- CHAR CmdLine[MAX_PATH];
- CHAR AppName[MAX_PATH];
- CHAR PifFile[MAX_PATH];
- CHAR Desktop[MAX_PATH];
- CHAR Title[MAX_PATH];
- ULONG EnvSize = 256;
- PVOID Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
- STARTUPINFOA StartupInfo;
- PROCESS_INFORMATION ProcessInfo;
-
- /* Get the binary type */
- if (!GetBinaryTypeA(ProgramName, &BinaryType)) return GetLastError();
-
- /* Did the caller specify an environment segment? */
- if (Parameters->Environment)
- {
- /* Yes, use it instead of the parent one */
- Environment = SEG_OFF_TO_PTR(Parameters->Environment, 0);
- }
-
- /* Set up the startup info structure */
- RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
- StartupInfo.cb = sizeof(StartupInfo);
-
- /* Create the process */
- if (!CreateProcessA(ProgramName,
- FAR_POINTER(Parameters->CommandLine),
- NULL,
- NULL,
- FALSE,
- 0,
- Environment,
- NULL,
- &StartupInfo,
- &ProcessInfo))
- {
- return GetLastError();
- }
-
- /* Check the type of the program */
- switch (BinaryType)
- {
- /* These are handled by NTVDM */
- case SCS_DOS_BINARY:
- case SCS_WOW_BINARY:
- {
- /* Clear the structure */
- RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
-
- /* Initialize the structure members */
- CommandInfo.TaskId = SessionId;
- CommandInfo.VDMState = VDM_FLAG_NESTED_TASK | VDM_FLAG_DONT_WAIT;
- CommandInfo.CmdLine = CmdLine;
- CommandInfo.CmdLen = sizeof(CmdLine);
- CommandInfo.AppName = AppName;
- CommandInfo.AppLen = sizeof(AppName);
- CommandInfo.PifFile = PifFile;
- CommandInfo.PifLen = sizeof(PifFile);
- CommandInfo.Desktop = Desktop;
- CommandInfo.DesktopLen = sizeof(Desktop);
- CommandInfo.Title = Title;
- CommandInfo.TitleLen = sizeof(Title);
- CommandInfo.Env = Env;
- CommandInfo.EnvLen = EnvSize;
-
-Command:
- /* Get the VDM command information */
- if (!GetNextVDMCommand(&CommandInfo))
- {
- if (CommandInfo.EnvLen > EnvSize)
- {
- /* Expand the environment size */
- EnvSize = CommandInfo.EnvLen;
- CommandInfo.Env = Env = RtlReAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize);
-
- /* Repeat the request */
- CommandInfo.VDMState |= VDM_FLAG_RETRY;
- goto Command;
- }
-
- /* Shouldn't happen */
- ASSERT(FALSE);
- }
-
- /* Load the executable */
- Result = DosLoadExecutable(LoadType,
- AppName,
- CmdLine,
- Env,
- ReturnAddress,
- &Parameters->StackLocation,
- &Parameters->EntryPoint);
- if (Result == ERROR_SUCCESS)
- {
- /* Increment the re-entry count */
- CommandInfo.VDMState = VDM_INC_REENTER_COUNT;
- GetNextVDMCommand(&CommandInfo);
- }
- else
- {
- DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result);
- }
-
- break;
- }
-
- /* Not handled by NTVDM */
- default:
- {
- /* Wait for the process to finish executing */
- WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
- }
- }
-
- RtlFreeHeap(RtlGetProcessHeap(), 0, Env);
-
- /* Close the handles */
- CloseHandle(ProcessInfo.hProcess);
- CloseHandle(ProcessInfo.hThread);
-
- return ERROR_SUCCESS;
-}
-#endif
-
-VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode, WORD KeepResident)
-{
- WORD i;
- WORD McbSegment = FIRST_MCB_SEGMENT;
- PDOS_MCB CurrentMcb;
- LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
- PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
-
- DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X, KeepResident 0x%04X\n",
- Psp,
- ReturnCode,
- KeepResident);
-
- /* Check if this PSP is it's own parent */
- if (PspBlock->ParentPsp == Psp) goto Done;
-
- if (KeepResident == 0)
- {
- for (i = 0; i < PspBlock->HandleTableSize; i++)
- {
- /* Close the handle */
- DosCloseHandle(i);
- }
- }
-
- /* Free the memory used by the process */
- while (TRUE)
- {
- /* Get a pointer to the MCB */
- CurrentMcb = SEGMENT_TO_MCB(McbSegment);
-
- /* Make sure the MCB is valid */
- if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z') break;
-
- /* Check if this block was allocated by the process */
- if (CurrentMcb->OwnerPsp == Psp)
- {
- if (KeepResident == 0)
- {
- /* Free this entire block */
- DosFreeMemory(McbSegment + 1);
- }
- else if (KeepResident < CurrentMcb->Size)
- {
- /* Reduce the size of the block */
- DosResizeMemory(McbSegment + 1, KeepResident, NULL);
-
- /* No further paragraphs need to stay resident */
- KeepResident = 0;
- }
- else
- {
- /* Just reduce the amount of paragraphs we need to keep resident */
- KeepResident -= CurrentMcb->Size;
- }
- }
-
- /* If this was the last block, quit */
- if (CurrentMcb->BlockType == 'Z') break;
-
- /* Update the segment and continue */
- McbSegment += CurrentMcb->Size + 1;
- }
-
-Done:
- /* Restore the interrupt vectors */
- IntVecTable[0x22] = PspBlock->TerminateAddress;
- IntVecTable[0x23] = PspBlock->BreakAddress;
- IntVecTable[0x24] = PspBlock->CriticalAddress;
-
- /* Update the current PSP */
- if (Psp == CurrentPsp)
- {
- CurrentPsp = PspBlock->ParentPsp;
- if (CurrentPsp == SYSTEM_PSP)
- {
- ResetEvent(VdmTaskEvent);
- CpuUnsimulate();
- }
- }
-
-#ifndef STANDALONE
- // FIXME: This is probably not the best way to do it
- /* Check if this was a nested DOS task */
- if (CurrentPsp != SYSTEM_PSP)
- {
- VDM_COMMAND_INFO CommandInfo;
-
- /* Decrement the re-entry count */
- CommandInfo.TaskId = SessionId;
- CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
- GetNextVDMCommand(&CommandInfo);
-
- /* Clear the structure */
- RtlZeroMemory(&CommandInfo, sizeof(CommandInfo));
-
- /* Update the VDM state of the task */
- CommandInfo.TaskId = SessionId;
- CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
- GetNextVDMCommand(&CommandInfo);
- }
-#endif
-
- /* Save the return code - Normal termination */
- DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
-
- /* Return control to the parent process */
- CpuExecute(HIWORD(PspBlock->TerminateAddress),
- LOWORD(PspBlock->TerminateAddress));
-}
-
VOID WINAPI DosInt20h(LPWORD Stack)
{
/* This is the exit interrupt */
(*InDos)++;
+ /* Save the value of SS:SP on entry in the PSP */
+ SEGMENT_TO_PSP(CurrentPsp)->LastStack =
+ MAKELONG(getSP() + (STACK_FLAGS + 1) * 2, getSS());
+
/* Check the value in the AH register */
switch (getAH())
{
}
/* Update the length */
- InputBuffer->Length = Count - 1;
+ InputBuffer->Length = Count;
break;
}
/* Create New PSP */
case 0x26:
{
- DPRINT1("INT 21h, AH = 26h - Create New PSP is UNIMPLEMENTED\n");
+ DosClonePsp(getDX(), getCS());
break;
}
break;
}
+ /* Get Free Disk Space */
+ case 0x36:
+ {
+ CHAR RootPath[3] = "X:\\";
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD NumberOfFreeClusters;
+ DWORD TotalNumberOfClusters;
+
+ if (getDL() == 0) RootPath[0] = 'A' + CurrentDrive;
+ else RootPath[0] = 'A' + getDL() - 1;
+
+ if (GetDiskFreeSpaceA(RootPath,
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &NumberOfFreeClusters,
+ &TotalNumberOfClusters))
+ {
+ setAX(LOWORD(SectorsPerCluster));
+ setCX(LOWORD(BytesPerSector));
+ setBX(LOWORD(NumberOfFreeClusters));
+ setDX(LOWORD(TotalNumberOfClusters));
+ }
+ else
+ {
+ /* Error */
+ setAX(0xFFFF);
+ }
+
+ break;
+ }
+
/* SWITCH character - AVAILDEV */
case 0x37:
{
break;
}
-#ifndef STANDALONE
/* Execute */
case 0x4B:
{
- DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)getAL();
+ BYTE OrgAL = getAL();
LPSTR ProgramName = SEG_OFF_TO_PTR(getDS(), getDX());
PDOS_EXEC_PARAM_BLOCK ParamBlock = SEG_OFF_TO_PTR(getES(), getBX());
DWORD ReturnAddress = MAKELONG(Stack[STACK_IP], Stack[STACK_CS]);
WORD ErrorCode;
-
- if (LoadType != DOS_LOAD_OVERLAY)
+
+ if (OrgAL <= DOS_LOAD_OVERLAY)
+ {
+ DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)OrgAL;
+
+#ifndef STANDALONE
+ if (LoadType == DOS_LOAD_AND_EXECUTE)
+ {
+ /* Create a new process */
+ ErrorCode = DosCreateProcess(ProgramName,
+ ParamBlock,
+ ReturnAddress);
+ }
+ else
+#endif
+ {
+ /* Just load an executable */
+ ErrorCode = DosLoadExecutable(LoadType,
+ ProgramName,
+ ParamBlock,
+ NULL,
+ NULL,
+ ReturnAddress);
+ }
+ }
+ else if (OrgAL == 0x05)
{
- ErrorCode = DosCreateProcess(LoadType, ProgramName, ParamBlock, ReturnAddress);
+ // http://www.ctyme.com/intr/rb-2942.htm
+ DPRINT1("Set execution state is UNIMPLEMENTED\n");
+ ErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
}
else
{
- ErrorCode = DosLoadExecutable(DOS_LOAD_OVERLAY,
- ProgramName,
- FAR_POINTER(ParamBlock->CommandLine),
- SEG_OFF_TO_PTR(ParamBlock->Environment, 0),
- ReturnAddress,
- NULL,
- NULL);
+ ErrorCode = ERROR_INVALID_FUNCTION;
}
if (ErrorCode == ERROR_SUCCESS)
break;
}
-#endif
/* Terminate With Return Code */
case 0x4C:
/* Internal - Set Current Process ID (Set PSP Address) */
case 0x50:
{
- // FIXME: Is it really what it's done ??
- CurrentPsp = getBX();
+ DosSetProcessContext(getBX());
break;
}
break;
}
+ /* Create Child PSP */
+ case 0x55:
+ {
+ DosCreatePsp(getDX(), getSI());
+ break;
+ }
+
/* Rename File */
case 0x56:
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
+VOID WINAPI DosInt27h(LPWORD Stack)
+{
+ DosTerminateProcess(getCS(), 0, (getDX() + 0x0F) >> 4);
+}
+
VOID WINAPI DosFastConOut(LPWORD Stack)
{
/*
// RegisterDosInt32(0x22, DosInt22h ); // Termination
RegisterDosInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break
// RegisterDosInt32(0x24, DosInt24h ); // Critical Error
+ RegisterDosInt32(0x27, DosInt27h ); // Terminate and Stay Resident
RegisterDosInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output
RegisterDosInt32(0x2F, DosInt2Fh );