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 /* Get EMM Version */
201 setAH(EMS_STATUS_OK
);
202 setAL(EMS_VERSION_NUM
);
206 /* Move/Exchange Memory */
209 PUCHAR SourcePtr
, DestPtr
;
210 PEMS_HANDLE HandleEntry
;
212 BOOLEAN Exchange
= getAL();
213 PEMS_COPY_DATA Data
= (PEMS_COPY_DATA
)SEG_OFF_TO_PTR(getDS(), getSI());
215 if (Data
->SourceType
)
217 /* Expanded memory */
218 HandleEntry
= &HandleTable
[Data
->SourceHandle
];
220 if (Data
->SourceHandle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
)
222 setAL(EMS_STATUS_INVALID_HANDLE
);
226 PageEntry
= GetLogicalPage(HandleEntry
, Data
->SourceSegment
);
230 setAL(EMS_STATUS_INV_LOGICAL_PAGE
);
234 SourcePtr
= (PUCHAR
)REAL_TO_PHYS(EMS_ADDRESS
235 + ARRAY_INDEX(PageEntry
, PageTable
)
237 + Data
->SourceOffset
);
241 /* Conventional memory */
242 SourcePtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->SourceSegment
, Data
->SourceOffset
);
247 /* Expanded memory */
248 HandleEntry
= &HandleTable
[Data
->DestHandle
];
250 if (Data
->SourceHandle
>= EMS_MAX_HANDLES
|| !HandleEntry
->Allocated
)
252 setAL(EMS_STATUS_INVALID_HANDLE
);
256 PageEntry
= GetLogicalPage(HandleEntry
, Data
->DestSegment
);
260 setAL(EMS_STATUS_INV_LOGICAL_PAGE
);
264 DestPtr
= (PUCHAR
)REAL_TO_PHYS(EMS_ADDRESS
265 + ARRAY_INDEX(PageEntry
, PageTable
)
271 /* Conventional memory */
272 DestPtr
= (PUCHAR
)SEG_OFF_TO_PTR(Data
->DestSegment
, Data
->DestOffset
);
280 for (i
= 0; i
< Data
->RegionLength
; i
++)
282 UCHAR Temp
= DestPtr
[i
];
283 DestPtr
[i
] = SourcePtr
[i
];
290 RtlMoveMemory(DestPtr
, SourcePtr
, Data
->RegionLength
);
293 setAL(EMS_STATUS_OK
);
299 DPRINT1("EMS function AH = %02X NOT IMPLEMENTED\n", getAH());
300 setAH(EMS_STATUS_UNKNOWN_FUNCTION
);
306 static VOID NTAPI
EmsReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
309 ULONG RelativeAddress
= Address
- TO_LINEAR(EMS_SEGMENT
, 0);
310 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
311 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
312 ULONG Offset
, Length
;
314 for (i
= FirstPage
; i
<= LastPage
; i
++)
316 Offset
= (i
== FirstPage
) ? Address
& (EMS_PAGE_SIZE
- 1) : 0;
317 Length
= ((i
== LastPage
)
318 ? (Address
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
319 : EMS_PAGE_SIZE
) - Offset
;
321 if (Mapping
[i
]) RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Length
);
322 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
326 static BOOLEAN NTAPI
EmsWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
329 ULONG RelativeAddress
= Address
- TO_LINEAR(EMS_SEGMENT
, 0);
330 ULONG FirstPage
= RelativeAddress
/ EMS_PAGE_SIZE
;
331 ULONG LastPage
= (RelativeAddress
+ Size
- 1) / EMS_PAGE_SIZE
;
332 ULONG Offset
, Length
;
334 for (i
= FirstPage
; i
<= LastPage
; i
++)
336 Offset
= (i
== FirstPage
) ? Address
& (EMS_PAGE_SIZE
- 1) : 0;
337 Length
= ((i
== LastPage
)
338 ? (Address
+ Size
- (LastPage
<< EMS_PAGE_BITS
))
339 : EMS_PAGE_SIZE
) - Offset
;
341 if (Mapping
[i
]) RtlCopyMemory((PVOID
)((ULONG_PTR
)Mapping
[i
] + Offset
), Buffer
, Length
);
342 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Length
);
348 /* PUBLIC FUNCTIONS ***********************************************************/
350 VOID
EmsInitialize(VOID
)
354 RtlZeroMemory(BitmapBuffer
, sizeof(BitmapBuffer
));
355 RtlInitializeBitMap(&AllocBitmap
, BitmapBuffer
, EMS_TOTAL_PAGES
);
357 for (i
= 0; i
< EMS_MAX_HANDLES
; i
++)
359 HandleTable
[i
].Allocated
= FALSE
;
360 HandleTable
[i
].PageCount
= 0;
361 InitializeListHead(&HandleTable
[i
].PageList
);
364 MemInstallFastMemoryHook((PVOID
)TO_LINEAR(EMS_SEGMENT
, 0),
365 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
,
369 RegisterBiosInt32(EMS_INTERRUPT_NUM
, EmsIntHandler
);
372 VOID
EmsCleanup(VOID
)
374 MemRemoveFastMemoryHook((PVOID
)TO_LINEAR(EMS_SEGMENT
, 0),
375 EMS_PHYSICAL_PAGES
* EMS_PAGE_SIZE
);