2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: DOS XMS Driver
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
22 #define XMS_DEVICE_NAME "XMSXXXX0"
27 /* PRIVATE VARIABLES **********************************************************/
29 static const BYTE EntryProcedure
[] = {
30 0xEB, // jmp short +0x03
41 static PDOS_DEVICE_NODE Node
= NULL
;
42 static XMS_HANDLE HandleTable
[XMS_MAX_HANDLES
];
43 static WORD FreeBlocks
= XMS_BLOCKS
;
44 static RTL_BITMAP AllocBitmap
;
45 static ULONG BitmapBuffer
[(XMS_BLOCKS
+ 31) / 32];
47 /* PRIVATE FUNCTIONS **********************************************************/
49 static inline PXMS_HANDLE
GetHandleRecord(WORD Handle
)
52 if (Handle
== 0 || Handle
>= XMS_MAX_HANDLES
) return NULL
;
54 Entry
= &HandleTable
[Handle
- 1];
55 return Entry
->Size
? Entry
: NULL
;
58 static CHAR
XmsAlloc(WORD Size
, PWORD Handle
)
61 PXMS_HANDLE HandleEntry
;
63 if (Size
> FreeBlocks
) return XMS_STATUS_OUT_OF_MEMORY
;
65 for (i
= 0; i
< XMS_MAX_HANDLES
; i
++)
67 HandleEntry
= &HandleTable
[i
];
68 if (HandleEntry
->Handle
== 0)
75 if (i
== XMS_MAX_HANDLES
) return XMS_STATUS_OUT_OF_HANDLES
;
77 HandleEntry
->Handle
= i
+ 1;
78 HandleEntry
->LockCount
= 0;
79 HandleEntry
->Size
= Size
;
82 return XMS_STATUS_SUCCESS
;
85 static CHAR
XmsFree(WORD Handle
)
87 PXMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
88 if (HandleEntry
== NULL
) return XMS_STATUS_INVALID_HANDLE
;
89 if (HandleEntry
->LockCount
) return XMS_STATUS_LOCKED
;
91 HandleEntry
->Handle
= 0;
92 FreeBlocks
+= HandleEntry
->Size
;
94 return XMS_STATUS_SUCCESS
;
97 static CHAR
XmsLock(WORD Handle
, PDWORD Address
)
99 DWORD CurrentIndex
= 0;
100 PXMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
102 if (HandleEntry
== NULL
) return XMS_STATUS_INVALID_HANDLE
;
103 if (HandleEntry
->LockCount
== 0xFF) return XMS_STATUS_LOCK_OVERFLOW
;
105 if (HandleEntry
->LockCount
)
107 /* Just increment the lock count */
108 HandleEntry
->LockCount
++;
109 return XMS_STATUS_SUCCESS
;
112 while (CurrentIndex
< XMS_BLOCKS
)
115 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
116 if (RunSize
== 0) break;
118 if (RunSize
>= HandleEntry
->Size
)
121 HandleEntry
->LockCount
++;
122 HandleEntry
->Address
= XMS_ADDRESS
+ RunStart
* XMS_BLOCK_SIZE
;
124 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
125 *Address
= HandleEntry
->Address
;
126 return XMS_STATUS_SUCCESS
;
130 CurrentIndex
= RunStart
+ RunSize
;
133 /* Can't find any suitable range */
134 return XMS_STATUS_CANNOT_LOCK
;
137 static CHAR
XmsUnlock(WORD Handle
)
140 PXMS_HANDLE HandleEntry
= GetHandleRecord(Handle
);
142 if (HandleEntry
== NULL
) return XMS_STATUS_INVALID_HANDLE
;
143 if (!HandleEntry
->LockCount
) return XMS_STATUS_NOT_LOCKED
;
145 /* Decrement the lock count and exit early if it's still locked */
146 if (--HandleEntry
->LockCount
) return XMS_STATUS_SUCCESS
;
148 BlockNumber
= (HandleEntry
->Address
- XMS_ADDRESS
) / XMS_BLOCK_SIZE
;
149 RtlClearBits(&AllocBitmap
, BlockNumber
, HandleEntry
->Size
);
151 return XMS_STATUS_SUCCESS
;
154 static VOID WINAPI
XmsBopProcedure(LPWORD Stack
)
158 /* Get XMS Version */
161 setAX(0x0300); /* XMS version 3.0 */
162 setDX(0x0001); /* HMA present */
167 /* Global Enable A20 */
170 EmulatorSetA20(TRUE
);
174 /* Global Disable A20 */
177 EmulatorSetA20(FALSE
);
181 /* Query Free Extended Memory */
186 setBL(XMS_STATUS_SUCCESS
);
191 /* Allocate Extended Memory Block */
195 CHAR Result
= XmsAlloc(getDX(), &Handle
);
211 /* Free Extended Memory Block */
214 CHAR Result
= XmsFree(getDX());
222 /* Lock Extended Memory Block */
226 CHAR Result
= XmsLock(getDX(), &Address
);
232 /* Store the LINEAR address in DX:BX */
233 setDX(HIWORD(Address
));
234 setBX(LOWORD(Address
));
245 /* Unlock Extended Memory Block */
248 CHAR Result
= XmsUnlock(getDX());
258 DPRINT1("XMS command AH = 0x%02X NOT IMPLEMENTED\n", getAH());
259 setBL(XMS_STATUS_NOT_IMPLEMENTED
);
264 /* PUBLIC FUNCTIONS ***********************************************************/
266 BOOLEAN
XmsGetDriverEntry(PDWORD Pointer
)
268 if (Node
== NULL
) return FALSE
;
269 *Pointer
= DEVICE_PRIVATE_AREA(Node
->Driver
);
273 VOID
XmsInitialize(VOID
)
275 RtlZeroMemory(HandleTable
, sizeof(HandleTable
));
276 RtlZeroMemory(BitmapBuffer
, sizeof(BitmapBuffer
));
277 RtlInitializeBitMap(&AllocBitmap
, BitmapBuffer
, XMS_BLOCKS
);
279 Node
= DosCreateDeviceEx(DOS_DEVATTR_IOCTL
| DOS_DEVATTR_CHARACTER
,
281 sizeof(EntryProcedure
));
283 RegisterBop(BOP_XMS
, XmsBopProcedure
);
285 /* Copy the entry routine to the device private area */
286 RtlMoveMemory(FAR_POINTER(DEVICE_PRIVATE_AREA(Node
->Driver
)),
288 sizeof(EntryProcedure
));
291 VOID
XmsCleanup(VOID
)
293 RegisterBop(BOP_XMS
, NULL
);
294 DosDeleteDevice(Node
);