Author: aandrejevic Date: Wed Apr 22 03:10:11 2015 New Revision: 67340
URL: http://svn.reactos.org/svn/reactos?rev=67340&view=rev Log: [NTVDM] Implement basic XMS functions.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.c [iso-8859-1] Wed Apr 22 03:10:11 2015 @@ -17,6 +17,7 @@ #include "dos.h" #include "dos/dem.h" #include "device.h" +#include "himem.h"
#define XMS_DEVICE_NAME "XMSXXXX0" #define XMS_BOP 0x52 @@ -36,8 +37,116 @@ };
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 **********************************************************/ + +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) { @@ -52,9 +161,85 @@ 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: { DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH()); + setBL(XMS_STATUS_NOT_IMPLEMENTED); } } } @@ -70,6 +255,10 @@
VOID XmsInitialize(VOID) { + RtlZeroMemory(HandleTable, sizeof(HandleTable)); + RtlZeroMemory(BitmapBuffer, sizeof(BitmapBuffer)); + RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, XMS_BLOCKS); + Node = DosCreateDeviceEx(DOS_DEVATTR_IOCTL | DOS_DEVATTR_CHARACTER, XMS_DEVICE_NAME, sizeof(EntryProcedure));
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/himem.h [iso-8859-1] Wed Apr 22 03:10:11 2015 @@ -6,6 +6,32 @@ * 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 ******************************************************************/
BOOLEAN XmsGetDriverEntry(PDWORD Pointer);