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