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