2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: freeldr/winldr/wlmemory.c
5 * PURPOSE: Memory related routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES ***************************************************************/
16 extern ULONG LoaderPagesSpanned
;
18 PCHAR MemTypeDesc
[] = {
19 "ExceptionBlock ", // ?
23 "LoadedProgram ", // == Free
24 "FirmwareTemporary ", // == Free
25 "FirmwarePermanent ", // == Bad
26 "OsloaderHeap ", // used
27 "OsloaderStack ", // == Free
30 "BootDriver ", // not used
31 "ConsoleInDriver ", // ?
32 "ConsoleOutDriver ", // ?
33 "StartupDpcStack ", // ?
34 "StartupKernelStack", // ?
35 "StartupPanicStack ", // ?
36 "StartupPcrPage ", // ?
37 "StartupPdrPage ", // ?
38 "RegistryData ", // used
39 "MemoryData ", // not used
41 "SpecialMemory ", // == Bad
42 "BBTMemory " // == Bad
46 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock
);
50 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
55 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
56 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
);
59 WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
);
62 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG_PTR Pcr
, IN ULONG_PTR Tss
);
65 MempAllocatePageTables();
68 MempSetupPaging(IN ULONG StartPage
,
69 IN ULONG NumberOfPages
);
72 WinLdrMapSpecialPages(ULONG PcrBasePage
);
75 MempUnmapPage(ULONG Page
);
80 /* GLOBALS ***************************************************************/
82 MEMORY_ALLOCATION_DESCRIPTOR
*Mad
;
85 /* FUNCTIONS **************************************************************/
93 // We need to delete kernel mapping from memory areas which are
94 // marked as Special or Permanent memory (thus non-accessible)
97 for (i
=0; i
<MadCount
; i
++)
99 ULONG StartPage
, EndPage
, Page
;
101 StartPage
= Mad
[i
].BasePage
;
102 EndPage
= Mad
[i
].BasePage
+ Mad
[i
].PageCount
;
104 if (Mad
[i
].MemoryType
== LoaderFirmwarePermanent
||
105 Mad
[i
].MemoryType
== LoaderSpecialMemory
||
106 Mad
[i
].MemoryType
== LoaderFree
||
107 (Mad
[i
].MemoryType
== LoaderFirmwareTemporary
&& EndPage
<= LoaderPagesSpanned
) ||
108 Mad
[i
].MemoryType
== LoaderOsloaderStack
||
109 Mad
[i
].MemoryType
== LoaderLoadedProgram
)
112 // But, the first megabyte of memory always stays!
113 // And, to tell the truth, we don't care about what's higher
114 // than LoaderPagesSpanned
115 if (Mad
[i
].MemoryType
== LoaderFirmwarePermanent
||
116 Mad
[i
].MemoryType
== LoaderSpecialMemory
)
118 if (StartPage
< 0x100)
121 if (EndPage
> LoaderPagesSpanned
)
122 EndPage
= LoaderPagesSpanned
;
125 for (Page
= StartPage
; Page
< EndPage
; Page
++)
134 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
142 // Check for some weird stuff at the top
144 if (BasePage
+ PageCount
> 0xF0000)
147 // Just skip this, without even adding to MAD list
153 // Set Base page, page count and type
155 Mad
[MadCount
].BasePage
= BasePage
;
156 Mad
[MadCount
].PageCount
= PageCount
;
157 Mad
[MadCount
].MemoryType
= Type
;
160 // Check if it's more than the allowed for OS loader
161 // if yes - don't map the pages, just add as FirmwareTemporary
163 if (BasePage
+ PageCount
> LoaderPagesSpanned
)
165 if (Mad
[MadCount
].MemoryType
!= LoaderSpecialMemory
&&
166 Mad
[MadCount
].MemoryType
!= LoaderFirmwarePermanent
&&
167 Mad
[MadCount
].MemoryType
!= LoaderFree
)
169 DPRINTM(DPRINT_WINDOWS
, "Setting page %x %x to Temporary from %d\n",
170 BasePage
, PageCount
, Mad
[MadCount
].MemoryType
);
171 Mad
[MadCount
].MemoryType
= LoaderFirmwareTemporary
;
174 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
183 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
187 // Map it (don't map low 1Mb because it was already contiguously
188 // mapped in WinLdrTurnOnPaging)
190 if (BasePage
>= 0x100)
192 Status
= MempSetupPaging(BasePage
, PageCount
);
195 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging\n");
206 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
211 ULONG i
, PagesCount
, MemoryMapSizeInPages
;
212 ULONG LastPageIndex
, LastPageType
, MemoryMapStartPage
;
213 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
219 // Creating a suitable memory map for the Windows can be tricky, so let's
220 // give a few advices:
221 // 1) One must not map the whole available memory pages to PDE!
222 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
223 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
224 // the same quantity for KSEG0_BASE mapping, one more entry for
225 // hyperspace and one more entry for HAL physical pages mapping.
226 // 2) Memory descriptors must map *the whole* physical memory
227 // showing any memory above 16/24/32 as FirmwareTemporary
229 // 3) Overall memory blocks count must not exceed 30 (?? why?)
233 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
234 // 0xC0300000 - 0xC03007FC
236 // Then it finds the best place for non-paged pool:
237 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
240 // Before we start mapping pages, create a block of memory, which will contain
242 if (MempAllocatePageTables() == FALSE
)
245 // Allocate memory for memory allocation descriptors
246 Mad
= MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * 1024);
248 // Setup an entry for each descriptor
249 MemoryMap
= MmGetMemoryMap(&NoEntries
);
250 if (MemoryMap
== NULL
)
252 UiMessageBox("Can not retrieve the current memory map");
256 // Calculate parameters of the memory map
257 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
258 MemoryMapSizeInPages
= NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
260 DPRINTM(DPRINT_WINDOWS
, "Got memory map with %d entries\n", NoEntries
);
262 // Always contiguously map low 1Mb of memory
263 Status
= MempSetupPaging(0, 0x100);
266 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging of low 1Mb\n");
270 // Construct a good memory map from what we've got,
271 // but mark entries which the memory allocation bitmap takes
272 // as free entries (this is done in order to have the ability
273 // to place mem alloc bitmap outside lower 16Mb zone)
276 LastPageType
= MemoryMap
[0].PageAllocated
;
277 for (i
= 1; i
< NoEntries
; i
++)
279 // Check if its memory map itself
280 if (i
>= MemoryMapStartPage
&&
281 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
283 // Exclude it if current page belongs to the memory map
284 MemoryMap
[i
].PageAllocated
= LoaderFree
;
288 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
295 // Add the resulting region
296 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
298 // Reset our counter vars
300 LastPageType
= MemoryMap
[i
].PageAllocated
;
306 // adding special reserved memory zones for vmware workstation
309 Mad
[MadCount
].BasePage
= 0xfec00;
310 Mad
[MadCount
].PageCount
= 0x10;
311 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
312 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
315 Mad
[MadCount
].BasePage
= 0xfee00;
316 Mad
[MadCount
].PageCount
= 0x1;
317 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
318 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
321 Mad
[MadCount
].BasePage
= 0xfffe0;
322 Mad
[MadCount
].PageCount
= 0x20;
323 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
324 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
329 DPRINTM(DPRINT_WINDOWS
, "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 /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
342 WinLdrMapSpecialPages(PcrBasePage
);
344 Tss
= (PKTSS
)(KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
346 // Unmap what is not needed from kernel page table
349 // Fill the memory descriptor list and
350 //PrepareMemoryDescriptorList();
351 DPRINTM(DPRINT_WINDOWS
, "Memory Descriptor List prepared, printing PDE\n");
352 List_PaToVa(&LoaderBlock
->MemoryDescriptorListHead
);
358 // Set processor context
359 WinLdrSetProcessorContext(GdtIdt
, KIP0PCRADDRESS
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
361 // Zero KI_USER_SHARED_DATA page
362 memset((PVOID
)KI_USER_SHARED_DATA
, 0, MM_PAGE_SIZE
);
367 // Two special things this func does: it sorts descriptors,
368 // and it merges free ones
370 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
371 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
373 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
374 PLIST_ENTRY PreviousEntry
, NextEntry
;
375 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
377 DPRINTM(DPRINT_WINDOWS
, "BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
378 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
380 /* Find a place where to insert the new descriptor to */
381 PreviousEntry
= ListHead
;
382 NextEntry
= ListHead
->Flink
;
383 while (NextEntry
!= ListHead
)
385 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
386 MEMORY_ALLOCATION_DESCRIPTOR
,
388 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
391 PreviousEntry
= NextEntry
;
392 PreviousDescriptor
= NextDescriptor
;
393 NextEntry
= NextEntry
->Flink
;
396 /* Don't forget about merging free areas */
397 if (NewDescriptor
->MemoryType
!= LoaderFree
)
399 /* Just insert, nothing to merge */
400 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
404 /* Previous block also free? */
405 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
406 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
407 NewDescriptor
->BasePage
))
409 /* Just enlarge previous descriptor's PageCount */
410 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
411 NewDescriptor
= PreviousDescriptor
;
415 /* Nope, just insert */
416 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
419 /* Next block is free ?*/
420 if ((NextEntry
!= ListHead
) &&
421 (NextDescriptor
->MemoryType
== LoaderFree
) &&
422 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
424 /* Enlarge next descriptor's PageCount */
425 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
426 RemoveEntryList(&NextDescriptor
->ListEntry
);