2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Expanded Memory Support
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
14 #include "bios/bios32/bios32p.h"
15 #include <ndk/rtltypes.h>
16 #include <ndk/rtlfuncs.h>
20 /* PRIVATE VARIABLES **********************************************************/
22 static RTL_BITMAP AllocBitmap
;
23 static ULONG BitmapBuffer
[(EMS_TOTAL_PAGES
+ sizeof(ULONG
) - 1) / sizeof(ULONG
)];
24 static EMS_PAGE PageTable
[EMS_TOTAL_PAGES
];
25 static EMS_HANDLE HandleTable
[EMS_MAX_HANDLES
];
26 static PVOID Mapping
[EMS_PHYSICAL_PAGES
] = { NULL
};
28 /* PRIVATE FUNCTIONS **********************************************************/
30 static USHORT
EmsFree(USHORT Handle
)
33 PEMS_HANDLE HandleEntry
= &HandleTable
[Handle
];
35 if (Handle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
)
37 return EMS_STATUS_INVALID_HANDLE
;
40 for (Entry
= HandleEntry
->PageList
.Flink
;
41 Entry
!= &HandleEntry
->PageList
;
44 PEMS_PAGE PageEntry
= (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
45 ULONG PageNumber
= ARRAY_INDEX(PageEntry
, PageTable
);
48 RtlClearBits(&AllocBitmap
, PageNumber
, 1);
51 HandleEntry
->Allocated
= FALSE
;
52 HandleEntry
->PageCount
= 0;
53 InitializeListHead(&HandleEntry
->PageList
);
58 static UCHAR
EmsAlloc(USHORT NumPages
, PUSHORT Handle
)
60 ULONG i
, CurrentIndex
= 0;
61 PEMS_HANDLE HandleEntry
;
63 if (NumPages
== 0) return EMS_STATUS_ZERO_PAGES
;
65 for (i
= 0; i
< EMS_MAX_HANDLES
; i
++)
67 HandleEntry
= &HandleTable
[i
];
68 if (!HandleEntry
->Allocated
)
75 if (i
== EMS_MAX_HANDLES
) return EMS_STATUS_NO_MORE_HANDLES
;
76 HandleEntry
->Allocated
= TRUE
;
78 while (HandleEntry
->PageCount
< NumPages
)
81 ULONG RunSize
= RtlFindNextForwardRunClear(&AllocBitmap
, CurrentIndex
, &RunStart
);
85 /* Free what's been allocated already and report failure */
87 return EMS_STATUS_INSUFFICIENT_PAGES
;
89 else if ((HandleEntry
->PageCount
+ RunSize
) > NumPages
)
91 /* We don't need the entire run */
92 RunSize
= NumPages
- HandleEntry
->PageCount
;
95 CurrentIndex
= RunStart
+ RunSize
;
96 HandleEntry
->PageCount
+= RunSize
;
97 RtlSetBits(&AllocBitmap
, RunStart
, RunSize
);
99 for (i
= 0; i
< RunSize
; i
++)
101 PageTable
[RunStart
+ i
].Handle
= *Handle
;
102 InsertTailList(&HandleEntry
->PageList
, &PageTable
[RunStart
+ i
].Entry
);
106 return EMS_STATUS_OK
;
109 static PEMS_PAGE
GetLogicalPage(PEMS_HANDLE Handle
, USHORT LogicalPage
)
111 PLIST_ENTRY Entry
= Handle
->PageList
.Flink
;
115 if (Entry
== &Handle
->PageList
) return NULL
;
117 Entry
= Entry
->Flink
;
120 return (PEMS_PAGE
)CONTAINING_RECORD(Entry
, EMS_PAGE
, Entry
);
123 static USHORT
EmsMap(USHORT Handle
, UCHAR PhysicalPage
, USHORT LogicalPage
)
126 PEMS_HANDLE HandleEntry
= &HandleTable
[Handle
];
128 if (PhysicalPage
>= EMS_PHYSICAL_PAGES
) return EMS_STATUS_INV_PHYSICAL_PAGE
;
129 if (LogicalPage
== 0xFFFF)
132 Mapping
[PhysicalPage
] = NULL
;
133 return EMS_STATUS_OK
;
136 if (Handle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
) return EMS_STATUS_INVALID_HANDLE
;
138 PageEntry
= GetLogicalPage(HandleEntry
, LogicalPage
);
139 if (!PageEntry
) return EMS_STATUS_INV_LOGICAL_PAGE
;
141 Mapping
[PhysicalPage
] = (PVOID
)(EMS_ADDRESS
+ ARRAY_INDEX(PageEntry
, PageTable
) * EMS_PAGE_SIZE
);
142 return EMS_STATUS_OK
;
145 static VOID WINAPI
EmsIntHandler(LPWORD Stack
)
149 /* Get Manager Status */
152 setAH(EMS_STATUS_OK
);
156 /* Get Page Frame Segment */
159 setAH(EMS_STATUS_OK
);
164 /* Get Number Of Pages */
167 setAH(EMS_STATUS_OK
);
168 setBX(RtlNumberOfClearBits(&AllocBitmap
));
169 setDX(EMS_TOTAL_PAGES
);
173 /* Get Handle And Allocate Memory */
177 UCHAR Status
= EmsAlloc(getBX(), &Handle
);
180 if (Status
== EMS_STATUS_OK
) setDX(Handle
);
187 setAH(EmsMap(getDX(), getAL(), getBX()));
191 /* Release Handle And Memory */
194 setAH(EmsFree(getDX()));
198 /* Move/Exchange Memory */
201 PUCHAR SourcePtr
, DestPtr
;
202 PEMS_HANDLE HandleEntry
;
204 BOOLEAN Exchange
= getAL();
205 PEMS_COPY_DATA Data
= (PEMS_COPY_DATA
)SEG_OFF_TO_PTR(getDS(), getSI());
207 if (Data
->SourceType
)
209 /* Expanded memory */
210 HandleEntry
= &HandleTable
[Data
->SourceHandle
];
212 if (Data
->SourceHandle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
)
214 setAL(EMS_STATUS_INVALID_HANDLE
);
218 PageEntry
= GetLogicalPage(HandleEntry
, Data
->SourceSegment
);
222 setAL(EMS_STATUS_INV_LOGICAL_PAGE
);
226 SourcePtr
= (PUCHAR
)REAL_TO_PHYS(EMS_ADDRESS
227 + ARRAY_INDEX(PageEntry
, PageTable
)
229 + Data
->SourceOffset
);
233 /* Conventional memory */
234 SourcePtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->SourceSegment
, Data
->SourceOffset
);
239 /* Expanded memory */
240 HandleEntry
= &HandleTable
[Data
->DestHandle
];
242 if (Data
->SourceHandle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
)
244 setAL(EMS_STATUS_INVALID_HANDLE
);
248 PageEntry
= GetLogicalPage(HandleEntry
, Data
->DestSegment
);
252 setAL(EMS_STATUS_INV_LOGICAL_PAGE
);
256 DestPtr
= (PUCHAR
)REAL_TO_PHYS(EMS_ADDRESS
257 + ARRAY_INDEX(PageEntry
, PageTable
)
263 /* Conventional memory */
264 DestPtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->DestSegment
, Data
->DestOffset
);
272 for (i
= 0; i
< Data
->RegionLength
; i
++)
274 UCHAR Temp
= DestPtr
[i
];
275 DestPtr
[i
] = SourcePtr
[i
];
282 RtlMoveMemory(DestPtr
, SourcePtr
, Data
->RegionLength
);
285 setAL(EMS_STATUS_OK
);
291 DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
292 setAH(EMS_STATUS_UNKNOWN_FUNCTION
);
298 static VOID NTAPI
EmsReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
301 ULONG RelativeAddress
= Address
- TO_LINEAR(EMS_SEGMENT
, 0);
302 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
303 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
304 ULONG Offset
, Length
;
306 for (i
= FirstPage
; i
<= LastPage
; i
++)
308 Offset
= (i
== FirstPage
) ? Address
& (EMS_PAGE_SIZE
- 1) : 0;
309 Length
= ((i
== LastPage
)
310 ? (Address
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
311 : EMS_PAGE_SIZE
) - Offset
;
313 if (Mapping
[i
]) RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Length
);
314 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
318 static BOOLEAN NTAPI
EmsWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
321 ULONG RelativeAddress
= Address
- TO_LINEAR(EMS_SEGMENT
, 0);
322 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
323 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
324 ULONG Offset
, Length
;
326 for (i
= FirstPage
; i
<= LastPage
; i
++)
328 Offset
= (i
== FirstPage
) ? Address
& (EMS_PAGE_SIZE
- 1) : 0;
329 Length
= ((i
== LastPage
)
330 ? (Address
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
331 : EMS_PAGE_SIZE
) - Offset
;
333 if (Mapping
[i
]) RtlCopyMemory((PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Buffer
, Length
);
334 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
340 /* PUBLIC FUNCTIONS ***********************************************************/
342 VOID
EmsInitialize(VOID
)
346 RtlZeroMemory(BitmapBuffer
, sizeof(BitmapBuffer
));
347 RtlInitializeBitMap(&AllocBitmap
, BitmapBuffer
, EMS_TOTAL_PAGES
);
349 for (i
= 0; i
< EMS_MAX_HANDLES
; i
++)
351 HandleTable
[i
].Allocated
= FALSE
;
352 HandleTable
[i
].PageCount
= 0;
353 InitializeListHead(&HandleTable
[i
].PageList
);
356 MemInstallFastMemoryHook((PVOID
)TO_LINEAR(EMS_SEGMENT
, 0),
357 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
,
361 RegisterBiosInt32(EMS_INTERRUPT_NUM
, EmsIntHandler
);
364 VOID
EmsCleanup(VOID
)
366 MemRemoveFastMemoryHook((PVOID
)TO_LINEAR(EMS_SEGMENT
, 0),
367 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
);