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 } 419