[FREELDR] Add some missing UiDrawBackdrop() calls.
[reactos.git] / boot / freeldr / freeldr / ntldr / wlmemory.c
1 /*
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)
7 */
8
9 /* INCLUDES ***************************************************************/
10
11 #include <freeldr.h>
12 #include "winldr.h"
13
14 #include <debug.h>
15
16 DBG_DEFAULT_CHANNEL(WINDOWS);
17
18 extern ULONG LoaderPagesSpanned;
19
20 static const PCSTR MemTypeDesc[] = {
21 "ExceptionBlock ", // ?
22 "SystemBlock ", // ?
23 "Free ",
24 "Bad ", // used
25 "LoadedProgram ", // == Free
26 "FirmwareTemporary ", // == Free
27 "FirmwarePermanent ", // == Bad
28 "OsloaderHeap ", // used
29 "OsloaderStack ", // == Free
30 "SystemCode ",
31 "HalCode ",
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
42 "NlsData ", // used
43 "SpecialMemory ", // == Bad
44 "BBTMemory " // == Bad
45 };
46
47 static VOID
48 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
49 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
50
51 extern PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap;
52 extern ULONG BiosMemoryMapEntryCount;
53 extern PFN_NUMBER MmLowestPhysicalPage;
54 extern PFN_NUMBER MmHighestPhysicalPage;
55
56 /* GLOBALS ***************************************************************/
57
58 MEMORY_ALLOCATION_DESCRIPTOR *Mad;
59 ULONG MadCount = 0;
60 /* 200 MADs fit into 1 page, that should really be enough! */
61 #define MAX_MAD_COUNT 200
62
63 /* FUNCTIONS **************************************************************/
64
65 VOID
66 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
67 PFN_NUMBER BasePage,
68 PFN_NUMBER PageCount,
69 ULONG Type)
70 {
71 TRACE("MempAddMemoryBlock(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
72 BasePage, PageCount, Type);
73
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)
77 {
78 /* Just skip this, without even adding to MAD list */
79 return;
80 }
81
82 /* Check if last page is after 4GB limit and shorten this block if needed */
83 if (BasePage + PageCount > MM_MAX_PAGE)
84 {
85 /* Shorten this block */
86 PageCount = MM_MAX_PAGE - BasePage;
87 }
88
89 /* Check if we have slots left */
90 if (MadCount >= MAX_MAD_COUNT)
91 {
92 ERR("Error: no MAD slots left!\n");
93 return;
94 }
95
96 /* Set Base page, page count and type */
97 Mad[MadCount].BasePage = BasePage;
98 Mad[MadCount].PageCount = PageCount;
99 Mad[MadCount].MemoryType = Type;
100
101 /* Add descriptor */
102 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
103 MadCount++;
104 }
105
106 VOID
107 MempSetupPagingForRegion(
108 PFN_NUMBER BasePage,
109 PFN_NUMBER PageCount,
110 ULONG Type)
111 {
112 BOOLEAN Status = TRUE;
113
114 TRACE("MempSetupPagingForRegion(BasePage=0x%lx, PageCount=0x%lx, Type=%ld)\n",
115 BasePage, PageCount, Type);
116
117 /* Make sure we don't map too high */
118 if (BasePage + PageCount > LoaderPagesSpanned) return;
119
120 switch (Type)
121 {
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);
128 break;
129
130 /* Pages used by the kernel */
131 case LoaderExceptionBlock:
132 case LoaderSystemBlock:
133 case LoaderFirmwarePermanent:
134 case LoaderSystemCode:
135 case LoaderHalCode:
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:
146 case LoaderNlsData:
147 case LoaderXIPRom:
148 case LoaderOsloaderHeap: // FIXME
149 /* Map these pages into kernel mode */
150 Status = MempSetupPaging(BasePage, PageCount, TRUE);
151 break;
152
153 /* Pages not in use */
154 case LoaderFree:
155 case LoaderBad:
156 break;
157
158 /* Invisible to kernel */
159 case LoaderSpecialMemory:
160 case LoaderHALCachedMemory:
161 case LoaderBBTMemory:
162 break;
163
164 // FIXME: not known (not used anyway)
165 case LoaderReserve:
166 case LoaderLargePageFiller:
167 case LoaderErrorLogMemory:
168 break;
169 }
170
171 if (!Status)
172 {
173 ERR("Error during MempSetupPaging\n");
174 }
175 }
176
177 #ifdef _M_ARM
178 #define PKTSS PVOID
179 #endif
180
181 BOOLEAN
182 WinLdrSetupMemoryLayout(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock)
183 {
184 PFN_NUMBER i, PagesCount, MemoryMapSizeInPages, NoEntries;
185 PFN_NUMBER LastPageIndex, MemoryMapStartPage;
186 PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
187 ULONG LastPageType;
188 //PKTSS Tss;
189 //BOOLEAN Status;
190
191 /* Cleanup heap */
192 FrLdrHeapCleanupAll();
193
194 //
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
204 //
205 // 3) Overall memory blocks count must not exceed 30 (?? why?)
206 //
207
208 //
209 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
210 // 0xC0300000 - 0xC03007FC
211 //
212 // Then it finds the best place for non-paged pool:
213 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
214 //
215
216 // Allocate memory for memory allocation descriptors
217 Mad = MmAllocateMemoryWithType(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * MAX_MAD_COUNT,
218 LoaderMemoryData);
219
220 // Setup an entry for each descriptor
221 MemoryMap = MmGetMemoryMap(&NoEntries);
222 if (MemoryMap == NULL)
223 {
224 UiMessageBox("Can not retrieve the current memory map.");
225 return FALSE;
226 }
227
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;
231
232 TRACE("Got memory map with %d entries\n", NoEntries);
233 #if 0
234 // Always contiguously map low 1Mb of memory
235 Status = MempSetupPaging(0, 0x100, FALSE);
236 if (!Status)
237 {
238 ERR("Error during MempSetupPaging of low 1Mb\n");
239 return FALSE;
240 }
241 #endif
242
243 /* Before creating the map, we need to map pages to kernel mode */
244 LastPageIndex = 1;
245 LastPageType = MemoryMap[1].PageAllocated;
246 for (i = 2; i < NoEntries; i++)
247 {
248 if ((MemoryMap[i].PageAllocated != LastPageType) ||
249 (i == NoEntries - 1))
250 {
251 MempSetupPagingForRegion(LastPageIndex, i - LastPageIndex, LastPageType);
252 LastPageIndex = i;
253 LastPageType = MemoryMap[i].PageAllocated;
254 }
255 }
256
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)
261 PagesCount = 1;
262 LastPageIndex = 0;
263 LastPageType = MemoryMap[0].PageAllocated;
264 for (i = 1; i < NoEntries; i++)
265 {
266 // Check if its memory map itself
267 if (i >= MemoryMapStartPage &&
268 i < (MemoryMapStartPage+MemoryMapSizeInPages))
269 {
270 // Exclude it if current page belongs to the memory map
271 MemoryMap[i].PageAllocated = LoaderFree;
272 }
273
274 // Process entry
275 if (MemoryMap[i].PageAllocated == LastPageType &&
276 (i != NoEntries-1) )
277 {
278 PagesCount++;
279 }
280 else
281 {
282 // Add the resulting region
283 MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);
284
285 // Reset our counter vars
286 LastPageIndex = i;
287 LastPageType = MemoryMap[i].PageAllocated;
288 PagesCount = 1;
289 }
290 }
291
292 // TEMP, DEBUG!
293 // adding special reserved memory zones for vmware workstation
294 #if 0
295 {
296 Mad[MadCount].BasePage = 0xfec00;
297 Mad[MadCount].PageCount = 0x10;
298 Mad[MadCount].MemoryType = LoaderSpecialMemory;
299 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
300 MadCount++;
301
302 Mad[MadCount].BasePage = 0xfee00;
303 Mad[MadCount].PageCount = 0x1;
304 Mad[MadCount].MemoryType = LoaderSpecialMemory;
305 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
306 MadCount++;
307
308 Mad[MadCount].BasePage = 0xfffe0;
309 Mad[MadCount].PageCount = 0x20;
310 Mad[MadCount].MemoryType = LoaderSpecialMemory;
311 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
312 MadCount++;
313 }
314 #endif
315
316 /* Now we need to add high descriptors from the bios memory map */
317 for (i = 0; i < BiosMemoryMapEntryCount; i++)
318 {
319 /* Check if its higher than the lookup table */
320 if (BiosMemoryMap->BasePage > MmHighestPhysicalPage)
321 {
322 /* Copy this descriptor */
323 MempAddMemoryBlock(LoaderBlock,
324 BiosMemoryMap->BasePage,
325 BiosMemoryMap->PageCount,
326 BiosMemoryMap->MemoryType);
327 }
328 }
329
330 TRACE("MadCount: %d\n", MadCount);
331
332 WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!
333
334 // Map our loader image, so we can continue running
335 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
336 if (!Status)
337 {
338 UiMessageBox("Error during MempSetupPaging.");
339 return;
340 }*/
341
342 // Fill the memory descriptor list and
343 //PrepareMemoryDescriptorList();
344 TRACE("Memory Descriptor List prepared, printing PDE\n");
345 List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
346
347 #if DBG
348 MempDump();
349 #endif
350
351 return TRUE;
352 }
353
354 // Two special things this func does: it sorts descriptors,
355 // and it merges free ones
356 static VOID
357 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
358 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
359 {
360 PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;
361 PLIST_ENTRY PreviousEntry, NextEntry;
362 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;
363
364 TRACE("BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,
365 NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]);
366
367 /* Find a place where to insert the new descriptor to */
368 PreviousEntry = ListHead;
369 NextEntry = ListHead->Flink;
370 while (NextEntry != ListHead)
371 {
372 NextDescriptor = CONTAINING_RECORD(NextEntry,
373 MEMORY_ALLOCATION_DESCRIPTOR,
374 ListEntry);
375 if (NewDescriptor->BasePage < NextDescriptor->BasePage)
376 break;
377
378 PreviousEntry = NextEntry;
379 PreviousDescriptor = NextDescriptor;
380 NextEntry = NextEntry->Flink;
381 }
382
383 /* Don't forget about merging free areas */
384 if (NewDescriptor->MemoryType != LoaderFree)
385 {
386 /* Just insert, nothing to merge */
387 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
388 }
389 else
390 {
391 /* Previous block also free? */
392 if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&
393 ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
394 NewDescriptor->BasePage))
395 {
396 /* Just enlarge previous descriptor's PageCount */
397 PreviousDescriptor->PageCount += NewDescriptor->PageCount;
398 NewDescriptor = PreviousDescriptor;
399 }
400 else
401 {
402 /* Nope, just insert */
403 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
404 }
405
406 /* Next block is free ?*/
407 if ((NextEntry != ListHead) &&
408 (NextDescriptor->MemoryType == LoaderFree) &&
409 ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))
410 {
411 /* Enlarge next descriptor's PageCount */
412 NewDescriptor->PageCount += NextDescriptor->PageCount;
413 RemoveEntryList(&NextDescriptor->ListEntry);
414 }
415 }
416
417 return;
418 }