Author: aandrejevic
Date: Thu Mar 26 00:21:25 2015
New Revision: 66895
URL:
http://svn.reactos.org/svn/reactos?rev=66895&view=rev
Log:
[NTVDM]
Implement DOS character device support and driver loading support.
Separate the DOS memory manager code from the main DOS kernel source file.
CORE-9370 #resolve #comment Committed in revision r66895.
Added:
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c (with props)
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h (with props)
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.c
trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.h
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
trunk/reactos/subsystems/mvdm/ntvdm/emulator.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/CMak…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/CMakeLists.txt [iso-8859-1] Thu Mar 26 00:21:25
2015
@@ -29,8 +29,12 @@
hardware/sound/speaker.c
hardware/video/vga.c
dos/dos32krnl/bios.c
+ dos/dos32krnl/condrv.c
+ dos/dos32krnl/device.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
+ dos/dos32krnl/emsdrv.c
+ dos/dos32krnl/memory.c
dos/mouse32.c
dos/dem.c
clock.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.c [iso-8859-1] Thu Mar 26 00:21:25
2015
@@ -313,9 +313,9 @@
for (i = FirstPage; i <= LastPage; i++)
{
- Offset = (i == FirstPage) ? Address & (EMS_PAGE_SIZE - 1) : 0;
+ Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
- ? (Address + Size - (LastPage << EMS_PAGE_BITS))
+ ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Mapping[i] + Offset),
Length);
@@ -333,9 +333,9 @@
for (i = FirstPage; i <= LastPage; i++)
{
- Offset = (i == FirstPage) ? Address & (EMS_PAGE_SIZE - 1) : 0;
+ Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
Length = ((i == LastPage)
- ? (Address + Size - (LastPage << EMS_PAGE_BITS))
+ ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
: EMS_PAGE_SIZE) - Offset;
if (Mapping[i]) RtlCopyMemory((PVOID)((ULONG_PTR)Mapping[i] + Offset), Buffer,
Length);
Modified: trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/bios…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/bios/bios32/ems.h [iso-8859-1] Thu Mar 26 00:21:25
2015
@@ -30,8 +30,6 @@
#define EMS_STATUS_INV_LOGICAL_PAGE 0x8A
#define EMS_STATUS_INV_PHYSICAL_PAGE 0x8B
#define EMS_STATUS_UNKNOWN_FUNCTION 0x8F
-
-#define ARRAY_INDEX(ptr, array) ((ULONG)(((ULONG_PTR)(ptr) - (ULONG_PTR)(array)) /
sizeof(*array)))
typedef struct _EMS_HANDLE
{
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/bios.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -14,6 +14,7 @@
#include "int32.h"
#include "dos.h"
+#include "memory.h"
#include "bios/bios.h"
// This is needed because on UNICODE this symbol is redirected to
@@ -27,6 +28,8 @@
#undef FreeEnvironmentStrings
#define FreeEnvironmentStrings FreeEnvironmentStringsA
+#define CHARACTER_ADDRESS 0x007000FF /* 0070:00FF */
+
/* PRIVATE VARIABLES **********************************************************/
// static BYTE CurrentDrive;
@@ -38,53 +41,60 @@
CHAR DosReadCharacter(WORD FileHandle)
{
- CHAR Character = '\0';
+ PCHAR Character = (PCHAR)FAR_POINTER(CHARACTER_ADDRESS);
WORD BytesRead;
+ *Character = '\0';
DPRINT("DosReadCharacter\n");
/* Use the file reading function */
- DosReadFile(FileHandle, &Character, 1, &BytesRead);
-
- return Character;
+ DosReadFile(FileHandle, CHARACTER_ADDRESS, 1, &BytesRead);
+
+ return *Character;
}
BOOLEAN DosCheckInput(VOID)
{
- HANDLE Handle = DosGetRealHandle(DOS_INPUT_HANDLE);
-
- if (IsConsoleHandle(Handle))
- {
- /* Save AX */
- USHORT AX = getAX();
-
- /* Call the BIOS */
- setAH(0x01); // or 0x11 for enhanced, but what to choose?
- Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
-
- /* Restore AX */
- setAX(AX);
-
- /* Return keyboard status */
- return (getZF() == 0);
- }
- else
- {
- DWORD FileSizeHigh;
- DWORD FileSize = GetFileSize(Handle, &FileSizeHigh);
- LONG LocationHigh = 0;
- DWORD Location = SetFilePointer(Handle, 0, &LocationHigh, FILE_CURRENT);
-
- return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(DOS_INPUT_HANDLE);
+
+ switch (SftEntry->Type)
+ {
+ case DOS_SFT_ENTRY_WIN32:
+ {
+ DWORD FileSizeHigh;
+ DWORD FileSize = GetFileSize(SftEntry->Handle, &FileSizeHigh);
+ LONG LocationHigh = 0;
+ DWORD Location = SetFilePointer(SftEntry->Handle, 0, &LocationHigh,
FILE_CURRENT);
+
+ return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
+ }
+
+ case DOS_SFT_ENTRY_DEVICE:
+ {
+ WORD Result;
+
+ if (!SftEntry->DeviceNode->InputStatusRoutine) return FALSE;
+
+ Result =
SftEntry->DeviceNode->InputStatusRoutine(SftEntry->DeviceNode);
+ return !(Result & DOS_DEVSTAT_BUSY);
+ }
+
+ default:
+ {
+ /* Invalid handle */
+ DosLastError = ERROR_INVALID_HANDLE;
+ return FALSE;
+ }
}
}
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
{
WORD BytesWritten;
+ *((PCHAR)FAR_POINTER(CHARACTER_ADDRESS)) = Character;
/* Use the file writing function */
- DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
+ DosWriteFile(FileHandle, CHARACTER_ADDRESS, 1, &BytesWritten);
}
BOOLEAN DosBIOSInitialize(VOID)
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,155 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dos/dos32krnl/condrv.c
+ * PURPOSE: DOS32 CON Driver
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "emulator.h"
+
+#include "dos.h"
+#include "dos/dem.h"
+
+#include "bios/bios.h"
+
+/* PRIVATE VARIABLES **********************************************************/
+
+PDOS_DEVICE_NODE ConIn = NULL, ConOut = NULL;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+WORD NTAPI ConDrvReadInput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
+{
+ CHAR Character;
+ WORD BytesRead;
+ PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
+
+ /* Save AX */
+ USHORT AX = getAX();
+
+ /*
+ * Use BIOS Get Keystroke function
+ */
+ for (BytesRead = 0; BytesRead < *Length; BytesRead++)
+ {
+ /* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
+ setAH(0x00);
+ Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
+
+ /* Retrieve the character in AL (scan code is in AH) */
+ Character = getAL();
+
+ if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
+ Pointer[BytesRead] = Character;
+
+ /* Stop on first carriage return */
+ if (Character == '\r')
+ {
+ if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
+ break;
+ }
+ }
+
+ *Length = BytesRead;
+
+ /* Restore AX */
+ setAX(AX);
+ return DOS_DEVSTAT_DONE;
+}
+
+WORD NTAPI ConDrvInputStatus(PDOS_DEVICE_NODE Device)
+{
+ /* Save AX */
+ USHORT AX = getAX();
+
+ /* Call the BIOS */
+ setAH(0x01); // or 0x11 for enhanced, but what to choose?
+ Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
+
+ /* Restore AX */
+ setAX(AX);
+
+ /* If ZF is set, set the busy bit */
+ if (getZF()) return DOS_DEVSTAT_BUSY;
+ else return DOS_DEVSTAT_DONE;
+}
+
+WORD NTAPI ConDrvWriteOutput(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
+{
+ WORD BytesWritten;
+ PCHAR Pointer = (PCHAR)FAR_POINTER(Buffer);
+
+ /*
+ * Use BIOS Teletype function
+ */
+
+ /* Save AX and BX */
+ USHORT AX = getAX();
+ USHORT BX = getBX();
+
+ // FIXME: Use BIOS Write String function INT 10h, AH=13h ??
+ for (BytesWritten = 0; BytesWritten < *Length; BytesWritten++)
+ {
+ /* Set the parameters */
+ setAL(Pointer[BytesWritten]);
+ setBL(DOS_CHAR_ATTRIBUTE);
+ setBH(Bda->VideoPage);
+
+ /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
+ setAH(0x0E);
+ Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
+ }
+
+ /* Restore AX and BX */
+ setBX(BX);
+ setAX(AX);
+ return DOS_DEVSTAT_DONE;
+}
+
+WORD NTAPI ConDrvOpen(PDOS_DEVICE_NODE Device)
+{
+ DPRINT("Handle to %Z opened\n", &Device->Name);
+ return DOS_DEVSTAT_DONE;
+}
+
+WORD NTAPI ConDrvClose(PDOS_DEVICE_NODE Device)
+{
+ DPRINT("Handle to %Z closed\n", &Device->Name);
+ return DOS_DEVSTAT_DONE;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID ConDrvInitialize(PDOS_DEVICE_NODE *InputDevice, PDOS_DEVICE_NODE *OutputDevice)
+{
+ ConIn = DosCreateDevice(DOS_DEVATTR_STDIN
+ | DOS_DEVATTR_CON
+ | DOS_DEVATTR_CHARACTER,
+ "CONIN$");
+ ConOut = DosCreateDevice(DOS_DEVATTR_STDOUT
+ | DOS_DEVATTR_CON
+ | DOS_DEVATTR_CHARACTER,
+ "CONOUT$");
+ ASSERT(ConIn != NULL && ConOut != NULL);
+
+ ConIn->ReadRoutine = ConDrvReadInput;
+ ConIn->InputStatusRoutine = ConDrvInputStatus;
+ ConOut->WriteRoutine = ConDrvWriteOutput;
+ ConIn->OpenRoutine = ConOut->OpenRoutine = ConDrvOpen;
+ ConIn->CloseRoutine = ConOut->CloseRoutine = ConDrvClose;
+
+ if (InputDevice) *InputDevice = ConIn;
+ if (OutputDevice) *OutputDevice = ConOut;
+}
+
+VOID ConDrvCleanup(VOID)
+{
+ if (ConIn) DosDeleteDevice(ConIn);
+ if (ConOut) DosDeleteDevice(ConOut);
+}
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/condrv.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,383 @@
+/*
+ * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: device.c
+ * PURPOSE: DOS Device Support
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "emulator.h"
+#include "dos.h"
+#include "dos/dem.h"
+#include "memory.h"
+#include "device.h"
+
+/* PRIVATE VARIABLES **********************************************************/
+
+static LIST_ENTRY DeviceList = { &DeviceList, &DeviceList };
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static VOID DosCallDriver(DWORD Driver, PDOS_REQUEST_HEADER Request)
+{
+ PDOS_DRIVER DriverBlock = (PDOS_DRIVER)FAR_POINTER(Driver);
+ PDOS_REQUEST_HEADER RemoteRequest;
+
+ /* Call the strategy routine first */
+ Call16(HIWORD(Driver), DriverBlock->StrategyRoutine);
+ RemoteRequest = (PDOS_REQUEST_HEADER)SEG_OFF_TO_PTR(getES(), getBX());
+
+ /* Copy the request structure to ES:BX */
+ RtlMoveMemory(RemoteRequest, Request, Request->RequestLength);
+
+ /* Call the interrupt routine */
+ Call16(HIWORD(Driver), DriverBlock->InterruptRoutine);
+
+ /* Get the request structure from ES:BX */
+ RtlMoveMemory(Request, RemoteRequest, RemoteRequest->RequestLength);
+}
+
+static inline WORD NTAPI DosDriverReadInternal(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length,
+ BOOLEAN IoControl)
+{
+ DOS_RW_REQUEST Request;
+
+ Request.Header.RequestLength = IoControl ? sizeof(DOS_IOCTL_RW_REQUEST)
+ : sizeof(DOS_RW_REQUEST);
+ Request.Header.CommandCode = IoControl ? DOS_DEVCMD_IOCTL_READ : DOS_DEVCMD_READ;
+ Request.BufferPointer = Buffer;
+ Request.Length = *Length;
+
+ DosCallDriver(DeviceNode->Driver, &Request.Header);
+
+ *Length = Request.Length;
+ return Request.Header.Status;
+}
+
+static inline WORD NTAPI DosDriverWriteInternal(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length,
+ BOOLEAN IoControl)
+{
+ DOS_RW_REQUEST Request;
+
+ Request.Header.RequestLength = IoControl ? sizeof(DOS_IOCTL_RW_REQUEST)
+ : sizeof(DOS_RW_REQUEST);
+ Request.Header.CommandCode = IoControl ? DOS_DEVCMD_IOCTL_WRITE : DOS_DEVCMD_WRITE;
+ Request.BufferPointer = Buffer;
+ Request.Length = *Length;
+
+ DosCallDriver(DeviceNode->Driver, &Request.Header);
+
+ *Length = Request.Length;
+ return Request.Header.Status;
+}
+
+static inline WORD NTAPI DosDriverGenericRequest(PDOS_DEVICE_NODE DeviceNode,
+ BYTE CommandCode)
+{
+ DOS_REQUEST_HEADER Request;
+
+ Request.RequestLength = sizeof(DOS_REQUEST_HEADER);
+ Request.CommandCode = CommandCode;
+
+ DosCallDriver(DeviceNode->Driver, &Request);
+
+ return Request.Status;
+}
+
+static WORD NTAPI DosDriverDispatchIoctlRead(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length)
+{
+ return DosDriverReadInternal(DeviceNode, Buffer, Length, TRUE);
+}
+
+static WORD NTAPI DosDriverDispatchRead(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length)
+{
+ return DosDriverReadInternal(DeviceNode, Buffer, Length, FALSE);
+}
+
+static WORD NTAPI DosDriverDispatchPeek(PDOS_DEVICE_NODE DeviceNode,
+ PBYTE Character)
+{
+ DOS_PEEK_REQUEST Request;
+
+ Request.Header.RequestLength = sizeof(DOS_PEEK_REQUEST);
+ Request.Header.CommandCode = DOS_DEVCMD_PEEK;
+
+ DosCallDriver(DeviceNode->Driver, &Request.Header);
+
+ *Character = Request.Character;
+ return Request.Header.Status;
+}
+
+static WORD NTAPI DosDriverDispatchInputStatus(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_INSTAT);
+}
+
+static WORD NTAPI DosDriverDispatchFlushInput(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_FLUSH_INPUT);
+}
+
+static WORD NTAPI DosDriverDispatchIoctlWrite(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length)
+{
+ return DosDriverWriteInternal(DeviceNode, Buffer, Length, TRUE);
+}
+
+static WORD NTAPI DosDriverDispatchWrite(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length)
+{
+ return DosDriverWriteInternal(DeviceNode, Buffer, Length, FALSE);
+}
+
+static WORD NTAPI DosDriverDispatchOutputStatus(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_OUTSTAT);
+}
+
+static WORD NTAPI DosDriverDispatchFlushOutput(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_FLUSH_OUTPUT);
+}
+
+static WORD NTAPI DosDriverDispatchOpen(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_OPEN);
+}
+
+static WORD NTAPI DosDriverDispatchClose(PDOS_DEVICE_NODE DeviceNode)
+{
+ return DosDriverGenericRequest(DeviceNode, DOS_DEVCMD_CLOSE);
+}
+
+static WORD NTAPI DosDriverDispatchOutputUntilBusy(PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length)
+{
+ DOS_OUTPUT_BUSY_REQUEST Request;
+
+ Request.Header.RequestLength = sizeof(DOS_OUTPUT_BUSY_REQUEST);
+ Request.Header.CommandCode = DOS_DEVCMD_OUTPUT_BUSY;
+ Request.BufferPointer = Buffer;
+ Request.Length = *Length;
+
+ DosCallDriver(DeviceNode->Driver, &Request.Header);
+
+ *Length = Request.Length;
+ return Request.Header.Status;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName)
+{
+ PLIST_ENTRY i;
+ PDOS_DEVICE_NODE Node;
+ ANSI_STRING DeviceNameString;
+
+ RtlInitAnsiString(&DeviceNameString, DeviceName);
+
+ for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
+ {
+ Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
+ if (RtlEqualString(&Node->Name, &DeviceNameString, TRUE)) return
Node;
+ }
+
+ return NULL;
+}
+
+PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName)
+{
+ BYTE i;
+ PDOS_DEVICE_NODE Node;
+
+ /* Make sure this is a character device */
+ if (!(Attributes & DOS_DEVATTR_CHARACTER))
+ {
+ DPRINT1("ERROR: Block devices are not supported.\n");
+ return FALSE;
+ }
+
+ Node = (PDOS_DEVICE_NODE)RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(DOS_DEVICE_NODE));
+ if (Node == NULL) return NULL;
+
+ Node->DeviceAttributes = Attributes;
+
+ /* Initialize the name string */
+ Node->Name.Buffer = Node->NameBuffer;
+ Node->Name.MaximumLength = MAX_DEVICE_NAME;
+
+ for (i = 0; i < MAX_DEVICE_NAME; i++)
+ {
+ if (DeviceName[i] == '\0' || DeviceName[i] == ' ') break;
+ Node->Name.Buffer[i] = DeviceName[i];
+ }
+
+ Node->Name.Length = i;
+
+ InsertTailList(&DeviceList, &Node->Entry);
+ return Node;
+}
+
+VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode)
+{
+ RemoveEntryList(&DeviceNode->Entry);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNode);
+}
+
+DWORD DosLoadDriver(LPCSTR DriverFile)
+{
+ DWORD Result = ERROR_SUCCESS;
+ HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
+ LPBYTE Address = NULL;
+ DWORD Driver;
+ PDOS_DRIVER DriverHeader;
+ WORD Segment = 0;
+ DWORD FileSize;
+ DWORD DriversLoaded = 0;
+ DOS_INIT_REQUEST Request;
+ PDOS_DEVICE_NODE DeviceNode;
+
+ /* Open a handle to the driver file */
+ FileHandle = CreateFileA(DriverFile,
+ 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);
+
+ /* Allocate DOS memory for the driver */
+ Segment = DosAllocateMemory(FileSize >> 4, NULL);
+ if (Segment == 0)
+ {
+ Result = DosLastError;
+ goto Cleanup;
+ }
+
+ /* 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 entire file to the DOS memory */
+ Driver = MAKELONG(0, Segment);
+ DriverHeader = (PDOS_DRIVER)FAR_POINTER(Driver);
+ RtlCopyMemory(DriverHeader, Address, FileSize);
+
+ /* Loop through all the drivers in this file */
+ while (TRUE)
+ {
+ if (!(DriverHeader->DeviceAttributes & DOS_DEVATTR_CHARACTER))
+ {
+ DPRINT1("Error loading driver at %04X:%04X: "
+ "Block device drivers are not supported.\n",
+ HIWORD(Driver),
+ LOWORD(Driver));
+ goto Next;
+ }
+
+ /* Send the driver an init request */
+ RtlZeroMemory(&Request, sizeof(Request));
+ Request.Header.RequestLength = sizeof(DOS_INIT_REQUEST);
+ Request.Header.CommandCode = DOS_DEVCMD_INIT;
+ // TODO: Set Request.DeviceString to the appropriate line in CONFIG.NT!
+ DosCallDriver(Driver, &Request.Header);
+
+ if (Request.Header.Status & DOS_DEVSTAT_ERROR)
+ {
+ DPRINT1("Error loading driver at %04X:%04X: "
+ "Initialization routine returned error %u.\n",
+ HIWORD(Driver),
+ LOWORD(Driver),
+ Request.Header.Status & 0x7F);
+ goto Next;
+ }
+
+ /* Create the device */
+ DeviceNode = DosCreateDevice(DriverHeader->DeviceAttributes,
+ DriverHeader->DeviceName);
+ DeviceNode->Driver = Driver;
+ DeviceNode->IoctlReadRoutine = DosDriverDispatchIoctlRead;
+ DeviceNode->ReadRoutine = DosDriverDispatchRead;
+ DeviceNode->PeekRoutine = DosDriverDispatchPeek;
+ DeviceNode->InputStatusRoutine = DosDriverDispatchInputStatus;
+ DeviceNode->FlushInputRoutine = DosDriverDispatchFlushInput;
+ DeviceNode->IoctlWriteRoutine = DosDriverDispatchIoctlWrite;
+ DeviceNode->WriteRoutine = DosDriverDispatchWrite;
+ DeviceNode->OutputStatusRoutine = DosDriverDispatchOutputStatus;
+ DeviceNode->FlushOutputRoutine = DosDriverDispatchFlushOutput;
+ DeviceNode->OpenRoutine = DosDriverDispatchOpen;
+ DeviceNode->CloseRoutine = DosDriverDispatchClose;
+ DeviceNode->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
+
+ DriversLoaded++;
+
+Next:
+ if (LOWORD(DriverHeader->Link) == 0xFFFF) break;
+ Driver = DriverHeader->Link;
+ DriverHeader = (PDOS_DRIVER)FAR_POINTER(Driver);
+ }
+
+ DPRINT1("%u drivers loaded from %s.\n", DriversLoaded, DriverFile);
+
+Cleanup:
+ if (Result != ERROR_SUCCESS)
+ {
+ /* It was not successful, cleanup the DOS memory */
+ 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;
+}
+
+
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,199 @@
+/*
+ * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: device.h
+ * PURPOSE: DOS Device Support
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+#ifndef _DEVICE_H_
+#define _DEVICE_H_
+
+#include <ndk/rtlfuncs.h>
+
+/* DEFINITIONS ****************************************************************/
+
+#define MAX_DEVICE_NAME 8
+
+#define DOS_DEVATTR_STDIN (1 << 0)
+#define DOS_DEVATTR_STDOUT (1 << 1)
+#define DOS_DEVATTR_NUL (1 << 2)
+#define DOS_DEVATTR_CLOCK (1 << 3)
+#define DOS_DEVATTR_CON (1 << 4)
+#define DOS_DEVATTR_OPENCLOSE (1 << 11)
+#define DOS_DEVATTR_SPECIAL (1 << 13)
+#define DOS_DEVATTR_IOCTL (1 << 14)
+#define DOS_DEVATTR_CHARACTER (1 << 15)
+
+#define DOS_DEVCMD_INIT 0
+#define DOS_DEVCMD_MEDIACHK 1
+#define DOS_DEVCMD_BUILDBPB 2
+#define DOS_DEVCMD_IOCTL_READ 3
+#define DOS_DEVCMD_READ 4
+#define DOS_DEVCMD_PEEK 5
+#define DOS_DEVCMD_INSTAT 6
+#define DOS_DEVCMD_FLUSH_INPUT 7
+#define DOS_DEVCMD_WRITE 8
+#define DOS_DEVCMD_WRITE_VERIFY 9
+#define DOS_DEVCMD_OUTSTAT 10
+#define DOS_DEVCMD_FLUSH_OUTPUT 11
+#define DOS_DEVCMD_IOCTL_WRITE 12
+#define DOS_DEVCMD_OPEN 13
+#define DOS_DEVCMD_CLOSE 14
+#define DOS_DEVCMD_REMOVABLE 15
+#define DOS_DEVCMD_OUTPUT_BUSY 16
+
+#define DOS_DEVSTAT_DONE (1 << 8)
+#define DOS_DEVSTAT_BUSY (1 << 9)
+#define DOS_DEVSTAT_ERROR (1 << 15)
+
+#define DOS_DEVERR_WRITE_PROTECT 0
+#define DOS_DEVERR_UNKNOWN_UNIT 1
+#define DOS_DEVERR_NOT_READY 2
+#define DOS_DEVERR_UNKNOWN_COMMAND 3
+#define DOS_DEVERR_BAD_DATA_CRC 4
+#define DOS_DEVERR_BAD_REQUEST 5
+#define DOS_DEVERR_INVALID_SEEK 6
+#define DOS_DEVERR_UNKNOWN_MEDIUM 7
+#define DOS_DEVERR_BAD_BLOCK 8
+#define DOS_DEVERR_OUT_OF_PAPER 9
+#define DOS_DEVERR_WRITE_FAULT 10
+#define DOS_DEVERR_READ_FAULT 11
+#define DOS_DEVERR_GENERAL 12
+#define DOS_DEVERR_BAD_MEDIA_CHANGE 15
+
+typedef struct _DOS_DEVICE_NODE DOS_DEVICE_NODE, *PDOS_DEVICE_NODE;
+
+typedef WORD (NTAPI *PDOS_DEVICE_GENERIC_ROUTINE)(PDOS_DEVICE_NODE DeviceNode);
+
+typedef WORD (NTAPI *PDOS_DEVICE_IO_ROUTINE)
+(
+ PDOS_DEVICE_NODE DeviceNode,
+ DWORD Buffer,
+ PWORD Length
+);
+
+typedef WORD (NTAPI *PDOS_DEVICE_PEEK_ROUTINE)
+(
+ PDOS_DEVICE_NODE DeviceNode,
+ PBYTE Character
+);
+
+struct _DOS_DEVICE_NODE
+{
+ LIST_ENTRY Entry;
+ WORD DeviceAttributes;
+ ANSI_STRING Name;
+ CHAR NameBuffer[MAX_DEVICE_NAME];
+ PDOS_DEVICE_IO_ROUTINE IoctlReadRoutine;
+ PDOS_DEVICE_IO_ROUTINE ReadRoutine;
+ PDOS_DEVICE_PEEK_ROUTINE PeekRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE InputStatusRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE FlushInputRoutine;
+ PDOS_DEVICE_IO_ROUTINE IoctlWriteRoutine;
+ PDOS_DEVICE_IO_ROUTINE WriteRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE OutputStatusRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE FlushOutputRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE OpenRoutine;
+ PDOS_DEVICE_GENERIC_ROUTINE CloseRoutine;
+ PDOS_DEVICE_IO_ROUTINE OutputUntilBusyRoutine;
+ DWORD Driver;
+};
+
+#pragma pack(push, 1)
+
+typedef struct _DOS_DRIVER
+{
+ DWORD Link;
+ WORD DeviceAttributes;
+ WORD StrategyRoutine;
+ WORD InterruptRoutine;
+
+ union
+ {
+ CHAR DeviceName[MAX_DEVICE_NAME]; // for character devices
+
+ struct // for block devices
+ {
+ BYTE UnitCount;
+ BYTE Reserved[MAX_DEVICE_NAME - 1];
+ };
+ };
+} DOS_DRIVER, *PDOS_DRIVER;
+
+typedef struct _DOS_REQUEST_HEADER
+{
+ IN BYTE RequestLength;
+ IN BYTE UnitNumber OPTIONAL;
+ IN BYTE CommandCode;
+ OUT WORD Status;
+
+ BYTE Reserved[8];
+} DOS_REQUEST_HEADER, *PDOS_REQUEST_HEADER;
+
+typedef struct _DOS_INIT_REQUEST
+{
+ DOS_REQUEST_HEADER Header;
+
+ OUT BYTE UnitsInitialized;
+ OUT DWORD ReturnBreakAddress;
+
+ union
+ {
+ IN DWORD DeviceString; // for character devices
+
+ struct // for block devices
+ {
+ IN BYTE FirstDriveLetter;
+ OUT DWORD BpbPointer;
+ };
+ };
+
+} DOS_INIT_REQUEST, *PDOS_INIT_REQUEST;
+
+typedef struct _DOS_IOCTL_RW_REQUEST
+{
+ DOS_REQUEST_HEADER Header;
+
+ IN BYTE MediaDescriptorByte OPTIONAL;
+ IN DWORD BufferPointer;
+ IN OUT WORD Length;
+ IN WORD StartingBlock OPTIONAL;
+} DOS_IOCTL_RW_REQUEST, *PDOS_IOCTL_RW_REQUEST;
+
+typedef struct _DOS_RW_REQUEST
+{
+ DOS_REQUEST_HEADER Header;
+
+ IN BYTE MediaDescriptorByte OPTIONAL;
+ IN DWORD BufferPointer;
+ IN OUT WORD Length;
+ IN WORD StartingBlock OPTIONAL;
+ OUT DWORD VolumeLabelPtr OPTIONAL;
+} DOS_RW_REQUEST, *PDOS_RW_REQUEST;
+
+typedef struct _DOS_PEEK_REQUEST
+{
+ DOS_REQUEST_HEADER Header;
+ OUT BYTE Character;
+} DOS_PEEK_REQUEST, *PDOS_PEEK_REQUEST;
+
+typedef struct _DOS_OUTPUT_BUSY_REQUEST
+{
+ DOS_REQUEST_HEADER Header;
+
+ IN DWORD BufferPointer;
+ IN OUT WORD Length;
+} DOS_OUTPUT_BUSY_REQUEST, *PDOS_OUTPUT_BUSY_REQUEST;
+
+#pragma pack(pop)
+
+/* FUNCTIONS ******************************************************************/
+
+PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName);
+PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName);
+VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode);
+
+#endif // _DEVICE_H_
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/device.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -17,6 +17,8 @@
#include "dos.h"
#include "dos/dem.h"
+#include "device.h"
+#include "memory.h"
#include "bios/bios.h"
@@ -27,381 +29,21 @@
CALLBACK16 DosContext;
-static WORD CurrentPsp = SYSTEM_PSP;
-static WORD DosLastError = 0;
static DWORD DiskTransferArea;
/*static*/ BYTE CurrentDrive;
static CHAR LastDrive = 'E';
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
-
-static struct
-{
- HANDLE Handle;
- WORD RefCount;
-} DosSystemFileTable[DOS_SFT_SIZE];
-
-static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
-static BOOLEAN DosUmbLinked = FALSE;
+static DOS_SFT_ENTRY DosSystemFileTable[DOS_SFT_SIZE];
static WORD DosErrorLevel = 0x0000;
+
+/* PUBLIC VARIABLES ***********************************************************/
/* Echo state for INT 21h, AH = 01h and AH = 3Fh */
BOOLEAN DoEcho = FALSE;
+WORD CurrentPsp = SYSTEM_PSP;
+WORD DosLastError = 0;
/* PRIVATE FUNCTIONS **********************************************************/
-
-/*
- * Memory management functions
- */
-static VOID DosCombineFreeBlocks(WORD StartBlock)
-{
- PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
-
- /* If this is the last block or it's not free, quit */
- if (CurrentMcb->BlockType == 'Z' || CurrentMcb->OwnerPsp != 0) return;
-
- while (TRUE)
- {
- /* Get a pointer to the next MCB */
- NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
-
- /* Check if the next MCB is free */
- if (NextMcb->OwnerPsp == 0)
- {
- /* Combine them */
- CurrentMcb->Size += NextMcb->Size + 1;
- CurrentMcb->BlockType = NextMcb->BlockType;
- NextMcb->BlockType = 'I';
- }
- else
- {
- /* No more adjoining free blocks */
- break;
- }
- }
-}
-
-static WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
-{
- WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0;
- PDOS_MCB CurrentMcb, NextMcb;
- BOOLEAN SearchUmb = FALSE;
-
- DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
-
- if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH |
DOS_ALLOC_HIGH_LOW)))
- {
- /* Search UMB first */
- Segment = UMB_START_SEGMENT;
- SearchUmb = TRUE;
- }
-
- while (TRUE)
- {
- /* Get a pointer to the MCB */
- CurrentMcb = SEGMENT_TO_MCB(Segment);
-
- /* Make sure it's valid */
- if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType
!= 'Z')
- {
- DPRINT("The DOS memory arena is corrupted!\n");
- DosLastError = ERROR_ARENA_TRASHED;
- return 0;
- }
-
- /* Only check free blocks */
- if (CurrentMcb->OwnerPsp != 0) goto Next;
-
- /* Combine this free block with adjoining free blocks */
- DosCombineFreeBlocks(Segment);
-
- /* Update the maximum block size */
- if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size;
-
- /* Check if this block is big enough */
- if (CurrentMcb->Size < Size) goto Next;
-
- switch (DosAllocStrategy & 0x3F)
- {
- case DOS_ALLOC_FIRST_FIT:
- {
- /* For first fit, stop immediately */
- Result = Segment;
- goto Done;
- }
-
- case DOS_ALLOC_BEST_FIT:
- {
- /* For best fit, update the smallest block found so far */
- if ((Result == 0) || (CurrentMcb->Size <
SEGMENT_TO_MCB(Result)->Size))
- {
- Result = Segment;
- }
-
- break;
- }
-
- case DOS_ALLOC_LAST_FIT:
- {
- /* For last fit, make the current block the result, but keep searching
*/
- Result = Segment;
- break;
- }
- }
-
-Next:
- /* If this was the last MCB in the chain, quit */
- if (CurrentMcb->BlockType == 'Z')
- {
- /* Check if nothing was found while searching through UMBs */
- if ((Result == 0) && SearchUmb && (DosAllocStrategy &
DOS_ALLOC_HIGH_LOW))
- {
- /* Search low memory */
- Segment = FIRST_MCB_SEGMENT;
- continue;
- }
-
- break;
- }
-
- /* Otherwise, update the segment and continue */
- Segment += CurrentMcb->Size + 1;
- }
-
-Done:
-
- /* If we didn't find a free block, return 0 */
- if (Result == 0)
- {
- DosLastError = ERROR_NOT_ENOUGH_MEMORY;
- if (MaxAvailable) *MaxAvailable = MaxSize;
- return 0;
- }
-
- /* Get a pointer to the MCB */
- CurrentMcb = SEGMENT_TO_MCB(Result);
-
- /* Check if the block is larger than requested */
- if (CurrentMcb->Size > Size)
- {
- /* It is, split it into two blocks */
- NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
-
- /* Initialize the new MCB structure */
- NextMcb->BlockType = CurrentMcb->BlockType;
- NextMcb->Size = CurrentMcb->Size - Size - 1;
- NextMcb->OwnerPsp = 0;
-
- /* Update the current block */
- CurrentMcb->BlockType = 'M';
- CurrentMcb->Size = Size;
- }
-
- /* Take ownership of the block */
- CurrentMcb->OwnerPsp = CurrentPsp;
-
- /* Return the segment of the data portion of the block */
- return Result + 1;
-}
-
-static BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
-{
- BOOLEAN Success = TRUE;
- WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment;
- PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb;
-
- DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
- BlockData,
- NewSize);
-
- /* Make sure this is a valid, allocated block */
- if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') ||
Mcb->OwnerPsp == 0)
- {
- Success = FALSE;
- DosLastError = ERROR_INVALID_HANDLE;
- goto Done;
- }
-
- ReturnSize = Mcb->Size;
-
- /* Check if we need to expand or contract the block */
- if (NewSize > Mcb->Size)
- {
- /* We can't expand the last block */
- if (Mcb->BlockType != 'M')
- {
- Success = FALSE;
- goto Done;
- }
-
- /* Get the pointer and segment of the next MCB */
- NextSegment = Segment + Mcb->Size + 1;
- NextMcb = SEGMENT_TO_MCB(NextSegment);
-
- /* Make sure the next segment is free */
- if (NextMcb->OwnerPsp != 0)
- {
- DPRINT("Cannot expand memory block: next segment is not free!\n");
- DosLastError = ERROR_NOT_ENOUGH_MEMORY;
- Success = FALSE;
- goto Done;
- }
-
- /* Combine this free block with adjoining free blocks */
- DosCombineFreeBlocks(NextSegment);
-
- /* Set the maximum possible size of the block */
- ReturnSize += NextMcb->Size + 1;
-
- if (ReturnSize < NewSize)
- {
- DPRINT("Cannot expand memory block: insufficient free segments
available!\n");
- DosLastError = ERROR_NOT_ENOUGH_MEMORY;
- Success = FALSE;
- goto Done;
- }
-
- /* Maximize the current block */
- Mcb->Size = ReturnSize;
- Mcb->BlockType = NextMcb->BlockType;
-
- /* Invalidate the next block */
- NextMcb->BlockType = 'I';
-
- /* Check if the block is larger than requested */
- if (Mcb->Size > NewSize)
- {
- DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
- Mcb->Size,
- NewSize);
-
- /* It is, split it into two blocks */
- NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
-
- /* Initialize the new MCB structure */
- NextMcb->BlockType = Mcb->BlockType;
- NextMcb->Size = Mcb->Size - NewSize - 1;
- NextMcb->OwnerPsp = 0;
-
- /* Update the current block */
- Mcb->BlockType = 'M';
- Mcb->Size = NewSize;
- }
- }
- else if (NewSize < Mcb->Size)
- {
- DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
- Mcb->Size,
- NewSize);
-
- /* Just split the block */
- NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
- NextMcb->BlockType = Mcb->BlockType;
- NextMcb->Size = Mcb->Size - NewSize - 1;
- NextMcb->OwnerPsp = 0;
-
- /* Update the MCB */
- Mcb->BlockType = 'M';
- Mcb->Size = NewSize;
- }
-
-Done:
- /* Check if the operation failed */
- if (!Success)
- {
- DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n",
- ReturnSize);
-
- /* Return the maximum possible size */
- if (MaxAvailable) *MaxAvailable = ReturnSize;
- }
-
- return Success;
-}
-
-static BOOLEAN DosFreeMemory(WORD BlockData)
-{
- PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1);
-
- DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData);
-
- /* Make sure the MCB is valid */
- if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z')
- {
- DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType);
- return FALSE;
- }
-
- /* Mark the block as free */
- Mcb->OwnerPsp = 0;
-
- return TRUE;
-}
-
-static BOOLEAN DosLinkUmb(VOID)
-{
- DWORD Segment = FIRST_MCB_SEGMENT;
- PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
-
- DPRINT("Linking UMB\n");
-
- /* Check if UMBs are already linked */
- if (DosUmbLinked) return FALSE;
-
- /* Find the last block */
- while ((Mcb->BlockType == 'M') && (Segment <= 0xFFFF))
- {
- Segment += Mcb->Size + 1;
- Mcb = SEGMENT_TO_MCB(Segment);
- }
-
- /* Make sure it's valid */
- if (Mcb->BlockType != 'Z') return FALSE;
-
- /* Connect the MCB with the UMB chain */
- Mcb->BlockType = 'M';
-
- DosUmbLinked = TRUE;
- return TRUE;
-}
-
-static BOOLEAN DosUnlinkUmb(VOID)
-{
- DWORD Segment = FIRST_MCB_SEGMENT;
- PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
-
- DPRINT("Unlinking UMB\n");
-
- /* Check if UMBs are already unlinked */
- if (!DosUmbLinked) return FALSE;
-
- /* Find the block preceding the MCB that links it with the UMB chain */
- while (Segment <= 0xFFFF)
- {
- if ((Segment + Mcb->Size) == (FIRST_MCB_SEGMENT + USER_MEMORY_SIZE))
- {
- /* This is the last non-UMB segment */
- break;
- }
-
- /* Advance to the next MCB */
- Segment += Mcb->Size + 1;
- Mcb = SEGMENT_TO_MCB(Segment);
- }
-
- /* Mark the MCB as the last MCB */
- Mcb->BlockType = 'Z';
-
- DosUmbLinked = FALSE;
- return TRUE;
-}
-
-static VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
-{
- PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
-
- /* Just set the owner */
- Mcb->OwnerPsp = NewOwner;
-}
static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL,
LPCSTR ProgramName)
@@ -471,13 +113,8 @@
return DestSegment;
}
-
-
-
-
-
/* Taken from base/shell/cmd/console.c */
-BOOL IsConsoleHandle(HANDLE hHandle)
+static BOOL IsConsoleHandle(HANDLE hHandle)
{
DWORD dwMode;
@@ -500,12 +137,59 @@
return GetConsoleMode(hHandle, &dwMode);
}
+static inline PDOS_SFT_ENTRY DosFindFreeSftEntry(VOID)
+{
+ INT 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)
+{
+ INT 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)
+{
+ INT 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)
{
- BYTE i;
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;
@@ -524,59 +208,95 @@
if (DosHandle == PspBlock->HandleTableSize) return INVALID_DOS_HANDLE;
/* Check if the handle is already in the SFT */
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- /* Check if this is the same handle */
- if (DosSystemFileTable[i].Handle != Handle) continue;
-
+ SftEntry = DosFindWin32SftEntry(Handle);
+
+ if (SftEntry != NULL)
+ {
/* Already in the table, reference it */
- DosSystemFileTable[i].RefCount++;
-
- /* Set the JFT entry to that SFT index */
- HandleTable[DosHandle] = i;
-
- /* Return the new handle */
- return DosHandle;
- }
-
- /* Add the handle to the SFT */
- for (i = 0; i < DOS_SFT_SIZE; i++)
- {
- /* Make sure this is an empty table entry */
- if (DosSystemFileTable[i].Handle != INVALID_HANDLE_VALUE) continue;
-
- /* Initialize the empty table entry */
- DosSystemFileTable[i].Handle = Handle;
- DosSystemFileTable[i].RefCount = 1;
-
- /* Set the JFT entry to that SFT index */
- HandleTable[DosHandle] = i;
-
- /* Return the new handle */
- return DosHandle;
- }
-
- /* The SFT is full */
- return INVALID_DOS_HANDLE;
+ 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;
}
-HANDLE DosGetRealHandle(WORD 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_HANDLE_VALUE;
+ 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);
- /* Make sure the handle is open */
- if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
-
- /* Return the Win32 handle */
- return DosSystemFileTable[HandleTable[DosHandle]].Handle;
+ /* 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)
@@ -591,31 +311,77 @@
/* Check if this is the initial process */
if (CurrentPsp == SYSTEM_PSP)
{
- /* Set up the standard I/O devices */
- for (i = 0; i <= 2; i++)
- {
- /* Set the index in the SFT */
- DestinationTable[i] = (BYTE)i;
+ PDOS_SFT_ENTRY SftEntry;
+ HANDLE StandardHandles[3];
+ PDOS_DEVICE_NODE ConIn = DosGetDevice("CONIN$");
+ PDOS_DEVICE_NODE ConOut = DosGetDevice("CONOUT$");
+ ASSERT(ConIn != NULL && ConOut != 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++)
+ {
+ PDOS_DEVICE_NODE Device = (i == 0) ? ConIn : ConOut;
+
+ /* Find the corresponding SFT entry */
+ if (IsConsoleHandle(StandardHandles[i]))
+ {
+ SftEntry = DosFindDeviceSftEntry(Device);
+ }
+ 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 = Device;
+
+ /* Call the open routine */
+ if (Device->OpenRoutine) Device->OpenRoutine(Device);
+ }
+ 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[i].RefCount++;
- }
-
- /* Done */
- return;
- }
-
- /* 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 < 20; i++)
- {
- DestinationTable[i] = SourceTable[i];
-
- /* Increase the reference count */
- DosSystemFileTable[SourceTable[i]].RefCount++;
+ DosSystemFileTable[SourceTable[i]].RefCount++;
+ }
}
}
@@ -634,12 +400,12 @@
return TRUE;
}
- if (PspBlock->HandleTableSize > 20)
+ if (PspBlock->HandleTableSize > DEFAULT_JFT_SIZE)
{
/* Get the segment of the current table */
Segment = (LOWORD(PspBlock->HandleTablePtr) >> 4) +
HIWORD(PspBlock->HandleTablePtr);
- if (NewSize <= 20)
+ if (NewSize <= DEFAULT_JFT_SIZE)
{
/* Get the current handle table */
HandleTable = FAR_POINTER(PspBlock->HandleTablePtr);
@@ -679,7 +445,7 @@
PspBlock->HandleTableSize = NewSize;
}
}
- else if (NewSize > 20)
+ else if (NewSize > DEFAULT_JFT_SIZE)
{
Segment = DosAllocateMemory(NewSize, NULL);
if (Segment == 0) return FALSE;
@@ -702,9 +468,9 @@
static BOOLEAN DosCloseHandle(WORD DosHandle)
{
- BYTE SftIndex;
PDOS_PSP PspBlock;
LPBYTE HandleTable;
+ PDOS_SFT_ENTRY SftEntry;
DPRINT("DosCloseHandle: DosHandle 0x%04X\n", DosHandle);
@@ -718,18 +484,45 @@
/* 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 */
- SftIndex = HandleTable[DosHandle];
- DosSystemFileTable[SftIndex].RefCount--;
+ SftEntry->RefCount--;
/* Check if the reference count fell to zero */
- if (!DosSystemFileTable[SftIndex].RefCount)
- {
- /* Close the file, it's no longer needed */
- CloseHandle(DosSystemFileTable[SftIndex].Handle);
-
- /* Clear the handle */
- DosSystemFileTable[SftIndex].Handle = INVALID_HANDLE_VALUE;
+ 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 */
@@ -776,12 +569,6 @@
return TRUE;
}
-
-
-
-
-
-
static BOOLEAN DosChangeDrive(BYTE Drive)
{
WCHAR DirectoryPath[DOS_CMDLINE_LENGTH];
@@ -870,6 +657,25 @@
}
/* 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)
{
@@ -1020,19 +826,22 @@
/* Make sure it does not pass 0xFFFF */
if (ExeSize > 0xFFFF) ExeSize = 0xFFFF;
- /* Reduce the size one by one until the allocation is successful */
- for (i = Header->e_maxalloc; i >= Header->e_minalloc; i--, ExeSize--)
- {
- /* Try to allocate that much memory */
+ /* 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);
- if (Segment != 0) break;
- }
-
- /* Check if at least the lowest allocation was successful */
- if (Segment == 0)
- {
- Result = DosLastError;
- goto Cleanup;
+ ASSERT(Segment != 0);
}
/* Initialize the PSP */
@@ -1403,11 +1212,12 @@
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
{
- HANDLE Handle = DosGetRealHandle(FileHandle);
-
- if (Handle == INVALID_HANDLE_VALUE)
- {
- /* Doesn't exist */
+ PDOS_SFT_ENTRY Entry = DosGetSftEntry(FileHandle);
+ PDOS_DEVICE_NODE Node = Entry->DeviceNode;
+
+ /* Make sure it exists and is a device */
+ if (!Entry || Entry->Type != DOS_SFT_ENTRY_DEVICE)
+ {
DosLastError = ERROR_FILE_NOT_FOUND;
return FALSE;
}
@@ -1417,32 +1227,68 @@
/* 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 (Handle == DosSystemFileTable[DOS_INPUT_HANDLE].Handle)
- {
- /* Console input */
- InfoWord |= 1 << 0;
-
- /* It is a device */
- InfoWord |= 1 << 7;
- }
- else if (Handle == DosSystemFileTable[DOS_OUTPUT_HANDLE].Handle)
- {
- /* Console output */
- InfoWord |= 1 << 1;
-
- /* It is a device */
- InfoWord |= 1 << 7;
- }
-
/* Return the device information word */
- setDX(InfoWord);
+ setDX(Node->DeviceAttributes);
+ return TRUE;
+ }
+
+ /* Set Device Information */
+ case 0x01:
+ {
+ Node->DeviceAttributes = getDX();
+ return TRUE;
+ }
+
+ /* Read From Device I/O Control Channel */
+ case 0x02:
+ {
+ WORD Length = getCX();
+
+ if (!(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;
+ }
+
+ /* Write To Device I/O Control Channel */
+ case 0x03:
+ {
+ WORD Length = getCX();
+
+ if (!(Node->DeviceAttributes & DOS_DEVATTR_IOCTL))
+ {
+ DosLastError = ERROR_INVALID_FUNCTION;
+ return FALSE;
+ }
+
+ /* Do nothing if there is no IOCTL routine */
+ if (!Node->IoctlWriteRoutine)
+ {
+ setAX(0);
+ return TRUE;
+ }
+
+ Node->IoctlWriteRoutine(Node, MAKELONG(getDX(), getDS()), &Length);
+
+ setAX(Length);
return TRUE;
}
@@ -2130,13 +1976,24 @@
break;
}
- /* Open File */
+ /* Open File or Device */
case 0x3D:
{
WORD FileHandle;
- WORD ErrorCode = DosOpenFile(&FileHandle,
- (LPCSTR)SEG_OFF_TO_PTR(getDS(), getDX()),
- getAL());
+ 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());
+ }
if (ErrorCode == ERROR_SUCCESS)
{
@@ -2152,7 +2009,7 @@
break;
}
- /* Close File */
+ /* Close File or Device */
case 0x3E:
{
if (DosCloseHandle(getBX()))
@@ -2174,11 +2031,11 @@
WORD BytesRead = 0;
WORD ErrorCode;
- DPRINT("INT 21h, AH = 3Fh\n");
+ DPRINT1("INT 21h, AH = 3Fh\n");
DoEcho = TRUE;
ErrorCode = DosReadFile(getBX(),
- SEG_OFF_TO_PTR(getDS(), getDX()),
+ MAKELONG(getDX(), getDS()),
getCX(),
&BytesRead);
DoEcho = FALSE;
@@ -2202,7 +2059,7 @@
{
WORD BytesWritten = 0;
WORD ErrorCode = DosWriteFile(getBX(),
- SEG_OFF_TO_PTR(getDS(), getDX()),
+ MAKELONG(getDX(), getDS()),
getCX(),
&BytesWritten);
@@ -2335,9 +2192,9 @@
case 0x45:
{
WORD NewHandle;
- HANDLE Handle = DosGetRealHandle(getBX());
-
- if (Handle == INVALID_HANDLE_VALUE)
+ 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;
@@ -2346,7 +2203,26 @@
}
/* Open a new handle to the same entry */
- NewHandle = DosOpenHandle(Handle);
+ switch (SftEntry->Type)
+ {
+ 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);
+ }
+ }
if (NewHandle == INVALID_DOS_HANDLE)
{
@@ -2742,9 +2618,9 @@
/* Lock/Unlock Region of File */
case 0x5C:
{
- HANDLE Handle = DosGetRealHandle(getBX());
-
- if (Handle == INVALID_HANDLE_VALUE)
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(getBX());
+
+ if (SftEntry->Type != DOS_SFT_ENTRY_WIN32)
{
/* The handle is invalid */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
@@ -2755,7 +2631,7 @@
if (getAL() == 0x00)
{
/* Lock region of file */
- if (LockFile(Handle,
+ if (LockFile(SftEntry->Handle,
MAKELONG(getCX(), getDX()), 0,
MAKELONG(getSI(), getDI()), 0))
{
@@ -2770,7 +2646,7 @@
else if (getAL() == 0x01)
{
/* Unlock region of file */
- if (UnlockFile(Handle,
+ if (UnlockFile(SftEntry->Handle,
MAKELONG(getCX(), getDX()), 0,
MAKELONG(getSI(), getDI()), 0))
{
@@ -2979,6 +2855,7 @@
CHAR CurrentDirectory[MAX_PATH];
CHAR DosDirectory[DOS_DIR_LENGTH];
LPSTR Path;
+ PDOS_DEVICE_NODE ConInDevice, ConOutDevice;
FILE *Stream;
WCHAR Buffer[256];
@@ -3031,19 +2908,15 @@
/* Initialize the SFT */
for (i = 0; i < DOS_SFT_SIZE; i++)
{
- DosSystemFileTable[i].Handle = INVALID_HANDLE_VALUE;
+ DosSystemFileTable[i].Type = DOS_SFT_ENTRY_NONE;
DosSystemFileTable[i].RefCount = 0;
}
- /* Get handles to standard I/O devices */
- DosSystemFileTable[0].Handle = GetStdHandle(STD_INPUT_HANDLE);
- DosSystemFileTable[1].Handle = GetStdHandle(STD_OUTPUT_HANDLE);
- DosSystemFileTable[2].Handle = GetStdHandle(STD_ERROR_HANDLE);
-
- /* Initialize the reference counts */
- DosSystemFileTable[0].RefCount =
- DosSystemFileTable[1].RefCount =
- DosSystemFileTable[2].RefCount = 1;
+ /* Load the EMS driver */
+ EmsDrvInitialize();
+
+ /* Load the CON driver */
+ ConDrvInitialize(&ConInDevice, &ConOutDevice);
#endif
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.h [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -12,6 +12,7 @@
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
+#include "device.h"
/**/ #include "int32.h" /**/
@@ -48,13 +49,7 @@
#define NUM_DRIVES ('Z' - 'A' + 1)
#define DOS_CHAR_ATTRIBUTE 0x07
#define DOS_PROGRAM_NAME_TAG 0x0001
-
-enum DOS_ALLOC_STRATEGY
-{
- DOS_ALLOC_FIRST_FIT,
- DOS_ALLOC_BEST_FIT,
- DOS_ALLOC_LAST_FIT
-};
+#define DEFAULT_JFT_SIZE 20
typedef enum
{
@@ -63,16 +58,26 @@
DOS_LOAD_OVERLAY = 0x03
} DOS_EXEC_TYPE;
+typedef enum
+{
+ DOS_SFT_ENTRY_NONE,
+ DOS_SFT_ENTRY_WIN32,
+ DOS_SFT_ENTRY_DEVICE
+} DOS_SFT_ENTRY_TYPE;
+
+typedef struct _DOS_SFT_ENTRY
+{
+ DOS_SFT_ENTRY_TYPE Type;
+ WORD RefCount;
+
+ union
+ {
+ HANDLE Handle;
+ PDOS_DEVICE_NODE DeviceNode;
+ };
+} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY;
+
#pragma pack(push, 1)
-
-typedef struct _DOS_MCB
-{
- CHAR BlockType;
- WORD OwnerPsp;
- WORD Size;
- BYTE Unused[3];
- CHAR Name[8];
-} DOS_MCB, *PDOS_MCB;
typedef struct _DOS_FCB
{
@@ -169,7 +174,11 @@
#pragma pack(pop)
+/* VARIABLES ******************************************************************/
+
extern BOOLEAN DoEcho;
+extern WORD CurrentPsp;
+extern WORD DosLastError;
/* FUNCTIONS ******************************************************************/
@@ -190,15 +199,17 @@
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
BOOLEAN DosBIOSInitialize(VOID);
-
+VOID EmsDrvInitialize(VOID);
+VOID EmsDrvCleanup(VOID);
+VOID ConDrvInitialize(PDOS_DEVICE_NODE *InputDevice, PDOS_DEVICE_NODE *OutputDevice);
+VOID ConDrvCleanup(VOID);
/*
* DOS Kernel Functions
* See dos.c
*/
-BOOL IsConsoleHandle(HANDLE hHandle);
WORD DosOpenHandle(HANDLE Handle);
-HANDLE DosGetRealHandle(WORD DosHandle);
+PDOS_SFT_ENTRY DosGetSftEntry(WORD DosHandle);
WORD DosCreateFileEx(LPWORD Handle,
LPWORD CreationStatus,
@@ -214,11 +225,11 @@
LPCSTR FilePath,
BYTE AccessShareModes);
WORD DosReadFile(WORD FileHandle,
- LPVOID Buffer,
+ DWORD Buffer,
WORD Count,
LPWORD BytesRead);
WORD DosWriteFile(WORD FileHandle,
- LPVOID Buffer,
+ DWORD Buffer,
WORD Count,
LPWORD BytesWritten);
WORD DosSeekFile(WORD FileHandle,
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dosfiles.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -394,129 +394,84 @@
}
WORD DosReadFile(WORD FileHandle,
- LPVOID Buffer,
+ DWORD Buffer,
WORD Count,
LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
- DWORD BytesRead32 = 0;
- HANDLE Handle = DosGetRealHandle(FileHandle);
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle,
Count);
- /* Make sure the handle is valid */
- if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
-
- if (IsConsoleHandle(Handle))
- {
- CHAR Character;
-
- /*
- * Use BIOS Get Keystroke function
- */
-
- /* Save AX */
- USHORT AX = getAX();
-
- for (BytesRead32 = 0; BytesRead32 < Count; BytesRead32++)
- {
- /* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
- setAH(0x00);
- Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
-
- /* Retrieve the character in AL (scan code is in AH) */
- Character = getAL();
-
- if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
-
- ((PCHAR)Buffer)[BytesRead32] = Character;
-
- /* Stop on first carriage return */
- if (Character == '\r')
- {
- if (DoEcho) DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
- break;
- }
-
- // BytesRead32++;
- }
-
- /* Restore AX */
- setAX(AX);
- }
- else
- {
+ if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
+ {
+ DWORD BytesRead32 = 0;
+
/* Read the file */
- if (!ReadFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesRead32,
NULL))
+ if (!ReadFile(SftEntry->Handle, FAR_POINTER(Buffer), Count, &BytesRead32,
NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
- }
-
- /* The number of bytes read is always 16-bit */
- *BytesRead = LOWORD(BytesRead32);
+
+ /* The number of bytes read is always 16-bit */
+ *BytesRead = LOWORD(BytesRead32);
+ }
+ else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
+ {
+ if (!SftEntry->DeviceNode->ReadRoutine) return ERROR_INVALID_FUNCTION;
+
+ /* Read the device */
+ SftEntry->DeviceNode->ReadRoutine(SftEntry->DeviceNode, Buffer,
&Count);
+ *BytesRead = Count;
+ }
+ else
+ {
+ /* Invalid handle */
+ return ERROR_INVALID_HANDLE;
+ }
/* Return the error code */
return Result;
}
WORD DosWriteFile(WORD FileHandle,
- LPVOID Buffer,
+ DWORD Buffer,
WORD Count,
LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
- DWORD BytesWritten32 = 0;
- HANDLE Handle = DosGetRealHandle(FileHandle);
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle,
Count);
- /* Make sure the handle is valid */
- if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
-
- if (IsConsoleHandle(Handle))
- {
- /*
- * Use BIOS Teletype function
- */
-
- /* Save AX and BX */
- USHORT AX = getAX();
- USHORT BX = getBX();
-
- // FIXME: Use BIOS Write String function INT 10h, AH=13h ??
-
- for (BytesWritten32 = 0; BytesWritten32 < Count; BytesWritten32++)
- {
- /* Set the parameters */
- setAL(((PCHAR)Buffer)[BytesWritten32]);
- setBL(DOS_CHAR_ATTRIBUTE);
- setBH(Bda->VideoPage);
-
- /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
- setAH(0x0E);
- Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
-
- // BytesWritten32++;
- }
-
- /* Restore AX and BX */
- setBX(BX);
- setAX(AX);
- }
- else
- {
+ if (SftEntry->Type == DOS_SFT_ENTRY_WIN32)
+ {
+ DWORD BytesWritten32 = 0;
+
/* Write the file */
- if (!WriteFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesWritten32,
NULL))
+ if (!WriteFile(SftEntry->Handle, FAR_POINTER(Buffer), Count,
&BytesWritten32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
- }
-
- /* The number of bytes written is always 16-bit */
- *BytesWritten = LOWORD(BytesWritten32);
+
+ /* The number of bytes written is always 16-bit */
+ *BytesWritten = LOWORD(BytesWritten32);
+ }
+ else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
+ {
+ if (!SftEntry->DeviceNode->WriteRoutine) return ERROR_INVALID_FUNCTION;
+
+ /* Read the device */
+ SftEntry->DeviceNode->WriteRoutine(SftEntry->DeviceNode, Buffer,
&Count);
+ *BytesWritten = Count;
+ }
+ else
+ {
+ /* Invalid handle */
+ return ERROR_INVALID_HANDLE;
+ }
/* Return the error code */
return Result;
@@ -529,15 +484,23 @@
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
- HANDLE Handle = DosGetRealHandle(FileHandle);
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
- /* Make sure the handle is valid */
- if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
+ if (SftEntry->Type == DOS_SFT_ENTRY_NONE)
+ {
+ /* Invalid handle */
+ return ERROR_INVALID_HANDLE;
+ }
+ else if (SftEntry->Type == DOS_SFT_ENTRY_DEVICE)
+ {
+ /* For character devices, always return success */
+ return ERROR_SUCCESS;
+ }
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin !=
FILE_END)
@@ -545,17 +508,7 @@
return ERROR_INVALID_FUNCTION;
}
- /* Move the file pointer */
- if (IsConsoleHandle(Handle))
- {
- /* Always succeeds when seeking a console handle */
- FilePointer = 0;
- Result = ERROR_SUCCESS;
- }
- else
- {
- FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
- }
+ FilePointer = SetFilePointer(SftEntry->Handle, Offset, NULL, Origin);
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
@@ -579,17 +532,34 @@
BOOL DosFlushFileBuffers(WORD FileHandle)
{
- HANDLE Handle = DosGetRealHandle(FileHandle);
-
- /* Make sure the handle is valid */
- if (Handle == INVALID_HANDLE_VALUE) return FALSE;
-
- /*
- * This function can either flush files back to disks, or flush
- * console input buffers, in which case there is no need to check
- * whether the handle is a console handle. FlushFileBuffers()
- * automatically does this check and calls FlushConsoleInputBuffer()
- * if needed.
- */
- return FlushFileBuffers(Handle);
-}
+ PDOS_SFT_ENTRY SftEntry = DosGetSftEntry(FileHandle);
+
+ switch (SftEntry->Type)
+ {
+ case DOS_SFT_ENTRY_WIN32:
+ {
+ return FlushFileBuffers(SftEntry->Handle);
+ }
+
+ case DOS_SFT_ENTRY_DEVICE:
+ {
+ if (SftEntry->DeviceNode->FlushInputRoutine)
+ {
+ SftEntry->DeviceNode->FlushInputRoutine(SftEntry->DeviceNode);
+ }
+
+ if (SftEntry->DeviceNode->FlushOutputRoutine)
+ {
+ SftEntry->DeviceNode->FlushOutputRoutine(SftEntry->DeviceNode);
+ }
+
+ return TRUE;
+ }
+
+ default:
+ {
+ /* Invalid handle */
+ return FALSE;
+ }
+ }
+}
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,48 @@
+/*
+ * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: emsdrv.c
+ * PURPOSE: DOS EMS Driver
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "dos.h"
+#include "dos/dem.h"
+#include "device.h"
+
+#define EMS_DEVICE_NAME "EMMXXXX0"
+
+/* PRIVATE VARIABLES **********************************************************/
+
+static PDOS_DEVICE_NODE Node;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+WORD NTAPI EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
+{
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+
+ return DOS_DEVSTAT_DONE;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID EmsDrvInitialize(VOID)
+{
+ /* Create the device */
+ Node = DosCreateDevice(DOS_DEVATTR_IOCTL
+ | DOS_DEVATTR_CHARACTER,
+ EMS_DEVICE_NAME);
+ Node->IoctlReadRoutine = EmsDrvDispatchIoctlRead;
+}
+
+VOID EmsDrvCleanup(VOID)
+{
+ /* Delete the device */
+ DosDeleteDevice(Node);
+}
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/emsdrv.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,378 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dos/dos32krnl/memory.c
+ * PURPOSE: DOS32 Memory Manager
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "emulator.h"
+
+#include "dos.h"
+#include "dos/dem.h"
+#include "memory.h"
+
+/* PUBLIC VARIABLES ***********************************************************/
+
+BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
+BOOLEAN DosUmbLinked = FALSE;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static VOID DosCombineFreeBlocks(WORD StartBlock)
+{
+ PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
+
+ /* If this is the last block or it's not free, quit */
+ if (CurrentMcb->BlockType == 'Z' || CurrentMcb->OwnerPsp != 0) return;
+
+ while (TRUE)
+ {
+ /* Get a pointer to the next MCB */
+ NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
+
+ /* Check if the next MCB is free */
+ if (NextMcb->OwnerPsp == 0)
+ {
+ /* Combine them */
+ CurrentMcb->Size += NextMcb->Size + 1;
+ CurrentMcb->BlockType = NextMcb->BlockType;
+ NextMcb->BlockType = 'I';
+ }
+ else
+ {
+ /* No more adjoining free blocks */
+ break;
+ }
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
+{
+ WORD Result = 0, Segment = FIRST_MCB_SEGMENT, MaxSize = 0;
+ PDOS_MCB CurrentMcb, NextMcb;
+ BOOLEAN SearchUmb = FALSE;
+
+ DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
+
+ if (DosUmbLinked && (DosAllocStrategy & (DOS_ALLOC_HIGH |
DOS_ALLOC_HIGH_LOW)))
+ {
+ /* Search UMB first */
+ Segment = UMB_START_SEGMENT;
+ SearchUmb = TRUE;
+ }
+
+ while (TRUE)
+ {
+ /* Get a pointer to the MCB */
+ CurrentMcb = SEGMENT_TO_MCB(Segment);
+
+ /* Make sure it's valid */
+ if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType
!= 'Z')
+ {
+ DPRINT("The DOS memory arena is corrupted!\n");
+ DosLastError = ERROR_ARENA_TRASHED;
+ return 0;
+ }
+
+ /* Only check free blocks */
+ if (CurrentMcb->OwnerPsp != 0) goto Next;
+
+ /* Combine this free block with adjoining free blocks */
+ DosCombineFreeBlocks(Segment);
+
+ /* Update the maximum block size */
+ if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size;
+
+ /* Check if this block is big enough */
+ if (CurrentMcb->Size < Size) goto Next;
+
+ switch (DosAllocStrategy & 0x3F)
+ {
+ case DOS_ALLOC_FIRST_FIT:
+ {
+ /* For first fit, stop immediately */
+ Result = Segment;
+ goto Done;
+ }
+
+ case DOS_ALLOC_BEST_FIT:
+ {
+ /* For best fit, update the smallest block found so far */
+ if ((Result == 0) || (CurrentMcb->Size <
SEGMENT_TO_MCB(Result)->Size))
+ {
+ Result = Segment;
+ }
+
+ break;
+ }
+
+ case DOS_ALLOC_LAST_FIT:
+ {
+ /* For last fit, make the current block the result, but keep searching
*/
+ Result = Segment;
+ break;
+ }
+ }
+
+Next:
+ /* If this was the last MCB in the chain, quit */
+ if (CurrentMcb->BlockType == 'Z')
+ {
+ /* Check if nothing was found while searching through UMBs */
+ if ((Result == 0) && SearchUmb && (DosAllocStrategy &
DOS_ALLOC_HIGH_LOW))
+ {
+ /* Search low memory */
+ Segment = FIRST_MCB_SEGMENT;
+ continue;
+ }
+
+ break;
+ }
+
+ /* Otherwise, update the segment and continue */
+ Segment += CurrentMcb->Size + 1;
+ }
+
+Done:
+
+ /* If we didn't find a free block, return 0 */
+ if (Result == 0)
+ {
+ DosLastError = ERROR_NOT_ENOUGH_MEMORY;
+ if (MaxAvailable) *MaxAvailable = MaxSize;
+ return 0;
+ }
+
+ /* Get a pointer to the MCB */
+ CurrentMcb = SEGMENT_TO_MCB(Result);
+
+ /* Check if the block is larger than requested */
+ if (CurrentMcb->Size > Size)
+ {
+ /* It is, split it into two blocks */
+ NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
+
+ /* Initialize the new MCB structure */
+ NextMcb->BlockType = CurrentMcb->BlockType;
+ NextMcb->Size = CurrentMcb->Size - Size - 1;
+ NextMcb->OwnerPsp = 0;
+
+ /* Update the current block */
+ CurrentMcb->BlockType = 'M';
+ CurrentMcb->Size = Size;
+ }
+
+ /* Take ownership of the block */
+ CurrentMcb->OwnerPsp = CurrentPsp;
+
+ /* Return the segment of the data portion of the block */
+ return Result + 1;
+}
+
+BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
+{
+ BOOLEAN Success = TRUE;
+ WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment;
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), NextMcb;
+
+ DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
+ BlockData,
+ NewSize);
+
+ /* Make sure this is a valid, allocated block */
+ if ((Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') ||
Mcb->OwnerPsp == 0)
+ {
+ Success = FALSE;
+ DosLastError = ERROR_INVALID_HANDLE;
+ goto Done;
+ }
+
+ ReturnSize = Mcb->Size;
+
+ /* Check if we need to expand or contract the block */
+ if (NewSize > Mcb->Size)
+ {
+ /* We can't expand the last block */
+ if (Mcb->BlockType != 'M')
+ {
+ Success = FALSE;
+ goto Done;
+ }
+
+ /* Get the pointer and segment of the next MCB */
+ NextSegment = Segment + Mcb->Size + 1;
+ NextMcb = SEGMENT_TO_MCB(NextSegment);
+
+ /* Make sure the next segment is free */
+ if (NextMcb->OwnerPsp != 0)
+ {
+ DPRINT("Cannot expand memory block: next segment is not free!\n");
+ DosLastError = ERROR_NOT_ENOUGH_MEMORY;
+ Success = FALSE;
+ goto Done;
+ }
+
+ /* Combine this free block with adjoining free blocks */
+ DosCombineFreeBlocks(NextSegment);
+
+ /* Set the maximum possible size of the block */
+ ReturnSize += NextMcb->Size + 1;
+
+ if (ReturnSize < NewSize)
+ {
+ DPRINT("Cannot expand memory block: insufficient free segments
available!\n");
+ DosLastError = ERROR_NOT_ENOUGH_MEMORY;
+ Success = FALSE;
+ goto Done;
+ }
+
+ /* Maximize the current block */
+ Mcb->Size = ReturnSize;
+ Mcb->BlockType = NextMcb->BlockType;
+
+ /* Invalidate the next block */
+ NextMcb->BlockType = 'I';
+
+ /* Check if the block is larger than requested */
+ if (Mcb->Size > NewSize)
+ {
+ DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
+ Mcb->Size,
+ NewSize);
+
+ /* It is, split it into two blocks */
+ NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+
+ /* Initialize the new MCB structure */
+ NextMcb->BlockType = Mcb->BlockType;
+ NextMcb->Size = Mcb->Size - NewSize - 1;
+ NextMcb->OwnerPsp = 0;
+
+ /* Update the current block */
+ Mcb->BlockType = 'M';
+ Mcb->Size = NewSize;
+ }
+ }
+ else if (NewSize < Mcb->Size)
+ {
+ DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
+ Mcb->Size,
+ NewSize);
+
+ /* Just split the block */
+ NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+ NextMcb->BlockType = Mcb->BlockType;
+ NextMcb->Size = Mcb->Size - NewSize - 1;
+ NextMcb->OwnerPsp = 0;
+
+ /* Update the MCB */
+ Mcb->BlockType = 'M';
+ Mcb->Size = NewSize;
+ }
+
+Done:
+ /* Check if the operation failed */
+ if (!Success)
+ {
+ DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n",
+ ReturnSize);
+
+ /* Return the maximum possible size */
+ if (MaxAvailable) *MaxAvailable = ReturnSize;
+ }
+
+ return Success;
+}
+
+BOOLEAN DosFreeMemory(WORD BlockData)
+{
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1);
+
+ DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData);
+
+ /* Make sure the MCB is valid */
+ if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z')
+ {
+ DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType);
+ return FALSE;
+ }
+
+ /* Mark the block as free */
+ Mcb->OwnerPsp = 0;
+
+ return TRUE;
+}
+
+BOOLEAN DosLinkUmb(VOID)
+{
+ DWORD Segment = FIRST_MCB_SEGMENT;
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
+
+ DPRINT("Linking UMB\n");
+
+ /* Check if UMBs are already linked */
+ if (DosUmbLinked) return FALSE;
+
+ /* Find the last block */
+ while ((Mcb->BlockType == 'M') && (Segment <= 0xFFFF))
+ {
+ Segment += Mcb->Size + 1;
+ Mcb = SEGMENT_TO_MCB(Segment);
+ }
+
+ /* Make sure it's valid */
+ if (Mcb->BlockType != 'Z') return FALSE;
+
+ /* Connect the MCB with the UMB chain */
+ Mcb->BlockType = 'M';
+
+ DosUmbLinked = TRUE;
+ return TRUE;
+}
+
+BOOLEAN DosUnlinkUmb(VOID)
+{
+ DWORD Segment = FIRST_MCB_SEGMENT;
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
+
+ DPRINT("Unlinking UMB\n");
+
+ /* Check if UMBs are already unlinked */
+ if (!DosUmbLinked) return FALSE;
+
+ /* Find the block preceding the MCB that links it with the UMB chain */
+ while (Segment <= 0xFFFF)
+ {
+ if ((Segment + Mcb->Size) == (FIRST_MCB_SEGMENT + USER_MEMORY_SIZE))
+ {
+ /* This is the last non-UMB segment */
+ break;
+ }
+
+ /* Advance to the next MCB */
+ Segment += Mcb->Size + 1;
+ Mcb = SEGMENT_TO_MCB(Segment);
+ }
+
+ /* Mark the MCB as the last MCB */
+ Mcb->BlockType = 'Z';
+
+ DosUmbLinked = FALSE;
+ return TRUE;
+}
+
+VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
+{
+ PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment - 1);
+
+ /* Just set the owner */
+ Mcb->OwnerPsp = NewOwner;
+}
+
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h (added)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h [iso-8859-1] Thu Mar 26
00:21:25 2015
@@ -0,0 +1,46 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: dos/dos32krnl/memory.h
+ * PURPOSE: DOS32 Memory Manager
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+#ifndef _MEMORY_H_
+#define _MEMORY_H_
+
+/* TYPEDEFS *******************************************************************/
+
+enum DOS_ALLOC_STRATEGY
+{
+ DOS_ALLOC_FIRST_FIT,
+ DOS_ALLOC_BEST_FIT,
+ DOS_ALLOC_LAST_FIT
+};
+
+typedef struct _DOS_MCB
+{
+ CHAR BlockType;
+ WORD OwnerPsp;
+ WORD Size;
+ BYTE Unused[3];
+ CHAR Name[8];
+} DOS_MCB, *PDOS_MCB;
+
+/* VARIABLES ******************************************************************/
+
+extern BYTE DosAllocStrategy;
+extern BOOLEAN DosUmbLinked;
+
+/* FUNCTIONS ******************************************************************/
+
+WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable);
+BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable);
+BOOLEAN DosFreeMemory(WORD BlockData);
+BOOLEAN DosLinkUmb(VOID);
+BOOLEAN DosUnlinkUmb(VOID);
+VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner);
+
+#endif // _MEMORY_H_
+
+/* EOF */
Propchange: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/memory.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/subsystems/mvdm/ntvdm/emulator.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/emul…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/emulator.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/emulator.h [iso-8859-1] Thu Mar 26 00:21:25 2015
@@ -34,6 +34,7 @@
#define REAL_TO_PHYS(ptr) (PVOID)((ULONG_PTR)(ptr) + (ULONG_PTR)BaseAddress)
#define PHYS_TO_REAL(ptr) (PVOID)((ULONG_PTR)(ptr) - (ULONG_PTR)BaseAddress)
+#define ARRAY_INDEX(ptr, array) ((ULONG)(((ULONG_PTR)(ptr) - (ULONG_PTR)(array)) /
sizeof(*array)))
/* BCD-Binary conversion */