Implement basic XMS functions.


svn path=/trunk/; revision=67340
This commit is contained in:
Aleksandar Andrejevic 2015-04-22 03:10:11 +00:00
parent 274901555c
commit 25840ba03f
2 changed files with 215 additions and 0 deletions

View file

@ -17,6 +17,7 @@
#include "dos.h" #include "dos.h"
#include "dos/dem.h" #include "dos/dem.h"
#include "device.h" #include "device.h"
#include "himem.h"
#define XMS_DEVICE_NAME "XMSXXXX0" #define XMS_DEVICE_NAME "XMSXXXX0"
#define XMS_BOP 0x52 #define XMS_BOP 0x52
@ -36,9 +37,117 @@ static const BYTE EntryProcedure[] = {
}; };
static PDOS_DEVICE_NODE Node = NULL; static PDOS_DEVICE_NODE Node = NULL;
static XMS_HANDLE HandleTable[XMS_MAX_HANDLES];
static WORD FreeBlocks = XMS_BLOCKS;
static RTL_BITMAP AllocBitmap;
static ULONG BitmapBuffer[(XMS_BLOCKS + 31) / 32];
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
static inline PXMS_HANDLE GetHandleRecord(WORD Handle)
{
PXMS_HANDLE Entry = &HandleTable[Handle - 1];
if (Handle == 0 || Handle >= XMS_MAX_HANDLES) return NULL;
return Entry->Size ? Entry : NULL;
}
static CHAR XmsAlloc(WORD Size, PWORD Handle)
{
BYTE i;
PXMS_HANDLE HandleEntry;
if (Size > FreeBlocks) return XMS_STATUS_OUT_OF_MEMORY;
for (i = 0; i < XMS_MAX_HANDLES; i++)
{
HandleEntry = &HandleTable[i];
if (HandleEntry->Handle == 0)
{
*Handle = i + 1;
break;
}
}
if (i == XMS_MAX_HANDLES) return XMS_STATUS_OUT_OF_HANDLES;
HandleEntry->Handle = i + 1;
HandleEntry->LockCount = 0;
HandleEntry->Size = Size;
FreeBlocks -= Size;
return XMS_STATUS_SUCCESS;
}
static CHAR XmsFree(WORD Handle)
{
PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
if (HandleEntry->LockCount) return XMS_STATUS_LOCKED;
HandleEntry->Handle = 0;
FreeBlocks += HandleEntry->Size;
return XMS_STATUS_SUCCESS;
}
static CHAR XmsLock(WORD Handle, PDWORD Address)
{
DWORD CurrentIndex = 0;
PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
if (HandleEntry->LockCount == 0xFF) return XMS_STATUS_LOCK_OVERFLOW;
if (HandleEntry->LockCount)
{
/* Just increment the lock count */
HandleEntry->LockCount++;
return XMS_STATUS_SUCCESS;
}
while (CurrentIndex < XMS_BLOCKS)
{
ULONG RunStart;
ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart);
if (RunSize == 0) break;
if (RunSize >= HandleEntry->Size)
{
/* Lock it here */
HandleEntry->LockCount++;
HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE;
RtlSetBits(&AllocBitmap, RunStart, RunSize);
*Address = HandleEntry->Address;
return XMS_STATUS_SUCCESS;
}
/* Keep searching */
CurrentIndex = RunStart + RunSize;
}
/* Can't find any suitable range */
return XMS_STATUS_CANNOT_LOCK;
}
static CHAR XmsUnlock(WORD Handle)
{
DWORD BlockNumber;
PXMS_HANDLE HandleEntry = GetHandleRecord(Handle);
if (HandleEntry == NULL) return XMS_STATUS_INVALID_HANDLE;
if (!HandleEntry->LockCount) return XMS_STATUS_NOT_LOCKED;
/* Decrement the lock count and exit early if it's still locked */
if (--HandleEntry->LockCount) return XMS_STATUS_SUCCESS;
BlockNumber = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE;
RtlClearBits(&AllocBitmap, BlockNumber, HandleEntry->Size);
return XMS_STATUS_SUCCESS;
}
static VOID WINAPI XmsBopProcedure(LPWORD Stack) static VOID WINAPI XmsBopProcedure(LPWORD Stack)
{ {
switch (getAH()) switch (getAH())
@ -52,9 +161,85 @@ static VOID WINAPI XmsBopProcedure(LPWORD Stack)
break; break;
} }
/* Query Free Extended Memory */
case 0x08:
{
setAX(FreeBlocks);
setDX(XMS_BLOCKS);
setBL(XMS_STATUS_SUCCESS);
break;
}
/* Allocate Extended Memory Block */
case 0x09:
{
WORD Handle;
CHAR Result = XmsAlloc(getDX(), &Handle);
if (Result >= 0)
{
setAX(1);
setDX(Handle);
}
else
{
setAX(0);
setBL(Result);
}
break;
}
/* Free Extended Memory Block */
case 0x0A:
{
CHAR Result = XmsFree(getDX());
setAX(Result >= 0);
setBL(Result);
break;
}
/* Lock Extended Memory Block */
case 0x0C:
{
DWORD Address;
CHAR Result = XmsLock(getDX(), &Address);
if (Result >= 0)
{
setAX(1);
/* Store the LINEAR address in DX:BX */
setDX(HIWORD(Address));
setBX(LOWORD(Address));
}
else
{
setAX(0);
setBL(Result);
}
break;
}
/* Unlock Extended Memory Block */
case 0x0D:
{
CHAR Result = XmsUnlock(getDX());
setAX(Result >= 0);
setBL(Result);
break;
}
default: default:
{ {
DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH()); DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH());
setBL(XMS_STATUS_NOT_IMPLEMENTED);
} }
} }
} }
@ -70,6 +255,10 @@ BOOLEAN XmsGetDriverEntry(PDWORD Pointer)
VOID XmsInitialize(VOID) VOID XmsInitialize(VOID)
{ {
RtlZeroMemory(HandleTable, sizeof(HandleTable));
RtlZeroMemory(BitmapBuffer, sizeof(BitmapBuffer));
RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, XMS_BLOCKS);
Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER, Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER,
XMS_DEVICE_NAME, XMS_DEVICE_NAME,
sizeof(EntryProcedure)); sizeof(EntryProcedure));

View file

@ -6,6 +6,32 @@
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/ */
/* DEFINITIONS ****************************************************************/
#define XMS_ADDRESS 0x110000
#define XMS_BLOCKS 0x37C0
#define XMS_BLOCK_SIZE 1024
#define XMS_MAX_HANDLES 16
#define XMS_STATUS_SUCCESS 0x00
#define XMS_STATUS_NOT_IMPLEMENTED 0x80
#define XMS_STATUS_HMA_IN_USE 0x91
#define XMS_STATUS_OUT_OF_MEMORY 0xA0
#define XMS_STATUS_OUT_OF_HANDLES 0xA1
#define XMS_STATUS_INVALID_HANDLE 0xA2
#define XMS_STATUS_NOT_LOCKED 0xAA
#define XMS_STATUS_LOCKED 0xAB
#define XMS_STATUS_LOCK_OVERFLOW 0xAC
#define XMS_STATUS_CANNOT_LOCK 0xAD
typedef struct _XMS_HANDLE
{
BYTE Handle;
BYTE LockCount;
WORD Size;
DWORD Address;
} XMS_HANDLE, *PXMS_HANDLE;
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
BOOLEAN XmsGetDriverEntry(PDWORD Pointer); BOOLEAN XmsGetDriverEntry(PDWORD Pointer);