- Move the EMS code from the BIOS to the DOS driver where it belongs.
- Expand the DOS device API with a new function, DosCreateDeviceEx, which
will allow 32-bit DOS driver to reserve private memory.
- For each DOS device, create an entry in guest memory so that 16-bit code
can call 32-bit DOS drivers directly.
- Implement an XMS driver stub that uses the above.
- Arch, that's not how the DOS driver strategy routine works, you need to
give it the request in ES:BX which it will store somewhere, and then call
the interrupt routine.
svn path=/trunk/; revision=67339
bios/bios32/kbdbios32.c
bios/bios32/vidbios32.c
bios/bios32/moubios32.c
- bios/bios32/ems.c
bios/bios.c
bios/kbdbios.c
bios/rom.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
dos/dos32krnl/emsdrv.c
+ dos/dos32krnl/himem.c
dos/dos32krnl/memory.c
dos/mouse32.c
dos/dem.c
#include "vidbios32.h"
#include "moubios32.h"
-#include "ems.h"
-
#include "io.h"
#include "hardware/cmos.h"
#include "hardware/pic.h"
SearchAndInitRoms(&BiosContext);
- /* Initialize EMS */
- if (!EmsInitialize(EMS_TOTAL_PAGES))
- {
- DPRINT1("Could not initialize EMS. EMS will not be available.\n"
- "Try reducing the number of EMS pages.\n");
- }
-
/*
* End of the 32-bit POST portion. We then fall back into 16-bit where
* the rest of the POST code is executed, typically calling INT 19h
VOID Bios32Cleanup(VOID)
{
- EmsCleanup();
MouseBios32Cleanup();
VidBios32Cleanup();
KbdBios32Cleanup();
// #define BIOS_TIME_INTERRUPT 0x1A
// #define BIOS_SYS_TIMER_INTERRUPT 0x1C
-/* 16 MB of EMS memory */
-#define EMS_TOTAL_PAGES 1024
-
/* FUNCTIONS ******************************************************************/
BOOLEAN Bios32Initialize(VOID);
+++ /dev/null
-/*
- * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
- * PROJECT: ReactOS Virtual DOS Machine
- * FILE: ems.c
- * PURPOSE: Expanded Memory Support
- * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
- */
-
-/* INCLUDES *******************************************************************/
-
-#define NDEBUG
-
-#include "ntvdm.h"
-#include "emulator.h"
-#include "bios/bios32/bios32p.h"
-#include "ems.h"
-#include "memory.h"
-
-/* PRIVATE VARIABLES **********************************************************/
-
-static RTL_BITMAP AllocBitmap;
-static PULONG BitmapBuffer = NULL;
-static PEMS_PAGE PageTable = NULL;
-static EMS_HANDLE HandleTable[EMS_MAX_HANDLES];
-static PVOID Mapping[EMS_PHYSICAL_PAGES] = { NULL };
-static ULONG EmsTotalPages = 0;
-static PVOID EmsMemory = NULL;
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-static USHORT EmsFree(USHORT Handle)
-{
- PLIST_ENTRY Entry;
- PEMS_HANDLE HandleEntry = &HandleTable[Handle];
-
- if (Handle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
- {
- return EMS_STATUS_INVALID_HANDLE;
- }
-
- for (Entry = HandleEntry->PageList.Flink;
- Entry != &HandleEntry->PageList;
- Entry = Entry->Flink)
- {
- PEMS_PAGE PageEntry = (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
- ULONG PageNumber = ARRAY_INDEX(PageEntry, PageTable);
-
- /* Free the page */
- RtlClearBits(&AllocBitmap, PageNumber, 1);
- }
-
- HandleEntry->Allocated = FALSE;
- HandleEntry->PageCount = 0;
- InitializeListHead(&HandleEntry->PageList);
-
- return EMS_STATUS_OK;
-}
-
-static UCHAR EmsAlloc(USHORT NumPages, PUSHORT Handle)
-{
- ULONG i, CurrentIndex = 0;
- PEMS_HANDLE HandleEntry;
-
- if (NumPages == 0) return EMS_STATUS_ZERO_PAGES;
-
- for (i = 0; i < EMS_MAX_HANDLES; i++)
- {
- HandleEntry = &HandleTable[i];
- if (!HandleEntry->Allocated)
- {
- *Handle = i;
- break;
- }
- }
-
- if (i == EMS_MAX_HANDLES) return EMS_STATUS_NO_MORE_HANDLES;
- HandleEntry->Allocated = TRUE;
-
- while (HandleEntry->PageCount < NumPages)
- {
- ULONG RunStart;
- ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
-
- if (RunSize == 0)
- {
- /* Free what's been allocated already and report failure */
- EmsFree(*Handle);
- return EMS_STATUS_INSUFFICIENT_PAGES;
- }
- else if ((HandleEntry->PageCount + RunSize) > NumPages)
- {
- /* We don't need the entire run */
- RunSize = NumPages - HandleEntry->PageCount;
- }
-
- CurrentIndex = RunStart + RunSize;
- HandleEntry->PageCount += RunSize;
- RtlSetBits(&AllocBitmap, RunStart, RunSize);
-
- for (i = 0; i < RunSize; i++)
- {
- PageTable[RunStart + i].Handle = *Handle;
- InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry);
- }
- }
-
- return EMS_STATUS_OK;
-}
-
-static PEMS_PAGE GetLogicalPage(PEMS_HANDLE Handle, USHORT LogicalPage)
-{
- PLIST_ENTRY Entry = Handle->PageList.Flink;
-
- while (LogicalPage)
- {
- if (Entry == &Handle->PageList) return NULL;
- LogicalPage--;
- Entry = Entry->Flink;
- }
-
- return (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
-}
-
-static USHORT EmsMap(USHORT Handle, UCHAR PhysicalPage, USHORT LogicalPage)
-{
- PEMS_PAGE PageEntry;
- PEMS_HANDLE HandleEntry = &HandleTable[Handle];
-
- if (PhysicalPage >= EMS_PHYSICAL_PAGES) return EMS_STATUS_INV_PHYSICAL_PAGE;
- if (LogicalPage == 0xFFFF)
- {
- /* Unmap */
- Mapping[PhysicalPage] = NULL;
- return EMS_STATUS_OK;
- }
-
- if (Handle >= EMS_MAX_HANDLES || !HandleEntry->Allocated) return EMS_STATUS_INVALID_HANDLE;
-
- PageEntry = GetLogicalPage(HandleEntry, LogicalPage);
- if (!PageEntry) return EMS_STATUS_INV_LOGICAL_PAGE;
-
- Mapping[PhysicalPage] = (PVOID)((ULONG_PTR)EmsMemory
- + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE);
- return EMS_STATUS_OK;
-}
-
-static VOID WINAPI EmsIntHandler(LPWORD Stack)
-{
- switch (getAH())
- {
- /* Get Manager Status */
- case 0x40:
- {
- setAH(EMS_STATUS_OK);
- break;
- }
-
- /* Get Page Frame Segment */
- case 0x41:
- {
- setAH(EMS_STATUS_OK);
- setBX(EMS_SEGMENT);
- break;
- }
-
- /* Get Number Of Pages */
- case 0x42:
- {
- setAH(EMS_STATUS_OK);
- setBX(RtlNumberOfClearBits(&AllocBitmap));
- setDX(EmsTotalPages);
- break;
- }
-
- /* Get Handle And Allocate Memory */
- case 0x43:
- {
- USHORT Handle;
- UCHAR Status = EmsAlloc(getBX(), &Handle);
-
- setAH(Status);
- if (Status == EMS_STATUS_OK) setDX(Handle);
- break;
- }
-
- /* Map Memory */
- case 0x44:
- {
- setAH(EmsMap(getDX(), getAL(), getBX()));
- break;
- }
-
- /* Release Handle And Memory */
- case 0x45:
- {
- setAH(EmsFree(getDX()));
- break;
- }
-
- /* Get EMM Version */
- case 0x46:
- {
- setAH(EMS_STATUS_OK);
- setAL(EMS_VERSION_NUM);
- break;
- }
-
- /* Move/Exchange Memory */
- case 0x57:
- {
- PUCHAR SourcePtr, DestPtr;
- PEMS_HANDLE HandleEntry;
- PEMS_PAGE PageEntry;
- BOOLEAN Exchange = getAL();
- PEMS_COPY_DATA Data = (PEMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI());
-
- if (Data->SourceType)
- {
- /* Expanded memory */
- HandleEntry = &HandleTable[Data->SourceHandle];
-
- if (Data->SourceHandle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
- {
- setAL(EMS_STATUS_INVALID_HANDLE);
- break;
- }
-
- PageEntry = GetLogicalPage(HandleEntry, Data->SourceSegment);
-
- if (!PageEntry)
- {
- setAL(EMS_STATUS_INV_LOGICAL_PAGE);
- break;
- }
-
- SourcePtr = (PUCHAR)((ULONG_PTR)EmsMemory
- + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
- + Data->SourceOffset);
- }
- else
- {
- /* Conventional memory */
- SourcePtr = (PUCHAR)SEG_OFF_TO_PTR(Data->SourceSegment, Data->SourceOffset);
- }
-
- if (Data->DestType)
- {
- /* Expanded memory */
- HandleEntry = &HandleTable[Data->DestHandle];
-
- if (Data->SourceHandle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
- {
- setAL(EMS_STATUS_INVALID_HANDLE);
- break;
- }
-
- PageEntry = GetLogicalPage(HandleEntry, Data->DestSegment);
-
- if (!PageEntry)
- {
- setAL(EMS_STATUS_INV_LOGICAL_PAGE);
- break;
- }
-
- DestPtr = (PUCHAR)((ULONG_PTR)EmsMemory
- + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
- + Data->DestOffset);
- }
- else
- {
- /* Conventional memory */
- DestPtr = (PUCHAR)SEG_OFF_TO_PTR(Data->DestSegment, Data->DestOffset);
- }
-
- if (Exchange)
- {
- ULONG i;
-
- /* Exchange */
- for (i = 0; i < Data->RegionLength; i++)
- {
- UCHAR Temp = DestPtr[i];
- DestPtr[i] = SourcePtr[i];
- SourcePtr[i] = Temp;
- }
- }
- else
- {
- /* Move */
- RtlMoveMemory(DestPtr, SourcePtr, Data->RegionLength);
- }
-
- setAL(EMS_STATUS_OK);
- break;
- }
-
- default:
- {
- DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
- setAH(EMS_STATUS_UNKNOWN_FUNCTION);
- break;
- }
- }
-}
-
-static VOID NTAPI EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
-{
- ULONG i;
- ULONG RelativeAddress = Address - TO_LINEAR(EMS_SEGMENT, 0);
- ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
- ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
- ULONG Offset, Length;
-
- for (i = FirstPage; i <= LastPage; i++)
- {
- Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
- Length = ((i == LastPage)
- ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
- : EMS_PAGE_SIZE) - Offset;
-
- if (Mapping[i]) RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Mapping[i] + Offset), Length);
- Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
- }
-}
-
-static BOOLEAN NTAPI EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
-{
- ULONG i;
- ULONG RelativeAddress = Address - TO_LINEAR(EMS_SEGMENT, 0);
- ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
- ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
- ULONG Offset, Length;
-
- for (i = FirstPage; i <= LastPage; i++)
- {
- Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
- Length = ((i == LastPage)
- ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
- : EMS_PAGE_SIZE) - Offset;
-
- if (Mapping[i]) RtlCopyMemory((PVOID)((ULONG_PTR)Mapping[i] + Offset), Buffer, Length);
- Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
- }
-
- return TRUE;
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-BOOLEAN EmsInitialize(ULONG TotalPages)
-{
- ULONG i;
-
- for (i = 0; i < EMS_MAX_HANDLES; i++)
- {
- HandleTable[i].Allocated = FALSE;
- HandleTable[i].PageCount = 0;
- InitializeListHead(&HandleTable[i].PageList);
- }
-
- EmsTotalPages = TotalPages;
- BitmapBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- ((TotalPages + 31) / 32) * sizeof(ULONG));
- if (BitmapBuffer == NULL) return FALSE;
-
- RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, TotalPages);
-
- PageTable = (PEMS_PAGE)RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- TotalPages * sizeof(EMS_PAGE));
- if (PageTable == NULL)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
- BitmapBuffer = NULL;
-
- return FALSE;
- }
-
- EmsMemory = (PVOID)RtlAllocateHeap(RtlGetProcessHeap(), 0, TotalPages * EMS_PAGE_SIZE);
- if (EmsMemory == NULL)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
- PageTable = NULL;
- RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
- BitmapBuffer = NULL;
-
- return FALSE;
- }
-
- MemInstallFastMemoryHook((PVOID)TO_LINEAR(EMS_SEGMENT, 0),
- EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE,
- EmsReadMemory,
- EmsWriteMemory);
-
- RegisterBiosInt32(EMS_INTERRUPT_NUM, EmsIntHandler);
- return TRUE;
-}
-
-VOID EmsCleanup(VOID)
-{
- MemRemoveFastMemoryHook((PVOID)TO_LINEAR(EMS_SEGMENT, 0),
- EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE);
-
- if (EmsMemory)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory);
- EmsMemory = NULL;
- }
-
- if (PageTable)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
- PageTable = NULL;
- }
-
- if (BitmapBuffer)
- {
- RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
- BitmapBuffer = NULL;
- }
-}
#include "utils.h"
#include "dem.h"
+#include "dos/dos32krnl/device.h"
#include "cpu/bop.h"
#include "bios/bios.h"
/**/extern BYTE CurrentDrive;/**/
-/* DEFINES ********************************************************************/
-
-/* BOP Identifiers */
-#define BOP_LOAD_DOS 0x2B // DOS Loading and Initializing BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
-#define BOP_START_DOS 0x2C // DOS Starting BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
-#define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
-#define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
-
/* PRIVATE FUNCTIONS **********************************************************/
static VOID WINAPI DosSystemBop(LPWORD Stack)
break;
}
+ /* Call 32-bit Driver Strategy Routine */
+ case BOP_DRV_STRATEGY:
+ {
+ DeviceStrategyBop();
+ break;
+ }
+
+ /* Call 32-bit Driver Interrupt Routine */
+ case BOP_DRV_INTERRUPT:
+ {
+ DeviceInterruptBop();
+ break;
+ }
+
default:
{
DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
#include "dos32krnl/dos.h"
+/* DEFINES ********************************************************************/
+
+/* BOP Identifiers */
+#define BOP_LOAD_DOS 0x2B // DOS Loading and Initializing BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
+#define BOP_START_DOS 0x2C // DOS Starting BOP. In parameter (following bytes) we take a NULL-terminated string indicating the name of the DOS kernel file.
+#define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
+#define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
+
/* FUNCTIONS ******************************************************************/
DWORD
#include "ntvdm.h"
#include "emulator.h"
+#include "cpu/bop.h"
#include "device.h"
#include "dos.h"
/* PRIVATE VARIABLES **********************************************************/
+static const BYTE StrategyRoutine[] = {
+ LOBYTE(EMULATOR_BOP),
+ HIBYTE(EMULATOR_BOP),
+ BOP_DOS,
+ BOP_DRV_STRATEGY,
+ 0xCB // retf
+};
+
+static const BYTE InterruptRoutine[] = {
+ LOBYTE(EMULATOR_BOP),
+ HIBYTE(EMULATOR_BOP),
+ BOP_DOS,
+ BOP_DRV_INTERRUPT,
+ 0xCB // retf
+};
+
+C_ASSERT((sizeof(StrategyRoutine) + sizeof(InterruptRoutine)) == DEVICE_CODE_SIZE);
+
static LIST_ENTRY DeviceList = { &DeviceList, &DeviceList };
+static DWORD FirstDriver = 0xFFFFFFFF;
+static PDOS_REQUEST_HEADER DeviceRequest;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID DosCallDriver(DWORD Driver, PDOS_REQUEST_HEADER Request)
{
PDOS_DRIVER DriverBlock = (PDOS_DRIVER)FAR_POINTER(Driver);
- PDOS_REQUEST_HEADER RemoteRequest;
+ PDOS_REQUEST_HEADER RemoteRequest = FAR_POINTER(REQUEST_LOCATION);
+ WORD ES = getES();
+ WORD BX = getBX();
- /* Call the strategy routine first */
- Call16(HIWORD(Driver), DriverBlock->StrategyRoutine);
- RemoteRequest = (PDOS_REQUEST_HEADER)SEG_OFF_TO_PTR(getES(), getBX());
+ /* Set ES:BX to the location of the request */
+ setES(HIWORD(REQUEST_LOCATION));
+ setBX(LOWORD(REQUEST_LOCATION));
/* Copy the request structure to ES:BX */
RtlMoveMemory(RemoteRequest, Request, Request->RequestLength);
- /* Call the interrupt routine */
+ /* Call the strategy routine, and then the interrupt routine */
+ Call16(HIWORD(Driver), DriverBlock->StrategyRoutine);
Call16(HIWORD(Driver), DriverBlock->InterruptRoutine);
/* Get the request structure from ES:BX */
- RtlMoveMemory(Request, RemoteRequest, RemoteRequest->RequestLength);
+ RtlMoveMemory(Request, RemoteRequest, Request->RequestLength);
+
+ /* Restore ES:BX */
+ setES(ES);
+ setBX(BX);
}
static inline WORD NTAPI DosDriverReadInternal(PDOS_DEVICE_NODE DeviceNode,
return Request.Header.Status;
}
+static VOID DosAddDriver(DWORD Driver)
+{
+ PDOS_DRIVER LastDriver;
+
+ if (LOWORD(FirstDriver) == 0xFFFF)
+ {
+ /* This is the first driver */
+ FirstDriver = Driver;
+ return;
+ }
+
+ /* The list isn't empty, so find the last driver in it */
+ LastDriver = (PDOS_DRIVER)FAR_POINTER(FirstDriver);
+ while (LOWORD(LastDriver->Link) != 0xFFFF)
+ {
+ LastDriver = (PDOS_DRIVER)FAR_POINTER(LastDriver->Link);
+ }
+
+ /* Add the new driver to the list */
+ LastDriver->Link = Driver;
+}
+
+static VOID DosRemoveDriver(DWORD Driver)
+{
+ DWORD CurrentDriver = FirstDriver;
+
+ if (FirstDriver == Driver)
+ {
+ /* Update the first driver */
+ FirstDriver = ((PDOS_DRIVER)FAR_POINTER(FirstDriver))->Link;
+ return;
+ }
+
+ while (LOWORD(CurrentDriver) != 0xFFFF)
+ {
+ PDOS_DRIVER DriverHeader = (PDOS_DRIVER)FAR_POINTER(CurrentDriver);
+
+ if (DriverHeader->Link == Driver)
+ {
+ /* Remove it from the list */
+ DriverHeader->Link = ((PDOS_DRIVER)FAR_POINTER(DriverHeader->Link))->Link;
+ return;
+ }
+
+ CurrentDriver = DriverHeader->Link;
+ }
+}
+
+static PDOS_DEVICE_NODE DosCreateDeviceNode(DWORD Driver)
+{
+ BYTE i;
+ PDOS_DRIVER DriverHeader = (PDOS_DRIVER)FAR_POINTER(Driver);
+ PDOS_DEVICE_NODE Node = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(*Node));
+ if (Node == NULL) return NULL;
+
+ Node->Driver = Driver;
+ Node->DeviceAttributes = DriverHeader->DeviceAttributes;
+
+ /* Initialize the name string */
+ Node->Name.Buffer = Node->NameBuffer;
+ Node->Name.MaximumLength = MAX_DEVICE_NAME;
+
+ for (i = 0; i < MAX_DEVICE_NAME; i++)
+ {
+ if (DriverHeader->DeviceName[i] == ' ') break;
+ Node->Name.Buffer[i] = DriverHeader->DeviceName[i];
+ }
+
+ Node->Name.Length = i;
+
+ InsertTailList(&DeviceList, &Node->Entry);
+ return Node;
+}
+
/* PUBLIC FUNCTIONS ***********************************************************/
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName)
{
PLIST_ENTRY i;
- PDOS_DEVICE_NODE Node;
+ DWORD CurrentDriver = FirstDriver;
ANSI_STRING DeviceNameString;
RtlInitAnsiString(&DeviceNameString, DeviceName);
- for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
+ while (LOWORD(CurrentDriver) != 0xFFFF)
{
- Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
+ PDOS_DEVICE_NODE Node;
+ PDOS_DRIVER DriverHeader = (PDOS_DRIVER)FAR_POINTER(CurrentDriver);
+
+ /* Get the device node for this driver */
+ for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
+ {
+ Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
+ if (Node->Driver == CurrentDriver) break;
+ }
+
+ if (i == &DeviceList)
+ {
+ DPRINT1("The driver at %04X:%04X has no associated device node. "
+ "Installing automagically.\n",
+ HIWORD(CurrentDriver),
+ LOWORD(CurrentDriver));
+
+ /* Create the device node */
+ Node = DosCreateDeviceNode(CurrentDriver);
+ Node->IoctlReadRoutine = DosDriverDispatchIoctlRead;
+ Node->ReadRoutine = DosDriverDispatchRead;
+ Node->PeekRoutine = DosDriverDispatchPeek;
+ Node->InputStatusRoutine = DosDriverDispatchInputStatus;
+ Node->FlushInputRoutine = DosDriverDispatchFlushInput;
+ Node->IoctlWriteRoutine = DosDriverDispatchIoctlWrite;
+ Node->WriteRoutine = DosDriverDispatchWrite;
+ Node->OutputStatusRoutine = DosDriverDispatchOutputStatus;
+ Node->FlushOutputRoutine = DosDriverDispatchFlushOutput;
+ Node->OpenRoutine = DosDriverDispatchOpen;
+ Node->CloseRoutine = DosDriverDispatchClose;
+ Node->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
+ }
+
if (RtlEqualString(&Node->Name, &DeviceNameString, TRUE)) return Node;
+ CurrentDriver = DriverHeader->Link;
}
return NULL;
}
-PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName)
+PDOS_DEVICE_NODE DosCreateDeviceEx(WORD Attributes, PCHAR DeviceName, WORD PrivateDataSize)
{
BYTE i;
+ WORD Segment;
+ PDOS_DRIVER DriverHeader;
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;
+ return NULL;
}
- Node = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*Node));
- if (Node == NULL) return NULL;
+ /* Create a driver header for this device */
+ Segment = DosAllocateMemory(sizeof(DOS_DRIVER) + 10 + PrivateDataSize, NULL);
+ if (Segment == 0) return NULL;
- Node->DeviceAttributes = Attributes;
-
- /* Initialize the name string */
- Node->Name.Buffer = Node->NameBuffer;
- Node->Name.MaximumLength = MAX_DEVICE_NAME;
+ /* Fill the header with data */
+ DriverHeader = SEG_OFF_TO_PTR(Segment, 0);
+ DriverHeader->Link = 0xFFFFFFFF;
+ DriverHeader->DeviceAttributes = Attributes;
+ DriverHeader->StrategyRoutine = sizeof(DOS_DRIVER);
+ DriverHeader->InterruptRoutine = sizeof(DOS_DRIVER) + sizeof(StrategyRoutine);
+ RtlFillMemory(DriverHeader->DeviceName, MAX_DEVICE_NAME, ' ');
for (i = 0; i < MAX_DEVICE_NAME; i++)
{
if (DeviceName[i] == '\0' || DeviceName[i] == ' ') break;
- Node->Name.Buffer[i] = DeviceName[i];
+ DriverHeader->DeviceName[i] = DeviceName[i];
}
- Node->Name.Length = i;
+ /* Write the routines */
+ RtlMoveMemory(SEG_OFF_TO_PTR(Segment, DriverHeader->StrategyRoutine),
+ StrategyRoutine,
+ sizeof(StrategyRoutine));
+ RtlMoveMemory(SEG_OFF_TO_PTR(Segment, DriverHeader->StrategyRoutine),
+ InterruptRoutine,
+ sizeof(InterruptRoutine));
+
+ /* Create the node */
+ Node = DosCreateDeviceNode(MAKELONG(0, Segment));
+ if (Node == NULL)
+ {
+ DosFreeMemory(Segment);
+ return NULL;
+ }
- InsertTailList(&DeviceList, &Node->Entry);
+ DosAddDriver(Node->Driver);
return Node;
}
+PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName)
+{
+ /* Call the extended API */
+ return DosCreateDeviceEx(Attributes, DeviceName, 0);
+}
+
VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode)
{
+ DosRemoveDriver(DeviceNode->Driver);
+
+ ASSERT(LOWORD(DeviceNode->Driver) == 0);
+ DosFreeMemory(HIWORD(DeviceNode->Driver));
+
RemoveEntryList(&DeviceNode->Entry);
RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNode);
}
+VOID DeviceStrategyBop(VOID)
+{
+ /* Save ES:BX */
+ DeviceRequest = (PDOS_REQUEST_HEADER)SEG_OFF_TO_PTR(getES(), getBX());
+}
+
+VOID DeviceInterruptBop(VOID)
+{
+ PLIST_ENTRY i;
+ PDOS_DEVICE_NODE Node;
+ DWORD DriverAddress = (getCS() << 4) + getIP() - sizeof(DOS_DRIVER) - 9;
+
+ /* Get the device node for this driver */
+ for (i = DeviceList.Flink; i != &DeviceList; i = i->Flink)
+ {
+ Node = CONTAINING_RECORD(i, DOS_DEVICE_NODE, Entry);
+ if (TO_LINEAR(HIWORD(Node->Driver), LOWORD(Node->Driver)) == DriverAddress) break;
+ }
+
+ if (i == &DeviceList)
+ {
+ DPRINT1("Device interrupt BOP from an unknown location.\n");
+ return;
+ }
+
+ switch (DeviceRequest->CommandCode)
+ {
+ case DOS_DEVCMD_IOCTL_READ:
+ {
+ PDOS_IOCTL_RW_REQUEST Request = (PDOS_IOCTL_RW_REQUEST)DeviceRequest;
+
+ DeviceRequest->Status = Node->IoctlReadRoutine(
+ Node,
+ Request->BufferPointer,
+ &Request->Length
+ );
+
+ break;
+ }
+
+ case DOS_DEVCMD_READ:
+ {
+ PDOS_RW_REQUEST Request = (PDOS_RW_REQUEST)DeviceRequest;
+
+ DeviceRequest->Status = Node->ReadRoutine(
+ Node,
+ Request->BufferPointer,
+ &Request->Length
+ );
+
+ break;
+ }
+
+ case DOS_DEVCMD_PEEK:
+ {
+ PDOS_PEEK_REQUEST Request = (PDOS_PEEK_REQUEST)DeviceRequest;
+ DeviceRequest->Status = Node->PeekRoutine(Node, &Request->Character);
+ break;
+ }
+
+ case DOS_DEVCMD_INSTAT:
+ {
+ DeviceRequest->Status = Node->InputStatusRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_FLUSH_INPUT:
+ {
+ DeviceRequest->Status = Node->FlushInputRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_IOCTL_WRITE:
+ {
+ PDOS_IOCTL_RW_REQUEST Request = (PDOS_IOCTL_RW_REQUEST)DeviceRequest;
+
+ DeviceRequest->Status = Node->IoctlWriteRoutine(
+ Node,
+ Request->BufferPointer,
+ &Request->Length
+ );
+
+ break;
+ }
+
+ case DOS_DEVCMD_WRITE:
+ {
+ PDOS_RW_REQUEST Request = (PDOS_RW_REQUEST)DeviceRequest;
+
+ DeviceRequest->Status = Node->WriteRoutine(Node,
+ Request->BufferPointer,
+ &Request->Length
+ );
+
+ break;
+ }
+
+ case DOS_DEVCMD_OUTSTAT:
+ {
+ DeviceRequest->Status = Node->OutputStatusRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_FLUSH_OUTPUT:
+ {
+ DeviceRequest->Status = Node->FlushOutputRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_OPEN:
+ {
+ DeviceRequest->Status = Node->OpenRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_CLOSE:
+ {
+ DeviceRequest->Status = Node->CloseRoutine(Node);
+ break;
+ }
+
+ case DOS_DEVCMD_OUTPUT_BUSY:
+ {
+ PDOS_OUTPUT_BUSY_REQUEST Request = (PDOS_OUTPUT_BUSY_REQUEST)DeviceRequest;
+
+ DeviceRequest->Status = Node->OutputUntilBusyRoutine(
+ Node,
+ Request->BufferPointer,
+ &Request->Length
+ );
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("Unknown device command code: %u\n", DeviceRequest->CommandCode);
+ }
+ }
+}
+
DWORD DosLoadDriver(LPCSTR DriverFile)
{
DWORD Result = ERROR_SUCCESS;
goto Next;
}
- /* Create the device */
- DeviceNode = DosCreateDevice(DriverHeader->DeviceAttributes,
- DriverHeader->DeviceName);
- DeviceNode->Driver = Driver;
+ /* Create the device node */
+ DeviceNode = DosCreateDeviceNode(Driver);
DeviceNode->IoctlReadRoutine = DosDriverDispatchIoctlRead;
DeviceNode->ReadRoutine = DosDriverDispatchRead;
DeviceNode->PeekRoutine = DosDriverDispatchPeek;
DeviceNode->CloseRoutine = DosDriverDispatchClose;
DeviceNode->OutputUntilBusyRoutine = DosDriverDispatchOutputUntilBusy;
+ DosAddDriver(Driver);
DriversLoaded++;
Next:
/* DEFINITIONS ****************************************************************/
#define MAX_DEVICE_NAME 8
+#define REQUEST_LOCATION 0x00700100 // 0070:0100
+#define DEVICE_CODE_SIZE 10
+#define DEVICE_PRIVATE_AREA(Driver) (Driver + sizeof(DOS_DRIVER) + DEVICE_CODE_SIZE)
+
+#define BOP_DRV_STRATEGY 0x42
+#define BOP_DRV_INTERRUPT 0x43
#define DOS_DEVATTR_STDIN (1 << 0)
#define DOS_DEVATTR_STDOUT (1 << 1)
struct _DOS_DEVICE_NODE
{
LIST_ENTRY Entry;
+ DWORD Driver;
WORD DeviceAttributes;
ANSI_STRING Name;
CHAR NameBuffer[MAX_DEVICE_NAME];
PDOS_DEVICE_GENERIC_ROUTINE OpenRoutine;
PDOS_DEVICE_GENERIC_ROUTINE CloseRoutine;
PDOS_DEVICE_IO_ROUTINE OutputUntilBusyRoutine;
- DWORD Driver;
};
#pragma pack(push, 1)
PDOS_DEVICE_NODE DosGetDevice(LPCSTR DeviceName);
PDOS_DEVICE_NODE DosCreateDevice(WORD Attributes, PCHAR DeviceName);
+PDOS_DEVICE_NODE DosCreateDeviceEx
+(
+ WORD Attributes,
+ PCHAR DeviceName,
+ WORD PrivateDataSize
+);
VOID DosDeleteDevice(PDOS_DEVICE_NODE DeviceNode);
+VOID DeviceStrategyBop(VOID);
+VOID DeviceInterruptBop(VOID);
+DWORD DosLoadDriver(LPCSTR DriverFile);
#endif // _DEVICE_H_
#include "dos/dem.h"
#include "device.h"
#include "memory.h"
+#include "himem.h"
#include "bios/bios.h"
#include "io.h"
#include "hardware/ps2.h"
+#include "emsdrv.h"
+
/* PRIVATE VARIABLES **********************************************************/
CALLBACK16 DosContext;
VOID WINAPI DosInt2Fh(LPWORD Stack)
{
- DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
- getAH(), getAL());
- Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ switch (getAH())
+ {
+ /* Extended Memory Specification */
+ case 0x43:
+ {
+ DWORD DriverEntry;
+ if (!XmsGetDriverEntry(&DriverEntry)) break;
+
+ if (getAL() == 0x00)
+ {
+ /* The driver is loaded */
+ setAL(0x80);
+ }
+ else if (getAL() == 0x10)
+ {
+ setES(HIWORD(DriverEntry));
+ setBX(LOWORD(DriverEntry));
+ }
+ else
+ {
+ DPRINT1("Unknown DOS XMS Function: INT 0x2F, AH = 43h, AL = %xh\n", getAL());
+ }
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
+ getAH(), getAL());
+ Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
+ }
+ }
}
BOOLEAN DosKRNLInitialize(VOID)
DosSystemFileTable[i].RefCount = 0;
}
- /* Load the EMS driver */
- EmsDrvInitialize();
-
- /* Load the CON driver */
- ConDrvInitialize();
-
#endif
/* Initialize the callback context */
RegisterDosInt32(0x29, DosFastConOut ); // DOS 2+ Fast Console Output
RegisterDosInt32(0x2F, DosInt2Fh );
+ /* Load the EMS driver */
+ if (!EmsDrvInitialize(EMS_TOTAL_PAGES))
+ {
+ DPRINT1("Could not initialize EMS. EMS will not be available.\n"
+ "Try reducing the number of EMS pages.\n");
+ }
+
+ /* Load the XMS driver (HIMEM) */
+ XmsInitialize();
+
+ /* Load the CON driver */
+ ConDrvInitialize();
+
return TRUE;
}
#define DOS_PROGRAM_NAME_TAG 0x0001
#define DEFAULT_JFT_SIZE 20
+/* 16 MB of EMS memory */
+#define EMS_TOTAL_PAGES 1024
+
typedef enum
{
DOS_LOAD_AND_EXECUTE = 0x00,
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
BOOLEAN DosBIOSInitialize(VOID);
-VOID EmsDrvInitialize(VOID);
-VOID EmsDrvCleanup(VOID);
VOID ConDrvInitialize(VOID);
VOID ConDrvCleanup(VOID);
#define NDEBUG
#include "ntvdm.h"
+#include "emulator.h"
#include "dos.h"
#include "dos/dem.h"
#include "device.h"
+#include "../../memory.h"
+#include "emsdrv.h"
+
#define EMS_DEVICE_NAME "EMMXXXX0"
/* PRIVATE VARIABLES **********************************************************/
static PDOS_DEVICE_NODE Node;
+static RTL_BITMAP AllocBitmap;
+static PULONG BitmapBuffer = NULL;
+static PEMS_PAGE PageTable = NULL;
+static EMS_HANDLE HandleTable[EMS_MAX_HANDLES];
+static PVOID Mapping[EMS_PHYSICAL_PAGES] = { NULL };
+static ULONG EmsTotalPages = 0;
+static PVOID EmsMemory = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
+static USHORT EmsFree(USHORT Handle)
+{
+ PLIST_ENTRY Entry;
+ PEMS_HANDLE HandleEntry = &HandleTable[Handle];
+
+ if (Handle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
+ {
+ return EMS_STATUS_INVALID_HANDLE;
+ }
+
+ for (Entry = HandleEntry->PageList.Flink;
+ Entry != &HandleEntry->PageList;
+ Entry = Entry->Flink)
+ {
+ PEMS_PAGE PageEntry = (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
+ ULONG PageNumber = ARRAY_INDEX(PageEntry, PageTable);
+
+ /* Free the page */
+ RtlClearBits(&AllocBitmap, PageNumber, 1);
+ }
+
+ HandleEntry->Allocated = FALSE;
+ HandleEntry->PageCount = 0;
+ InitializeListHead(&HandleEntry->PageList);
+
+ return EMS_STATUS_OK;
+}
+
+static UCHAR EmsAlloc(USHORT NumPages, PUSHORT Handle)
+{
+ ULONG i, CurrentIndex = 0;
+ PEMS_HANDLE HandleEntry;
+
+ if (NumPages == 0) return EMS_STATUS_ZERO_PAGES;
+
+ for (i = 0; i < EMS_MAX_HANDLES; i++)
+ {
+ HandleEntry = &HandleTable[i];
+ if (!HandleEntry->Allocated)
+ {
+ *Handle = i;
+ break;
+ }
+ }
+
+ if (i == EMS_MAX_HANDLES) return EMS_STATUS_NO_MORE_HANDLES;
+ HandleEntry->Allocated = TRUE;
+
+ while (HandleEntry->PageCount < NumPages)
+ {
+ ULONG RunStart;
+ ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
+
+ if (RunSize == 0)
+ {
+ /* Free what's been allocated already and report failure */
+ EmsFree(*Handle);
+ return EMS_STATUS_INSUFFICIENT_PAGES;
+ }
+ else if ((HandleEntry->PageCount + RunSize) > NumPages)
+ {
+ /* We don't need the entire run */
+ RunSize = NumPages - HandleEntry->PageCount;
+ }
+
+ CurrentIndex = RunStart + RunSize;
+ HandleEntry->PageCount += RunSize;
+ RtlSetBits(&AllocBitmap, RunStart, RunSize);
+
+ for (i = 0; i < RunSize; i++)
+ {
+ PageTable[RunStart + i].Handle = *Handle;
+ InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry);
+ }
+ }
+
+ return EMS_STATUS_OK;
+}
+
+static PEMS_PAGE GetLogicalPage(PEMS_HANDLE Handle, USHORT LogicalPage)
+{
+ PLIST_ENTRY Entry = Handle->PageList.Flink;
+
+ while (LogicalPage)
+ {
+ if (Entry == &Handle->PageList) return NULL;
+ LogicalPage--;
+ Entry = Entry->Flink;
+ }
+
+ return (PEMS_PAGE)CONTAINING_RECORD(Entry, EMS_PAGE, Entry);
+}
+
+static USHORT EmsMap(USHORT Handle, UCHAR PhysicalPage, USHORT LogicalPage)
+{
+ PEMS_PAGE PageEntry;
+ PEMS_HANDLE HandleEntry = &HandleTable[Handle];
+
+ if (PhysicalPage >= EMS_PHYSICAL_PAGES) return EMS_STATUS_INV_PHYSICAL_PAGE;
+ if (LogicalPage == 0xFFFF)
+ {
+ /* Unmap */
+ Mapping[PhysicalPage] = NULL;
+ return EMS_STATUS_OK;
+ }
+
+ if (Handle >= EMS_MAX_HANDLES || !HandleEntry->Allocated) return EMS_STATUS_INVALID_HANDLE;
+
+ PageEntry = GetLogicalPage(HandleEntry, LogicalPage);
+ if (!PageEntry) return EMS_STATUS_INV_LOGICAL_PAGE;
+
+ Mapping[PhysicalPage] = (PVOID)((ULONG_PTR)EmsMemory
+ + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE);
+ return EMS_STATUS_OK;
+}
+
+static VOID WINAPI EmsIntHandler(LPWORD Stack)
+{
+ switch (getAH())
+ {
+ /* Get Manager Status */
+ case 0x40:
+ {
+ setAH(EMS_STATUS_OK);
+ break;
+ }
+
+ /* Get Page Frame Segment */
+ case 0x41:
+ {
+ setAH(EMS_STATUS_OK);
+ setBX(EMS_SEGMENT);
+ break;
+ }
+
+ /* Get Number Of Pages */
+ case 0x42:
+ {
+ setAH(EMS_STATUS_OK);
+ setBX(RtlNumberOfClearBits(&AllocBitmap));
+ setDX(EmsTotalPages);
+ break;
+ }
+
+ /* Get Handle And Allocate Memory */
+ case 0x43:
+ {
+ USHORT Handle;
+ UCHAR Status = EmsAlloc(getBX(), &Handle);
+
+ setAH(Status);
+ if (Status == EMS_STATUS_OK) setDX(Handle);
+ break;
+ }
+
+ /* Map Memory */
+ case 0x44:
+ {
+ setAH(EmsMap(getDX(), getAL(), getBX()));
+ break;
+ }
+
+ /* Release Handle And Memory */
+ case 0x45:
+ {
+ setAH(EmsFree(getDX()));
+ break;
+ }
+
+ /* Get EMM Version */
+ case 0x46:
+ {
+ setAH(EMS_STATUS_OK);
+ setAL(EMS_VERSION_NUM);
+ break;
+ }
+
+ /* Move/Exchange Memory */
+ case 0x57:
+ {
+ PUCHAR SourcePtr, DestPtr;
+ PEMS_HANDLE HandleEntry;
+ PEMS_PAGE PageEntry;
+ BOOLEAN Exchange = getAL();
+ PEMS_COPY_DATA Data = (PEMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI());
+
+ if (Data->SourceType)
+ {
+ /* Expanded memory */
+ HandleEntry = &HandleTable[Data->SourceHandle];
+
+ if (Data->SourceHandle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
+ {
+ setAL(EMS_STATUS_INVALID_HANDLE);
+ break;
+ }
+
+ PageEntry = GetLogicalPage(HandleEntry, Data->SourceSegment);
+
+ if (!PageEntry)
+ {
+ setAL(EMS_STATUS_INV_LOGICAL_PAGE);
+ break;
+ }
+
+ SourcePtr = (PUCHAR)((ULONG_PTR)EmsMemory
+ + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
+ + Data->SourceOffset);
+ }
+ else
+ {
+ /* Conventional memory */
+ SourcePtr = (PUCHAR)SEG_OFF_TO_PTR(Data->SourceSegment, Data->SourceOffset);
+ }
+
+ if (Data->DestType)
+ {
+ /* Expanded memory */
+ HandleEntry = &HandleTable[Data->DestHandle];
+
+ if (Data->SourceHandle >= EMS_MAX_HANDLES || !HandleEntry->Allocated)
+ {
+ setAL(EMS_STATUS_INVALID_HANDLE);
+ break;
+ }
+
+ PageEntry = GetLogicalPage(HandleEntry, Data->DestSegment);
+
+ if (!PageEntry)
+ {
+ setAL(EMS_STATUS_INV_LOGICAL_PAGE);
+ break;
+ }
+
+ DestPtr = (PUCHAR)((ULONG_PTR)EmsMemory
+ + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE
+ + Data->DestOffset);
+ }
+ else
+ {
+ /* Conventional memory */
+ DestPtr = (PUCHAR)SEG_OFF_TO_PTR(Data->DestSegment, Data->DestOffset);
+ }
+
+ if (Exchange)
+ {
+ ULONG i;
+
+ /* Exchange */
+ for (i = 0; i < Data->RegionLength; i++)
+ {
+ UCHAR Temp = DestPtr[i];
+ DestPtr[i] = SourcePtr[i];
+ SourcePtr[i] = Temp;
+ }
+ }
+ else
+ {
+ /* Move */
+ RtlMoveMemory(DestPtr, SourcePtr, Data->RegionLength);
+ }
+
+ setAL(EMS_STATUS_OK);
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
+ setAH(EMS_STATUS_UNKNOWN_FUNCTION);
+ break;
+ }
+ }
+}
+
+static VOID NTAPI EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
+{
+ ULONG i;
+ ULONG RelativeAddress = Address - TO_LINEAR(EMS_SEGMENT, 0);
+ ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
+ ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
+ ULONG Offset, Length;
+
+ for (i = FirstPage; i <= LastPage; i++)
+ {
+ Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
+ Length = ((i == LastPage)
+ ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
+ : EMS_PAGE_SIZE) - Offset;
+
+ if (Mapping[i]) RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Mapping[i] + Offset), Length);
+ Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
+ }
+}
+
+static BOOLEAN NTAPI EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
+{
+ ULONG i;
+ ULONG RelativeAddress = Address - TO_LINEAR(EMS_SEGMENT, 0);
+ ULONG FirstPage = RelativeAddress / EMS_PAGE_SIZE;
+ ULONG LastPage = (RelativeAddress + Size - 1) / EMS_PAGE_SIZE;
+ ULONG Offset, Length;
+
+ for (i = FirstPage; i <= LastPage; i++)
+ {
+ Offset = (i == FirstPage) ? RelativeAddress & (EMS_PAGE_SIZE - 1) : 0;
+ Length = ((i == LastPage)
+ ? (RelativeAddress + Size - (LastPage << EMS_PAGE_BITS))
+ : EMS_PAGE_SIZE) - Offset;
+
+ if (Mapping[i]) RtlCopyMemory((PVOID)((ULONG_PTR)Mapping[i] + Offset), Buffer, Length);
+ Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
+ }
+
+ return TRUE;
+}
+
+
WORD NTAPI EmsDrvDispatchIoctlRead(PDOS_DEVICE_NODE Device, DWORD Buffer, PWORD Length)
{
// TODO: NOT IMPLEMENTED
/* PUBLIC FUNCTIONS ***********************************************************/
-VOID EmsDrvInitialize(VOID)
+BOOLEAN EmsDrvInitialize(ULONG TotalPages)
{
+ ULONG i;
+
+ for (i = 0; i < EMS_MAX_HANDLES; i++)
+ {
+ HandleTable[i].Allocated = FALSE;
+ HandleTable[i].PageCount = 0;
+ InitializeListHead(&HandleTable[i].PageList);
+ }
+
+ EmsTotalPages = TotalPages;
+ BitmapBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ ((TotalPages + 31) / 32) * sizeof(ULONG));
+ if (BitmapBuffer == NULL) return FALSE;
+
+ RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, TotalPages);
+
+ PageTable = (PEMS_PAGE)RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ TotalPages * sizeof(EMS_PAGE));
+ if (PageTable == NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
+ BitmapBuffer = NULL;
+
+ return FALSE;
+ }
+
+ EmsMemory = (PVOID)RtlAllocateHeap(RtlGetProcessHeap(), 0, TotalPages * EMS_PAGE_SIZE);
+ if (EmsMemory == NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
+ PageTable = NULL;
+ RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
+ BitmapBuffer = NULL;
+
+ return FALSE;
+ }
+
+ MemInstallFastMemoryHook((PVOID)TO_LINEAR(EMS_SEGMENT, 0),
+ EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE,
+ EmsReadMemory,
+ EmsWriteMemory);
+
+ RegisterDosInt32(EMS_INTERRUPT_NUM, EmsIntHandler);
+
/* Create the device */
- Node = DosCreateDevice(DOS_DEVATTR_IOCTL
- | DOS_DEVATTR_CHARACTER,
+ Node = DosCreateDevice(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
EMS_DEVICE_NAME);
Node->IoctlReadRoutine = EmsDrvDispatchIoctlRead;
+
+ return TRUE;
}
VOID EmsDrvCleanup(VOID)
{
/* Delete the device */
DosDeleteDevice(Node);
+
+ MemRemoveFastMemoryHook((PVOID)TO_LINEAR(EMS_SEGMENT, 0),
+ EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE);
+
+ if (EmsMemory)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, EmsMemory);
+ EmsMemory = NULL;
+ }
+
+ if (PageTable)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PageTable);
+ PageTable = NULL;
+ }
+
+ if (BitmapBuffer)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, BitmapBuffer);
+ BitmapBuffer = NULL;
+ }
}
/*
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
- * FILE: ems.h
- * PURPOSE: Expanded Memory Support
+ * FILE: emsdrv.h
+ * PURPOSE: DOS EMS Driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
-#ifndef _EMS_H_
-#define _EMS_H_
+#ifndef _EMSDRV_H_
+#define _EMSDRV_H_
/* DEFINITIONS ****************************************************************/
#pragma pack(pop)
-/* FUNCTIONS ******************************************************************/
-
-BOOLEAN EmsInitialize(ULONG TotalPages);
-VOID EmsCleanup(VOID);
+#endif
-#endif // _EMS_H_
+/* FUNCTIONS ******************************************************************/
-/* EOF */
+BOOLEAN EmsDrvInitialize(ULONG TotalPages);
+VOID EmsDrvCleanup(VOID);
--- /dev/null
+/*
+ * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: himem.c
+ * PURPOSE: DOS XMS Driver
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "ntvdm.h"
+#include "emulator.h"
+#include "cpu/bop.h"
+
+#include "dos.h"
+#include "dos/dem.h"
+#include "device.h"
+
+#define XMS_DEVICE_NAME "XMSXXXX0"
+#define XMS_BOP 0x52
+
+/* PRIVATE VARIABLES **********************************************************/
+
+static const BYTE EntryProcedure[] = {
+ 0xEB, // jmp short +0x03
+ 0x03,
+ 0x90, // nop
+ 0x90, // nop
+ 0x90, // nop
+ LOBYTE(EMULATOR_BOP),
+ HIBYTE(EMULATOR_BOP),
+ XMS_BOP,
+ 0xCB // retf
+};
+
+static PDOS_DEVICE_NODE Node = NULL;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static VOID WINAPI XmsBopProcedure(LPWORD Stack)
+{
+ switch (getAH())
+ {
+ /* Get XMS Version */
+ case 0x00:
+ {
+ setAX(0x0300); /* XMS version 3.0 */
+ setDX(0x0001); /* HMA present */
+
+ break;
+ }
+
+ default:
+ {
+ DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH());
+ }
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+BOOLEAN XmsGetDriverEntry(PDWORD Pointer)
+{
+ if (Node == NULL) return FALSE;
+ *Pointer = DEVICE_PRIVATE_AREA(Node->Driver);
+ return TRUE;
+}
+
+VOID XmsInitialize(VOID)
+{
+ Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
+ XMS_DEVICE_NAME,
+ sizeof(EntryProcedure));
+
+ RegisterBop(XMS_BOP, XmsBopProcedure);
+
+ /* Copy the entry routine to the device private area */
+ RtlMoveMemory(FAR_POINTER(DEVICE_PRIVATE_AREA(Node->Driver)),
+ EntryProcedure,
+ sizeof(EntryProcedure));
+}
+
+VOID XmsCleanup(VOID)
+{
+ RegisterBop(XMS_BOP, NULL);
+ DosDeleteDevice(Node);
+}
--- /dev/null
+/*
+ * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: himem.h
+ * PURPOSE: DOS XMS Driver
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* FUNCTIONS ******************************************************************/
+
+BOOLEAN XmsGetDriverEntry(PDWORD Pointer);
+VOID XmsInitialize(VOID);
+VOID XmsCleanup(VOID);