1 /** @file 2 PI SMM MemoryAttributes support 3 4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include <PiDxe.h> 16 #include <Library/BaseLib.h> 17 #include <Library/BaseMemoryLib.h> 18 #include <Library/MemoryAllocationLib.h> 19 #include <Library/UefiBootServicesTableLib.h> 20 #include <Library/SmmServicesTableLib.h> 21 #include <Library/DebugLib.h> 22 #include <Library/PcdLib.h> 23 24 #include <Library/PeCoffLib.h> 25 #include <Library/PeCoffGetEntryPointLib.h> 26 27 #include <Guid/PiSmmMemoryAttributesTable.h> 28 29 #include "PiSmmCore.h" 30 31 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ 32 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) 33 34 #define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C') 35 36 typedef struct { 37 UINT32 Signature; 38 LIST_ENTRY Link; 39 EFI_PHYSICAL_ADDRESS CodeSegmentBase; 40 UINT64 CodeSegmentSize; 41 } IMAGE_PROPERTIES_RECORD_CODE_SECTION; 42 43 #define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D') 44 45 typedef struct { 46 UINT32 Signature; 47 LIST_ENTRY Link; 48 EFI_PHYSICAL_ADDRESS ImageBase; 49 UINT64 ImageSize; 50 UINTN CodeSegmentCount; 51 LIST_ENTRY CodeSegmentList; 52 } IMAGE_PROPERTIES_RECORD; 53 54 #define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D') 55 56 typedef struct { 57 UINT32 Signature; 58 UINTN ImageRecordCount; 59 UINTN CodeSegmentCountMax; 60 LIST_ENTRY ImageRecordList; 61 } IMAGE_PROPERTIES_PRIVATE_DATA; 62 63 IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = { 64 IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE, 65 0, 66 0, 67 INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList) 68 }; 69 70 #define EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA BIT0 71 72 UINT64 mMemoryProtectionAttribute = EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA; 73 74 // 75 // Below functions are for MemoryMap 76 // 77 78 /** 79 Converts a number of EFI_PAGEs to a size in bytes. 80 81 NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only. 82 83 @param[in] Pages The number of EFI_PAGES. 84 85 @return The number of bytes associated with the number of EFI_PAGEs specified 86 by Pages. 87 **/ 88 STATIC 89 UINT64 90 EfiPagesToSize ( 91 IN UINT64 Pages 92 ) 93 { 94 return LShiftU64 (Pages, EFI_PAGE_SHIFT); 95 } 96 97 /** 98 Converts a size, in bytes, to a number of EFI_PAGESs. 99 100 NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only. 101 102 @param[in] Size A size in bytes. 103 104 @return The number of EFI_PAGESs associated with the number of bytes specified 105 by Size. 106 107 **/ 108 STATIC 109 UINT64 110 EfiSizeToPages ( 111 IN UINT64 Size 112 ) 113 { 114 return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0); 115 } 116 117 /** 118 Check the consistency of Smm memory attributes table. 119 120 @param[in] MemoryAttributesTable PI SMM memory attributes table 121 **/ 122 VOID 123 SmmMemoryAttributesTableConsistencyCheck ( 124 IN EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable 125 ) 126 { 127 EFI_MEMORY_DESCRIPTOR *MemoryMap; 128 UINTN MemoryMapEntryCount; 129 UINTN DescriptorSize; 130 UINTN Index; 131 UINT64 Address; 132 133 Address = 0; 134 MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries; 135 DescriptorSize = MemoryAttributesTable->DescriptorSize; 136 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1); 137 for (Index = 0; Index < MemoryMapEntryCount; Index++) { 138 if (Address != 0) { 139 ASSERT (Address == MemoryMap->PhysicalStart); 140 } 141 Address = MemoryMap->PhysicalStart + EfiPagesToSize(MemoryMap->NumberOfPages); 142 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize); 143 } 144 } 145 146 /** 147 Sort memory map entries based upon PhysicalStart, from low to high. 148 149 @param[in,out] MemoryMap A pointer to the buffer in which firmware places 150 the current memory map. 151 @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer. 152 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 153 **/ 154 STATIC 155 VOID 156 SortMemoryMap ( 157 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 158 IN UINTN MemoryMapSize, 159 IN UINTN DescriptorSize 160 ) 161 { 162 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 163 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; 164 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 165 EFI_MEMORY_DESCRIPTOR TempMemoryMap; 166 167 MemoryMapEntry = MemoryMap; 168 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 169 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize); 170 while (MemoryMapEntry < MemoryMapEnd) { 171 while (NextMemoryMapEntry < MemoryMapEnd) { 172 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) { 173 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 174 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 175 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR)); 176 } 177 178 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); 179 } 180 181 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 182 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 183 } 184 185 return ; 186 } 187 188 /** 189 Merge continous memory map entries whose have same attributes. 190 191 @param[in, out] MemoryMap A pointer to the buffer in which firmware places 192 the current memory map. 193 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the 194 MemoryMap buffer. On input, this is the size of 195 the current memory map. On output, 196 it is the size of new memory map after merge. 197 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 198 **/ 199 STATIC 200 VOID 201 MergeMemoryMap ( 202 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 203 IN OUT UINTN *MemoryMapSize, 204 IN UINTN DescriptorSize 205 ) 206 { 207 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 208 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 209 UINT64 MemoryBlockLength; 210 EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry; 211 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; 212 213 MemoryMapEntry = MemoryMap; 214 NewMemoryMapEntry = MemoryMap; 215 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize); 216 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { 217 CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 218 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 219 220 do { 221 MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages)); 222 if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && 223 (MemoryMapEntry->Type == NextMemoryMapEntry->Type) && 224 (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) && 225 ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) { 226 MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; 227 if (NewMemoryMapEntry != MemoryMapEntry) { 228 NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; 229 } 230 231 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); 232 continue; 233 } else { 234 MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); 235 break; 236 } 237 } while (TRUE); 238 239 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 240 NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize); 241 } 242 243 *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap; 244 245 return ; 246 } 247 248 /** 249 Enforce memory map attributes. 250 This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP. 251 252 @param[in, out] MemoryMap A pointer to the buffer in which firmware places 253 the current memory map. 254 @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer. 255 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 256 **/ 257 STATIC 258 VOID 259 EnforceMemoryMapAttribute ( 260 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 261 IN UINTN MemoryMapSize, 262 IN UINTN DescriptorSize 263 ) 264 { 265 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 266 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 267 268 MemoryMapEntry = MemoryMap; 269 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize); 270 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { 271 if (MemoryMapEntry->Attribute != 0) { 272 // It is PE image, the attribute is already set. 273 } else { 274 switch (MemoryMapEntry->Type) { 275 case EfiRuntimeServicesCode: 276 MemoryMapEntry->Attribute = EFI_MEMORY_RO; 277 break; 278 case EfiRuntimeServicesData: 279 default: 280 MemoryMapEntry->Attribute |= EFI_MEMORY_XP; 281 break; 282 } 283 } 284 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 285 } 286 287 return ; 288 } 289 290 /** 291 Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length]. 292 293 @param[in] Buffer Start Address 294 @param[in] Length Address length 295 296 @return first image record covered by [buffer, length] 297 **/ 298 STATIC 299 IMAGE_PROPERTIES_RECORD * 300 GetImageRecordByAddress ( 301 IN EFI_PHYSICAL_ADDRESS Buffer, 302 IN UINT64 Length 303 ) 304 { 305 IMAGE_PROPERTIES_RECORD *ImageRecord; 306 LIST_ENTRY *ImageRecordLink; 307 LIST_ENTRY *ImageRecordList; 308 309 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; 310 311 for (ImageRecordLink = ImageRecordList->ForwardLink; 312 ImageRecordLink != ImageRecordList; 313 ImageRecordLink = ImageRecordLink->ForwardLink) { 314 ImageRecord = CR ( 315 ImageRecordLink, 316 IMAGE_PROPERTIES_RECORD, 317 Link, 318 IMAGE_PROPERTIES_RECORD_SIGNATURE 319 ); 320 321 if ((Buffer <= ImageRecord->ImageBase) && 322 (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) { 323 return ImageRecord; 324 } 325 } 326 327 return NULL; 328 } 329 330 /** 331 Set the memory map to new entries, according to one old entry, 332 based upon PE code section and data section in image record 333 334 @param[in] ImageRecord An image record whose [ImageBase, ImageSize] covered 335 by old memory map entry. 336 @param[in, out] NewRecord A pointer to several new memory map entries. 337 The caller gurantee the buffer size be 1 + 338 (SplitRecordCount * DescriptorSize) calculated 339 below. 340 @param[in] OldRecord A pointer to one old memory map entry. 341 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 342 **/ 343 STATIC 344 UINTN 345 SetNewRecord ( 346 IN IMAGE_PROPERTIES_RECORD *ImageRecord, 347 IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord, 348 IN EFI_MEMORY_DESCRIPTOR *OldRecord, 349 IN UINTN DescriptorSize 350 ) 351 { 352 EFI_MEMORY_DESCRIPTOR TempRecord; 353 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; 354 LIST_ENTRY *ImageRecordCodeSectionLink; 355 LIST_ENTRY *ImageRecordCodeSectionEndLink; 356 LIST_ENTRY *ImageRecordCodeSectionList; 357 UINTN NewRecordCount; 358 UINT64 PhysicalEnd; 359 UINT64 ImageEnd; 360 361 CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR)); 362 PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages); 363 NewRecordCount = 0; 364 365 // 366 // Always create a new entry for non-PE image record 367 // 368 if (ImageRecord->ImageBase > TempRecord.PhysicalStart) { 369 NewRecord->Type = TempRecord.Type; 370 NewRecord->PhysicalStart = TempRecord.PhysicalStart; 371 NewRecord->VirtualStart = 0; 372 NewRecord->NumberOfPages = EfiSizeToPages(ImageRecord->ImageBase - TempRecord.PhysicalStart); 373 NewRecord->Attribute = TempRecord.Attribute; 374 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); 375 NewRecordCount ++; 376 TempRecord.PhysicalStart = ImageRecord->ImageBase; 377 TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart); 378 } 379 380 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; 381 382 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; 383 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; 384 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { 385 ImageRecordCodeSection = CR ( 386 ImageRecordCodeSectionLink, 387 IMAGE_PROPERTIES_RECORD_CODE_SECTION, 388 Link, 389 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE 390 ); 391 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; 392 393 if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) { 394 // 395 // DATA 396 // 397 NewRecord->Type = EfiRuntimeServicesData; 398 NewRecord->PhysicalStart = TempRecord.PhysicalStart; 399 NewRecord->VirtualStart = 0; 400 NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart); 401 NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; 402 if (NewRecord->NumberOfPages != 0) { 403 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); 404 NewRecordCount ++; 405 } 406 407 // 408 // CODE 409 // 410 NewRecord->Type = EfiRuntimeServicesCode; 411 NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase; 412 NewRecord->VirtualStart = 0; 413 NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize); 414 NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO; 415 if (NewRecord->NumberOfPages != 0) { 416 NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); 417 NewRecordCount ++; 418 } 419 420 TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize)); 421 TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart); 422 if (TempRecord.NumberOfPages == 0) { 423 break; 424 } 425 } 426 } 427 428 ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; 429 430 // 431 // Final DATA 432 // 433 if (TempRecord.PhysicalStart < ImageEnd) { 434 NewRecord->Type = EfiRuntimeServicesData; 435 NewRecord->PhysicalStart = TempRecord.PhysicalStart; 436 NewRecord->VirtualStart = 0; 437 NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart); 438 NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; 439 NewRecordCount ++; 440 } 441 442 return NewRecordCount; 443 } 444 445 /** 446 Return the max number of new splitted entries, according to one old entry, 447 based upon PE code section and data section. 448 449 @param[in] OldRecord A pointer to one old memory map entry. 450 451 @retval 0 no entry need to be splitted. 452 @return the max number of new splitted entries 453 **/ 454 STATIC 455 UINTN 456 GetMaxSplitRecordCount ( 457 IN EFI_MEMORY_DESCRIPTOR *OldRecord 458 ) 459 { 460 IMAGE_PROPERTIES_RECORD *ImageRecord; 461 UINTN SplitRecordCount; 462 UINT64 PhysicalStart; 463 UINT64 PhysicalEnd; 464 465 SplitRecordCount = 0; 466 PhysicalStart = OldRecord->PhysicalStart; 467 PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages); 468 469 do { 470 ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart); 471 if (ImageRecord == NULL) { 472 break; 473 } 474 SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 2); 475 PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize; 476 } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd)); 477 478 return SplitRecordCount; 479 } 480 481 /** 482 Split the memory map to new entries, according to one old entry, 483 based upon PE code section and data section. 484 485 @param[in] OldRecord A pointer to one old memory map entry. 486 @param[in, out] NewRecord A pointer to several new memory map entries. 487 The caller gurantee the buffer size be 1 + 488 (SplitRecordCount * DescriptorSize) calculated 489 below. 490 @param[in] MaxSplitRecordCount The max number of splitted entries 491 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 492 493 @retval 0 no entry is splitted. 494 @return the real number of splitted record. 495 **/ 496 STATIC 497 UINTN 498 SplitRecord ( 499 IN EFI_MEMORY_DESCRIPTOR *OldRecord, 500 IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord, 501 IN UINTN MaxSplitRecordCount, 502 IN UINTN DescriptorSize 503 ) 504 { 505 EFI_MEMORY_DESCRIPTOR TempRecord; 506 IMAGE_PROPERTIES_RECORD *ImageRecord; 507 IMAGE_PROPERTIES_RECORD *NewImageRecord; 508 UINT64 PhysicalStart; 509 UINT64 PhysicalEnd; 510 UINTN NewRecordCount; 511 UINTN TotalNewRecordCount; 512 513 if (MaxSplitRecordCount == 0) { 514 CopyMem (NewRecord, OldRecord, DescriptorSize); 515 return 0; 516 } 517 518 TotalNewRecordCount = 0; 519 520 // 521 // Override previous record 522 // 523 CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR)); 524 PhysicalStart = TempRecord.PhysicalStart; 525 PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages); 526 527 ImageRecord = NULL; 528 do { 529 NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart); 530 if (NewImageRecord == NULL) { 531 // 532 // No more image covered by this range, stop 533 // 534 if (PhysicalEnd > PhysicalStart) { 535 // 536 // Always create a new entry for non-PE image record 537 // 538 NewRecord->Type = TempRecord.Type; 539 NewRecord->PhysicalStart = TempRecord.PhysicalStart; 540 NewRecord->VirtualStart = 0; 541 NewRecord->NumberOfPages = TempRecord.NumberOfPages; 542 NewRecord->Attribute = TempRecord.Attribute; 543 TotalNewRecordCount ++; 544 } 545 break; 546 } 547 ImageRecord = NewImageRecord; 548 549 // 550 // Set new record 551 // 552 NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize); 553 TotalNewRecordCount += NewRecordCount; 554 NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize); 555 556 // 557 // Update PhysicalStart, in order to exclude the image buffer already splitted. 558 // 559 PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize; 560 TempRecord.PhysicalStart = PhysicalStart; 561 TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart); 562 } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd)); 563 564 return TotalNewRecordCount - 1; 565 } 566 567 /** 568 Split the original memory map, and add more entries to describe PE code section and data section. 569 This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP. 570 This function will merge entries with same attributes finally. 571 572 NOTE: It assumes PE code/data section are page aligned. 573 NOTE: It assumes enough entry is prepared for new memory map. 574 575 Split table: 576 +---------------+ 577 | Record X | 578 +---------------+ 579 | Record RtCode | 580 +---------------+ 581 | Record Y | 582 +---------------+ 583 ==> 584 +---------------+ 585 | Record X | 586 +---------------+ 587 | Record RtCode | 588 +---------------+ ---- 589 | Record RtData | | 590 +---------------+ | 591 | Record RtCode | |-> PE/COFF1 592 +---------------+ | 593 | Record RtData | | 594 +---------------+ ---- 595 | Record RtCode | 596 +---------------+ ---- 597 | Record RtData | | 598 +---------------+ | 599 | Record RtCode | |-> PE/COFF2 600 +---------------+ | 601 | Record RtData | | 602 +---------------+ ---- 603 | Record RtCode | 604 +---------------+ 605 | Record Y | 606 +---------------+ 607 608 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the 609 MemoryMap buffer. On input, this is the size of 610 old MemoryMap before split. The actual buffer 611 size of MemoryMap is MemoryMapSize + 612 (AdditionalRecordCount * DescriptorSize) calculated 613 below. On output, it is the size of new MemoryMap 614 after split. 615 @param[in, out] MemoryMap A pointer to the buffer in which firmware places 616 the current memory map. 617 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. 618 **/ 619 STATIC 620 VOID 621 SplitTable ( 622 IN OUT UINTN *MemoryMapSize, 623 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 624 IN UINTN DescriptorSize 625 ) 626 { 627 INTN IndexOld; 628 INTN IndexNew; 629 UINTN MaxSplitRecordCount; 630 UINTN RealSplitRecordCount; 631 UINTN TotalSplitRecordCount; 632 UINTN AdditionalRecordCount; 633 634 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 2) * mImagePropertiesPrivateData.ImageRecordCount; 635 636 TotalSplitRecordCount = 0; 637 // 638 // Let old record point to end of valid MemoryMap buffer. 639 // 640 IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1; 641 // 642 // Let new record point to end of full MemoryMap buffer. 643 // 644 IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount; 645 for (; IndexOld >= 0; IndexOld--) { 646 MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize)); 647 // 648 // Split this MemoryMap record 649 // 650 IndexNew -= MaxSplitRecordCount; 651 RealSplitRecordCount = SplitRecord ( 652 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize), 653 (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize), 654 MaxSplitRecordCount, 655 DescriptorSize 656 ); 657 // 658 // Adjust IndexNew according to real split. 659 // 660 if (MaxSplitRecordCount != RealSplitRecordCount) { 661 CopyMem ( 662 ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize), 663 ((UINT8 *)MemoryMap + IndexNew * DescriptorSize), 664 (RealSplitRecordCount + 1) * DescriptorSize 665 ); 666 } 667 IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount; 668 TotalSplitRecordCount += RealSplitRecordCount; 669 IndexNew --; 670 } 671 // 672 // Move all records to the beginning. 673 // 674 CopyMem ( 675 MemoryMap, 676 (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize, 677 (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize 678 ); 679 680 *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount; 681 682 // 683 // Sort from low to high (Just in case) 684 // 685 SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize); 686 687 // 688 // Set RuntimeData to XP 689 // 690 EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize); 691 692 // 693 // Merge same type to save entry size 694 // 695 MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize); 696 697 return ; 698 } 699 700 /** 701 This function for GetMemoryMap() with memory attributes table. 702 703 It calls original GetMemoryMap() to get the original memory map information. Then 704 plus the additional memory map entries for PE Code/Data seperation. 705 706 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the 707 MemoryMap buffer. On input, this is the size of 708 the buffer allocated by the caller. On output, 709 it is the size of the buffer returned by the 710 firmware if the buffer was large enough, or the 711 size of the buffer needed to contain the map if 712 the buffer was too small. 713 @param[in, out] MemoryMap A pointer to the buffer in which firmware places 714 the current memory map. 715 @param[out] MapKey A pointer to the location in which firmware 716 returns the key for the current memory map. 717 @param[out] DescriptorSize A pointer to the location in which firmware 718 returns the size, in bytes, of an individual 719 EFI_MEMORY_DESCRIPTOR. 720 @param[out] DescriptorVersion A pointer to the location in which firmware 721 returns the version number associated with the 722 EFI_MEMORY_DESCRIPTOR. 723 724 @retval EFI_SUCCESS The memory map was returned in the MemoryMap 725 buffer. 726 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current 727 buffer size needed to hold the memory map is 728 returned in MemoryMapSize. 729 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. 730 731 **/ 732 STATIC 733 EFI_STATUS 734 EFIAPI 735 SmmCoreGetMemoryMapMemoryAttributesTable ( 736 IN OUT UINTN *MemoryMapSize, 737 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 738 OUT UINTN *MapKey, 739 OUT UINTN *DescriptorSize, 740 OUT UINT32 *DescriptorVersion 741 ) 742 { 743 EFI_STATUS Status; 744 UINTN OldMemoryMapSize; 745 UINTN AdditionalRecordCount; 746 747 // 748 // If PE code/data is not aligned, just return. 749 // 750 if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { 751 return SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); 752 } 753 754 if (MemoryMapSize == NULL) { 755 return EFI_INVALID_PARAMETER; 756 } 757 758 AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 2) * mImagePropertiesPrivateData.ImageRecordCount; 759 760 OldMemoryMapSize = *MemoryMapSize; 761 Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); 762 if (Status == EFI_BUFFER_TOO_SMALL) { 763 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; 764 } else if (Status == EFI_SUCCESS) { 765 if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) { 766 *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; 767 // 768 // Need update status to buffer too small 769 // 770 Status = EFI_BUFFER_TOO_SMALL; 771 } else { 772 // 773 // Split PE code/data 774 // 775 ASSERT(MemoryMap != NULL); 776 SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize); 777 } 778 } 779 780 return Status; 781 } 782 783 // 784 // Below functions are for ImageRecord 785 // 786 787 /** 788 Set MemoryProtectionAttribute accroding to PE/COFF image section alignment. 789 790 @param[in] SectionAlignment PE/COFF section alignment 791 **/ 792 STATIC 793 VOID 794 SetMemoryAttributesTableSectionAlignment ( 795 IN UINT32 SectionAlignment 796 ) 797 { 798 if (((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) && 799 ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) { 800 DEBUG ((DEBUG_VERBOSE, "SMM SetMemoryAttributesTableSectionAlignment - Clear\n")); 801 mMemoryProtectionAttribute &= ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); 802 } 803 } 804 805 /** 806 Swap two code sections in image record. 807 808 @param[in] FirstImageRecordCodeSection first code section in image record 809 @param[in] SecondImageRecordCodeSection second code section in image record 810 **/ 811 STATIC 812 VOID 813 SwapImageRecordCodeSection ( 814 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection, 815 IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection 816 ) 817 { 818 IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection; 819 820 TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase; 821 TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize; 822 823 FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase; 824 FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize; 825 826 SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase; 827 SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize; 828 } 829 830 /** 831 Sort code section in image record, based upon CodeSegmentBase from low to high. 832 833 @param[in] ImageRecord image record to be sorted 834 **/ 835 STATIC 836 VOID 837 SortImageRecordCodeSection ( 838 IN IMAGE_PROPERTIES_RECORD *ImageRecord 839 ) 840 { 841 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; 842 IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection; 843 LIST_ENTRY *ImageRecordCodeSectionLink; 844 LIST_ENTRY *NextImageRecordCodeSectionLink; 845 LIST_ENTRY *ImageRecordCodeSectionEndLink; 846 LIST_ENTRY *ImageRecordCodeSectionList; 847 848 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; 849 850 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; 851 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; 852 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; 853 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { 854 ImageRecordCodeSection = CR ( 855 ImageRecordCodeSectionLink, 856 IMAGE_PROPERTIES_RECORD_CODE_SECTION, 857 Link, 858 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE 859 ); 860 while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { 861 NextImageRecordCodeSection = CR ( 862 NextImageRecordCodeSectionLink, 863 IMAGE_PROPERTIES_RECORD_CODE_SECTION, 864 Link, 865 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE 866 ); 867 if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) { 868 SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection); 869 } 870 NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink; 871 } 872 873 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; 874 NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; 875 } 876 } 877 878 /** 879 Check if code section in image record is valid. 880 881 @param[in] ImageRecord image record to be checked 882 883 @retval TRUE image record is valid 884 @retval FALSE image record is invalid 885 **/ 886 STATIC 887 BOOLEAN 888 IsImageRecordCodeSectionValid ( 889 IN IMAGE_PROPERTIES_RECORD *ImageRecord 890 ) 891 { 892 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; 893 IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection; 894 LIST_ENTRY *ImageRecordCodeSectionLink; 895 LIST_ENTRY *ImageRecordCodeSectionEndLink; 896 LIST_ENTRY *ImageRecordCodeSectionList; 897 898 DEBUG ((DEBUG_VERBOSE, "SMM ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount)); 899 900 ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; 901 902 ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; 903 ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; 904 LastImageRecordCodeSection = NULL; 905 while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { 906 ImageRecordCodeSection = CR ( 907 ImageRecordCodeSectionLink, 908 IMAGE_PROPERTIES_RECORD_CODE_SECTION, 909 Link, 910 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE 911 ); 912 if (ImageRecordCodeSection->CodeSegmentSize == 0) { 913 return FALSE; 914 } 915 if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) { 916 return FALSE; 917 } 918 if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) { 919 return FALSE; 920 } 921 if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) { 922 return FALSE; 923 } 924 if (LastImageRecordCodeSection != NULL) { 925 if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) { 926 return FALSE; 927 } 928 } 929 930 LastImageRecordCodeSection = ImageRecordCodeSection; 931 ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; 932 } 933 934 return TRUE; 935 } 936 937 /** 938 Swap two image records. 939 940 @param[in] FirstImageRecord first image record. 941 @param[in] SecondImageRecord second image record. 942 **/ 943 STATIC 944 VOID 945 SwapImageRecord ( 946 IN IMAGE_PROPERTIES_RECORD *FirstImageRecord, 947 IN IMAGE_PROPERTIES_RECORD *SecondImageRecord 948 ) 949 { 950 IMAGE_PROPERTIES_RECORD TempImageRecord; 951 952 TempImageRecord.ImageBase = FirstImageRecord->ImageBase; 953 TempImageRecord.ImageSize = FirstImageRecord->ImageSize; 954 TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount; 955 956 FirstImageRecord->ImageBase = SecondImageRecord->ImageBase; 957 FirstImageRecord->ImageSize = SecondImageRecord->ImageSize; 958 FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount; 959 960 SecondImageRecord->ImageBase = TempImageRecord.ImageBase; 961 SecondImageRecord->ImageSize = TempImageRecord.ImageSize; 962 SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount; 963 964 SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList); 965 } 966 967 /** 968 Sort image record based upon the ImageBase from low to high. 969 **/ 970 STATIC 971 VOID 972 SortImageRecord ( 973 VOID 974 ) 975 { 976 IMAGE_PROPERTIES_RECORD *ImageRecord; 977 IMAGE_PROPERTIES_RECORD *NextImageRecord; 978 LIST_ENTRY *ImageRecordLink; 979 LIST_ENTRY *NextImageRecordLink; 980 LIST_ENTRY *ImageRecordEndLink; 981 LIST_ENTRY *ImageRecordList; 982 983 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; 984 985 ImageRecordLink = ImageRecordList->ForwardLink; 986 NextImageRecordLink = ImageRecordLink->ForwardLink; 987 ImageRecordEndLink = ImageRecordList; 988 while (ImageRecordLink != ImageRecordEndLink) { 989 ImageRecord = CR ( 990 ImageRecordLink, 991 IMAGE_PROPERTIES_RECORD, 992 Link, 993 IMAGE_PROPERTIES_RECORD_SIGNATURE 994 ); 995 while (NextImageRecordLink != ImageRecordEndLink) { 996 NextImageRecord = CR ( 997 NextImageRecordLink, 998 IMAGE_PROPERTIES_RECORD, 999 Link, 1000 IMAGE_PROPERTIES_RECORD_SIGNATURE 1001 ); 1002 if (ImageRecord->ImageBase > NextImageRecord->ImageBase) { 1003 SwapImageRecord (ImageRecord, NextImageRecord); 1004 } 1005 NextImageRecordLink = NextImageRecordLink->ForwardLink; 1006 } 1007 1008 ImageRecordLink = ImageRecordLink->ForwardLink; 1009 NextImageRecordLink = ImageRecordLink->ForwardLink; 1010 } 1011 } 1012 1013 /** 1014 Dump image record. 1015 **/ 1016 STATIC 1017 VOID 1018 DumpImageRecord ( 1019 VOID 1020 ) 1021 { 1022 IMAGE_PROPERTIES_RECORD *ImageRecord; 1023 LIST_ENTRY *ImageRecordLink; 1024 LIST_ENTRY *ImageRecordList; 1025 UINTN Index; 1026 1027 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; 1028 1029 for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0; 1030 ImageRecordLink != ImageRecordList; 1031 ImageRecordLink = ImageRecordLink->ForwardLink, Index++) { 1032 ImageRecord = CR ( 1033 ImageRecordLink, 1034 IMAGE_PROPERTIES_RECORD, 1035 Link, 1036 IMAGE_PROPERTIES_RECORD_SIGNATURE 1037 ); 1038 DEBUG ((DEBUG_VERBOSE, "SMM Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize)); 1039 } 1040 } 1041 1042 /** 1043 Insert image record. 1044 1045 @param[in] DriverEntry Driver information 1046 **/ 1047 VOID 1048 SmmInsertImageRecord ( 1049 IN EFI_SMM_DRIVER_ENTRY *DriverEntry 1050 ) 1051 { 1052 VOID *ImageAddress; 1053 EFI_IMAGE_DOS_HEADER *DosHdr; 1054 UINT32 PeCoffHeaderOffset; 1055 UINT32 SectionAlignment; 1056 EFI_IMAGE_SECTION_HEADER *Section; 1057 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; 1058 UINT8 *Name; 1059 UINTN Index; 1060 IMAGE_PROPERTIES_RECORD *ImageRecord; 1061 CHAR8 *PdbPointer; 1062 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; 1063 UINT16 Magic; 1064 1065 DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry)); 1066 DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%016lx - 0x%08x\n", DriverEntry->ImageBuffer, DriverEntry->NumberOfPage)); 1067 1068 ImageRecord = AllocatePool (sizeof(*ImageRecord)); 1069 if (ImageRecord == NULL) { 1070 return ; 1071 } 1072 ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE; 1073 1074 DEBUG ((DEBUG_VERBOSE, "SMM ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); 1075 1076 // 1077 // Step 1: record whole region 1078 // 1079 ImageRecord->ImageBase = DriverEntry->ImageBuffer; 1080 ImageRecord->ImageSize = EfiPagesToSize(DriverEntry->NumberOfPage); 1081 1082 ImageAddress = (VOID *)(UINTN)DriverEntry->ImageBuffer; 1083 1084 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); 1085 if (PdbPointer != NULL) { 1086 DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer)); 1087 } 1088 1089 // 1090 // Check PE/COFF image 1091 // 1092 DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; 1093 PeCoffHeaderOffset = 0; 1094 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { 1095 PeCoffHeaderOffset = DosHdr->e_lfanew; 1096 } 1097 1098 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); 1099 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { 1100 DEBUG ((DEBUG_VERBOSE, "SMM Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature)); 1101 goto Finish; 1102 } 1103 1104 // 1105 // Get SectionAlignment 1106 // 1107 if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 1108 // 1109 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value 1110 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the 1111 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 1112 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 1113 // 1114 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; 1115 } else { 1116 // 1117 // Get the magic value from the PE/COFF Optional Header 1118 // 1119 Magic = Hdr.Pe32->OptionalHeader.Magic; 1120 } 1121 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 1122 SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment; 1123 } else { 1124 SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment; 1125 } 1126 1127 SetMemoryAttributesTableSectionAlignment (SectionAlignment); 1128 if ((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { 1129 DEBUG ((DEBUG_WARN, "SMM !!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n", 1130 SectionAlignment, EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10)); 1131 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); 1132 if (PdbPointer != NULL) { 1133 DEBUG ((DEBUG_WARN, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); 1134 } 1135 goto Finish; 1136 } 1137 1138 Section = (EFI_IMAGE_SECTION_HEADER *) ( 1139 (UINT8 *) (UINTN) ImageAddress + 1140 PeCoffHeaderOffset + 1141 sizeof(UINT32) + 1142 sizeof(EFI_IMAGE_FILE_HEADER) + 1143 Hdr.Pe32->FileHeader.SizeOfOptionalHeader 1144 ); 1145 ImageRecord->CodeSegmentCount = 0; 1146 InitializeListHead (&ImageRecord->CodeSegmentList); 1147 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { 1148 Name = Section[Index].Name; 1149 DEBUG (( 1150 DEBUG_VERBOSE, 1151 "SMM Section - '%c%c%c%c%c%c%c%c'\n", 1152 Name[0], 1153 Name[1], 1154 Name[2], 1155 Name[3], 1156 Name[4], 1157 Name[5], 1158 Name[6], 1159 Name[7] 1160 )); 1161 1162 if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) { 1163 DEBUG ((DEBUG_VERBOSE, "SMM VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize)); 1164 DEBUG ((DEBUG_VERBOSE, "SMM VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress)); 1165 DEBUG ((DEBUG_VERBOSE, "SMM SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData)); 1166 DEBUG ((DEBUG_VERBOSE, "SMM PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData)); 1167 DEBUG ((DEBUG_VERBOSE, "SMM PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations)); 1168 DEBUG ((DEBUG_VERBOSE, "SMM PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers)); 1169 DEBUG ((DEBUG_VERBOSE, "SMM NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations)); 1170 DEBUG ((DEBUG_VERBOSE, "SMM NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers)); 1171 DEBUG ((DEBUG_VERBOSE, "SMM Characteristics - 0x%08x\n", Section[Index].Characteristics)); 1172 1173 // 1174 // Step 2: record code section 1175 // 1176 ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection)); 1177 if (ImageRecordCodeSection == NULL) { 1178 return ; 1179 } 1180 ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE; 1181 1182 ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress; 1183 ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData; 1184 1185 DEBUG ((DEBUG_VERBOSE, "SMM ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize)); 1186 1187 InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link); 1188 ImageRecord->CodeSegmentCount++; 1189 } 1190 } 1191 1192 if (ImageRecord->CodeSegmentCount == 0) { 1193 SetMemoryAttributesTableSectionAlignment (1); 1194 DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n")); 1195 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress); 1196 if (PdbPointer != NULL) { 1197 DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); 1198 } 1199 goto Finish; 1200 } 1201 1202 // 1203 // Final 1204 // 1205 SortImageRecordCodeSection (ImageRecord); 1206 // 1207 // Check overlap all section in ImageBase/Size 1208 // 1209 if (!IsImageRecordCodeSectionValid (ImageRecord)) { 1210 DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n")); 1211 goto Finish; 1212 } 1213 1214 InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link); 1215 mImagePropertiesPrivateData.ImageRecordCount++; 1216 1217 SortImageRecord (); 1218 1219 if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) { 1220 mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount; 1221 } 1222 1223 Finish: 1224 return ; 1225 } 1226 1227 /** 1228 Find image record accroding to image base and size. 1229 1230 @param[in] ImageBase Base of PE image 1231 @param[in] ImageSize Size of PE image 1232 1233 @return image record 1234 **/ 1235 STATIC 1236 IMAGE_PROPERTIES_RECORD * 1237 FindImageRecord ( 1238 IN EFI_PHYSICAL_ADDRESS ImageBase, 1239 IN UINT64 ImageSize 1240 ) 1241 { 1242 IMAGE_PROPERTIES_RECORD *ImageRecord; 1243 LIST_ENTRY *ImageRecordLink; 1244 LIST_ENTRY *ImageRecordList; 1245 1246 ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; 1247 1248 for (ImageRecordLink = ImageRecordList->ForwardLink; 1249 ImageRecordLink != ImageRecordList; 1250 ImageRecordLink = ImageRecordLink->ForwardLink) { 1251 ImageRecord = CR ( 1252 ImageRecordLink, 1253 IMAGE_PROPERTIES_RECORD, 1254 Link, 1255 IMAGE_PROPERTIES_RECORD_SIGNATURE 1256 ); 1257 1258 if ((ImageBase == ImageRecord->ImageBase) && 1259 (ImageSize == ImageRecord->ImageSize)) { 1260 return ImageRecord; 1261 } 1262 } 1263 1264 return NULL; 1265 } 1266 1267 /** 1268 Remove Image record. 1269 1270 @param[in] DriverEntry Driver information 1271 **/ 1272 VOID 1273 SmmRemoveImageRecord ( 1274 IN EFI_SMM_DRIVER_ENTRY *DriverEntry 1275 ) 1276 { 1277 IMAGE_PROPERTIES_RECORD *ImageRecord; 1278 LIST_ENTRY *CodeSegmentListHead; 1279 IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; 1280 1281 DEBUG ((DEBUG_VERBOSE, "SMM RemoveImageRecord - 0x%x\n", DriverEntry)); 1282 DEBUG ((DEBUG_VERBOSE, "SMM RemoveImageRecord - 0x%016lx - 0x%016lx\n", DriverEntry->ImageBuffer, DriverEntry->NumberOfPage)); 1283 1284 ImageRecord = FindImageRecord (DriverEntry->ImageBuffer, EfiPagesToSize(DriverEntry->NumberOfPage)); 1285 if (ImageRecord == NULL) { 1286 DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! ImageRecord not found !!!!!!!!\n")); 1287 return ; 1288 } 1289 1290 CodeSegmentListHead = &ImageRecord->CodeSegmentList; 1291 while (!IsListEmpty (CodeSegmentListHead)) { 1292 ImageRecordCodeSection = CR ( 1293 CodeSegmentListHead->ForwardLink, 1294 IMAGE_PROPERTIES_RECORD_CODE_SECTION, 1295 Link, 1296 IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE 1297 ); 1298 RemoveEntryList (&ImageRecordCodeSection->Link); 1299 FreePool (ImageRecordCodeSection); 1300 } 1301 1302 RemoveEntryList (&ImageRecord->Link); 1303 FreePool (ImageRecord); 1304 mImagePropertiesPrivateData.ImageRecordCount--; 1305 } 1306 1307 /** 1308 Publish MemoryAttributesTable to SMM configuration table. 1309 **/ 1310 VOID 1311 PublishMemoryAttributesTable ( 1312 VOID 1313 ) 1314 { 1315 UINTN MemoryMapSize; 1316 EFI_MEMORY_DESCRIPTOR *MemoryMap; 1317 UINTN MapKey; 1318 UINTN DescriptorSize; 1319 UINT32 DescriptorVersion; 1320 UINTN Index; 1321 EFI_STATUS Status; 1322 UINTN RuntimeEntryCount; 1323 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable; 1324 EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry; 1325 UINTN MemoryAttributesTableSize; 1326 1327 MemoryMapSize = 0; 1328 MemoryMap = NULL; 1329 Status = SmmCoreGetMemoryMapMemoryAttributesTable ( 1330 &MemoryMapSize, 1331 MemoryMap, 1332 &MapKey, 1333 &DescriptorSize, 1334 &DescriptorVersion 1335 ); 1336 ASSERT (Status == EFI_BUFFER_TOO_SMALL); 1337 1338 do { 1339 DEBUG ((DEBUG_INFO, "MemoryMapSize - 0x%x\n", MemoryMapSize)); 1340 MemoryMap = AllocatePool (MemoryMapSize); 1341 ASSERT (MemoryMap != NULL); 1342 DEBUG ((DEBUG_INFO, "MemoryMap - 0x%x\n", MemoryMap)); 1343 1344 Status = SmmCoreGetMemoryMapMemoryAttributesTable ( 1345 &MemoryMapSize, 1346 MemoryMap, 1347 &MapKey, 1348 &DescriptorSize, 1349 &DescriptorVersion 1350 ); 1351 if (EFI_ERROR (Status)) { 1352 FreePool (MemoryMap); 1353 } 1354 } while (Status == EFI_BUFFER_TOO_SMALL); 1355 1356 // 1357 // Allocate MemoryAttributesTable 1358 // 1359 RuntimeEntryCount = MemoryMapSize/DescriptorSize; 1360 MemoryAttributesTableSize = sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount; 1361 MemoryAttributesTable = AllocatePool (sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount); 1362 ASSERT (MemoryAttributesTable != NULL); 1363 MemoryAttributesTable->Version = EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION; 1364 MemoryAttributesTable->NumberOfEntries = (UINT32)RuntimeEntryCount; 1365 MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize; 1366 MemoryAttributesTable->Reserved = 0; 1367 DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n")); 1368 DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version)); 1369 DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries)); 1370 DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize)); 1371 MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1); 1372 for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) { 1373 CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize); 1374 DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryAttributesEntry)); 1375 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryAttributesEntry->Type)); 1376 DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart)); 1377 DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart)); 1378 DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages)); 1379 DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute)); 1380 MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize); 1381 1382 MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize); 1383 } 1384 1385 Status = gSmst->SmmInstallConfigurationTable (gSmst, &gEdkiiPiSmmMemoryAttributesTableGuid, MemoryAttributesTable, MemoryAttributesTableSize); 1386 ASSERT_EFI_ERROR (Status); 1387 } 1388 1389 /** 1390 This function returns if image is inside SMRAM. 1391 1392 @param[in] LoadedImage LoadedImage protocol instance for an image. 1393 1394 @retval TRUE the image is inside SMRAM. 1395 @retval FALSE the image is outside SMRAM. 1396 **/ 1397 BOOLEAN 1398 IsImageInsideSmram ( 1399 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage 1400 ) 1401 { 1402 UINTN Index; 1403 1404 for (Index = 0; Index < mFullSmramRangeCount; Index++) { 1405 if ((mFullSmramRanges[Index].PhysicalStart <= (UINTN)LoadedImage->ImageBase)&& 1406 (mFullSmramRanges[Index].PhysicalStart + mFullSmramRanges[Index].PhysicalSize >= (UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)) { 1407 return TRUE; 1408 } 1409 } 1410 1411 return FALSE; 1412 } 1413 1414 /** 1415 This function installs all SMM image record information. 1416 **/ 1417 VOID 1418 SmmInstallImageRecord ( 1419 VOID 1420 ) 1421 { 1422 EFI_STATUS Status; 1423 UINTN NoHandles; 1424 EFI_HANDLE *HandleBuffer; 1425 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 1426 UINTN Index; 1427 EFI_SMM_DRIVER_ENTRY DriverEntry; 1428 1429 Status = SmmLocateHandleBuffer ( 1430 ByProtocol, 1431 &gEfiLoadedImageProtocolGuid, 1432 NULL, 1433 &NoHandles, 1434 &HandleBuffer 1435 ); 1436 if (EFI_ERROR (Status)) { 1437 return ; 1438 } 1439 1440 for (Index = 0; Index < NoHandles; Index++) { 1441 Status = gSmst->SmmHandleProtocol ( 1442 HandleBuffer[Index], 1443 &gEfiLoadedImageProtocolGuid, 1444 (VOID **)&LoadedImage 1445 ); 1446 if (EFI_ERROR (Status)) { 1447 continue; 1448 } 1449 DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize)); 1450 { 1451 VOID *PdbPointer; 1452 PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); 1453 if (PdbPointer != NULL) { 1454 DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer)); 1455 } 1456 } 1457 DEBUG ((DEBUG_VERBOSE, "\n")); 1458 ZeroMem (&DriverEntry, sizeof(DriverEntry)); 1459 DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase; 1460 DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES((UINTN)LoadedImage->ImageSize); 1461 SmmInsertImageRecord (&DriverEntry); 1462 } 1463 1464 FreePool (HandleBuffer); 1465 } 1466 1467 /** 1468 Install MemoryAttributesTable. 1469 1470 @param[in] Protocol Points to the protocol's unique identifier. 1471 @param[in] Interface Points to the interface instance. 1472 @param[in] Handle The handle on which the interface was installed. 1473 1474 @retval EFI_SUCCESS Notification runs successfully. 1475 **/ 1476 EFI_STATUS 1477 EFIAPI 1478 SmmInstallMemoryAttributesTable ( 1479 IN CONST EFI_GUID *Protocol, 1480 IN VOID *Interface, 1481 IN EFI_HANDLE Handle 1482 ) 1483 { 1484 SmmInstallImageRecord (); 1485 1486 DEBUG ((DEBUG_INFO, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute)); 1487 if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { 1488 return EFI_SUCCESS; 1489 } 1490 1491 DEBUG ((DEBUG_VERBOSE, "SMM Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); 1492 DEBUG ((DEBUG_VERBOSE, "SMM Dump ImageRecord:\n")); 1493 DumpImageRecord (); 1494 1495 PublishMemoryAttributesTable (); 1496 1497 return EFI_SUCCESS; 1498 } 1499 1500 /** 1501 Initialize MemoryAttributesTable support. 1502 **/ 1503 VOID 1504 EFIAPI 1505 SmmCoreInitializeMemoryAttributesTable ( 1506 VOID 1507 ) 1508 { 1509 EFI_STATUS Status; 1510 VOID *Registration; 1511 1512 Status = gSmst->SmmRegisterProtocolNotify ( 1513 &gEfiSmmEndOfDxeProtocolGuid, 1514 SmmInstallMemoryAttributesTable, 1515 &Registration 1516 ); 1517 ASSERT_EFI_ERROR (Status); 1518 1519 return ; 1520 } 1521