#include "dos.h"
#include "dos/dem.h"
#include "device.h"
+#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 DOS_SFT_ENTRY DosSystemFileTable[DOS_SFT_SIZE];
-static WORD DosErrorLevel = 0x0000;
-
/* PUBLIC VARIABLES ***********************************************************/
+/* Global DOS data area contained in guest memory */
+PDOS_DATA DosData;
+/* Easy accessors to useful DOS data area parts */
+PDOS_SYSVARS SysVars;
+PDOS_SDA Sda;
+
/* Echo state for INT 21h, AH = 01h and AH = 3Fh */
BOOLEAN DoEcho = FALSE;
-WORD CurrentPsp = SYSTEM_PSP;
-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;
-}
-
-/* Taken from base/shell/cmd/console.c */
-static BOOL IsConsoleHandle(HANDLE hHandle)
-{
- DWORD dwMode;
-
- /* Check whether the handle may be that of a console... */
- if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE;
-
- /*
- * It may be. Perform another test... The idea comes from the
- * MSDN description of the WriteConsole API:
- *
- * "WriteConsole fails if it is used with a standard handle
- * that is redirected to a file. If an application processes
- * multilingual output that can be redirected, determine whether
- * the output handle is a console handle (one method is to call
- * the GetConsoleMode function and check whether it succeeds).
- * If the handle is a console handle, call WriteConsole. If the
- * handle is not a console handle, the output is redirected and
- * you should call WriteFile to perform the I/O."
- */
- return GetConsoleMode(hHandle, &dwMode);
-}
-
-static inline PDOS_SFT_ENTRY DosFindFreeSftEntry(VOID)
-{
- UINT i;
-
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_NONE)
- {
- return &DosSystemFileTable[i];
- }
- }
-
- return NULL;
-}
-
-static inline PDOS_SFT_ENTRY DosFindWin32SftEntry(HANDLE Handle)
-{
- UINT i;
-
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_WIN32
- && DosSystemFileTable[i].Handle == Handle)
- {
- return &DosSystemFileTable[i];
- }
- }
-
- return NULL;
-}
-
-static inline PDOS_SFT_ENTRY DosFindDeviceSftEntry(PDOS_DEVICE_NODE Device)
-{
- UINT i;
-
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- if (DosSystemFileTable[i].Type == DOS_SFT_ENTRY_DEVICE
- && DosSystemFileTable[i].DeviceNode == Device)
- {
- return &DosSystemFileTable[i];
- }
- }
-
- return NULL;
-}
-
-WORD DosOpenHandle(HANDLE Handle)
-{
- WORD DosHandle;
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
- PDOS_SFT_ENTRY SftEntry;
-
- /* The system PSP has no handle table */
- if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
-
- /* Get a pointer to the handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Find a free entry in the JFT */
- for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
- {
- if (HandleTable[DosHandle] == 0xFF) break;
- }
-
- /* If there are no free entries, fail */
- if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
-
- /* Check if the handle is already in the SFT */
- SftEntry = DosFindWin32SftEntry(Handle);
- if (SftEntry != NULL)
- {
- /* Already in the table, reference it */
- SftEntry->RefCount++;
- goto Finish;
- }
-
- /* Find a free SFT entry to use */
- SftEntry = DosFindFreeSftEntry();
- if (SftEntry == NULL)
- {
- /* The SFT is full */
- return INVALID_DOS_HANDLE;
- }
-
- /* Initialize the empty table entry */
- SftEntry->Type = DOS_SFT_ENTRY_WIN32;
- SftEntry->Handle = Handle;
- SftEntry->RefCount = 1;
-
-Finish:
-
- /* Set the JFT entry to that SFT index */
- HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
-
- /* Return the new handle */
- return DosHandle;
-}
-
-WORD DosOpenDevice(PDOS_DEVICE_NODE Device)
-{
- WORD DosHandle;
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
- PDOS_SFT_ENTRY SftEntry;
-
- DPRINT("DosOpenDevice(\"%Z\")\n", &Device->Name);
-
- /* The system PSP has no handle table */
- if (CurrentPsp == SYSTEM_PSP) return INVALID_DOS_HANDLE;
-
- /* Get a pointer to the handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Find a free entry in the JFT */
- for (DosHandle = 0; DosHandle < PspBlock->HandleTableSize; DosHandle++)
- {
- if (HandleTable[DosHandle] == 0xFF) break;
- }
-
- /* If there are no free entries, fail */
- if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
-
- /* Check if the device is already in the SFT */
- SftEntry = DosFindDeviceSftEntry(Device);
- if (SftEntry != NULL)
- {
- /* Already in the table, reference it */
- SftEntry->RefCount++;
- goto Finish;
- }
-
- /* Find a free SFT entry to use */
- SftEntry = DosFindFreeSftEntry();
- if (SftEntry == NULL)
- {
- /* The SFT is full */
- return INVALID_DOS_HANDLE;
- }
-
- /* Initialize the empty table entry */
- SftEntry->Type = DOS_SFT_ENTRY_DEVICE;
- SftEntry->DeviceNode = Device;
- SftEntry->RefCount = 1;
-
-Finish:
-
- /* Call the open routine, if it exists */
- if (Device->OpenRoutine) Device->OpenRoutine(Device);
-
- /* Set the JFT entry to that SFT index */
- HandleTable[DosHandle] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
-
- /* Return the new handle */
- return DosHandle;
-}
-
-static VOID DosCopyHandleTable(LPBYTE DestinationTable)
-{
- UINT i;
- PDOS_PSP PspBlock;
- LPBYTE SourceTable;
-
- /* Clear the table first */
- for (i = 0; i < 20; i++) DestinationTable[i] = 0xFF;
-
- /* Check if this is the initial process */
- if (CurrentPsp == SYSTEM_PSP)
- {
- PDOS_SFT_ENTRY SftEntry;
- HANDLE StandardHandles[3];
- PDOS_DEVICE_NODE Con = DosGetDevice("CON");
- ASSERT(Con != NULL);
-
- /* Get the native standard handles */
- StandardHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
- StandardHandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
- StandardHandles[2] = GetStdHandle(STD_ERROR_HANDLE);
-
- for (i = 0; i < 3; i++)
- {
- /* Find the corresponding SFT entry */
- if (IsConsoleHandle(StandardHandles[i]))
- {
- SftEntry = DosFindDeviceSftEntry(Con);
- }
- else
- {
- SftEntry = DosFindWin32SftEntry(StandardHandles[i]);
- }
-
- if (SftEntry == NULL)
- {
- /* Create a new SFT entry for it */
- SftEntry = DosFindFreeSftEntry();
- if (SftEntry == NULL)
- {
- DPRINT1("Cannot create standard handle %d, the SFT is full!\n", i);
- continue;
- }
-
- SftEntry->RefCount = 0;
-
- if (IsConsoleHandle(StandardHandles[i]))
- {
- SftEntry->Type = DOS_SFT_ENTRY_DEVICE;
- SftEntry->DeviceNode = Con;
-
- /* Call the open routine */
- if (Con->OpenRoutine) Con->OpenRoutine(Con);
- }
- else
- {
- SftEntry->Type = DOS_SFT_ENTRY_WIN32;
- SftEntry->Handle = StandardHandles[i];
- }
- }
-
- SftEntry->RefCount++;
- DestinationTable[i] = ARRAY_INDEX(SftEntry, DosSystemFileTable);
- }
- }
- else
- {
- /* Get the parent PSP block and handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- SourceTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Copy the first 20 handles into the new table */
- for (i = 0; i < DEFAULT_JFT_SIZE; i++)
- {
- DestinationTable[i] = SourceTable[i];
-
- /* Increase the reference count */
- DosSystemFileTable[SourceTable[i]].RefCount++;
- }
- }
-}
-
-static BOOLEAN DosResizeHandleTable(WORD NewSize)
-{
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
- WORD Segment;
-
- /* Get the PSP block */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
-
- if (NewSize == PspBlock->HandleTableSize)
- {
- /* No change */
- return TRUE;
- }
-
- if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE)
- {
- /* Get the segment of the current table */
- Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) + HIWORD(PspBlock->HandleTablePtr);
-
- if (NewSize <= DEFAULT_JFT_SIZE)
- {
- /* Get the current handle table */
- HandleTable = FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Copy it to the PSP */
- RtlCopyMemory(PspBlock->HandleTable, HandleTable, NewSize);
-
- /* Free the memory */
- DosFreeMemory(Segment);
-
- /* Update the handle table pointer and size */
- PspBlock->HandleTableSize = NewSize;
- PspBlock->HandleTablePtr = MAKELONG(0x18, CurrentPsp);
- }
- else
- {
- /* Resize the memory */
- if (!DosResizeMemory(Segment, NewSize, NULL))
- {
- /* Unable to resize, try allocating it somewhere else */
- Segment = DosAllocateMemory(NewSize, NULL);
- if (Segment == 0) return FALSE;
-
- /* Get the new handle table */
- HandleTable = SEG_OFF_TO_PTR(Segment, 0);
-
- /* Copy the handles to the new table */
- RtlCopyMemory(HandleTable,
- FAR_POINTER(PspBlock->HandleTablePtr),
- PspBlock->HandleTableSize);
-
- /* Update the handle table pointer */
- PspBlock->HandleTablePtr = MAKELONG(0, Segment);
- }
-
- /* Update the handle table size */
- PspBlock->HandleTableSize = NewSize;
- }
- }
- else if (NewSize > DEFAULT_JFT_SIZE)
- {
- Segment = DosAllocateMemory(NewSize, NULL);
- if (Segment == 0) return FALSE;
-
- /* Get the new handle table */
- HandleTable = SEG_OFF_TO_PTR(Segment, 0);
-
- /* Copy the handles from the PSP to the new table */
- RtlCopyMemory(HandleTable,
- FAR_POINTER(PspBlock->HandleTablePtr),
- PspBlock->HandleTableSize);
-
- /* Update the handle table pointer and size */
- PspBlock->HandleTableSize = NewSize;
- PspBlock->HandleTablePtr = MAKELONG(0, Segment);
- }
-
- return TRUE;
-}
-
-static BOOLEAN DosCloseHandle(WORD DosHandle)
-{
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
- PDOS_SFT_ENTRY SftEntry;
-
- DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle);
-
- /* The system PSP has no handle table */
- if (CurrentPsp == SYSTEM_PSP) return FALSE;
-
- /* Get a pointer to the handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Make sure the handle is open */
- if (HandleTable[DosHandle] == 0xFF) return FALSE;
-
- /* Make sure the SFT entry is valid */
- SftEntry = &DosSystemFileTable[HandleTable[DosHandle]];
- if (SftEntry->Type == DOS_SFT_ENTRY_NONE) return FALSE;
-
- /* Decrement the reference count of the SFT entry */
- SftEntry->RefCount--;
-
- /* Check if the reference count fell to zero */
- if (!SftEntry->RefCount)
- {
- switch (SftEntry->Type)
- {
- case DOS_SFT_ENTRY_WIN32:
- {
- /* Close the win32 handle and clear it */
- CloseHandle(SftEntry->Handle);
-
- break;
- }
-
- case DOS_SFT_ENTRY_DEVICE:
- {
- PDOS_DEVICE_NODE Node = SftEntry->DeviceNode;
-
- /* Call the close routine, if it exists */
- if (Node->CloseRoutine) SftEntry->DeviceNode->CloseRoutine(SftEntry->DeviceNode);
-
- break;
- }
-
- default:
- {
- /* Shouldn't happen */
- ASSERT(FALSE);
- }
- }
-
- /* Invalidate the SFT entry */
- SftEntry->Type = DOS_SFT_ENTRY_NONE;
- }
-
- /* Clear the entry in the JFT */
- HandleTable[DosHandle] = 0xFF;
-
- return TRUE;
-}
-
-static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
-{
- BYTE SftIndex;
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
-
- DPRINT("DosDuplicateHandle: OldHandle 0x%04X, NewHandle 0x%04X\n",
- OldHandle,
- NewHandle);
-
- /* The system PSP has no handle table */
- if (CurrentPsp == SYSTEM_PSP) return FALSE;
-
- /* Get a pointer to the handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Make sure the old handle is open */
- if (HandleTable[OldHandle] == 0xFF) return FALSE;
-
- /* Check if the new handle is open */
- if (HandleTable[NewHandle] != 0xFF)
- {
- /* Close it */
- DosCloseHandle(NewHandle);
- }
-
- /* Increment the reference count of the SFT entry */
- SftIndex = HandleTable[OldHandle];
- DosSystemFileTable[SftIndex].RefCount++;
-
- /* Make the new handle point to that SFT entry */
- HandleTable[NewHandle] = SftIndex;
-
- /* Return success */
- return TRUE;
-}
-
static BOOLEAN DosChangeDrive(BYTE Drive)
{
- WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
+ CHAR DirectoryPath[DOS_CMDLINE_LENGTH + 1];
/* Make sure the drive exists */
- if (Drive > (LastDrive - 'A')) return FALSE;
+ if (Drive >= SysVars->NumLocalDrives) return FALSE;
+
+ RtlZeroMemory(DirectoryPath, sizeof(DirectoryPath));
/* Find the path to the new current directory */
- swprintf(DirectoryPath, L"%c\\%S", Drive + 'A', CurrentDirectories[Drive]);
+ snprintf(DirectoryPath,
+ DOS_CMDLINE_LENGTH,
+ "%c:\\%s",
+ 'A' + Drive,
+ DosData->CurrentDirectories[Drive]);
/* Change the current directory of the process */
- if (!SetCurrentDirectory(DirectoryPath)) return FALSE;
+ if (!SetCurrentDirectoryA(DirectoryPath)) return FALSE;
/* Set the current drive */
- CurrentDrive = Drive;
+ Sda->CurrentDrive = Drive;
/* Return success */
return TRUE;
BYTE DriveNumber;
DWORD Attributes;
LPSTR Path;
+ CHAR CurrentDirectory[MAX_PATH];
+ CHAR DosDirectory[DOS_DIR_LENGTH];
/* Make sure the directory path is not too long */
if (strlen(Directory) >= DOS_DIR_LENGTH)
{
- DosLastError = ERROR_PATH_NOT_FOUND;
+ Sda->LastErrorCode = ERROR_PATH_NOT_FOUND;
return FALSE;
}
- /* Get the drive number */
- DriveNumber = Directory[0] - 'A';
-
- /* Make sure the drive exists */
- if (DriveNumber > (LastDrive - 'A'))
- {
- DosLastError = ERROR_PATH_NOT_FOUND;
- return FALSE;
- }
-
- /* Get the file attributes */
- Attributes = GetFileAttributesA(Directory);
-
- /* Make sure the path exists and is a directory */
- if ((Attributes == INVALID_FILE_ATTRIBUTES)
- || !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ /* Check whether the directory string is of format "?:..." */
+ if (strlen(Directory) >= 2 && Directory[1] == ':')
{
- DosLastError = ERROR_PATH_NOT_FOUND;
- return FALSE;
- }
+ /* Get the drive number */
+ DriveNumber = RtlUpperChar(Directory[0]) - 'A';
- /* Check if this is the current drive */
- if (DriveNumber == CurrentDrive)
- {
- /* Change the directory */
- if (!SetCurrentDirectoryA(Directory))
+ /* Make sure the drive exists */
+ if (DriveNumber >= SysVars->NumLocalDrives)
{
- DosLastError = LOWORD(GetLastError());
+ Sda->LastErrorCode = ERROR_PATH_NOT_FOUND;
return FALSE;
}
}
-
- /* Get the directory part of the path */
- Path = strchr(Directory, '\\');
- if (Path != NULL)
- {
- /* Skip the backslash */
- Path++;
- }
-
- /* Set the directory for the drive */
- if (Path != NULL)
- {
- strncpy(CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
- }
else
{
- CurrentDirectories[DriveNumber][0] = '\0';
- }
-
- /* Return success */
- return TRUE;
-}
-
-static BOOLEAN DosControlBreak(VOID)
-{
- setCF(0);
-
- /* Call interrupt 0x23 */
- Int32Call(&DosContext, 0x23);
-
- if (getCF())
- {
- DosTerminateProcess(CurrentPsp, 0, 0);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle)
-{
- PDOS_PSP PspBlock;
- LPBYTE HandleTable;
-
- /* The system PSP has no handle table */
- if (CurrentPsp == SYSTEM_PSP) return NULL;
-
- /* Get a pointer to the handle table */
- PspBlock = SEGMENT_TO_PSP(CurrentPsp);
- HandleTable = (LPBYTE)FAR_POINTER(PspBlock->HandleTablePtr);
-
- /* Make sure the handle is open */
- if (HandleTable[DosHandle] == 0xFF) return NULL;
-
- /* Return a pointer to the SFT entry */
- return &DosSystemFileTable[HandleTable[DosHandle]];
-}
-
-VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment)
-{
- 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 = IntVecTable[0x22];
- 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,
- 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);
-
- /* 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);
-
- 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;
-
- Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
- ExecutablePath,
- CommandLine,
- Environment,
- 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 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];
- CHAR Env[MAX_PATH];
- 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);
+ /* Keep the current drive number */
+ DriveNumber = Sda->CurrentDrive;
}
- /* 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 = sizeof(Env);
-
- /* Get the VDM command information */
- if (!GetNextVDMCommand(&CommandInfo))
- {
- /* Shouldn't happen */
- ASSERT(FALSE);
- }
-
- /* Increment the re-entry count */
- CommandInfo.VDMState = VDM_INC_REENTER_COUNT;
- GetNextVDMCommand(&CommandInfo);
-
- /* Load the executable */
- Result = DosLoadExecutable(LoadType,
- AppName,
- CmdLine,
- Env,
- &Parameters->StackLocation,
- &Parameters->EntryPoint);
- if (Result != ERROR_SUCCESS)
- {
- DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result);
- // FIXME: Decrement the reenter count. Or, instead, just increment
- // the VDM reenter count *only* if this call succeeds...
- }
-
- break;
- }
-
- /* Not handled by NTVDM */
- default:
- {
- /* Wait for the process to finish executing */
- WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
- }
- }
-
- /* 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));
-}
-
-BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
-{
- PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
- PDOS_DEVICE_NODE Node = NULL;
+ /* Get the file attributes */
+ Attributes = GetFileAttributesA(Directory);
- /* Make sure it exists */
- if (!SftEntry)
+ /* Make sure the path exists and is a directory */
+ if ((Attributes == INVALID_FILE_ATTRIBUTES)
+ || !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
{
- DosLastError = ERROR_FILE_NOT_FOUND;
+ Sda->LastErrorCode = ERROR_PATH_NOT_FOUND;
return FALSE;
- }
-
- if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE) Node = SftEntry->DeviceNode;
-
- switch (ControlCode)
- {
- /* Get Device Information */
- case 0x00:
- {
- WORD InfoWord = 0;
-
- /*
- * See Ralf Brown: http://www.ctyme.com/intr/rb-2820.htm
- * for a list of possible flags.
- */
-
- if (Node)
- {
- /* Return the device attributes with bit 7 set */
- InfoWord = Node->DeviceAttributes | (1 << 7);
- }
-
- setDX(InfoWord);
- return TRUE;
- }
+ }
- /* Set Device Information */
- case 0x01:
+ /* Check if this is the current drive */
+ if (DriveNumber == Sda->CurrentDrive)
+ {
+ /* Change the directory */
+ if (!SetCurrentDirectoryA(Directory))
{
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-
+ Sda->LastErrorCode = LOWORD(GetLastError());
return FALSE;
}
+ }
- /* Read From Device I/O Control Channel */
- case 0x02:
- {
- WORD Length = getCX();
-
- if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
- {
- DosLastError = ERROR_INVALID_FUNCTION;
- return FALSE;
- }
-
- /* Do nothing if there is no IOCTL routine */
- if (!Node->IoctlReadRoutine)
- {
- setAX(0);
- return TRUE;
- }
-
- Node->IoctlReadRoutine(Node, MAKELONG(getDX(), getDS()), &Length);
-
- setAX(Length);
- return TRUE;
- }
+ /* Get the (possibly new) current directory (needed if we specified a relative directory) */
+ if (!GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
- /* Write To Device I/O Control Channel */
- case 0x03:
- {
- WORD Length = getCX();
+ /* Convert it to a DOS path */
+ if (!GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory)))
+ {
+ // TODO: Use some kind of default path?
+ return FALSE;
+ }
- if (Node == NULL || !(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
- {
- DosLastError = ERROR_INVALID_FUNCTION;
- return FALSE;
- }
+ /* Get the directory part of the path */
+ Path = strchr(DosDirectory, '\\');
+ if (Path != NULL)
+ {
+ /* Skip the backslash */
+ Path++;
+ }
- /* Do nothing if there is no IOCTL routine */
- if (!Node->IoctlWriteRoutine)
- {
- setAX(0);
- return TRUE;
- }
+ /* Set the directory for the drive */
+ if (Path != NULL)
+ {
+ strncpy(DosData->CurrentDirectories[DriveNumber], Path, DOS_DIR_LENGTH);
+ }
+ else
+ {
+ DosData->CurrentDirectories[DriveNumber][0] = '\0';
+ }
- Node->IoctlWriteRoutine(Node, MAKELONG(getDX(), getDS()), &Length);
+ /* Return success */
+ return TRUE;
+}
- setAX(Length);
- return TRUE;
- }
+static BOOLEAN DosControlBreak(VOID)
+{
+ setCF(0);
- /* Unsupported control code */
- default:
- {
- DPRINT1("Unsupported IOCTL: 0x%02X\n", ControlCode);
+ /* Call interrupt 0x23 */
+ Int32Call(&DosContext, 0x23);
- DosLastError = ERROR_INVALID_PARAMETER;
- return FALSE;
- }
+ if (getCF())
+ {
+ DosTerminateProcess(Sda->CurrentPsp, 0, 0);
+ return TRUE;
}
+
+ return FALSE;
}
+/* PUBLIC FUNCTIONS ***********************************************************/
+
VOID WINAPI DosInt20h(LPWORD Stack)
{
/* This is the exit interrupt */
SYSTEMTIME SystemTime;
PCHAR String;
PDOS_INPUT_BUFFER InputBuffer;
- PDOS_COUNTRY_CODE_BUFFER CountryCodeBuffer;
- INT Return;
+
+ Sda->InDos++;
+
+ /* Save the value of SS:SP on entry in the PSP */
+ SEGMENT_TO_PSP(Sda->CurrentPsp)->LastStack =
+ MAKELONG(getSP() + (STACK_FLAGS + 1) * 2, getSS());
/* Check the value in the AH register */
switch (getAH())
DosPrintCharacter(DOS_OUTPUT_HANDLE, '^');
DosPrintCharacter(DOS_OUTPUT_HANDLE, 'C');
- if (DosControlBreak()) return;
+ if (DosControlBreak())
+ {
+ /* Set the character to a newline to exit the loop */
+ Character = '\r';
+ }
+
break;
}
{
/* Append it to the buffer */
InputBuffer->Buffer[Count] = Character;
- Count++; /* Carriage returns are also counted */
/* Check if this is a special character */
if (Character < 0x20 && Character != 0x0A && Character != 0x0D)
}
if (Character == '\r') break;
+ if (Character == '\b') continue;
+ Count++; /* Carriage returns are NOT counted */
}
/* Update the length */
/* Disk Reset */
case 0x0D:
{
- PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
// TODO: Flush what's needed.
DPRINT1("INT 21h, 0Dh is UNIMPLEMENTED\n");
case 0x0E:
{
DosChangeDrive(getDL());
- setAL(LastDrive - 'A' + 1);
+ setAL(SysVars->NumLocalDrives);
break;
}
/* Get Default Drive */
case 0x19:
{
- setAL(CurrentDrive);
+ setAL(Sda->CurrentDrive);
break;
}
/* Set Disk Transfer Area */
case 0x1A:
{
- DiskTransferArea = MAKELONG(getDX(), getDS());
+ Sda->DiskTransferArea = MAKELONG(getDX(), getDS());
break;
}
/* Create New PSP */
case 0x26:
{
- DPRINT1("INT 21h, AH = 26h - Create New PSP is UNIMPLEMENTED\n");
+ DosClonePsp(getDX(), getCS());
+ break;
+ }
+
+ /* Parse Filename into FCB */
+ case 0x29:
+ {
+ PCHAR FileName = (PCHAR)SEG_OFF_TO_PTR(getDS(), getSI());
+ PDOS_FCB Fcb = (PDOS_FCB)SEG_OFF_TO_PTR(getES(), getDI());
+ BYTE Options = getAL();
+ CHAR FillChar = ' ';
+ UINT i;
+
+ if (FileName[1] == ':')
+ {
+ /* Set the drive number */
+ Fcb->DriveNumber = RtlUpperChar(FileName[0]) - 'A' + 1;
+
+ /* Skip to the file name part */
+ FileName += 2;
+ }
+ else
+ {
+ /* No drive number specified */
+ if (Options & (1 << 1)) Fcb->DriveNumber = Sda->CurrentDrive + 1;
+ else Fcb->DriveNumber = 0;
+ }
+
+ /* Parse the file name */
+ i = 0;
+ while ((*FileName > 0x20) && (i < 8))
+ {
+ if (*FileName == '.') break;
+ else if (*FileName == '*')
+ {
+ FillChar = '?';
+ break;
+ }
+
+ Fcb->FileName[i++] = RtlUpperChar(*FileName++);
+ }
+
+ /* Fill the whole field with blanks only if bit 2 is not set */
+ if ((FillChar != ' ') || (i != 0) || !(Options & (1 << 2)))
+ {
+ for (; i < 8; i++) Fcb->FileName[i] = FillChar;
+ }
+
+ /* Skip to the extension part */
+ while (*FileName > 0x20 && *FileName != '.') FileName++;
+ if (*FileName == '.') FileName++;
+
+ /* Now parse the extension */
+ i = 0;
+ FillChar = ' ';
+
+ while ((*FileName > 0x20) && (i < 3))
+ {
+ if (*FileName == '*')
+ {
+ FillChar = '?';
+ break;
+ }
+
+ Fcb->FileExt[i++] = RtlUpperChar(*FileName++);
+ }
+
+ /* Fill the whole field with blanks only if bit 3 is not set */
+ if ((FillChar != ' ') || (i != 0) || !(Options & (1 << 3)))
+ {
+ for (; i < 3; i++) Fcb->FileExt[i] = FillChar;
+ }
+
break;
}
/* Get Disk Transfer Area */
case 0x2F:
{
- setES(HIWORD(DiskTransferArea));
- setBX(LOWORD(DiskTransferArea));
+ setES(HIWORD(Sda->DiskTransferArea));
+ setBX(LOWORD(Sda->DiskTransferArea));
break;
}
/* Get DOS Version */
case 0x30:
{
- PDOS_PSP PspBlock = SEGMENT_TO_PSP(CurrentPsp);
+ PDOS_PSP PspBlock = SEGMENT_TO_PSP(Sda->CurrentPsp);
/*
* DOS 2+ - GET DOS VERSION
case 0x31:
{
DPRINT1("Process going resident: %u paragraphs kept\n", getDX());
- DosTerminateProcess(CurrentPsp, getAL(), getDX());
+ DosTerminateProcess(Sda->CurrentPsp, getAL(), getDX());
break;
}
break;
}
+ /* Get Address of InDOS flag */
+ case 0x34:
+ {
+ setES(DOS_DATA_SEGMENT);
+ setBX(DOS_DATA_OFFSET(Sda.InDos));
+ break;
+ }
+
/* Get Interrupt Vector */
case 0x35:
{
- DWORD FarPointer = ((PDWORD)BaseAddress)[getAL()];
+ ULONG FarPointer = ((PULONG)BaseAddress)[getAL()];
/* Read the address from the IDT into ES:BX */
setES(HIWORD(FarPointer));
break;
}
+ /* Get Free Disk Space */
+ case 0x36:
+ {
+ CHAR RootPath[] = "?:\\";
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD NumberOfFreeClusters;
+ DWORD TotalNumberOfClusters;
+
+ if (getDL() == 0x00) RootPath[0] = 'A' + Sda->CurrentDrive;
+ else RootPath[0] = 'A' + getDL() - 1;
+
+ if (GetDiskFreeSpaceA(RootPath,
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &NumberOfFreeClusters,
+ &TotalNumberOfClusters))
+ {
+ setAX(LOWORD(SectorsPerCluster));
+ setCX(LOWORD(BytesPerSector));
+ setBX(min(NumberOfFreeClusters, 0xFFFF));
+ setDX(min(TotalNumberOfClusters, 0xFFFF));
+ }
+ else
+ {
+ /* Error */
+ setAX(0xFFFF);
+ }
+
+ break;
+ }
+
/* SWITCH character - AVAILDEV */
case 0x37:
{
/* Get/Set Country-dependent Information */
case 0x38:
{
- CountryCodeBuffer = (PDOS_COUNTRY_CODE_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
+ INT Return;
+ PDOS_COUNTRY_CODE_BUFFER CountryCodeBuffer =
+ (PDOS_COUNTRY_CODE_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
if (getAL() == 0x00)
{
/* Get */
- Return = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE,
- &CountryCodeBuffer->TimeFormat,
- sizeof(CountryCodeBuffer->TimeFormat) / sizeof(TCHAR));
+ Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDATE,
+ (LPSTR)&CountryCodeBuffer->TimeFormat,
+ sizeof(CountryCodeBuffer->TimeFormat));
if (Return == 0)
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
- Return = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY,
- &CountryCodeBuffer->CurrencySymbol,
- sizeof(CountryCodeBuffer->CurrencySymbol) / sizeof(TCHAR));
+ Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY,
+ (LPSTR)&CountryCodeBuffer->CurrencySymbol,
+ sizeof(CountryCodeBuffer->CurrencySymbol));
if (Return == 0)
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
- Return = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND,
- &CountryCodeBuffer->ThousandSep,
- sizeof(CountryCodeBuffer->ThousandSep) / sizeof(TCHAR));
+ Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND,
+ (LPSTR)&CountryCodeBuffer->ThousandSep,
+ sizeof(CountryCodeBuffer->ThousandSep));
if (Return == 0)
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
- Return = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
- &CountryCodeBuffer->DecimalSep,
- sizeof(CountryCodeBuffer->DecimalSep) / sizeof(TCHAR));
+ Return = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
+ (LPSTR)&CountryCodeBuffer->DecimalSep,
+ sizeof(CountryCodeBuffer->DecimalSep));
if (Return == 0)
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(DosLastError);
+ setAX(Sda->LastErrorCode);
}
break;
case 0x3D:
{
WORD FileHandle;
- WORD ErrorCode;
LPCSTR FileName = (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX());
- PDOS_DEVICE_NODE Device = DosGetDevice(FileName);
-
- if (Device)
- {
- FileHandle = DosOpenDevice(Device);
- ErrorCode = (FileHandle != INVALID_DOS_HANDLE)
- ? ERROR_SUCCESS : ERROR_TOO_MANY_OPEN_FILES;
- }
- else
- {
- ErrorCode = DosOpenFile(&FileHandle, FileName, getAL());
- }
+ WORD ErrorCode = DosOpenFile(&FileHandle, FileName, getAL());
if (ErrorCode == ERROR_SUCCESS)
{
/* IOCTL */
case 0x44:
{
- if (DosHandleIoctl(getAL(), getBX()))
+ WORD Length = getCX();
+
+ if (DosDeviceIoControl(getBX(), getAL(), MAKELONG(getDX(), getDS()), &Length))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ setAX(Length);
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(DosLastError);
+ setAX(Sda->LastErrorCode);
}
break;
/* Duplicate Handle */
case 0x45:
{
- WORD NewHandle;
- PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX());
-
- if (SftEntry == NULL || SftEntry->Type == DOS_SFT_ENTRY_NONE)
- {
- /* The handle is invalid */
- Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(ERROR_INVALID_HANDLE);
- break;
- }
+ WORD NewHandle = DosDuplicateHandle(getBX());
- /* Open a new handle to the same entry */
- switch (SftEntry->Type)
+ if (NewHandle != INVALID_DOS_HANDLE)
{
- case DOS_SFT_ENTRY_WIN32:
- {
- NewHandle = DosOpenHandle(SftEntry->Handle);
- break;
- }
-
- case DOS_SFT_ENTRY_DEVICE:
- {
- NewHandle = DosOpenDevice(SftEntry->DeviceNode);
- break;
- }
-
- default:
- {
- /* Shouldn't happen */
- ASSERT(FALSE);
- }
+ setAX(NewHandle);
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
-
- if (NewHandle == INVALID_DOS_HANDLE)
+ else
{
- /* Too many files open */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(ERROR_TOO_MANY_OPEN_FILES);
- break;
+ setAX(Sda->LastErrorCode);
}
- /* Return the result */
- Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- setAX(NewHandle);
break;
}
/* Force Duplicate Handle */
case 0x46:
{
- if (DosDuplicateHandle(getBX(), getCX()))
+ if (DosForceDuplicateHandle(getBX(), getCX()))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
/* Get the real drive number */
if (DriveNumber == 0)
{
- DriveNumber = CurrentDrive;
+ DriveNumber = Sda->CurrentDrive;
}
else
{
DriveNumber--;
}
- if (DriveNumber <= LastDrive - 'A')
+ if (DriveNumber < SysVars->NumLocalDrives)
{
/*
* Copy the current directory into the target buffer.
* It doesn't contain the drive letter and the backslash.
*/
- strncpy(String, CurrentDirectories[DriveNumber], DOS_DIR_LENGTH);
+ strncpy(String, DosData->CurrentDirectories[DriveNumber], DOS_DIR_LENGTH);
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
setAX(0x0100); // Undocumented, see Ralf Brown: http://www.ctyme.com/intr/rb-2933.htm
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(DosLastError);
+ setAX(Sda->LastErrorCode);
setBX(MaxAvailable);
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(DosLastError);
+ setAX(Sda->LastErrorCode);
setBX(Size);
}
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());
- WORD ErrorCode = DosCreateProcess(LoadType, ProgramName, ParamBlock);
+ WORD ErrorCode;
+
+ 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);
+ }
+ else
+#endif
+ {
+ /* Just load an executable */
+ ErrorCode = DosLoadExecutable(LoadType,
+ ProgramName,
+ ParamBlock,
+ NULL,
+ NULL);
+ }
+ }
+ else if (OrgAL == 0x05)
+ {
+ // http://www.ctyme.com/intr/rb-2942.htm
+ DPRINT1("Set execution state is UNIMPLEMENTED\n");
+ ErrorCode = ERROR_CALL_NOT_IMPLEMENTED;
+ }
+ else
+ {
+ ErrorCode = ERROR_INVALID_FUNCTION;
+ }
if (ErrorCode == ERROR_SUCCESS)
{
break;
}
-#endif
/* Terminate With Return Code */
case 0x4C:
{
- DosTerminateProcess(CurrentPsp, getAL(), 0);
+ DosTerminateProcess(Sda->CurrentPsp, getAL(), 0);
break;
}
* DosErrorLevel is cleared after being read by this function.
*/
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- setAX(DosErrorLevel);
- DosErrorLevel = 0x0000; // Clear it
+ setAX(Sda->ErrorLevel);
+ Sda->ErrorLevel = 0x0000; // Clear it
break;
}
/* Find First File */
case 0x4E:
{
- WORD Result = (WORD)demFileFindFirst(FAR_POINTER(DiskTransferArea),
+ WORD Result = (WORD)demFileFindFirst(FAR_POINTER(Sda->DiskTransferArea),
SEG_OFF_TO_PTR(getDS(), getDX()),
getCX());
/* Find Next File */
case 0x4F:
{
- WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
+ WORD Result = (WORD)demFileFindNext(FAR_POINTER(Sda->DiskTransferArea));
setAX(Result);
/* Internal - Set Current Process ID (Set PSP Address) */
case 0x50:
{
- // FIXME: Is it really what it's done ??
- CurrentPsp = getBX();
+ DosSetProcessContext(getBX());
break;
}
* and http://www.ctyme.com/intr/rb-3140.htm
* for more information.
*/
- setBX(CurrentPsp);
+ setBX(Sda->CurrentPsp);
break;
}
*/
/* Return the DOS "list of lists" in ES:BX */
- setES(0x0000);
- setBX(0x0000);
+ setES(DOS_DATA_SEGMENT);
+ setBX(DOS_DATA_OFFSET(SysVars.FirstDpb));
+
+ break;
+ }
- DPRINT1("INT 21h, AH=52h: This application requires the internal DOS List of lists (SYSVARS). UNIMPLEMENTED");
+ /* Create Child PSP */
+ case 0x55:
+ {
+ DosCreatePsp(getDX(), getSI());
break;
}
{
/* Get allocation strategy */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
- setAX(DosAllocStrategy);
+ setAX(Sda->AllocStrategy);
}
else if (getAL() == 0x01)
{
break;
}
- DosAllocStrategy = getBL();
+ Sda->AllocStrategy = getBL();
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else if (getAL() == 0x02)
/* Lock/Unlock Region of File */
case 0x5C:
{
- PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX());
-
- if (SftEntry == NULL || SftEntry->Type != DOS_SFT_ENTRY_WIN32)
- {
- /* The handle is invalid */
- Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(ERROR_INVALID_HANDLE);
- break;
- }
-
if (getAL() == 0x00)
{
/* Lock region of file */
- if (LockFile(SftEntry->Handle,
- MAKELONG(getCX(), getDX()), 0,
- MAKELONG(getSI(), getDI()), 0))
+ if (DosLockFile(getBX(), MAKELONG(getDX(), getCX()), MAKELONG(getDI(), getSI())))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(GetLastError());
+ setAX(Sda->LastErrorCode);
}
}
else if (getAL() == 0x01)
{
/* Unlock region of file */
- if (UnlockFile(SftEntry->Handle,
- MAKELONG(getCX(), getDX()), 0,
- MAKELONG(getSI(), getDI()), 0))
+ if (DosUnlockFile(getBX(), MAKELONG(getDX(), getCX()), MAKELONG(getDI(), getSI())))
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
}
else
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(GetLastError());
+ setAX(Sda->LastErrorCode);
}
}
else
break;
}
+ /* Miscellaneous Internal Functions */
+ case 0x5D:
+ {
+ switch (getAL())
+ {
+ /* Get Swappable Data Area */
+ case 0x06:
+ {
+ setDS(DOS_DATA_SEGMENT);
+ setSI(DOS_DATA_OFFSET(Sda.ErrorMode));
+ setCX(sizeof(DOS_SDA));
+ setDX(FIELD_OFFSET(DOS_SDA, LastAX));
+
+ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("INT 21h, AH = 5Dh, subfunction AL = %Xh NOT IMPLEMENTED\n",
+ getAL());
+ }
+ }
+
+ break;
+ }
+
/* Set Handle Count */
case 0x67:
{
if (!DosResizeHandleTable(getBX()))
{
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
- setAX(DosLastError);
+ setAX(Sda->LastErrorCode);
}
else Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
}
+
+ Sda->InDos--;
}
VOID WINAPI DosBreakInterrupt(LPWORD Stack)
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
+VOID WINAPI DosAbsoluteRead(LPWORD Stack)
+{
+ /*
+ * This call should leave the flags on the stack for some reason,
+ * so move the stack by one word.
+ */
+ Stack[STACK_INT_NUM] = Stack[STACK_IP];
+ Stack[STACK_IP] = Stack[STACK_CS];
+ Stack[STACK_CS] = Stack[STACK_FLAGS];
+ setSP(LOWORD(getSP() - 2));
+
+ // TODO: NOT IMPLEMENTED;
+ UNIMPLEMENTED;
+
+ /* General failure */
+ setAX(0x800C);
+ Stack[STACK_FLAGS - 1] |= EMULATOR_FLAG_CF;
+}
+
+VOID WINAPI DosAbsoluteWrite(LPWORD Stack)
+{
+ /*
+ * This call should leave the flags on the stack for some reason,
+ * so move the stack by one word.
+ */
+ Stack[STACK_INT_NUM] = Stack[STACK_IP];
+ Stack[STACK_IP] = Stack[STACK_CS];
+ Stack[STACK_CS] = Stack[STACK_FLAGS];
+ setSP(LOWORD(getSP() - 2));
+
+ // TODO: NOT IMPLEMENTED;
+ UNIMPLEMENTED;
+
+ /* General failure */
+ setAX(0x800C);
+ Stack[STACK_FLAGS - 1] |= EMULATOR_FLAG_CF;
+}
+
+VOID WINAPI DosInt27h(LPWORD Stack)
+{
+ DosTerminateProcess(getCS(), 0, (getDX() + 0x0F) >> 4);
+}
+
+VOID WINAPI DosIdle(LPWORD Stack)
+{
+ /*
+ * This will set the carry flag on the first call (to repeat the BOP),
+ * and clear it in the next, so that exactly one HLT occurs.
+ */
+ setCF(!getCF());
+}
+
VOID WINAPI DosFastConOut(LPWORD Stack)
{
/*
break;
}
-
+
default:
{
DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
BOOLEAN DosKRNLInitialize(VOID)
{
-
#if 1
UCHAR i;
+ PDOS_SFT Sft;
+ LPSTR Path;
CHAR CurrentDirectory[MAX_PATH];
CHAR DosDirectory[DOS_DIR_LENGTH];
- LPSTR Path;
+
+ const BYTE NullDriverRoutine[] = {
+ /* Strategy routine entry */
+ 0x26, // mov [Request.Status], DOS_DEVSTAT_DONE
+ 0xC7,
+ 0x47,
+ FIELD_OFFSET(DOS_REQUEST_HEADER, Status),
+ LOBYTE(DOS_DEVSTAT_DONE),
+ HIBYTE(DOS_DEVSTAT_DONE),
+
+ /* Interrupt routine entry */
+ 0xCB, // retf
+ };
FILE *Stream;
WCHAR Buffer[256];
- /* Clear the current directory buffer */
- RtlZeroMemory(CurrentDirectories, sizeof(CurrentDirectories));
+ /* Initialize the global DOS data area */
+ DosData = (PDOS_DATA)SEG_OFF_TO_PTR(DOS_DATA_SEGMENT, 0x0000);
+ RtlZeroMemory(DosData, sizeof(*DosData));
+
+ /* Initialize the list of lists */
+ SysVars = &DosData->SysVars;
+ RtlZeroMemory(SysVars, sizeof(*SysVars));
+ SysVars->FirstMcb = FIRST_MCB_SEGMENT;
+ SysVars->FirstSft = MAKELONG(DOS_DATA_OFFSET(Sft), DOS_DATA_SEGMENT);
+ SysVars->CurrentDirs = MAKELONG(DOS_DATA_OFFSET(CurrentDirectories),
+ DOS_DATA_SEGMENT);
+ /* The last drive can be redefined with the LASTDRIVE command. At the moment, set the real maximum possible, 'Z'. */
+ SysVars->NumLocalDrives = 'Z' - 'A' + 1;
+
+ /* Initialize the NUL device driver */
+ SysVars->NullDevice.Link = 0xFFFFFFFF;
+ SysVars->NullDevice.DeviceAttributes = DOS_DEVATTR_NUL | DOS_DEVATTR_CHARACTER;
+ SysVars->NullDevice.StrategyRoutine = FIELD_OFFSET(DOS_SYSVARS, NullDriverRoutine);
+ SysVars->NullDevice.InterruptRoutine = SysVars->NullDevice.StrategyRoutine + 6;
+ RtlFillMemory(SysVars->NullDevice.DeviceName,
+ sizeof(SysVars->NullDevice.DeviceName),
+ ' ');
+ RtlCopyMemory(SysVars->NullDevice.DeviceName, "NUL", strlen("NUL"));
+ RtlCopyMemory(SysVars->NullDriverRoutine,
+ NullDriverRoutine,
+ sizeof(NullDriverRoutine));
+
+ /* Initialize the swappable data area */
+ Sda = &DosData->Sda;
+ RtlZeroMemory(Sda, sizeof(*Sda));
/* Get the current directory */
- if (!GetCurrentDirectoryA(MAX_PATH, CurrentDirectory))
+ if (!GetCurrentDirectoryA(sizeof(CurrentDirectory), CurrentDirectory))
{
// TODO: Use some kind of default path?
return FALSE;
}
- /* Convert that to a DOS path */
- if (!GetShortPathNameA(CurrentDirectory, DosDirectory, DOS_DIR_LENGTH))
+ /* Convert it to a DOS path */
+ if (!GetShortPathNameA(CurrentDirectory, DosDirectory, sizeof(DosDirectory)))
{
// TODO: Use some kind of default path?
return FALSE;
}
/* Set the drive */
- CurrentDrive = DosDirectory[0] - 'A';
+ Sda->CurrentDrive = RtlUpperChar(DosDirectory[0]) - 'A';
/* Get the directory part of the path */
Path = strchr(DosDirectory, '\\');
/* Set the directory */
if (Path != NULL)
{
- strncpy(CurrentDirectories[CurrentDrive], Path, DOS_DIR_LENGTH);
+ strncpy(DosData->CurrentDirectories[Sda->CurrentDrive], Path, DOS_DIR_LENGTH);
+ }
+
+ /* Set the current PSP to the system PSP */
+ Sda->CurrentPsp = SYSTEM_PSP;
+
+ /* Set the initial allocation strategy to "best fit" */
+ Sda->AllocStrategy = DOS_ALLOC_BEST_FIT;
+
+ /* Initialize the SFT */
+ Sft = (PDOS_SFT)FAR_POINTER(SysVars->FirstSft);
+ Sft->Link = 0xFFFFFFFF;
+ Sft->NumDescriptors = DOS_SFT_SIZE;
+
+ for (i = 0; i < Sft->NumDescriptors; i++)
+ {
+ /* Clear the file descriptor entry */
+ RtlZeroMemory(&Sft->FileDescriptors[i], sizeof(DOS_FILE_DESCRIPTOR));
}
/* Read CONFIG.SYS */
fclose(Stream);
}
- /* Initialize the SFT */
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- DosSystemFileTable[i].Type = DOS_SFT_ENTRY_NONE;
- DosSystemFileTable[i].RefCount = 0;
- }
-
#endif
/* Initialize the callback context */
- InitializeContext(&DosContext, 0x0070, 0x0000);
+ InitializeContext(&DosContext, DOS_CODE_SEGMENT, 0x0000);
/* Register the DOS 32-bit Interrupts */
RegisterDosInt32(0x20, DosInt20h );
// RegisterDosInt32(0x22, DosInt22h ); // Termination
RegisterDosInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break
// RegisterDosInt32(0x24, DosInt24h ); // Critical Error
+ RegisterDosInt32(0x25, DosAbsoluteRead ); // Absolute Disk Read
+ RegisterDosInt32(0x26, DosAbsoluteWrite ); // Absolute Disk Write
+ RegisterDosInt32(0x27, DosInt27h ); // Terminate and Stay Resident
+ RegisterDosInt32(0x28, DosIdle ); // DOS Idle Interrupt
RegisterDosInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output
RegisterDosInt32(0x2F, DosInt2Fh );
+ /* Unimplemented DOS interrupts */
+ RegisterDosInt32(0x2A, NULL); // Network - Installation Check
+
+ /* Load the CON driver */
+ ConDrvInitialize();
+
+ /* Load the XMS driver (HIMEM) */
+ XmsInitialize();
+
/* Load the EMS driver */
if (!EmsDrvInitialize(EMS_TOTAL_PAGES))
{
"Try reducing the number of EMS pages.\n");
}
- /* Load the XMS driver (HIMEM) */
- XmsInitialize();
-
- /* Load the CON driver */
- ConDrvInitialize();
-
return TRUE;
}