--- /dev/null
+/** @file\r
+ PI SMM MemoryAttributes support\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+\r
+#include <Guid/PiSmmMemoryAttributesTable.h>\r
+\r
+#include "PiSmmCore.h"\r
+\r
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \\r
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))\r
+\r
+#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+ EFI_PHYSICAL_ADDRESS CodeSegmentBase;\r
+ UINT64 CodeSegmentSize;\r
+} IMAGE_PROPERTIES_RECORD_CODE_SECTION;\r
+\r
+#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+ EFI_PHYSICAL_ADDRESS ImageBase;\r
+ UINT64 ImageSize;\r
+ UINTN CodeSegmentCount;\r
+ LIST_ENTRY CodeSegmentList;\r
+} IMAGE_PROPERTIES_RECORD;\r
+\r
+#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ UINTN ImageRecordCount;\r
+ UINTN CodeSegmentCountMax;\r
+ LIST_ENTRY ImageRecordList;\r
+} IMAGE_PROPERTIES_PRIVATE_DATA;\r
+\r
+IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {\r
+ IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,\r
+ 0,\r
+ 0,\r
+ INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)\r
+};\r
+\r
+#define EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA BIT0\r
+\r
+UINT64 mMemoryProtectionAttribute = EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA;\r
+\r
+//\r
+// Below functions are for MemoryMap\r
+//\r
+\r
+/**\r
+ Converts a number of EFI_PAGEs to a size in bytes.\r
+\r
+ NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.\r
+\r
+ @param[in] Pages The number of EFI_PAGES.\r
+\r
+ @return The number of bytes associated with the number of EFI_PAGEs specified\r
+ by Pages.\r
+**/\r
+STATIC\r
+UINT64\r
+EfiPagesToSize (\r
+ IN UINT64 Pages\r
+ )\r
+{\r
+ return LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
+}\r
+\r
+/**\r
+ Converts a size, in bytes, to a number of EFI_PAGESs.\r
+\r
+ NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.\r
+\r
+ @param[in] Size A size in bytes.\r
+\r
+ @return The number of EFI_PAGESs associated with the number of bytes specified\r
+ by Size.\r
+\r
+**/\r
+STATIC\r
+UINT64\r
+EfiSizeToPages (\r
+ IN UINT64 Size\r
+ )\r
+{\r
+ return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Check the consistency of Smm memory attributes table.\r
+\r
+ @param[in] MemoryAttributesTable PI SMM memory attributes table\r
+**/\r
+VOID\r
+SmmMemoryAttributesTableConsistencyCheck (\r
+ IN EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+ UINTN MemoryMapEntryCount;\r
+ UINTN DescriptorSize;\r
+ UINTN Index;\r
+ UINT64 Address;\r
+\r
+ Address = 0;\r
+ MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;\r
+ DescriptorSize = MemoryAttributesTable->DescriptorSize;\r
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);\r
+ for (Index = 0; Index < MemoryMapEntryCount; Index++) {\r
+ if (Address != 0) {\r
+ ASSERT (Address == MemoryMap->PhysicalStart);\r
+ }\r
+ Address = MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE(MemoryMap->NumberOfPages);\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Sort memory map entries based upon PhysicalStart, from low to high.\r
+\r
+ @param[in] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+SortMemoryMap (\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN UINTN MemoryMapSize,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+ while (MemoryMapEntry < MemoryMapEnd) {\r
+ while (NextMemoryMapEntry < MemoryMapEnd) {\r
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {\r
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ }\r
+\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Merge continous memory map entries whose have same attributes.\r
+\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ the current memory map. On output,\r
+ it is the size of new memory map after merge.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+MergeMemoryMap (\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+ UINT64 MemoryBlockLength;\r
+ EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ NewMemoryMapEntry = MemoryMap;\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);\r
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+ CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+\r
+ do {\r
+ MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages));\r
+ if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&\r
+ (MemoryMapEntry->Type == NextMemoryMapEntry->Type) &&\r
+ (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&\r
+ ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {\r
+ MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+ if (NewMemoryMapEntry != MemoryMapEntry) {\r
+ NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;\r
+ }\r
+\r
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ continue;\r
+ } else {\r
+ MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);\r
+ break;\r
+ }\r
+ } while (TRUE);\r
+\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Enforce memory map attributes.\r
+ This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.\r
+\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+EnforceMemoryMapAttribute (\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN UINTN MemoryMapSize,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
+\r
+ MemoryMapEntry = MemoryMap;\r
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);\r
+ while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {\r
+ switch (MemoryMapEntry->Type) {\r
+ case EfiRuntimeServicesCode:\r
+ MemoryMapEntry->Attribute |= EFI_MEMORY_RO;\r
+ break;\r
+ case EfiRuntimeServicesData:\r
+ MemoryMapEntry->Attribute |= EFI_MEMORY_XP;\r
+ break;\r
+ }\r
+\r
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].\r
+\r
+ @param[in] Buffer Start Address\r
+ @param[in] Length Address length\r
+\r
+ @return first image record covered by [buffer, length]\r
+**/\r
+STATIC\r
+IMAGE_PROPERTIES_RECORD *\r
+GetImageRecordByAddress (\r
+ IN EFI_PHYSICAL_ADDRESS Buffer,\r
+ IN UINT64 Length\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ LIST_ENTRY *ImageRecordLink;\r
+ LIST_ENTRY *ImageRecordList;\r
+\r
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+ for (ImageRecordLink = ImageRecordList->ForwardLink;\r
+ ImageRecordLink != ImageRecordList;\r
+ ImageRecordLink = ImageRecordLink->ForwardLink) {\r
+ ImageRecord = CR (\r
+ ImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+\r
+ if ((Buffer <= ImageRecord->ImageBase) &&\r
+ (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
+ return ImageRecord;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Set the memory map to new entries, according to one old entry,\r
+ based upon PE code section and data section in image record\r
+\r
+ @param[in] ImageRecord An image record whose [ImageBase, ImageSize] covered\r
+ by old memory map entry.\r
+ @param[in, out] NewRecord A pointer to several new memory map entries.\r
+ The caller gurantee the buffer size be 1 +\r
+ (SplitRecordCount * DescriptorSize) calculated\r
+ below.\r
+ @param[in] OldRecord A pointer to one old memory map entry.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+UINTN\r
+SetNewRecord (\r
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,\r
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR TempRecord;\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+ LIST_ENTRY *ImageRecordCodeSectionLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionList;\r
+ UINTN NewRecordCount;\r
+ UINT64 PhysicalEnd;\r
+ UINT64 ImageEnd;\r
+\r
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
+ NewRecordCount = 0;\r
+\r
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+ ImageRecordCodeSection = CR (\r
+ ImageRecordCodeSectionLink,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+ );\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+\r
+ if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {\r
+ //\r
+ // DATA\r
+ //\r
+ NewRecord->Type = EfiRuntimeServicesData;\r
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+ NewRecord->VirtualStart = 0;\r
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);\r
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
+ if (NewRecord->NumberOfPages != 0) {\r
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+ NewRecordCount ++;\r
+ }\r
+\r
+ //\r
+ // CODE\r
+ //\r
+ NewRecord->Type = EfiRuntimeServicesCode;\r
+ NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;\r
+ NewRecord->VirtualStart = 0;\r
+ NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize);\r
+ NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;\r
+ if (NewRecord->NumberOfPages != 0) {\r
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+ NewRecordCount ++;\r
+ }\r
+\r
+ TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize));\r
+ TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart);\r
+ if (TempRecord.NumberOfPages == 0) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+\r
+ //\r
+ // Final DATA\r
+ //\r
+ if (TempRecord.PhysicalStart < ImageEnd) {\r
+ NewRecord->Type = EfiRuntimeServicesData;\r
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+ NewRecord->VirtualStart = 0;\r
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);\r
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
+ NewRecordCount ++;\r
+ }\r
+\r
+ return NewRecordCount;\r
+}\r
+\r
+/**\r
+ Return the max number of new splitted entries, according to one old entry,\r
+ based upon PE code section and data section.\r
+\r
+ @param[in] OldRecord A pointer to one old memory map entry.\r
+\r
+ @retval 0 no entry need to be splitted.\r
+ @return the max number of new splitted entries\r
+**/\r
+STATIC\r
+UINTN\r
+GetMaxSplitRecordCount (\r
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ UINTN SplitRecordCount;\r
+ UINT64 PhysicalStart;\r
+ UINT64 PhysicalEnd;\r
+\r
+ SplitRecordCount = 0;\r
+ PhysicalStart = OldRecord->PhysicalStart;\r
+ PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize(OldRecord->NumberOfPages);\r
+\r
+ do {\r
+ ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
+ if (ImageRecord == NULL) {\r
+ break;\r
+ }\r
+ SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 1);\r
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
+\r
+ if (SplitRecordCount != 0) {\r
+ SplitRecordCount--;\r
+ }\r
+\r
+ return SplitRecordCount;\r
+}\r
+\r
+/**\r
+ Split the memory map to new entries, according to one old entry,\r
+ based upon PE code section and data section.\r
+\r
+ @param[in] OldRecord A pointer to one old memory map entry.\r
+ @param[in, out] NewRecord A pointer to several new memory map entries.\r
+ The caller gurantee the buffer size be 1 +\r
+ (SplitRecordCount * DescriptorSize) calculated\r
+ below.\r
+ @param[in] MaxSplitRecordCount The max number of splitted entries\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+\r
+ @retval 0 no entry is splitted.\r
+ @return the real number of splitted record.\r
+**/\r
+STATIC\r
+UINTN\r
+SplitRecord (\r
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,\r
+ IN UINTN MaxSplitRecordCount,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ EFI_MEMORY_DESCRIPTOR TempRecord;\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ IMAGE_PROPERTIES_RECORD *NewImageRecord;\r
+ UINT64 PhysicalStart;\r
+ UINT64 PhysicalEnd;\r
+ UINTN NewRecordCount;\r
+ UINTN TotalNewRecordCount;\r
+\r
+ if (MaxSplitRecordCount == 0) {\r
+ CopyMem (NewRecord, OldRecord, DescriptorSize);\r
+ return 0;\r
+ }\r
+\r
+ TotalNewRecordCount = 0;\r
+\r
+ //\r
+ // Override previous record\r
+ //\r
+ CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR));\r
+ PhysicalStart = TempRecord.PhysicalStart;\r
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages);\r
+\r
+ ImageRecord = NULL;\r
+ do {\r
+ NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart);\r
+ if (NewImageRecord == NULL) {\r
+ //\r
+ // No more image covered by this range, stop\r
+ //\r
+ if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) {\r
+ //\r
+ // If this is still address in this record, need record.\r
+ //\r
+ NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+ if (NewRecord->Type == EfiRuntimeServicesData) {\r
+ //\r
+ // Last record is DATA, just merge it.\r
+ //\r
+ NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart);\r
+ } else {\r
+ //\r
+ // Last record is CODE, create a new DATA entry.\r
+ //\r
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);\r
+ NewRecord->Type = EfiRuntimeServicesData;\r
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;\r
+ NewRecord->VirtualStart = 0;\r
+ NewRecord->NumberOfPages = TempRecord.NumberOfPages;\r
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;\r
+ TotalNewRecordCount ++;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ ImageRecord = NewImageRecord;\r
+\r
+ //\r
+ // Set new record\r
+ //\r
+ NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);\r
+ TotalNewRecordCount += NewRecordCount;\r
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);\r
+\r
+ //\r
+ // Update PhysicalStart, in order to exclude the image buffer already splitted.\r
+ //\r
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;\r
+ TempRecord.PhysicalStart = PhysicalStart;\r
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);\r
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));\r
+\r
+ return TotalNewRecordCount - 1;\r
+}\r
+\r
+/**\r
+ Split the original memory map, and add more entries to describe PE code section and data section.\r
+ This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP.\r
+ This function will merge entries with same attributes finally.\r
+\r
+ NOTE: It assumes PE code/data section are page aligned.\r
+ NOTE: It assumes enough entry is prepared for new memory map.\r
+\r
+ Split table:\r
+ +---------------+\r
+ | Record X |\r
+ +---------------+\r
+ | Record RtCode |\r
+ +---------------+\r
+ | Record Y |\r
+ +---------------+\r
+ ==>\r
+ +---------------+\r
+ | Record X |\r
+ +---------------+ ----\r
+ | Record RtData | |\r
+ +---------------+ |\r
+ | Record RtCode | |-> PE/COFF1\r
+ +---------------+ |\r
+ | Record RtData | |\r
+ +---------------+ ----\r
+ | Record RtData | |\r
+ +---------------+ |\r
+ | Record RtCode | |-> PE/COFF2\r
+ +---------------+ |\r
+ | Record RtData | |\r
+ +---------------+ ----\r
+ | Record Y |\r
+ +---------------+\r
+\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ old MemoryMap before split. The actual buffer\r
+ size of MemoryMap is MemoryMapSize +\r
+ (AdditionalRecordCount * DescriptorSize) calculated\r
+ below. On output, it is the size of new MemoryMap\r
+ after split.\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
+**/\r
+STATIC\r
+VOID\r
+SplitTable (\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ IN UINTN DescriptorSize\r
+ )\r
+{\r
+ INTN IndexOld;\r
+ INTN IndexNew;\r
+ UINTN MaxSplitRecordCount;\r
+ UINTN RealSplitRecordCount;\r
+ UINTN TotalSplitRecordCount;\r
+ UINTN AdditionalRecordCount;\r
+\r
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
+\r
+ TotalSplitRecordCount = 0;\r
+ //\r
+ // Let old record point to end of valid MemoryMap buffer.\r
+ //\r
+ IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;\r
+ //\r
+ // Let new record point to end of full MemoryMap buffer.\r
+ //\r
+ IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount;\r
+ for (; IndexOld >= 0; IndexOld--) {\r
+ MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize));\r
+ //\r
+ // Split this MemoryMap record\r
+ //\r
+ IndexNew -= MaxSplitRecordCount;\r
+ RealSplitRecordCount = SplitRecord (\r
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),\r
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
+ MaxSplitRecordCount,\r
+ DescriptorSize\r
+ );\r
+ //\r
+ // Adjust IndexNew according to real split.\r
+ //\r
+ CopyMem (\r
+ ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize),\r
+ ((UINT8 *)MemoryMap + IndexNew * DescriptorSize),\r
+ RealSplitRecordCount * DescriptorSize\r
+ );\r
+ IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount;\r
+ TotalSplitRecordCount += RealSplitRecordCount;\r
+ IndexNew --;\r
+ }\r
+ //\r
+ // Move all records to the beginning.\r
+ //\r
+ CopyMem (\r
+ MemoryMap,\r
+ (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize,\r
+ (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize\r
+ );\r
+\r
+ *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount;\r
+\r
+ //\r
+ // Sort from low to high (Just in case)\r
+ //\r
+ SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);\r
+\r
+ //\r
+ // Set RuntimeData to XP\r
+ //\r
+ EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize);\r
+\r
+ //\r
+ // Merge same type to save entry size\r
+ //\r
+ MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize);\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ This function for GetMemoryMap() with memory attributes table.\r
+\r
+ It calls original GetMemoryMap() to get the original memory map information. Then\r
+ plus the additional memory map entries for PE Code/Data seperation.\r
+\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ the buffer allocated by the caller. On output,\r
+ it is the size of the buffer returned by the\r
+ firmware if the buffer was large enough, or the\r
+ size of the buffer needed to contain the map if\r
+ the buffer was too small.\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[out] MapKey A pointer to the location in which firmware\r
+ returns the key for the current memory map.\r
+ @param[out] DescriptorSize A pointer to the location in which firmware\r
+ returns the size, in bytes, of an individual\r
+ EFI_MEMORY_DESCRIPTOR.\r
+ @param[out] DescriptorVersion A pointer to the location in which firmware\r
+ returns the version number associated with the\r
+ EFI_MEMORY_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
+ buffer.\r
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
+ buffer size needed to hold the memory map is\r
+ returned in MemoryMapSize.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCoreGetMemoryMapMemoryAttributesTable (\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ OUT UINTN *MapKey,\r
+ OUT UINTN *DescriptorSize,\r
+ OUT UINT32 *DescriptorVersion\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN OldMemoryMapSize;\r
+ UINTN AdditionalRecordCount;\r
+\r
+ //\r
+ // If PE code/data is not aligned, just return.\r
+ //\r
+ if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
+ return SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
+ }\r
+\r
+ if (MemoryMapSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount;\r
+\r
+ OldMemoryMapSize = *MemoryMapSize;\r
+ Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
+ } else if (Status == EFI_SUCCESS) {\r
+ if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {\r
+ *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;\r
+ //\r
+ // Need update status to buffer too small\r
+ //\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ //\r
+ // Split PE code/data\r
+ //\r
+ ASSERT(MemoryMap != NULL);\r
+ SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+//\r
+// Below functions are for ImageRecord\r
+//\r
+\r
+/**\r
+ Set MemoryProtectionAttribute accroding to PE/COFF image section alignment.\r
+\r
+ @param[in] SectionAlignment PE/COFF section alignment\r
+**/\r
+STATIC\r
+VOID\r
+SetMemoryAttributesTableSectionAlignment (\r
+ IN UINT32 SectionAlignment\r
+ )\r
+{\r
+ if (((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) &&\r
+ ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) {\r
+ DEBUG ((DEBUG_VERBOSE, "SMM SetMemoryAttributesTableSectionAlignment - Clear\n"));\r
+ mMemoryProtectionAttribute &= ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);\r
+ }\r
+}\r
+\r
+/**\r
+ Swap two code sections in image record.\r
+\r
+ @param[in] FirstImageRecordCodeSection first code section in image record\r
+ @param[in] SecondImageRecordCodeSection second code section in image record\r
+**/\r
+STATIC\r
+VOID\r
+SwapImageRecordCodeSection (\r
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,\r
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;\r
+\r
+ TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;\r
+ TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;\r
+\r
+ FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;\r
+ FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;\r
+\r
+ SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;\r
+ SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;\r
+}\r
+\r
+/**\r
+ Sort code section in image record, based upon CodeSegmentBase from low to high.\r
+\r
+ @param[in] ImageRecord image record to be sorted\r
+**/\r
+STATIC\r
+VOID\r
+SortImageRecordCodeSection (\r
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;\r
+ LIST_ENTRY *ImageRecordCodeSectionLink;\r
+ LIST_ENTRY *NextImageRecordCodeSectionLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionList;\r
+\r
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+ ImageRecordCodeSection = CR (\r
+ ImageRecordCodeSectionLink,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+ );\r
+ while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+ NextImageRecordCodeSection = CR (\r
+ NextImageRecordCodeSectionLink,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+ );\r
+ if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {\r
+ SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);\r
+ }\r
+ NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;\r
+ }\r
+\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Check if code section in image record is valid.\r
+\r
+ @param[in] ImageRecord image record to be checked\r
+\r
+ @retval TRUE image record is valid\r
+ @retval FALSE image record is invalid\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsImageRecordCodeSectionValid (\r
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;\r
+ LIST_ENTRY *ImageRecordCodeSectionLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;\r
+ LIST_ENTRY *ImageRecordCodeSectionList;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));\r
+\r
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;\r
+\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;\r
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;\r
+ LastImageRecordCodeSection = NULL;\r
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {\r
+ ImageRecordCodeSection = CR (\r
+ ImageRecordCodeSectionLink,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+ );\r
+ if (ImageRecordCodeSection->CodeSegmentSize == 0) {\r
+ return FALSE;\r
+ }\r
+ if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {\r
+ return FALSE;\r
+ }\r
+ if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {\r
+ return FALSE;\r
+ }\r
+ if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {\r
+ return FALSE;\r
+ }\r
+ if (LastImageRecordCodeSection != NULL) {\r
+ if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ LastImageRecordCodeSection = ImageRecordCodeSection;\r
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Swap two image records.\r
+\r
+ @param[in] FirstImageRecord first image record.\r
+ @param[in] SecondImageRecord second image record.\r
+**/\r
+STATIC\r
+VOID\r
+SwapImageRecord (\r
+ IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,\r
+ IN IMAGE_PROPERTIES_RECORD *SecondImageRecord\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD TempImageRecord;\r
+\r
+ TempImageRecord.ImageBase = FirstImageRecord->ImageBase;\r
+ TempImageRecord.ImageSize = FirstImageRecord->ImageSize;\r
+ TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;\r
+\r
+ FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;\r
+ FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;\r
+ FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;\r
+\r
+ SecondImageRecord->ImageBase = TempImageRecord.ImageBase;\r
+ SecondImageRecord->ImageSize = TempImageRecord.ImageSize;\r
+ SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;\r
+\r
+ SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);\r
+}\r
+\r
+/**\r
+ Sort image record based upon the ImageBase from low to high.\r
+**/\r
+STATIC\r
+VOID\r
+SortImageRecord (\r
+ VOID\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ IMAGE_PROPERTIES_RECORD *NextImageRecord;\r
+ LIST_ENTRY *ImageRecordLink;\r
+ LIST_ENTRY *NextImageRecordLink;\r
+ LIST_ENTRY *ImageRecordEndLink;\r
+ LIST_ENTRY *ImageRecordList;\r
+\r
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+ ImageRecordLink = ImageRecordList->ForwardLink;\r
+ NextImageRecordLink = ImageRecordLink->ForwardLink;\r
+ ImageRecordEndLink = ImageRecordList;\r
+ while (ImageRecordLink != ImageRecordEndLink) {\r
+ ImageRecord = CR (\r
+ ImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+ while (NextImageRecordLink != ImageRecordEndLink) {\r
+ NextImageRecord = CR (\r
+ NextImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+ if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {\r
+ SwapImageRecord (ImageRecord, NextImageRecord);\r
+ }\r
+ NextImageRecordLink = NextImageRecordLink->ForwardLink;\r
+ }\r
+\r
+ ImageRecordLink = ImageRecordLink->ForwardLink;\r
+ NextImageRecordLink = ImageRecordLink->ForwardLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Dump image record.\r
+**/\r
+STATIC\r
+VOID\r
+DumpImageRecord (\r
+ VOID\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ LIST_ENTRY *ImageRecordLink;\r
+ LIST_ENTRY *ImageRecordList;\r
+ UINTN Index;\r
+\r
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+ for (ImageRecordLink = ImageRecordList->ForwardLink, Index= 0;\r
+ ImageRecordLink != ImageRecordList;\r
+ ImageRecordLink = ImageRecordLink->ForwardLink, Index++) {\r
+ ImageRecord = CR (\r
+ ImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->ImageBase, ImageRecord->ImageSize));\r
+ }\r
+}\r
+\r
+/**\r
+ Insert image record.\r
+\r
+ @param[in] DriverEntry Driver information\r
+**/\r
+VOID\r
+SmmInsertImageRecord (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ VOID *ImageAddress;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ UINT32 PeCoffHeaderOffset;\r
+ UINT32 SectionAlignment;\r
+ EFI_IMAGE_SECTION_HEADER *Section;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ UINT8 *Name;\r
+ UINTN Index;\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ CHAR8 *PdbPointer;\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+ UINT16 Magic;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%016lx - 0x%08x\n", DriverEntry->ImageBuffer, DriverEntry->NumberOfPage));\r
+\r
+ ImageRecord = AllocatePool (sizeof(*ImageRecord));\r
+ if (ImageRecord == NULL) {\r
+ return ;\r
+ }\r
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
+\r
+ //\r
+ // Step 1: record whole region\r
+ //\r
+ ImageRecord->ImageBase = DriverEntry->ImageBuffer;\r
+ ImageRecord->ImageSize = EFI_PAGES_TO_SIZE(DriverEntry->NumberOfPage);\r
+\r
+ ImageAddress = (VOID *)(UINTN)DriverEntry->ImageBuffer;\r
+\r
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+ if (PdbPointer != NULL) {\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer));\r
+ }\r
+\r
+ //\r
+ // Check PE/COFF image\r
+ //\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
+ PeCoffHeaderOffset = 0;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ PeCoffHeaderOffset = DosHdr->e_lfanew;\r
+ }\r
+\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));\r
+ goto Finish;\r
+ }\r
+\r
+ //\r
+ // Get SectionAlignment\r
+ //\r
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+ //\r
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ } else {\r
+ //\r
+ // Get the magic value from the PE/COFF Optional Header\r
+ //\r
+ Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+ }\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
+ } else {\r
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
+ }\r
+\r
+ SetMemoryAttributesTableSectionAlignment (SectionAlignment);\r
+ if ((SectionAlignment & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) {\r
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n",\r
+ SectionAlignment, EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));\r
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+ if (PdbPointer != NULL) {\r
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
+ }\r
+ goto Finish;\r
+ }\r
+\r
+ Section = (EFI_IMAGE_SECTION_HEADER *) (\r
+ (UINT8 *) (UINTN) ImageAddress +\r
+ PeCoffHeaderOffset +\r
+ sizeof(UINT32) +\r
+ sizeof(EFI_IMAGE_FILE_HEADER) +\r
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
+ );\r
+ ImageRecord->CodeSegmentCount = 0;\r
+ InitializeListHead (&ImageRecord->CodeSegmentList);\r
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+ Name = Section[Index].Name;\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "SMM Section - '%c%c%c%c%c%c%c%c'\n",\r
+ Name[0],\r
+ Name[1],\r
+ Name[2],\r
+ Name[3],\r
+ Name[4],\r
+ Name[5],\r
+ Name[6],\r
+ Name[7]\r
+ ));\r
+\r
+ if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {\r
+ DEBUG ((DEBUG_VERBOSE, "SMM VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Characteristics - 0x%08x\n", Section[Index].Characteristics));\r
+\r
+ //\r
+ // Step 2: record code section\r
+ //\r
+ ImageRecordCodeSection = AllocatePool (sizeof(*ImageRecordCodeSection));\r
+ if (ImageRecordCodeSection == NULL) {\r
+ return ;\r
+ }\r
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;\r
+\r
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageAddress + Section[Index].VirtualAddress;\r
+ ImageRecordCodeSection->CodeSegmentSize = Section[Index].SizeOfRawData;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM ImageCode: 0x%016lx - 0x%016lx\n", ImageRecordCodeSection->CodeSegmentBase, ImageRecordCodeSection->CodeSegmentSize));\r
+\r
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);\r
+ ImageRecord->CodeSegmentCount++;\r
+ }\r
+ }\r
+\r
+ if (ImageRecord->CodeSegmentCount == 0) {\r
+ SetMemoryAttributesTableSectionAlignment (1);\r
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));\r
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);\r
+ if (PdbPointer != NULL) {\r
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));\r
+ }\r
+ goto Finish;\r
+ }\r
+\r
+ //\r
+ // Final\r
+ //\r
+ SortImageRecordCodeSection (ImageRecord);\r
+ //\r
+ // Check overlap all section in ImageBase/Size\r
+ //\r
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {\r
+ DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n"));\r
+ goto Finish;\r
+ }\r
+\r
+ InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);\r
+ mImagePropertiesPrivateData.ImageRecordCount++;\r
+\r
+ SortImageRecord ();\r
+\r
+ if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {\r
+ mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;\r
+ }\r
+\r
+Finish:\r
+ return ;\r
+}\r
+\r
+/**\r
+ Find image record accroding to image base and size.\r
+\r
+ @param[in] ImageBase Base of PE image\r
+ @param[in] ImageSize Size of PE image\r
+\r
+ @return image record\r
+**/\r
+STATIC\r
+IMAGE_PROPERTIES_RECORD *\r
+FindImageRecord (\r
+ IN EFI_PHYSICAL_ADDRESS ImageBase,\r
+ IN UINT64 ImageSize\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ LIST_ENTRY *ImageRecordLink;\r
+ LIST_ENTRY *ImageRecordList;\r
+\r
+ ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList;\r
+\r
+ for (ImageRecordLink = ImageRecordList->ForwardLink;\r
+ ImageRecordLink != ImageRecordList;\r
+ ImageRecordLink = ImageRecordLink->ForwardLink) {\r
+ ImageRecord = CR (\r
+ ImageRecordLink,\r
+ IMAGE_PROPERTIES_RECORD,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_SIGNATURE\r
+ );\r
+\r
+ if ((ImageBase == ImageRecord->ImageBase) &&\r
+ (ImageSize == ImageRecord->ImageSize)) {\r
+ return ImageRecord;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Remove Image record.\r
+\r
+ @param[in] DriverEntry Driver information\r
+**/\r
+VOID\r
+SmmRemoveImageRecord (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ IMAGE_PROPERTIES_RECORD *ImageRecord;\r
+ LIST_ENTRY *CodeSegmentListHead;\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM RemoveImageRecord - 0x%x\n", DriverEntry));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM RemoveImageRecord - 0x%016lx - 0x%016lx\n", DriverEntry->ImageBuffer, DriverEntry->NumberOfPage));\r
+\r
+ ImageRecord = FindImageRecord (DriverEntry->ImageBuffer, EFI_PAGES_TO_SIZE(DriverEntry->NumberOfPage));\r
+ if (ImageRecord == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! ImageRecord not found !!!!!!!!\n"));\r
+ return ;\r
+ }\r
+\r
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;\r
+ while (!IsListEmpty (CodeSegmentListHead)) {\r
+ ImageRecordCodeSection = CR (\r
+ CodeSegmentListHead->ForwardLink,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,\r
+ Link,\r
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE\r
+ );\r
+ RemoveEntryList (&ImageRecordCodeSection->Link);\r
+ FreePool (ImageRecordCodeSection);\r
+ }\r
+\r
+ RemoveEntryList (&ImageRecord->Link);\r
+ FreePool (ImageRecord);\r
+ mImagePropertiesPrivateData.ImageRecordCount--;\r
+}\r
+\r
+/**\r
+ Publish MemoryAttributesTable to SMM configuration table.\r
+**/\r
+VOID\r
+PublishMemoryAttributesTable (\r
+ VOID\r
+ )\r
+{\r
+ UINTN MemoryMapSize;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
+ UINTN MapKey;\r
+ UINTN DescriptorSize;\r
+ UINT32 DescriptorVersion;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ UINTN RuntimeEntryCount;\r
+ EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;\r
+ EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;\r
+ UINTN MemoryAttributesTableSize;\r
+\r
+ MemoryMapSize = 0;\r
+ MemoryMap = NULL;\r
+ Status = SmmCoreGetMemoryMapMemoryAttributesTable (\r
+ &MemoryMapSize,\r
+ MemoryMap,\r
+ &MapKey,\r
+ &DescriptorSize,\r
+ &DescriptorVersion\r
+ );\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ do {\r
+ DEBUG ((DEBUG_INFO, "MemoryMapSize - 0x%x\n", MemoryMapSize));\r
+ MemoryMap = AllocatePool (MemoryMapSize);\r
+ ASSERT (MemoryMap != NULL);\r
+ DEBUG ((DEBUG_INFO, "MemoryMap - 0x%x\n", MemoryMap));\r
+\r
+ Status = SmmCoreGetMemoryMapMemoryAttributesTable (\r
+ &MemoryMapSize,\r
+ MemoryMap,\r
+ &MapKey,\r
+ &DescriptorSize,\r
+ &DescriptorVersion\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (MemoryMap);\r
+ }\r
+ } while (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ //\r
+ // Allocate MemoryAttributesTable\r
+ //\r
+ RuntimeEntryCount = MemoryMapSize/DescriptorSize;\r
+ MemoryAttributesTableSize = sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount;\r
+ MemoryAttributesTable = AllocatePool (sizeof(EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);\r
+ ASSERT (MemoryAttributesTable != NULL);\r
+ MemoryAttributesTable->Version = EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE_VERSION;\r
+ MemoryAttributesTable->NumberOfEntries = (UINT32)RuntimeEntryCount;\r
+ MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;\r
+ MemoryAttributesTable->Reserved = 0;\r
+ DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));\r
+ DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));\r
+ DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));\r
+ DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));\r
+ MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);\r
+ for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {\r
+ CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);\r
+ DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryAttributesEntry));\r
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryAttributesEntry->Type));\r
+ DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));\r
+ DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));\r
+ DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));\r
+ DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));\r
+ MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);\r
+\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);\r
+ }\r
+\r
+ Status = gSmst->SmmInstallConfigurationTable (gSmst, &gEdkiiPiSmmMemoryAttributesTableGuid, MemoryAttributesTable, MemoryAttributesTableSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+ This function returns if image is inside SMRAM.\r
+\r
+ @param[in] LoadedImage LoadedImage protocol instance for an image.\r
+\r
+ @retval TRUE the image is inside SMRAM.\r
+ @retval FALSE the image is outside SMRAM.\r
+**/\r
+BOOLEAN\r
+IsImageInsideSmram (\r
+ IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < mFullSmramRangeCount; Index++) {\r
+ if ((mFullSmramRanges[Index].PhysicalStart <= (UINTN)LoadedImage->ImageBase)&&\r
+ (mFullSmramRanges[Index].PhysicalStart + mFullSmramRanges[Index].PhysicalSize >= (UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ This function installs all SMM image record information.\r
+**/\r
+VOID\r
+SmmInstallImageRecord (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ UINTN Index;\r
+ EFI_SMM_DRIVER_ENTRY DriverEntry;\r
+\r
+ Status = SmmLocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ NULL,\r
+ &NoHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ for (Index = 0; Index < NoHandles; Index++) {\r
+ Status = gSmst->SmmHandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&LoadedImage\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize));\r
+ {\r
+ VOID *PdbPointer;\r
+ PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);\r
+ if (PdbPointer != NULL) {\r
+ DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer));\r
+ }\r
+ }\r
+ DEBUG ((DEBUG_VERBOSE, "\n"));\r
+ ZeroMem (&DriverEntry, sizeof(DriverEntry));\r
+ DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase;\r
+ DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES((UINTN)LoadedImage->ImageSize);\r
+ SmmInsertImageRecord (&DriverEntry);\r
+ }\r
+\r
+ FreePool (HandleBuffer);\r
+}\r
+\r
+/**\r
+ Install MemoryAttributesTable.\r
+\r
+ @param[in] Protocol Points to the protocol's unique identifier.\r
+ @param[in] Interface Points to the interface instance.\r
+ @param[in] Handle The handle on which the interface was installed.\r
+\r
+ @retval EFI_SUCCESS Notification runs successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallMemoryAttributesTable (\r
+ IN CONST EFI_GUID *Protocol,\r
+ IN VOID *Interface,\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ SmmInstallImageRecord ();\r
+\r
+ DEBUG ((DEBUG_INFO, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute));\r
+ if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Total Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));\r
+ DEBUG ((DEBUG_VERBOSE, "SMM Dump ImageRecord:\n"));\r
+ DumpImageRecord ();\r
+\r
+ PublishMemoryAttributesTable ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize MemoryAttributesTable support.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCoreInitializeMemoryAttributesTable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Registration;\r
+\r
+ Status = gSmst->SmmRegisterProtocolNotify (\r
+ &gEfiSmmEndOfDxeProtocolGuid,\r
+ SmmInstallMemoryAttributesTable,\r
+ &Registration\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return ;\r
+}\r
SMM Memory page management functions.\r
\r
Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available \r
- under the terms and conditions of the BSD License which accompanies this \r
- distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
#include "PiSmmCore.h"\r
+#include <Library/SmmServicesTableLib.h>\r
\r
#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)\r
\r
LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
\r
+//\r
+// For GetMemoryMap()\r
+//\r
+\r
+#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ BOOLEAN FromStack;\r
+ EFI_MEMORY_TYPE Type;\r
+ UINT64 Start;\r
+ UINT64 End;\r
+\r
+} MEMORY_MAP;\r
+\r
+LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);\r
+\r
+\r
+#define MAX_MAP_DEPTH 6\r
+\r
+///\r
+/// mMapDepth - depth of new descriptor stack\r
+///\r
+UINTN mMapDepth = 0;\r
+///\r
+/// mMapStack - space to use as temp storage to build new map descriptors\r
+///\r
+MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
+UINTN mFreeMapStack = 0;\r
+///\r
+/// This list maintain the free memory map list\r
+///\r
+LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
+\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+ @param[in] AddRegion If this memory is new added region.\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInternalAllocatePagesEx (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory,\r
+ IN BOOLEAN AddRegion\r
+ );\r
+\r
+/**\r
+ Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
+ If the list is emtry, then allocate a new page to refuel the list.\r
+ Please Note this algorithm to allocate the memory map descriptor has a property\r
+ that the memory allocated for memory entries always grows, and will never really be freed.\r
+\r
+ @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
+\r
+**/\r
+MEMORY_MAP *\r
+AllocateMemoryMapEntry (\r
+ VOID\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS Mem;\r
+ EFI_STATUS Status;\r
+ MEMORY_MAP* FreeDescriptorEntries;\r
+ MEMORY_MAP* Entry;\r
+ UINTN Index;\r
+\r
+ //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));\r
+\r
+ if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
+ //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));\r
+ //\r
+ // The list is empty, to allocate one page to refuel the list\r
+ //\r
+ Status = SmmInternalAllocatePagesEx (\r
+ AllocateAnyPages,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION),\r
+ &Mem,\r
+ TRUE\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if(!EFI_ERROR (Status)) {\r
+ FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;\r
+ //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));\r
+ //\r
+ // Enque the free memmory map entries into the list\r
+ //\r
+ for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {\r
+ FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
+ InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
+ }\r
+ } else {\r
+ return NULL;\r
+ }\r
+ }\r
+ //\r
+ // dequeue the first descriptor from the list\r
+ //\r
+ Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ RemoveEntryList (&Entry->Link);\r
+\r
+ return Entry;\r
+}\r
+\r
+\r
+/**\r
+ Internal function. Moves any memory descriptors that are on the\r
+ temporary descriptor stack to heap.\r
+\r
+**/\r
+VOID\r
+CoreFreeMemoryMapStack (\r
+ VOID\r
+ )\r
+{\r
+ MEMORY_MAP *Entry;\r
+\r
+ //\r
+ // If already freeing the map stack, then return\r
+ //\r
+ if (mFreeMapStack != 0) {\r
+ ASSERT (FALSE);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Move the temporary memory descriptor stack into pool\r
+ //\r
+ mFreeMapStack += 1;\r
+\r
+ while (mMapDepth != 0) {\r
+ //\r
+ // Deque an memory map entry from mFreeMemoryMapEntryList\r
+ //\r
+ Entry = AllocateMemoryMapEntry ();\r
+ ASSERT (Entry);\r
+\r
+ //\r
+ // Update to proper entry\r
+ //\r
+ mMapDepth -= 1;\r
+\r
+ if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
+\r
+ CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
+ Entry->FromStack = FALSE;\r
+\r
+ //\r
+ // Move this entry to general memory\r
+ //\r
+ InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);\r
+ RemoveEntryList (&mMapStack[mMapDepth].Link);\r
+ mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
+ }\r
+ }\r
+\r
+ mFreeMapStack -= 1;\r
+}\r
+\r
+/**\r
+ Insert new entry from memory map.\r
+\r
+ @param[in] Link The old memory map entry to be linked.\r
+ @param[in] Start The start address of new memory map entry.\r
+ @param[in] End The end address of new memory map entry.\r
+ @param[in] Type The type of new memory map entry.\r
+ @param[in] Next If new entry is inserted to the next of old entry.\r
+ @param[in] AddRegion If this memory is new added region.\r
+**/\r
+VOID\r
+InsertNewEntry (\r
+ IN LIST_ENTRY *Link,\r
+ IN UINT64 Start,\r
+ IN UINT64 End,\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN BOOLEAN Next,\r
+ IN BOOLEAN AddRegion\r
+ )\r
+{\r
+ MEMORY_MAP *Entry;\r
+\r
+ Entry = &mMapStack[mMapDepth];\r
+ mMapDepth += 1;\r
+ ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
+ Entry->FromStack = TRUE;\r
+\r
+ Entry->Signature = MEMORY_MAP_SIGNATURE;\r
+ Entry->Type = Type;\r
+ Entry->Start = Start;\r
+ Entry->End = End;\r
+ if (Next) {\r
+ InsertHeadList (Link, &Entry->Link);\r
+ } else {\r
+ InsertTailList (Link, &Entry->Link);\r
+ }\r
+}\r
+\r
+/**\r
+ Remove old entry from memory map.\r
+\r
+ @param[in] Entry Memory map entry to be removed.\r
+**/\r
+VOID\r
+RemoveOldEntry (\r
+ IN MEMORY_MAP *Entry\r
+ )\r
+{\r
+ RemoveEntryList (&Entry->Link);\r
+ if (!Entry->FromStack) {\r
+ InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
+ }\r
+}\r
+\r
+/**\r
+ Update SMM memory map entry.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] Memory The base of memory address.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[in] AddRegion If this memory is new added region.\r
+**/\r
+VOID\r
+ConvertSmmMemoryMapEntry (\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages,\r
+ IN BOOLEAN AddRegion\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ MEMORY_MAP *NextEntry;\r
+ LIST_ENTRY *NextLink;\r
+ MEMORY_MAP *PreviousEntry;\r
+ LIST_ENTRY *PreviousLink;\r
+ EFI_PHYSICAL_ADDRESS Start;\r
+ EFI_PHYSICAL_ADDRESS End;\r
+\r
+ Start = Memory;\r
+ End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;\r
+\r
+ //\r
+ // Exclude memory region\r
+ //\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
+ // +----------+ ^ +------+ +------+ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryX|\r
+ // +------+\r
+ //\r
+ if (Entry->Start > End) {\r
+ if ((Entry->Start == End + 1) && (Entry->Type == Type)) {\r
+ Entry->Start = Start;\r
+ return ;\r
+ }\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ Start,\r
+ End,\r
+ Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ return ;\r
+ }\r
+\r
+ if ((Entry->Start <= Start) && (Entry->End >= End)) {\r
+ if (Entry->Type != Type) {\r
+ if (Entry->Start < Start) {\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
+ // +----------+ +------+ ^ +------+ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryA|\r
+ // +------+\r
+ //\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ Entry->Start,\r
+ Start - 1,\r
+ Entry->Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ }\r
+ if (Entry->End > End) {\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
+ // +----------+ +------+ +------+ ^ +------+\r
+ // |\r
+ // +------+\r
+ // |EntryZ|\r
+ // +------+\r
+ //\r
+ InsertNewEntry (\r
+ &Entry->Link,\r
+ End + 1,\r
+ Entry->End,\r
+ Entry->Type,\r
+ TRUE,\r
+ AddRegion\r
+ );\r
+ }\r
+ //\r
+ // Update this node\r
+ //\r
+ Entry->Start = Start;\r
+ Entry->End = End;\r
+ Entry->Type = Type;\r
+\r
+ //\r
+ // Check adjacent\r
+ //\r
+ NextLink = Entry->Link.ForwardLink;\r
+ if (NextLink != &gMemoryMap) {\r
+ NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +-----------------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---\r
+ // +----------+ +------+ +-----------------+\r
+ //\r
+ if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {\r
+ Entry->End = NextEntry->End;\r
+ RemoveOldEntry (NextEntry);\r
+ }\r
+ }\r
+ PreviousLink = Entry->Link.BackLink;\r
+ if (PreviousLink != &gMemoryMap) {\r
+ PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +-----------------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---\r
+ // +----------+ +-----------------+ +------+\r
+ //\r
+ if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {\r
+ PreviousEntry->End = Entry->End;\r
+ RemoveOldEntry (Entry);\r
+ }\r
+ }\r
+ }\r
+ return ;\r
+ }\r
+ }\r
+\r
+ //\r
+ // ---------------------------------------------------\r
+ // | +----------+ +------+ +------+ +------+ |\r
+ // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
+ // +----------+ +------+ +------+ +------+ ^\r
+ // |\r
+ // +------+\r
+ // |EntryX|\r
+ // +------+\r
+ //\r
+ Link = gMemoryMap.BackLink;\r
+ if (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {\r
+ Entry->End = End;\r
+ return ;\r
+ }\r
+ }\r
+ InsertNewEntry (\r
+ &gMemoryMap,\r
+ Start,\r
+ End,\r
+ Type,\r
+ FALSE,\r
+ AddRegion\r
+ );\r
+ return ;\r
+}\r
+\r
+/**\r
+ Return the count of Smm memory map entry.\r
+\r
+ @return The count of Smm memory map entry.\r
+**/\r
+UINTN\r
+GetSmmMemoryMapEntryCount (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ UINTN Count;\r
+\r
+ Count = 0;\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Link = Link->ForwardLink;\r
+ Count++;\r
+ }\r
+ return Count;\r
+}\r
+\r
+/**\r
+ Dump Smm memory map entry.\r
+**/\r
+VOID\r
+DumpSmmMemoryMapEntry (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ EFI_PHYSICAL_ADDRESS Last;\r
+\r
+ Last = 0;\r
+ DEBUG ((DEBUG_INFO, "DumpSmmMemoryMapEntry:\n"));\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ if ((Last != 0) && (Last != (UINT64)-1)) {\r
+ if (Last + 1 != Entry->Start) {\r
+ Last = (UINT64)-1;\r
+ } else {\r
+ Last = Entry->End;\r
+ }\r
+ } else if (Last == 0) {\r
+ Last = Entry->End;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Entry (Link - 0x%x)\n", &Entry->Link));\r
+ DEBUG ((DEBUG_INFO, " Signature - 0x%x\n", Entry->Signature));\r
+ DEBUG ((DEBUG_INFO, " Link.ForwardLink - 0x%x\n", Entry->Link.ForwardLink));\r
+ DEBUG ((DEBUG_INFO, " Link.BackLink - 0x%x\n", Entry->Link.BackLink));\r
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Entry->Type));\r
+ DEBUG ((DEBUG_INFO, " Start - 0x%016lx\n", Entry->Start));\r
+ DEBUG ((DEBUG_INFO, " End - 0x%016lx\n", Entry->End));\r
+ }\r
+\r
+ ASSERT (Last != (UINT64)-1);\r
+}\r
+\r
+/**\r
+ Dump Smm memory map.\r
+**/\r
+VOID\r
+DumpSmmMemoryMap (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+\r
+ DEBUG ((DEBUG_INFO, "DumpSmmMemoryMap\n"));\r
+\r
+ Pages = NULL;\r
+ Node = mSmmMemoryMap.ForwardLink;\r
+ while (Node != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ DEBUG ((DEBUG_INFO, "Pages - 0x%x\n", Pages));\r
+ DEBUG ((DEBUG_INFO, "Pages->NumberOfPages - 0x%x\n", Pages->NumberOfPages));\r
+ Node = Node->ForwardLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Check if a Smm base~length is in Smm memory map.\r
+\r
+ @param[in] Base The base address of Smm memory to be checked.\r
+ @param[in] Length THe length of Smm memory to be checked.\r
+\r
+ @retval TRUE Smm base~length is in smm memory map.\r
+ @retval FALSE Smm base~length is in smm memory map.\r
+**/\r
+BOOLEAN\r
+SmmMemoryMapConsistencyCheckRange (\r
+ IN EFI_PHYSICAL_ADDRESS Base,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ BOOLEAN Result;\r
+\r
+ Result = FALSE;\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ if (Entry->Type != EfiConventionalMemory) {\r
+ continue;\r
+ }\r
+ if (Entry->Start == Base && Entry->End == Base + Length - 1) {\r
+ Result = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Result;\r
+}\r
+\r
+/**\r
+ Check the consistency of Smm memory map.\r
+**/\r
+VOID\r
+SmmMemoryMapConsistencyCheck (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+ BOOLEAN Result;\r
+\r
+ Pages = NULL;\r
+ Node = mSmmMemoryMap.ForwardLink;\r
+ while (Node != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ Result = SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS)(UINTN)Pages, (UINTN)EFI_PAGES_TO_SIZE(Pages->NumberOfPages));\r
+ ASSERT (Result);\r
+ Node = Node->ForwardLink;\r
+ }\r
+}\r
+\r
/**\r
Internal Function. Allocate n pages from given free page node.\r
\r
/**\r
Allocates pages from the memory map.\r
\r
- @param Type The type of allocation to perform.\r
- @param MemoryType The type of memory to turn the allocated pages\r
- into.\r
- @param NumberOfPages The number of pages to allocate.\r
- @param Memory A pointer to receive the base allocated memory\r
- address.\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+ @param[in] AddRegion If this memory is new added region.\r
\r
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-SmmInternalAllocatePages (\r
+SmmInternalAllocatePagesEx (\r
IN EFI_ALLOCATE_TYPE Type,\r
IN EFI_MEMORY_TYPE MemoryType,\r
IN UINTN NumberOfPages,\r
- OUT EFI_PHYSICAL_ADDRESS *Memory\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory,\r
+ IN BOOLEAN AddRegion\r
)\r
{\r
UINTN RequestedAddress;\r
);\r
if (*Memory == (UINTN)-1) {\r
return EFI_OUT_OF_RESOURCES;\r
- } \r
+ }\r
break;\r
case AllocateAddress:\r
*Memory = InternalAllocAddress (\r
default:\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
+ //\r
+ // Update SmmMemoryMap here.\r
+ //\r
+ ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);\r
+ if (!AddRegion) {\r
+ CoreFreeMemoryMapStack();\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param[in] Type The type of allocation to perform.\r
+ @param[in] MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param[in] NumberOfPages The number of pages to allocate.\r
+ @param[out] Memory A pointer to receive the base allocated memory\r
+ address.\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInternalAllocatePages (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory\r
+ )\r
+{\r
+ return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory, FALSE);\r
+}\r
+\r
/**\r
Allocates pages from the memory map.\r
\r
/**\r
Frees previous allocated pages.\r
\r
- @param Memory Base address of memory being freed.\r
- @param NumberOfPages The number of pages to free.\r
+ @param[in] Memory Base address of memory being freed.\r
+ @param[in] NumberOfPages The number of pages to free.\r
+ @param[in] AddRegion If this memory is new added region.\r
\r
@retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
@retval EFI_INVALID_PARAMETER Address not aligned.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-SmmInternalFreePages (\r
+SmmInternalFreePagesEx (\r
IN EFI_PHYSICAL_ADDRESS Memory,\r
- IN UINTN NumberOfPages\r
+ IN UINTN NumberOfPages,\r
+ IN BOOLEAN AddRegion\r
)\r
{\r
LIST_ENTRY *Node;\r
InternalMergeNodes (Pages);\r
}\r
\r
+ //\r
+ // Update SmmMemoryMap here.\r
+ //\r
+ ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);\r
+ if (!AddRegion) {\r
+ CoreFreeMemoryMapStack();\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Frees previous allocated pages.\r
+\r
+ @param[in] Memory Base address of memory being freed.\r
+ @param[in] NumberOfPages The number of pages to free.\r
+\r
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
+ @retval EFI_INVALID_PARAMETER Address not aligned.\r
+ @return EFI_SUCCESS Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInternalFreePages (\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages\r
+ )\r
+{\r
+ return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);\r
+}\r
+\r
/**\r
Frees previous allocated pages.\r
\r
UINTN AlignedMemBase;\r
\r
//\r
- // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization\r
+ // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization\r
//\r
if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
- return;\r
+ Type = EfiRuntimeServicesData;\r
+ } else {\r
+ Type = EfiConventionalMemory;\r
}\r
- \r
+\r
+ DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));\r
+ DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));\r
+ DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));\r
+ DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));\r
+ DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));\r
+\r
//\r
// Align range on an EFI_PAGE_SIZE boundary\r
- // \r
+ //\r
AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
MemLength -= AlignedMemBase - MemBase;\r
- SmmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));\r
+ if (Type == EfiConventionalMemory) {\r
+ SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
+ } else {\r
+ ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
+ }\r
+\r
+ CoreFreeMemoryMapStack ();\r
+}\r
+\r
+/**\r
+ This function returns a copy of the current memory map. The map is an array of\r
+ memory descriptors, each of which describes a contiguous block of memory.\r
+\r
+ @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
+ MemoryMap buffer. On input, this is the size of\r
+ the buffer allocated by the caller. On output,\r
+ it is the size of the buffer returned by the\r
+ firmware if the buffer was large enough, or the\r
+ size of the buffer needed to contain the map if\r
+ the buffer was too small.\r
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
+ the current memory map.\r
+ @param[out] MapKey A pointer to the location in which firmware\r
+ returns the key for the current memory map.\r
+ @param[out] DescriptorSize A pointer to the location in which firmware\r
+ returns the size, in bytes, of an individual\r
+ EFI_MEMORY_DESCRIPTOR.\r
+ @param[out] DescriptorVersion A pointer to the location in which firmware\r
+ returns the version number associated with the\r
+ EFI_MEMORY_DESCRIPTOR.\r
+\r
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
+ buffer.\r
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
+ buffer size needed to hold the memory map is\r
+ returned in MemoryMapSize.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCoreGetMemoryMap (\r
+ IN OUT UINTN *MemoryMapSize,\r
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
+ OUT UINTN *MapKey,\r
+ OUT UINTN *DescriptorSize,\r
+ OUT UINT32 *DescriptorVersion\r
+ )\r
+{\r
+ UINTN Count;\r
+ LIST_ENTRY *Link;\r
+ MEMORY_MAP *Entry;\r
+ UINTN Size;\r
+ UINTN BufferSize;\r
+\r
+ Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
+\r
+ //\r
+ // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
+ // prevent people from having pointer math bugs in their code.\r
+ // now you have to use *DescriptorSize to make things work.\r
+ //\r
+ Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
+\r
+ if (DescriptorSize != NULL) {\r
+ *DescriptorSize = Size;\r
+ }\r
+\r
+ if (DescriptorVersion != NULL) {\r
+ *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
+ }\r
+\r
+ Count = GetSmmMemoryMapEntryCount ();\r
+ BufferSize = Size * Count;\r
+ if (*MemoryMapSize < BufferSize) {\r
+ *MemoryMapSize = BufferSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *MemoryMapSize = BufferSize;\r
+ if (MemoryMap == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (MemoryMap, BufferSize);\r
+ Link = gMemoryMap.ForwardLink;\r
+ while (Link != &gMemoryMap) {\r
+ Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
+ Link = Link->ForwardLink;\r
+\r
+ MemoryMap->Type = Entry->Type;\r
+ MemoryMap->PhysicalStart = Entry->Start;\r
+ MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
+\r
+ MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r