2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: boot/freeldr/freeldr/windows/wlmemory.c
5 * PURPOSE: Memory related routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES ***************************************************************/
16 DBG_DEFAULT_CHANNEL(WINDOWS
);
18 extern ULONG LoaderPagesSpanned
;
20 static const PCSTR MemTypeDesc
[] = {
21 "ExceptionBlock ", // ?
25 "LoadedProgram ", // == Free
26 "FirmwareTemporary ", // == Free
27 "FirmwarePermanent ", // == Bad
28 "OsloaderHeap ", // used
29 "OsloaderStack ", // == Free
32 "BootDriver ", // not used
33 "ConsoleInDriver ", // ?
34 "ConsoleOutDriver ", // ?
35 "StartupDpcStack ", // ?
36 "StartupKernelStack", // ?
37 "StartupPanicStack ", // ?
38 "StartupPcrPage ", // ?
39 "StartupPdrPage ", // ?
40 "RegistryData ", // used
41 "MemoryData ", // not used
43 "SpecialMemory ", // == Bad
44 "BBTMemory " // == Bad
48 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
49 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
);
51 extern PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap
;
52 extern ULONG BiosMemoryMapEntryCount
;
53 extern PFN_NUMBER MmLowestPhysicalPage
;
54 extern PFN_NUMBER MmHighestPhysicalPage
;
56 /* GLOBALS ***************************************************************/
58 MEMORY_ALLOCATION_DESCRIPTOR
*Mad
;
60 /* 200 MADs fit into 1 page, that should really be enough! */
61 #define MAX_MAD_COUNT 200
63 /* FUNCTIONS **************************************************************/
66 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
71 TRACE("MempAddMemoryBlock(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
72 BasePage
, PageCount
, Type
);
74 /* Check for memory block after 4GB - we don't support it yet
75 Note: Even last page before 4GB limit is not supported */
76 if (BasePage
>= MM_MAX_PAGE
)
78 /* Just skip this, without even adding to MAD list */
82 /* Check if last page is after 4GB limit and shorten this block if needed */
83 if (BasePage
+ PageCount
> MM_MAX_PAGE
)
85 /* Shorten this block */
86 PageCount
= MM_MAX_PAGE
- BasePage
;
89 /* Check if we have slots left */
90 if (MadCount
>= MAX_MAD_COUNT
)
92 ERR("Error: no MAD slots left!\n");
96 /* Set Base page, page count and type */
97 Mad
[MadCount
].BasePage
= BasePage
;
98 Mad
[MadCount
].PageCount
= PageCount
;
99 Mad
[MadCount
].MemoryType
= Type
;
102 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
107 MempSetupPagingForRegion(
109 PFN_NUMBER PageCount
,
112 BOOLEAN Status
= TRUE
;
114 TRACE("MempSetupPagingForRegion(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
115 BasePage
, PageCount
, Type
);
117 /* Make sure we don't map too high */
118 if (BasePage
+ PageCount
> LoaderPagesSpanned
) return;
122 /* Pages used by the loader */
123 case LoaderLoadedProgram
:
124 case LoaderOsloaderStack
:
125 case LoaderFirmwareTemporary
:
126 /* Map these pages into user mode */
127 Status
= MempSetupPaging(BasePage
, PageCount
, FALSE
);
130 /* Pages used by the kernel */
131 case LoaderExceptionBlock
:
132 case LoaderSystemBlock
:
133 case LoaderFirmwarePermanent
:
134 case LoaderSystemCode
:
136 case LoaderBootDriver
:
137 case LoaderConsoleInDriver
:
138 case LoaderConsoleOutDriver
:
139 case LoaderStartupDpcStack
:
140 case LoaderStartupKernelStack
:
141 case LoaderStartupPanicStack
:
142 case LoaderStartupPcrPage
:
143 case LoaderStartupPdrPage
:
144 case LoaderRegistryData
:
145 case LoaderMemoryData
:
148 case LoaderOsloaderHeap
: // FIXME
149 /* Map these pages into kernel mode */
150 Status
= MempSetupPaging(BasePage
, PageCount
, TRUE
);
153 /* Pages not in use */
158 /* Invisible to kernel */
159 case LoaderSpecialMemory
:
160 case LoaderHALCachedMemory
:
161 case LoaderBBTMemory
:
164 // FIXME: not known (not used anyway)
166 case LoaderLargePageFiller
:
167 case LoaderErrorLogMemory
:
173 ERR("Error during MempSetupPaging\n");
182 WinLdrSetupMemoryLayout(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
)
184 PFN_NUMBER i
, PagesCount
, MemoryMapSizeInPages
, NoEntries
;
185 PFN_NUMBER LastPageIndex
, MemoryMapStartPage
;
186 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
192 FrLdrHeapCleanupAll();
195 // Creating a suitable memory map for Windows can be tricky, so let's
196 // give a few advices:
197 // 1) One must not map the whole available memory pages to PDE!
198 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
199 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
200 // the same quantity for KSEG0_BASE mapping, one more entry for
201 // hyperspace and one more entry for HAL physical pages mapping.
202 // 2) Memory descriptors must map *the whole* physical memory
203 // showing any memory above 16/24/32 as FirmwareTemporary
205 // 3) Overall memory blocks count must not exceed 30 (?? why?)
209 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
210 // 0xC0300000 - 0xC03007FC
212 // Then it finds the best place for non-paged pool:
213 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
216 // Allocate memory for memory allocation descriptors
217 Mad
= MmAllocateMemoryWithType(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * MAX_MAD_COUNT
,
220 // Setup an entry for each descriptor
221 MemoryMap
= MmGetMemoryMap(&NoEntries
);
222 if (MemoryMap
== NULL
)
224 UiMessageBox("Can not retrieve the current memory map.");
228 // Calculate parameters of the memory map
229 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
230 MemoryMapSizeInPages
= (NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
) + MM_PAGE_SIZE
- 1) / MM_PAGE_SIZE
;
232 TRACE("Got memory map with %d entries\n", NoEntries
);
234 // Always contiguously map low 1Mb of memory
235 Status
= MempSetupPaging(0, 0x100, FALSE
);
238 ERR("Error during MempSetupPaging of low 1Mb\n");
243 /* Before creating the map, we need to map pages to kernel mode */
245 LastPageType
= MemoryMap
[1].PageAllocated
;
246 for (i
= 2; i
< NoEntries
; i
++)
248 if ((MemoryMap
[i
].PageAllocated
!= LastPageType
) ||
249 (i
== NoEntries
- 1))
251 MempSetupPagingForRegion(LastPageIndex
, i
- LastPageIndex
, LastPageType
);
253 LastPageType
= MemoryMap
[i
].PageAllocated
;
257 // Construct a good memory map from what we've got,
258 // but mark entries which the memory allocation bitmap takes
259 // as free entries (this is done in order to have the ability
260 // to place mem alloc bitmap outside lower 16Mb zone)
263 LastPageType
= MemoryMap
[0].PageAllocated
;
264 for (i
= 1; i
< NoEntries
; i
++)
266 // Check if its memory map itself
267 if (i
>= MemoryMapStartPage
&&
268 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
270 // Exclude it if current page belongs to the memory map
271 MemoryMap
[i
].PageAllocated
= LoaderFree
;
275 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
282 // Add the resulting region
283 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
285 // Reset our counter vars
287 LastPageType
= MemoryMap
[i
].PageAllocated
;
293 // adding special reserved memory zones for vmware workstation
296 Mad
[MadCount
].BasePage
= 0xfec00;
297 Mad
[MadCount
].PageCount
= 0x10;
298 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
299 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
302 Mad
[MadCount
].BasePage
= 0xfee00;
303 Mad
[MadCount
].PageCount
= 0x1;
304 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
305 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
308 Mad
[MadCount
].BasePage
= 0xfffe0;
309 Mad
[MadCount
].PageCount
= 0x20;
310 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
311 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
316 /* Now we need to add high descriptors from the bios memory map */
317 for (i
= 0; i
< BiosMemoryMapEntryCount
; i
++)
319 /* Check if its higher than the lookup table */
320 if (BiosMemoryMap
->BasePage
> MmHighestPhysicalPage
)
322 /* Copy this descriptor */
323 MempAddMemoryBlock(LoaderBlock
,
324 BiosMemoryMap
->BasePage
,
325 BiosMemoryMap
->PageCount
,
326 BiosMemoryMap
->MemoryType
);
330 TRACE("MadCount: %d\n", MadCount
);
332 WinLdrpDumpMemoryDescriptors(LoaderBlock
); //FIXME: Delete!
334 // Map our loader image, so we can continue running
335 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
338 UiMessageBox("Error during MempSetupPaging.");
342 // Fill the memory descriptor list and
343 //PrepareMemoryDescriptorList();
344 TRACE("Memory Descriptor List prepared, printing PDE\n");
345 List_PaToVa(&LoaderBlock
->MemoryDescriptorListHead
);
354 // Two special things this func does: it sorts descriptors,
355 // and it merges free ones
357 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
358 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
360 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
361 PLIST_ENTRY PreviousEntry
, NextEntry
;
362 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
364 TRACE("BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
365 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
367 /* Find a place where to insert the new descriptor to */
368 PreviousEntry
= ListHead
;
369 NextEntry
= ListHead
->Flink
;
370 while (NextEntry
!= ListHead
)
372 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
373 MEMORY_ALLOCATION_DESCRIPTOR
,
375 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
378 PreviousEntry
= NextEntry
;
379 PreviousDescriptor
= NextDescriptor
;
380 NextEntry
= NextEntry
->Flink
;
383 /* Don't forget about merging free areas */
384 if (NewDescriptor
->MemoryType
!= LoaderFree
)
386 /* Just insert, nothing to merge */
387 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
391 /* Previous block also free? */
392 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
393 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
394 NewDescriptor
->BasePage
))
396 /* Just enlarge previous descriptor's PageCount */
397 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
398 NewDescriptor
= PreviousDescriptor
;
402 /* Nope, just insert */
403 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
406 /* Next block is free ?*/
407 if ((NextEntry
!= ListHead
) &&
408 (NextDescriptor
->MemoryType
== LoaderFree
) &&
409 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
411 /* Enlarge next descriptor's PageCount */
412 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
413 RemoveEntryList(&NextDescriptor
->ListEntry
);