2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/bios/umamgr.c
5 * PURPOSE: Upper Memory Area Manager
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 * NOTE: The UMA Manager is used by the DOS XMS Driver (UMB Provider part),
9 * indirectly by the DOS EMS Driver, and by VDD memory management functions.
17 /* PRIVATE VARIABLES **********************************************************/
19 typedef struct _UMA_DESCRIPTOR
25 } UMA_DESCRIPTOR
, *PUMA_DESCRIPTOR
;
28 * Sorted list of UMA descriptors.
30 * The descriptor list is (and must always be) sorted by memory addresses,
31 * and all consecutive free descriptors are always merged together, so that
32 * free ones are always separated from each other by descriptors of other types.
34 * TODO: Add the fact that no blocks of size == 0 are allowed.
36 static LIST_ENTRY UmaDescriptorList
= { &UmaDescriptorList
, &UmaDescriptorList
};
38 /* PRIVATE FUNCTIONS **********************************************************/
40 static PUMA_DESCRIPTOR
41 CreateUmaDescriptor(IN OUT PLIST_ENTRY ListHead
,
44 IN UMA_DESC_TYPE Type
)
46 PUMA_DESCRIPTOR UmaDesc
;
50 UmaDesc
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*UmaDesc
));
51 if (!UmaDesc
) return NULL
;
53 UmaDesc
->Start
= Address
;
58 * We use the trick of http://www.osronline.com/article.cfm?article=499 to insert
59 * the new descriptor just after the current entry that we specify via 'ListHead'.
60 * If 'ListHead' is NULL then we insert the descriptor at the tail of 'UmaDescriptorList'
61 * (which is equivalent to inserting it at the head of 'UmaDescriptorList.Blink').
63 if (ListHead
== NULL
) ListHead
= UmaDescriptorList
.Blink
;
64 InsertHeadList(ListHead
, &UmaDesc
->Entry
);
69 static VOID
FreeUmaDescriptor(PUMA_DESCRIPTOR UmaDesc
)
71 RemoveEntryList(&UmaDesc
->Entry
);
72 RtlFreeHeap(RtlGetProcessHeap(), 0, UmaDesc
);
75 /* PUBLIC FUNCTIONS ***********************************************************/
77 BOOLEAN
UmaDescReserve(IN OUT PUSHORT Segment
, IN OUT PUSHORT Size
)
79 ULONG Address
= (*Segment
<< 4); // Convert segment number into address.
80 ULONG RequestSize
= (*Size
<< 4); // Convert size in paragraphs into size in bytes.
83 PUMA_DESCRIPTOR UmaDesc
, NewUmaDesc
;
84 PUMA_DESCRIPTOR FoundUmaDesc
= NULL
;
86 // FIXME: Check! What to do?
87 if (RequestSize
== 0) DPRINT1("Requesting UMA descriptor with null size?!\n");
89 Entry
= UmaDescriptorList
.Flink
;
90 while (Entry
!= &UmaDescriptorList
)
92 UmaDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(Entry
, UMA_DESCRIPTOR
, Entry
);
95 /* Only check free descriptors */
96 if (UmaDesc
->Type
!= UMA_FREE
) continue;
98 /* Update the maximum descriptor size */
99 if (UmaDesc
->Size
> MaxSize
) MaxSize
= UmaDesc
->Size
;
101 /* Descriptor too small, continue... */
102 if (UmaDesc
->Size
< RequestSize
) continue;
104 /* Do we want to reserve the descriptor at a precise address? */
107 /* If the descriptor ends before the desired region, try again */
108 if (UmaDesc
->Start
+ UmaDesc
->Size
<= Address
) continue;
111 * If we have a descriptor, but one of its boundaries crosses the
112 * desired region (it starts after the desired region, or ends
113 * before the end of the desired region), this means that there
114 * is already something inside the region, so that we cannot
115 * allocate the region here. Bail out.
117 if (UmaDesc
->Start
> Address
||
118 UmaDesc
->Start
+ UmaDesc
->Size
< Address
+ RequestSize
)
123 /* We now have a free descriptor that overlaps our desired region: split it */
126 * Here, UmaDesc->Start == Address or UmaDesc->Start < Address,
127 * in which case we need to split the descriptor to the left.
129 if (UmaDesc
->Start
< Address
)
131 /* Create a new free descriptor and insert it after the current one */
132 NewUmaDesc
= CreateUmaDescriptor(&UmaDesc
->Entry
,
134 UmaDesc
->Size
- (Address
- UmaDesc
->Start
),
135 UmaDesc
->Type
); // UMA_FREE
138 DPRINT1("CreateUmaDescriptor failed, UMA descriptor list possibly corrupted!\n");
142 /* Reduce the size of the splitted left descriptor */
143 UmaDesc
->Size
= (Address
- UmaDesc
->Start
);
145 /* Current descriptor is now the new created one */
146 UmaDesc
= NewUmaDesc
;
149 /* Here, UmaDesc->Start == Address */
152 /* Descriptor of large enough size: split it to the right if needed */
153 // FIXME: It might be needed to consider a minimum size starting which we need to split.
154 // if (UmaDesc->Size - RequestSize > (3 << 4))
155 if (UmaDesc
->Size
> RequestSize
)
158 * Create a new free descriptor and insert it after the current one.
159 * Because consecutive free descriptors are always merged together,
160 * the descriptor following 'UmaDesc' cannot be free, so that this
161 * new free descriptor does not need to be merged with some others.
163 NewUmaDesc
= CreateUmaDescriptor(&UmaDesc
->Entry
,
164 UmaDesc
->Start
+ RequestSize
,
165 UmaDesc
->Size
- RequestSize
,
166 UmaDesc
->Type
); // UMA_FREE
169 DPRINT1("CreateUmaDescriptor failed, UMA descriptor list possibly corrupted!\n");
173 /* Reduce the size of the splitted left descriptor */
174 UmaDesc
->Size
= RequestSize
;
177 /* We have a descriptor of correct size, initialize it */
178 UmaDesc
->Type
= UMA_UMB
;
179 FoundUmaDesc
= UmaDesc
;
185 /* Returned address is a segment and size is in paragraphs */
186 *Segment
= (FoundUmaDesc
->Start
>> 4);
187 *Size
= (FoundUmaDesc
->Size
>> 4);
193 /* Returned address is a segment and size is in paragraphs */
195 *Size
= (MaxSize
>> 4);
200 BOOLEAN
UmaDescRelease(IN USHORT Segment
)
202 ULONG Address
= (Segment
<< 4); // Convert segment number into address.
203 PLIST_ENTRY Entry
, PrevEntry
, NextEntry
;
204 PUMA_DESCRIPTOR UmaDesc
, PrevDesc
= NULL
, NextDesc
= NULL
;
205 PUMA_DESCRIPTOR FoundUmaDesc
= NULL
;
207 Entry
= UmaDescriptorList
.Flink
;
208 while (Entry
!= &UmaDescriptorList
)
210 UmaDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(Entry
, UMA_DESCRIPTOR
, Entry
);
211 Entry
= Entry
->Flink
;
213 /* Search for the descriptor in the list */
214 if (UmaDesc
->Start
== Address
&& UmaDesc
->Type
== UMA_UMB
)
217 FoundUmaDesc
= UmaDesc
;
224 FoundUmaDesc
->Type
= UMA_FREE
;
226 /* Combine free descriptors adjacent to this one */
227 PrevEntry
= FoundUmaDesc
->Entry
.Blink
;
228 NextEntry
= FoundUmaDesc
->Entry
.Flink
;
230 if (PrevEntry
!= &UmaDescriptorList
)
231 PrevDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(PrevEntry
, UMA_DESCRIPTOR
, Entry
);
232 if (NextEntry
!= &UmaDescriptorList
)
233 NextDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(NextEntry
, UMA_DESCRIPTOR
, Entry
);
235 if (NextDesc
&& NextDesc
->Type
== FoundUmaDesc
->Type
) // UMA_FREE
237 FoundUmaDesc
->Size
+= NextDesc
->Size
;
238 FreeUmaDescriptor(NextDesc
);
241 if (PrevDesc
&& PrevDesc
->Type
== FoundUmaDesc
->Type
) // UMA_FREE
243 PrevDesc
->Size
+= FoundUmaDesc
->Size
;
244 FreeUmaDescriptor(FoundUmaDesc
);
253 BOOLEAN
UmaDescReallocate(IN USHORT Segment
, IN OUT PUSHORT Size
)
255 ULONG Address
= (Segment
<< 4); // Convert segment number into address.
256 ULONG RequestSize
= (*Size
<< 4); // Convert size in paragraphs into size in bytes.
258 PLIST_ENTRY Entry
, NextEntry
;
259 PUMA_DESCRIPTOR UmaDesc
, NextDesc
= NULL
, NewUmaDesc
;
260 PUMA_DESCRIPTOR FoundUmaDesc
= NULL
;
262 // FIXME: Check! What to do?
263 if (RequestSize
== 0) DPRINT1("Resizing UMA descriptor %04X to null size?!\n", Segment
);
265 Entry
= UmaDescriptorList
.Flink
;
266 while (Entry
!= &UmaDescriptorList
)
268 UmaDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(Entry
, UMA_DESCRIPTOR
, Entry
);
269 Entry
= Entry
->Flink
;
271 /* Only get the maximum size of free descriptors */
272 if (UmaDesc
->Type
== UMA_FREE
)
274 /* Update the maximum descriptor size */
275 if (UmaDesc
->Size
> MaxSize
) MaxSize
= UmaDesc
->Size
;
278 /* Search for the descriptor in the list */
279 if (UmaDesc
->Start
== Address
&& UmaDesc
->Type
== UMA_UMB
)
282 FoundUmaDesc
= UmaDesc
;
289 /* If we do not resize anything, just quit with success */
290 if (FoundUmaDesc
->Size
== RequestSize
) goto Success
;
292 NextEntry
= FoundUmaDesc
->Entry
.Flink
;
294 if (NextEntry
!= &UmaDescriptorList
)
295 NextDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(NextEntry
, UMA_DESCRIPTOR
, Entry
);
297 /* Check for reduction or enlargement */
298 if (FoundUmaDesc
->Size
> RequestSize
)
303 * Check if the next descriptor is free, in which case we
304 * extend it, otherwise we create a new free descriptor.
306 if (NextDesc
&& NextDesc
->Type
== UMA_FREE
)
308 /* Yes it is, expand its size and move it down */
309 NextDesc
->Size
+= (FoundUmaDesc
->Size
- RequestSize
);
310 NextDesc
->Start
-= (FoundUmaDesc
->Size
- RequestSize
);
314 // FIXME: It might be needed to consider a minimum size starting which we need to split.
315 // if (FoundUmaDesc->Size - RequestSize > (3 << 4))
317 /* Create a new free descriptor and insert it after the current one */
318 NewUmaDesc
= CreateUmaDescriptor(&FoundUmaDesc
->Entry
,
319 FoundUmaDesc
->Start
+ RequestSize
,
320 FoundUmaDesc
->Size
- RequestSize
,
324 DPRINT1("CreateUmaDescriptor failed, UMA descriptor list possibly corrupted!\n");
330 else // if (FoundUmaDesc->Size <= RequestSize)
334 /* Check whether the next descriptor is free and large enough for merging */
335 if (NextDesc
&& NextDesc
->Type
== UMA_FREE
&&
336 FoundUmaDesc
->Size
+ NextDesc
->Size
>= RequestSize
)
338 /* Yes it is, reduce its size and move it up, and enlarge the reallocated descriptor */
339 NextDesc
->Size
-= (RequestSize
- FoundUmaDesc
->Size
);
340 NextDesc
->Start
+= (RequestSize
- FoundUmaDesc
->Size
);
342 if (NextDesc
->Size
== 0) FreeUmaDescriptor(NextDesc
);
351 /* Finally, resize the descriptor */
352 FoundUmaDesc
->Size
= RequestSize
;
355 /* Returned size is in paragraphs */
356 *Size
= (FoundUmaDesc
->Size
>> 4);
362 /* Returned size is in paragraphs */
363 *Size
= (MaxSize
>> 4);
368 BOOLEAN
UmaMgrInitialize(VOID
)
371 #define ROM_AREA_START 0xE0000
372 #define ROM_AREA_END 0xFFFFF
374 #define OPTION_ROM_SIGNATURE 0xAA55
376 PUMA_DESCRIPTOR UmaDesc
= NULL
;
377 ULONG StartAddress
= 0;
379 UMA_DESC_TYPE Type
= UMA_FREE
;
388 // ULONG RomStart[] = {};
389 // ULONG RomEnd[] = {};
390 ULONG RomBoundaries
[] = {0xA0000, 0xC0000, /*0xC8000, 0xE0000,*/ 0xF0000, 0x100000};
391 ULONG SizeIncrement
[] = {0x20000, 0x00800, /*0x00800, 0x10000,*/ 0x10000, 0x0000 };
393 // InitializeListHead(&UmaDescriptorList);
395 /* NOTE: There must be always one UMA descriptor at least */
396 // FIXME: Maybe it should be a static object?
398 for (i
= 0; i
< ARRAYSIZE(RomBoundaries
) - 1; i
++)
400 Start
= RomBoundaries
[i
]; // RomStart[i]
401 End
= RomBoundaries
[i
+1]; // RomEnd[i]
402 Increment
= SizeIncrement
[i
];
404 for (Address
= Start
; Address
< End
; Address
+= Increment
)
406 if (StartAddress
== 0)
408 /* Initialize data for a new descriptor */
409 StartAddress
= Address
;
414 /* Is it a normal system zone/user-excluded zone? */
415 if (Address
>= 0xA0000 && Address
< 0xC0000)
417 // StartAddress = Address;
421 /* Create descriptor */
422 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
423 if (!UmaDesc
) return FALSE
;
428 /* Is it the PC ROM BIOS? */
429 else if (Address
>= 0xF0000)
431 // StartAddress = Address;
432 Size
= 0x10000; // Increment;
435 /* Create descriptor */
436 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
437 if (!UmaDesc
) return FALSE
;
442 /* Is it an option ROM? */
443 else if (Address
>= 0xC0000 && Address
< 0xF0000)
446 ULONG PrevRomAddress
= 0;
447 ULONG PrevRomSize
= 0;
449 // while (Address < 0xF0000)
450 for (; Address
< 0xF0000; Address
+= Increment
)
453 #if 0 // FIXME: Is this block, better here...
455 // We may be looping inside a ROM block, if: Type == 2 and:
456 // (StartAddress <= Address &&) StartAddress + Size > Address.
457 // In this case, do nothing (do not increase size either)
458 // But if we are now outside of a ROM block, then we need
459 // to create the previous block, and initialize a new empty one!
460 // (and following the next passages, increase its size).
462 // if (StartAddress < Address && Type != 2)
463 if (Type
== UMA_ROM
&& StartAddress
+ Size
> Address
)
465 /* We are inside ROM, do nothing */
467 else if (Type
== UMA_ROM
&& StartAddress
+ Size
<= Address
)
469 /* We finished a ROM descriptor */
471 /* Create descriptor */
472 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
473 if (!UmaDesc
) return FALSE
;
478 else if (Type
!= UMA_ROM
)
486 /// if (Address >= 0xE0000) { Increment = 0x10000; }
488 if (StartAddress
== 0)
490 /* Initialize data for a new descriptor */
491 StartAddress
= Address
;
499 if (*(PUSHORT
)REAL_TO_PHYS(Address
) == OPTION_ROM_SIGNATURE
)
502 * If this is an adapter ROM (Start: C8000, End: E0000),
503 * its reported size is stored in byte 2 of the ROM.
505 * If this is an expansion ROM (Start: E0000, End: F0000),
506 * its real length is 64kB.
508 RomSize
= *(PUCHAR
)REAL_TO_PHYS(Address
+ 2) * 512;
509 // if (Address >= 0xE0000) RomSize = 0x10000;
510 if (Address
>= 0xE0000) { RomSize
= 0x10000; Increment
= RomSize
; }
512 DPRINT1("ROM present @ address 0x%p\n", Address
);
514 if (StartAddress
!= 0 && Size
!= 0 &&
515 StartAddress
+ Size
<= Address
)
517 /* Finish old descriptor */
518 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
519 if (!UmaDesc
) return FALSE
;
523 * We may have overlapping ROMs, when PrevRomAddress + PrevRomSize > RomAddress.
524 * They must be put inside the same UMA descriptor.
526 if (PrevRomAddress
+ PrevRomSize
> /*Rom*/Address
)
531 * PrevRomAddress remains the same, but adjust
532 * PrevRomSize (ROM descriptors merging).
534 PrevRomSize
= max(PrevRomSize
, RomSize
+ Address
- PrevRomAddress
);
536 // FIX: Confirm that the start address is really
537 // the one of the previous descriptor.
538 StartAddress
= PrevRomAddress
;
544 // Non-overlapping ROM
546 PrevRomAddress
= Address
;
547 PrevRomSize
= RomSize
;
549 /* Initialize a new descriptor. We will create it when it's OK */
550 StartAddress
= Address
;
556 #if 1 // FIXME: ...or there??
559 // We may be looping inside a ROM block, if: Type == 2 and:
560 // (StartAddress <= Address &&) StartAddress + Size > Address.
561 // In this case, do nothing (do not increase size either)
562 // But if we are now outside of a ROM block, then we need
563 // to create the previous block, and initialize a new empty one!
564 // (and following the next passages, increase its size).
566 // if (StartAddress < Address && Type != UMA_ROM)
567 if (Type
== UMA_ROM
&& StartAddress
+ Size
> Address
)
569 // We are inside ROM, do nothing
571 else if (Type
== UMA_ROM
&& StartAddress
+ Size
<= Address
)
573 // We finished a ROM descriptor.
575 /* Create descriptor */
576 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
577 if (!UmaDesc
) return FALSE
;
582 else if (Type
!= UMA_ROM
)
589 // Fixed incroment; we may encounter again overlapping ROMs, etc.
590 // Address += Increment;
593 if (StartAddress
!= 0 && Size
!= 0)
595 /* Create descriptor */
596 UmaDesc
= CreateUmaDescriptor(NULL
, StartAddress
, Size
, Type
);
597 if (!UmaDesc
) return FALSE
;
609 VOID
UmaMgrCleanup(VOID
)
611 PUMA_DESCRIPTOR UmaDesc
;
613 while (!IsListEmpty(&UmaDescriptorList
))
615 UmaDesc
= (PUMA_DESCRIPTOR
)CONTAINING_RECORD(UmaDescriptorList
.Flink
, UMA_DESCRIPTOR
, Entry
);
616 FreeUmaDescriptor(UmaDesc
);