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