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 ***************************************************************/
15 DBG_DEFAULT_CHANNEL(WINDOWS
);
17 extern ULONG LoaderPagesSpanned
;
19 static const PCSTR MemTypeDesc
[] = {
20 "ExceptionBlock ", // ?
24 "LoadedProgram ", // == Free
25 "FirmwareTemporary ", // == Free
26 "FirmwarePermanent ", // == Bad
27 "OsloaderHeap ", // used
28 "OsloaderStack ", // == Free
31 "BootDriver ", // not used
32 "ConsoleInDriver ", // ?
33 "ConsoleOutDriver ", // ?
34 "StartupDpcStack ", // ?
35 "StartupKernelStack", // ?
36 "StartupPanicStack ", // ?
37 "StartupPcrPage ", // ?
38 "StartupPdrPage ", // ?
39 "RegistryData ", // used
40 "MemoryData ", // not used
42 "SpecialMemory ", // == Bad
43 "BBTMemory " // == Bad
47 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
48 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
);
50 extern PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap
;
51 extern ULONG BiosMemoryMapEntryCount
;
52 extern PFN_NUMBER MmLowestPhysicalPage
;
53 extern PFN_NUMBER MmHighestPhysicalPage
;
55 /* GLOBALS ***************************************************************/
57 MEMORY_ALLOCATION_DESCRIPTOR
*Mad
;
59 /* 200 MADs fit into 1 page, that should really be enough! */
60 #define MAX_MAD_COUNT 200
62 /* FUNCTIONS **************************************************************/
65 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
70 TRACE("MempAddMemoryBlock(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
71 BasePage
, PageCount
, Type
);
73 /* Check for memory block after 4GB - we don't support it yet
74 Note: Even last page before 4GB limit is not supported */
75 if (BasePage
>= MM_MAX_PAGE
)
77 /* Just skip this, without even adding to MAD list */
81 /* Check if last page is after 4GB limit and shorten this block if needed */
82 if (BasePage
+ PageCount
> MM_MAX_PAGE
)
84 /* Shorten this block */
85 PageCount
= MM_MAX_PAGE
- BasePage
;
88 /* Check if we have slots left */
89 if (MadCount
>= MAX_MAD_COUNT
)
91 ERR("Error: no MAD slots left!\n");
95 /* Set Base page, page count and type */
96 Mad
[MadCount
].BasePage
= BasePage
;
97 Mad
[MadCount
].PageCount
= PageCount
;
98 Mad
[MadCount
].MemoryType
= Type
;
101 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
106 MempSetupPagingForRegion(
108 PFN_NUMBER PageCount
,
111 BOOLEAN Status
= TRUE
;
113 TRACE("MempSetupPagingForRegion(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
114 BasePage
, PageCount
, Type
);
116 /* Make sure we don't map too high */
117 if (BasePage
+ PageCount
> LoaderPagesSpanned
) return;
121 /* Pages used by the loader */
122 case LoaderLoadedProgram
:
123 case LoaderOsloaderStack
:
124 case LoaderFirmwareTemporary
:
125 /* Map these pages into user mode */
126 Status
= MempSetupPaging(BasePage
, PageCount
, FALSE
);
129 /* Pages used by the kernel */
130 case LoaderExceptionBlock
:
131 case LoaderSystemBlock
:
132 case LoaderFirmwarePermanent
:
133 case LoaderSystemCode
:
135 case LoaderBootDriver
:
136 case LoaderConsoleInDriver
:
137 case LoaderConsoleOutDriver
:
138 case LoaderStartupDpcStack
:
139 case LoaderStartupKernelStack
:
140 case LoaderStartupPanicStack
:
141 case LoaderStartupPcrPage
:
142 case LoaderStartupPdrPage
:
143 case LoaderRegistryData
:
144 case LoaderMemoryData
:
147 case LoaderOsloaderHeap
: // FIXME
148 /* Map these pages into kernel mode */
149 Status
= MempSetupPaging(BasePage
, PageCount
, TRUE
);
152 /* Pages not in use */
157 /* Invisible to kernel */
158 case LoaderSpecialMemory
:
159 case LoaderHALCachedMemory
:
160 case LoaderBBTMemory
:
163 // FIXME: not known (not used anyway)
165 case LoaderLargePageFiller
:
166 case LoaderErrorLogMemory
:
172 ERR("Error during MempSetupPaging\n");
181 WinLdrSetupMemoryLayout(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
)
183 PFN_NUMBER i
, PagesCount
, MemoryMapSizeInPages
, NoEntries
;
184 PFN_NUMBER LastPageIndex
, MemoryMapStartPage
;
185 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
191 FrLdrHeapCleanupAll();
194 // Creating a suitable memory map for Windows can be tricky, so let's
195 // give a few advices:
196 // 1) One must not map the whole available memory pages to PDE!
197 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
198 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
199 // the same quantity for KSEG0_BASE mapping, one more entry for
200 // hyperspace and one more entry for HAL physical pages mapping.
201 // 2) Memory descriptors must map *the whole* physical memory
202 // showing any memory above 16/24/32 as FirmwareTemporary
204 // 3) Overall memory blocks count must not exceed 30 (?? why?)
208 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
209 // 0xC0300000 - 0xC03007FC
211 // Then it finds the best place for non-paged pool:
212 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
215 // Allocate memory for memory allocation descriptors
216 Mad
= MmAllocateMemoryWithType(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * MAX_MAD_COUNT
,
219 // Setup an entry for each descriptor
220 MemoryMap
= MmGetMemoryMap(&NoEntries
);
221 if (MemoryMap
== NULL
)
223 UiMessageBox("Can not retrieve the current memory map.");
227 // Calculate parameters of the memory map
228 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
229 MemoryMapSizeInPages
= (NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
) + MM_PAGE_SIZE
- 1) / MM_PAGE_SIZE
;
231 TRACE("Got memory map with %d entries\n", NoEntries
);
233 // Always contiguously map low 1Mb of memory
234 Status
= MempSetupPaging(0, 0x100, FALSE
);
237 ERR("Error during MempSetupPaging of low 1Mb\n");
242 /* Before creating the map, we need to map pages to kernel mode */
244 LastPageType
= MemoryMap
[1].PageAllocated
;
245 for (i
= 2; i
< NoEntries
; i
++)
247 if ((MemoryMap
[i
].PageAllocated
!= LastPageType
) ||
248 (i
== NoEntries
- 1))
250 MempSetupPagingForRegion(LastPageIndex
, i
- LastPageIndex
, LastPageType
);
252 LastPageType
= MemoryMap
[i
].PageAllocated
;
256 // Construct a good memory map from what we've got,
257 // but mark entries which the memory allocation bitmap takes
258 // as free entries (this is done in order to have the ability
259 // to place mem alloc bitmap outside lower 16Mb zone)
262 LastPageType
= MemoryMap
[0].PageAllocated
;
263 for (i
= 1; i
< NoEntries
; i
++)
265 // Check if its memory map itself
266 if (i
>= MemoryMapStartPage
&&
267 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
269 // Exclude it if current page belongs to the memory map
270 MemoryMap
[i
].PageAllocated
= LoaderFree
;
274 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
281 // Add the resulting region
282 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
284 // Reset our counter vars
286 LastPageType
= MemoryMap
[i
].PageAllocated
;
292 // adding special reserved memory zones for vmware workstation
295 Mad
[MadCount
].BasePage
= 0xfec00;
296 Mad
[MadCount
].PageCount
= 0x10;
297 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
298 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
301 Mad
[MadCount
].BasePage
= 0xfee00;
302 Mad
[MadCount
].PageCount
= 0x1;
303 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
304 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
307 Mad
[MadCount
].BasePage
= 0xfffe0;
308 Mad
[MadCount
].PageCount
= 0x20;
309 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
310 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
315 /* Now we need to add high descriptors from the bios memory map */
316 for (i
= 0; i
< BiosMemoryMapEntryCount
; i
++)
318 /* Check if its higher than the lookup table */
319 if (BiosMemoryMap
->BasePage
> MmHighestPhysicalPage
)
321 /* Copy this descriptor */
322 MempAddMemoryBlock(LoaderBlock
,
323 BiosMemoryMap
->BasePage
,
324 BiosMemoryMap
->PageCount
,
325 BiosMemoryMap
->MemoryType
);
329 TRACE("MadCount: %d\n", MadCount
);
331 WinLdrpDumpMemoryDescriptors(LoaderBlock
); //FIXME: Delete!
333 // Map our loader image, so we can continue running
334 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
337 UiMessageBox("Error during MempSetupPaging.");
341 // Fill the memory descriptor list and
342 //PrepareMemoryDescriptorList();
343 TRACE("Memory Descriptor List prepared, printing PDE\n");
344 List_PaToVa(&LoaderBlock
->MemoryDescriptorListHead
);
353 // Two special things this func does: it sorts descriptors,
354 // and it merges free ones
356 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
357 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
359 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
360 PLIST_ENTRY PreviousEntry
, NextEntry
;
361 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
363 TRACE("BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
364 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
366 /* Find a place where to insert the new descriptor to */
367 PreviousEntry
= ListHead
;
368 NextEntry
= ListHead
->Flink
;
369 while (NextEntry
!= ListHead
)
371 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
372 MEMORY_ALLOCATION_DESCRIPTOR
,
374 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
377 PreviousEntry
= NextEntry
;
378 PreviousDescriptor
= NextDescriptor
;
379 NextEntry
= NextEntry
->Flink
;
382 /* Don't forget about merging free areas */
383 if (NewDescriptor
->MemoryType
!= LoaderFree
)
385 /* Just insert, nothing to merge */
386 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
390 /* Previous block also free? */
391 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
392 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
393 NewDescriptor
->BasePage
))
395 /* Just enlarge previous descriptor's PageCount */
396 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
397 NewDescriptor
= PreviousDescriptor
;
401 /* Nope, just insert */
402 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
405 /* Next block is free ?*/
406 if ((NextEntry
!= ListHead
) &&
407 (NextDescriptor
->MemoryType
== LoaderFree
) &&
408 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
410 /* Enlarge next descriptor's PageCount */
411 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
412 RemoveEntryList(&NextDescriptor
->ListEntry
);