Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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
13 #include <debug.h>
14
15 DBG_DEFAULT_CHANNEL(WINDOWS);
16
17 extern ULONG LoaderPagesSpanned;
18
19 PCHAR 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
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
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
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 #if 0
233 // Always contiguously map low 1Mb of memory
234 Status = MempSetupPaging(0, 0x100, FALSE);
235 if (!Status)
236 {
237 ERR("Error during MempSetupPaging of low 1Mb\n");
238 return FALSE;
239 }
240 #endif
241
242 /* Before creating the map, we need to map pages to kernel mode */
243 LastPageIndex = 1;
244 LastPageType = MemoryMap[1].PageAllocated;
245 for (i = 2; i < NoEntries; i++)
246 {
247 if ((MemoryMap[i].PageAllocated != LastPageType) ||
248 (i == NoEntries - 1))
249 {
250 MempSetupPagingForRegion(LastPageIndex, i - LastPageIndex, LastPageType);
251 LastPageIndex = i;
252 LastPageType = MemoryMap[i].PageAllocated;
253 }
254 }
255
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)
260 PagesCount = 1;
261 LastPageIndex = 0;
262 LastPageType = MemoryMap[0].PageAllocated;
263 for (i = 1; i < NoEntries; i++)
264 {
265 // Check if its memory map itself
266 if (i >= MemoryMapStartPage &&
267 i < (MemoryMapStartPage+MemoryMapSizeInPages))
268 {
269 // Exclude it if current page belongs to the memory map
270 MemoryMap[i].PageAllocated = LoaderFree;
271 }
272
273 // Process entry
274 if (MemoryMap[i].PageAllocated == LastPageType &&
275 (i != NoEntries-1) )
276 {
277 PagesCount++;
278 }
279 else
280 {
281 // Add the resulting region
282 MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);
283
284 // Reset our counter vars
285 LastPageIndex = i;
286 LastPageType = MemoryMap[i].PageAllocated;
287 PagesCount = 1;
288 }
289 }
290
291 // TEMP, DEBUG!
292 // adding special reserved memory zones for vmware workstation
293 #if 0
294 {
295 Mad[MadCount].BasePage = 0xfec00;
296 Mad[MadCount].PageCount = 0x10;
297 Mad[MadCount].MemoryType = LoaderSpecialMemory;
298 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
299 MadCount++;
300
301 Mad[MadCount].BasePage = 0xfee00;
302 Mad[MadCount].PageCount = 0x1;
303 Mad[MadCount].MemoryType = LoaderSpecialMemory;
304 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
305 MadCount++;
306
307 Mad[MadCount].BasePage = 0xfffe0;
308 Mad[MadCount].PageCount = 0x20;
309 Mad[MadCount].MemoryType = LoaderSpecialMemory;
310 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
311 MadCount++;
312 }
313 #endif
314
315 /* Now we need to add high descriptors from the bios memory map */
316 for (i = 0; i < BiosMemoryMapEntryCount; i++)
317 {
318 /* Check if its higher than the lookup table */
319 if (BiosMemoryMap->BasePage > MmHighestPhysicalPage)
320 {
321 /* Copy this descriptor */
322 MempAddMemoryBlock(LoaderBlock,
323 BiosMemoryMap->BasePage,
324 BiosMemoryMap->PageCount,
325 BiosMemoryMap->MemoryType);
326 }
327 }
328
329 TRACE("MadCount: %d\n", MadCount);
330
331 WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!
332
333 // Map our loader image, so we can continue running
334 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
335 if (!Status)
336 {
337 UiMessageBox("Error during MempSetupPaging.");
338 return;
339 }*/
340
341 // Fill the memory descriptor list and
342 //PrepareMemoryDescriptorList();
343 TRACE("Memory Descriptor List prepared, printing PDE\n");
344 List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
345
346 #if DBG
347 MempDump();
348 #endif
349
350 return TRUE;
351 }
352
353 // Two special things this func does: it sorts descriptors,
354 // and it merges free ones
355 static VOID
356 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
357 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
358 {
359 PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;
360 PLIST_ENTRY PreviousEntry, NextEntry;
361 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;
362
363 TRACE("BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,
364 NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]);
365
366 /* Find a place where to insert the new descriptor to */
367 PreviousEntry = ListHead;
368 NextEntry = ListHead->Flink;
369 while (NextEntry != ListHead)
370 {
371 NextDescriptor = CONTAINING_RECORD(NextEntry,
372 MEMORY_ALLOCATION_DESCRIPTOR,
373 ListEntry);
374 if (NewDescriptor->BasePage < NextDescriptor->BasePage)
375 break;
376
377 PreviousEntry = NextEntry;
378 PreviousDescriptor = NextDescriptor;
379 NextEntry = NextEntry->Flink;
380 }
381
382 /* Don't forget about merging free areas */
383 if (NewDescriptor->MemoryType != LoaderFree)
384 {
385 /* Just insert, nothing to merge */
386 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
387 }
388 else
389 {
390 /* Previous block also free? */
391 if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&
392 ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
393 NewDescriptor->BasePage))
394 {
395 /* Just enlarge previous descriptor's PageCount */
396 PreviousDescriptor->PageCount += NewDescriptor->PageCount;
397 NewDescriptor = PreviousDescriptor;
398 }
399 else
400 {
401 /* Nope, just insert */
402 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
403 }
404
405 /* Next block is free ?*/
406 if ((NextEntry != ListHead) &&
407 (NextDescriptor->MemoryType == LoaderFree) &&
408 ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))
409 {
410 /* Enlarge next descriptor's PageCount */
411 NewDescriptor->PageCount += NextDescriptor->PageCount;
412 RemoveEntryList(&NextDescriptor->ListEntry);
413 }
414 }
415
416 return;
417 }