summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/ImagePropertiesRecordLib
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/ImagePropertiesRecordLib
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Library/ImagePropertiesRecordLib')
-rw-r--r--MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c2380
-rw-r--r--MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf62
-rw-r--r--MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c1876
-rw-r--r--MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf70
4 files changed, 2194 insertions, 2194 deletions
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
index 3ac043f980..1fd095a542 100644
--- a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c
@@ -1,1190 +1,1190 @@
-/** @file
-
- Provides definitions and functionality for manipulating IMAGE_PROPERTIES_RECORD.
-
- Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
- Copyright (c) Microsoft Corporation.
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
-
-/**
- Converts a number of pages to a size in bytes.
-
- NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
-
- @param[in] Pages The number of EFI_PAGES.
-
- @retval The number of bytes associated with the input number of pages.
-**/
-STATIC
-UINT64
-EfiPagesToSize (
- IN UINT64 Pages
- )
-{
- return LShiftU64 (Pages, EFI_PAGE_SHIFT);
-}
-
-/**
- Converts a size, in bytes, to a number of EFI_PAGESs.
-
- NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
-
- @param[in] Size A size in bytes.
-
- @retval The number of pages associated with the input number of bytes.
-
-**/
-STATIC
-UINT64
-EfiSizeToPages (
- IN UINT64 Size
- )
-{
- return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
-}
-
-/**
- Frees the memory for each ImageRecordCodeSection within an ImageRecord
- and removes the entries from the list. It does not free the ImageRecord
- itself.
-
- @param[in] ImageRecord The ImageRecord in which to free code sections
-**/
-STATIC
-VOID
-FreeImageRecordCodeSections (
- IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- LIST_ENTRY *CodeSegmentListHead;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
-
- if (ImageRecord == NULL) {
- return;
- }
-
- CodeSegmentListHead = &ImageRecord->CodeSegmentList;
- while (!IsListEmpty (CodeSegmentListHead)) {
- ImageRecordCodeSection = CR (
- CodeSegmentListHead->ForwardLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- RemoveEntryList (&ImageRecordCodeSection->Link);
- FreePool (ImageRecordCodeSection);
- }
-}
-
-/**
- Sort memory map entries based upon PhysicalStart from low to high.
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-SortMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_MEMORY_DESCRIPTOR TempMemoryMap;
-
- MemoryMapEntry = MemoryMap;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while (MemoryMapEntry < MemoryMapEnd) {
- while (NextMemoryMapEntry < MemoryMapEnd) {
- if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
- CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- return;
-}
-
-/**
- Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
-
- @param[in] Buffer Starting Address
- @param[in] Length Length to check
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries to check against
- the memory range Buffer -> Buffer + Length
-
- @retval The first image record covered by [Buffer, Length]
-**/
-STATIC
-IMAGE_PROPERTIES_RECORD *
-GetImageRecordByAddress (
- IN EFI_PHYSICAL_ADDRESS Buffer,
- IN UINT64 Length,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- LIST_ENTRY *ImageRecordLink;
-
- for (ImageRecordLink = ImageRecordList->ForwardLink;
- ImageRecordLink != ImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- if ((Buffer <= ImageRecord->ImageBase) &&
- (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize))
- {
- return ImageRecord;
- }
- }
-
- return NULL;
-}
-
-/**
- Break up the input OldRecord into multiple new records based on the code
- and data sections in the input ImageRecord.
-
- @param[in] ImageRecord An IMAGE_PROPERTIES_RECORD whose ImageBase and
- ImageSize is covered by by OldRecord.
- @param[in, out] NewRecord A pointer to several new memory map entries.
- The caller gurantee the buffer size be 1 +
- (SplitRecordCount * DescriptorSize) calculated
- below.
- @param[in] OldRecord A pointer to one old memory map entry.
- @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-
- @retval The number of new descriptors created.
-**/
-STATIC
-UINTN
-SetNewRecord (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord,
- IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
- IN EFI_MEMORY_DESCRIPTOR *OldRecord,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR TempRecord;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- LIST_ENTRY *ImageRecordCodeSectionEndLink;
- LIST_ENTRY *ImageRecordCodeSectionList;
- UINTN NewRecordCount;
- UINT64 PhysicalEnd;
- UINT64 ImageEnd;
-
- CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
- PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
- NewRecordCount = 0;
-
- ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
- ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
- while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
-
- if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
- //
- // DATA
- //
- NewRecord->Type = TempRecord.Type;
- NewRecord->PhysicalStart = TempRecord.PhysicalStart;
- NewRecord->VirtualStart = 0;
- NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
- NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
- if (NewRecord->NumberOfPages != 0) {
- NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
- NewRecordCount++;
- }
-
- //
- // CODE
- //
- NewRecord->Type = TempRecord.Type;
- NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
- NewRecord->VirtualStart = 0;
- NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize);
- NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
- if (NewRecord->NumberOfPages != 0) {
- NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
- NewRecordCount++;
- }
-
- TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize));
- TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - TempRecord.PhysicalStart);
- if (TempRecord.NumberOfPages == 0) {
- break;
- }
- }
- }
-
- ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
-
- //
- // Final DATA
- //
- if (TempRecord.PhysicalStart < ImageEnd) {
- NewRecord->Type = TempRecord.Type;
- NewRecord->PhysicalStart = TempRecord.PhysicalStart;
- NewRecord->VirtualStart = 0;
- NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
- NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
- NewRecordCount++;
- }
-
- return NewRecordCount;
-}
-
-/**
- Return the maximum number of new entries required to describe the code and data sections
- of all images covered by the input OldRecord.
-
- @param[in] OldRecord A pointer to one old memory map entry.
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
- for an image record contained by the memory range described by
- OldRecord
-
- @retval The maximum number of new descriptors required to describe the code and data sections
- of all images covered by OldRecord.
-**/
-STATIC
-UINTN
-GetMaxSplitRecordCount (
- IN EFI_MEMORY_DESCRIPTOR *OldRecord,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- UINTN SplitRecordCount;
- UINT64 PhysicalStart;
- UINT64 PhysicalEnd;
-
- SplitRecordCount = 0;
- PhysicalStart = OldRecord->PhysicalStart;
- PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize (OldRecord->NumberOfPages);
-
- do {
- ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
- if (ImageRecord == NULL) {
- break;
- }
-
- SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 3);
- PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
- } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
-
- if (SplitRecordCount != 0) {
- SplitRecordCount--;
- }
-
- return SplitRecordCount;
-}
-
-/**
- Split the memory map into new entries based upon the PE code and data sections
- in ImageRecordList covered by the input OldRecord.
-
- @param[in] OldRecord A pointer to one old memory map entry.
- @param[in, out] NewRecord A pointer to several new memory map entries.
- The caller gurantee the buffer size be
- (SplitRecordCount * DescriptorSize).
- @param[in] MaxSplitRecordCount The maximum number of entries post-split.
- @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
- for an image record contained by the memory range described in
- the existing EFI memory map descriptor OldRecord
-
- @retval The number of split entries.
-**/
-STATIC
-UINTN
-SplitRecord (
- IN EFI_MEMORY_DESCRIPTOR *OldRecord,
- IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
- IN UINTN MaxSplitRecordCount,
- IN UINTN DescriptorSize,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- EFI_MEMORY_DESCRIPTOR TempRecord;
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- IMAGE_PROPERTIES_RECORD *NewImageRecord;
- UINT64 PhysicalStart;
- UINT64 PhysicalEnd;
- UINTN NewRecordCount;
- UINTN TotalNewRecordCount;
-
- if (MaxSplitRecordCount == 0) {
- CopyMem (NewRecord, OldRecord, DescriptorSize);
- return 0;
- }
-
- TotalNewRecordCount = 0;
-
- //
- // Override previous record
- //
- CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
- PhysicalStart = TempRecord.PhysicalStart;
- PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
-
- ImageRecord = NULL;
- do {
- NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
- if (NewImageRecord == NULL) {
- //
- // No more images cover this range, check if we've reached the end of the old descriptor. If not,
- // add the remaining range to the new descriptor list.
- //
- if (PhysicalEnd > PhysicalStart) {
- NewRecord->Type = TempRecord.Type;
- NewRecord->PhysicalStart = PhysicalStart;
- NewRecord->VirtualStart = 0;
- NewRecord->NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
- NewRecord->Attribute = TempRecord.Attribute;
- TotalNewRecordCount++;
- }
-
- break;
- }
-
- ImageRecord = NewImageRecord;
-
- //
- // Update PhysicalStart to exclude the portion before the image buffer
- //
- if (TempRecord.PhysicalStart < ImageRecord->ImageBase) {
- NewRecord->Type = TempRecord.Type;
- NewRecord->PhysicalStart = TempRecord.PhysicalStart;
- NewRecord->VirtualStart = 0;
- NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->ImageBase - TempRecord.PhysicalStart);
- NewRecord->Attribute = TempRecord.Attribute;
- TotalNewRecordCount++;
-
- PhysicalStart = ImageRecord->ImageBase;
- TempRecord.PhysicalStart = PhysicalStart;
- TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
-
- NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + DescriptorSize);
- }
-
- //
- // Set new record
- //
- NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
- TotalNewRecordCount += NewRecordCount;
- NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
-
- //
- // Update PhysicalStart, in order to exclude the image buffer already splitted.
- //
- PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
- TempRecord.PhysicalStart = PhysicalStart;
- TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
- } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
-
- //
- // The logic in function SplitTable() ensures that TotalNewRecordCount will not be zero if the
- // code reaches here.
- //
- ASSERT (TotalNewRecordCount != 0);
- return TotalNewRecordCount - 1;
-}
-
-/**
- Split the original memory map and add more entries to describe PE code
- and data sections for each image in the input ImageRecordList.
-
- NOTE: This function assumes PE code/data section are page aligned.
- NOTE: This function assumes there are enough entries for the new memory map.
-
- | | | | | | | |
- | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE |
- | | | | | | | |
- Assume the above memory region is the result of one split memory map descriptor. It's unlikely
- that a linker will orient an image this way, but the caller must assume the worst case scenario.
- This image layout example contains code sections oriented in a way that maximizes the number of
- descriptors which would be required to describe each section. To ensure we have enough space
- for every descriptor of the broken up memory map, the caller must assume that every image will
- have the maximum number of code sections oriented in a way which maximizes the number of data
- sections with unrelated memory regions flanking each image within a single descriptor.
-
- Given an image record list, the caller should use the following formula when allocating extra descriptors:
- NumberOfAdditionalDescriptors = (MemoryMapSize / DescriptorSize) +
- ((2 * <Most Code Segments in a Single Image> + 3) * <Number of Images>)
-
- @param[in, out] MemoryMapSize IN: The size, in bytes, of the old memory map before the split.
- OUT: The size, in bytes, of the used descriptors of the split
- memory map
- @param[in, out] MemoryMap IN: A pointer to the buffer containing the current memory map.
- This buffer must have enough space to accomodate the "worst case"
- scenario where every image in ImageRecordList needs a new descriptor
- to describe its code and data sections.
- OUT: A pointer to the updated memory map with separated image section
- descriptors.
- @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
- for an image record contained by the memory range described in
- EFI memory map descriptors.
- @param[in] NumberOfAdditionalDescriptors The number of unused descriptors at the end of the input MemoryMap.
- The formula in the description should be used to calculate this value.
-
- @retval EFI_SUCCESS The memory map was successfully split.
- @retval EFI_INVALID_PARAMETER MemoryMapSize, MemoryMap, or ImageRecordList was NULL.
-**/
-EFI_STATUS
-EFIAPI
-SplitTable (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN DescriptorSize,
- IN LIST_ENTRY *ImageRecordList,
- IN UINTN NumberOfAdditionalDescriptors
- )
-{
- INTN IndexOld;
- INTN IndexNew;
- INTN IndexNewStarting;
- UINTN MaxSplitRecordCount;
- UINTN RealSplitRecordCount;
- UINTN TotalSkippedRecords;
-
- if ((MemoryMapSize == NULL) || (MemoryMap == NULL) || (ImageRecordList == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- TotalSkippedRecords = 0;
- //
- // Let old record point to end of valid MemoryMap buffer.
- //
- IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
- //
- // Let new record point to end of full MemoryMap buffer.
- //
- IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + NumberOfAdditionalDescriptors;
- IndexNewStarting = IndexNew;
- for ( ; IndexOld >= 0; IndexOld--) {
- MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize), ImageRecordList);
- //
- // Split this MemoryMap record
- //
- IndexNew -= MaxSplitRecordCount;
- RealSplitRecordCount = SplitRecord (
- (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
- (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
- MaxSplitRecordCount,
- DescriptorSize,
- ImageRecordList
- );
-
- // If we didn't utilize all the extra allocated descriptor slots, set the physical address of the unused slots
- // to MAX_ADDRESS so they are moved to the bottom of the list when sorting.
- for ( ; RealSplitRecordCount < MaxSplitRecordCount; RealSplitRecordCount++) {
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + ((IndexNew + RealSplitRecordCount + 1) * DescriptorSize)))->PhysicalStart = MAX_ADDRESS;
- TotalSkippedRecords++;
- }
-
- IndexNew--;
- }
-
- //
- // Move all records to the beginning.
- //
- CopyMem (
- MemoryMap,
- (UINT8 *)MemoryMap + ((IndexNew + 1) * DescriptorSize),
- (IndexNewStarting - IndexNew) * DescriptorSize
- );
-
- //
- // Sort from low to high to filter out the MAX_ADDRESS records.
- //
- SortMemoryMap (MemoryMap, (IndexNewStarting - IndexNew) * DescriptorSize, DescriptorSize);
-
- *MemoryMapSize = (IndexNewStarting - IndexNew - TotalSkippedRecords) * DescriptorSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- Swap two code sections in a single IMAGE_PROPERTIES_RECORD.
-
- @param[in] FirstImageRecordCodeSection The first code section
- @param[in] SecondImageRecordCodeSection The second code section
-
- @retval EFI_SUCCESS The code sections were swapped successfully
- @retval EFI_INVALID_PARAMETER FirstImageRecordCodeSection or SecondImageRecordCodeSection is NULL
-**/
-EFI_STATUS
-EFIAPI
-SwapImageRecordCodeSection (
- IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
- IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
- )
-{
- IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
-
- if ((FirstImageRecordCodeSection == NULL) || (SecondImageRecordCodeSection == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
- TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
-
- FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
- FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
-
- SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
- SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- Sort the code sections in the input ImageRecord based upon CodeSegmentBase from low to high.
-
- @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be sorted
-
- @retval EFI_SUCCESS The code sections in the input ImageRecord were sorted successfully
- @retval EFI_ABORTED An error occurred while sorting the code sections in the input ImageRecord
- @retval EFI_INVALID_PARAMETER ImageRecord is NULL
-**/
-EFI_STATUS
-EFIAPI
-SortImageRecordCodeSection (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- EFI_STATUS Status;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- LIST_ENTRY *NextImageRecordCodeSectionLink;
- LIST_ENTRY *ImageRecordCodeSectionEndLink;
- LIST_ENTRY *ImageRecordCodeSectionList;
-
- if (ImageRecord == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
- NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
- ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
- while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- NextImageRecordCodeSection = CR (
- NextImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
- Status = SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return EFI_ABORTED;
- }
- }
-
- NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
- }
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
- NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Check if the code sections in the input ImageRecord are valid.
- The code sections are valid if they don't overlap, are contained
- within the the ImageRecord's ImageBase and ImageSize, and are
- contained within the MAX_ADDRESS.
-
- @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be checked
-
- @retval TRUE The code sections in the input ImageRecord are valid
- @retval FALSE The code sections in the input ImageRecord are invalid
-**/
-BOOLEAN
-EFIAPI
-IsImageRecordCodeSectionValid (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- LIST_ENTRY *ImageRecordCodeSectionEndLink;
- LIST_ENTRY *ImageRecordCodeSectionList;
-
- if (ImageRecord == NULL) {
- return FALSE;
- }
-
- DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
-
- ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
- ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
- LastImageRecordCodeSection = NULL;
- while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- if (ImageRecordCodeSection->CodeSegmentSize == 0) {
- return FALSE;
- }
-
- if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
- return FALSE;
- }
-
- if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
- return FALSE;
- }
-
- if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
- return FALSE;
- }
-
- if (LastImageRecordCodeSection != NULL) {
- if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
- return FALSE;
- }
- }
-
- LastImageRecordCodeSection = ImageRecordCodeSection;
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
- }
-
- return TRUE;
-}
-
-/**
- Swap two image records.
-
- @param[in] FirstImageRecord The first image record.
- @param[in] SecondImageRecord The second image record.
-
- @retval EFI_SUCCESS The image records were swapped successfully
- @retval EFI_INVALID_PARAMETER FirstImageRecord or SecondImageRecord is NULL
-**/
-EFI_STATUS
-EFIAPI
-SwapImageRecord (
- IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
- IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
- )
-{
- IMAGE_PROPERTIES_RECORD TempImageRecord;
-
- if ((FirstImageRecord == NULL) || (SecondImageRecord == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
- TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
- TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
-
- FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
- FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
- FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
-
- SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
- SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
- SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
-
- SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
- return EFI_SUCCESS;
-}
-
-/**
- Sort the input ImageRecordList based upon the ImageBase from low to high.
-
- @param[in] ImageRecordList Image record list to be sorted
-
- @retval EFI_SUCCESS The image record list was sorted successfully
- @retval EFI_ABORTED An error occurred while sorting the image record list
- @retval EFI_INVALID_PARAMETER ImageRecordList is NULL
-**/
-EFI_STATUS
-EFIAPI
-SortImageRecord (
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- IMAGE_PROPERTIES_RECORD *NextImageRecord;
- LIST_ENTRY *ImageRecordLink;
- LIST_ENTRY *NextImageRecordLink;
- LIST_ENTRY *ImageRecordEndLink;
- EFI_STATUS Status;
-
- if (ImageRecordList == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- ImageRecordLink = ImageRecordList->ForwardLink;
- NextImageRecordLink = ImageRecordLink->ForwardLink;
- ImageRecordEndLink = ImageRecordList;
- while (ImageRecordLink != ImageRecordEndLink) {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
- while (NextImageRecordLink != ImageRecordEndLink) {
- NextImageRecord = CR (
- NextImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
-
- );
- if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
- Status = SwapImageRecord (ImageRecord, NextImageRecord);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return EFI_ABORTED;
- }
- }
-
- NextImageRecordLink = NextImageRecordLink->ForwardLink;
- }
-
- ImageRecordLink = ImageRecordLink->ForwardLink;
- NextImageRecordLink = ImageRecordLink->ForwardLink;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Extract the .efi filename out of the input PDB.
-
- @param[in] PdbPointer Pointer to the PDB file path.
- @param[out] EfiFileName Pointer to the .efi filename.
- @param[in] EfiFileNameSize Size of the .efi filename buffer.
-**/
-STATIC
-VOID
-GetFilename (
- IN CHAR8 *PdbPointer,
- OUT CHAR8 *EfiFileName,
- IN UINTN EfiFileNameSize
- )
-{
- UINTN Index;
- UINTN StartIndex;
-
- if ((PdbPointer == NULL) || (EfiFileNameSize < 5)) {
- return;
- }
-
- // Print Module Name by Pdb file path.
- StartIndex = 0;
- for (Index = 0; PdbPointer[Index] != 0; Index++) {
- if ((PdbPointer[Index] == '\\') || (PdbPointer[Index] == '/')) {
- StartIndex = Index + 1;
- }
- }
-
- // Copy the PDB file name to EfiFileName and replace .pdb with .efi
- for (Index = 0; Index < EfiFileNameSize - 4; Index++) {
- EfiFileName[Index] = PdbPointer[Index + StartIndex];
- if (EfiFileName[Index] == 0) {
- EfiFileName[Index] = '.';
- }
-
- if (EfiFileName[Index] == '.') {
- EfiFileName[Index + 1] = 'e';
- EfiFileName[Index + 2] = 'f';
- EfiFileName[Index + 3] = 'i';
- EfiFileName[Index + 4] = 0;
- break;
- }
- }
-
- if (Index == sizeof (EfiFileName) - 4) {
- EfiFileName[Index] = 0;
- }
-}
-
-/**
- Debug dumps the input list of IMAGE_PROPERTIES_RECORD structs.
-
- @param[in] ImageRecordList Head of the IMAGE_PROPERTIES_RECORD list
-**/
-VOID
-EFIAPI
-DumpImageRecords (
- IN LIST_ENTRY *ImageRecordList
- )
-{
- LIST_ENTRY *ImageRecordLink;
- IMAGE_PROPERTIES_RECORD *CurrentImageRecord;
- LIST_ENTRY *CodeSectionLink;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CurrentCodeSection;
- CHAR8 *PdbPointer;
- CHAR8 EfiFileName[256];
-
- if (ImageRecordList == NULL) {
- return;
- }
-
- ImageRecordLink = ImageRecordList->ForwardLink;
-
- while (ImageRecordLink != ImageRecordList) {
- CurrentImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)CurrentImageRecord->ImageBase);
- if (PdbPointer != NULL) {
- GetFilename (PdbPointer, EfiFileName, sizeof (EfiFileName));
- DEBUG ((
- DEBUG_INFO,
- "%a: 0x%llx - 0x%llx\n",
- EfiFileName,
- CurrentImageRecord->ImageBase,
- CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
- ));
- } else {
- DEBUG ((
- DEBUG_INFO,
- "Unknown Image: 0x%llx - 0x%llx\n",
- CurrentImageRecord->ImageBase,
- CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
- ));
- }
-
- CodeSectionLink = CurrentImageRecord->CodeSegmentList.ForwardLink;
-
- while (CodeSectionLink != &CurrentImageRecord->CodeSegmentList) {
- CurrentCodeSection = CR (
- CodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
-
- DEBUG ((
- DEBUG_INFO,
- " Code Section: 0x%llx - 0x%llx\n",
- CurrentCodeSection->CodeSegmentBase,
- CurrentCodeSection->CodeSegmentBase + CurrentCodeSection->CodeSegmentSize
- ));
-
- CodeSectionLink = CodeSectionLink->ForwardLink;
- }
-
- ImageRecordLink = ImageRecordLink->ForwardLink;
- }
-}
-
-/**
- Find image record according to image base and size.
-
- @param[in] ImageBase Base of PE image
- @param[in] ImageSize Size of PE image
- @param[in] ImageRecordList Image record list to be searched
-
- @retval NULL No IMAGE_PROPERTIES_RECORD matches ImageBase
- and ImageSize in the input ImageRecordList
- @retval Other The found IMAGE_PROPERTIES_RECORD
-**/
-IMAGE_PROPERTIES_RECORD *
-EFIAPI
-FindImageRecord (
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- LIST_ENTRY *ImageRecordLink;
-
- if (ImageRecordList == NULL) {
- return NULL;
- }
-
- for (ImageRecordLink = ImageRecordList->ForwardLink;
- ImageRecordLink != ImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- if ((ImageBase == ImageRecord->ImageBase) &&
- (ImageSize == ImageRecord->ImageSize))
- {
- return ImageRecord;
- }
- }
-
- return NULL;
-}
-
-/**
- Creates an IMAGE_PROPERTIES_RECORD from a loaded PE image. The PE/COFF header will be found
- and parsed to determine the number of code segments and their base addresses and sizes.
-
- @param[in] ImageBase Base of the PE image
- @param[in] ImageSize Size of the PE image
- @param[in] RequiredAlignment If non-NULL, the alignment specified in the PE/COFF header
- will be compared against this value.
- @param[out] ImageRecord On out, a populated image properties record
-
- @retval EFI_INVALID_PARAMETER This function ImageBase or ImageRecord was NULL, or the
- image located at ImageBase was not a valid PE/COFF image
- @retval EFI_OUT_OF_RESOURCES Failure to Allocate()
- @retval EFI_ABORTED The input Alignment was non-NULL and did not match the
- alignment specified in the PE/COFF header
- @retval EFI_SUCCESS The image properties record was successfully created
-**/
-EFI_STATUS
-EFIAPI
-CreateImagePropertiesRecord (
- IN CONST VOID *ImageBase,
- IN CONST UINT64 ImageSize,
- IN CONST UINT32 *RequiredAlignment OPTIONAL,
- OUT IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- EFI_STATUS Status;
- EFI_IMAGE_DOS_HEADER *DosHdr;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- EFI_IMAGE_SECTION_HEADER *Section;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- UINTN Index;
- UINT8 *Name;
- UINT32 SectionAlignment;
- UINT32 PeCoffHeaderOffset;
- CHAR8 *PdbPointer;
-
- if ((ImageRecord == NULL) || (ImageBase == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- DEBUG ((
- DEBUG_VERBOSE,
- "Creating Image Properties Record: 0x%016lx - 0x%016lx\n",
- (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase,
- ImageSize
- ));
-
- //
- // Step 1: record whole region
- //
- Status = EFI_SUCCESS;
- ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
- ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase;
- ImageRecord->ImageSize = ImageSize;
- ImageRecord->CodeSegmentCount = 0;
- InitializeListHead (&ImageRecord->Link);
- InitializeListHead (&ImageRecord->CodeSegmentList);
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, " Image - %a\n", PdbPointer));
- }
-
- // Check PE/COFF image
- DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
- PeCoffHeaderOffset = 0;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- PeCoffHeaderOffset = DosHdr->e_lfanew;
- }
-
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageBase + PeCoffHeaderOffset);
- if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
- DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
- return EFI_INVALID_PARAMETER;
- }
-
- // Get SectionAlignment
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
- } else {
- SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
- }
-
- // Check RequiredAlignment
- if ((RequiredAlignment != NULL) && ((SectionAlignment & (*RequiredAlignment - 1)) != 0)) {
- DEBUG ((
- DEBUG_WARN,
- "!!!!!!!! Image Section Alignment(0x%x) does not match Required Alignment (0x%x) !!!!!!!!\n",
- SectionAlignment,
- *RequiredAlignment
- ));
-
- return EFI_ABORTED;
- }
-
- Section = (EFI_IMAGE_SECTION_HEADER *)(
- (UINT8 *)(UINTN)ImageBase +
- PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- Hdr.Pe32->FileHeader.SizeOfOptionalHeader
- );
- for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
- Name = Section[Index].Name;
- DEBUG ((
- DEBUG_VERBOSE,
- " Section - '%c%c%c%c%c%c%c%c'\n",
- Name[0],
- Name[1],
- Name[2],
- Name[3],
- Name[4],
- Name[5],
- Name[6],
- Name[7]
- ));
-
- if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
- DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
- DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
- DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
- DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
- DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
- DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
- DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
- DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
- DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
-
- // Record code section(s)
- ImageRecordCodeSection = AllocatePool (sizeof (*ImageRecordCodeSection));
- if (ImageRecordCodeSection == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CreateImagePropertiesRecordEnd;
- }
-
- ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
-
- ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress;
- // We still need to align the VirtualSize to the SectionAlignment because MSVC does not do
- // this when creating a PE image. It expects the loader to do this.
- ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].Misc.VirtualSize, SectionAlignment);
-
- InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
- ImageRecord->CodeSegmentCount++;
- }
- }
-
- if (ImageRecord->CodeSegmentCount > 0) {
- SortImageRecordCodeSection (ImageRecord);
- }
-
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
- Status = EFI_INVALID_PARAMETER;
- goto CreateImagePropertiesRecordEnd;
- }
-
- //
- // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
- // Given that the loader always allocates full pages, we know the space after the image is not used.
- //
- ImageRecord->ImageSize = ALIGN_VALUE (ImageRecord->ImageSize, EFI_PAGE_SIZE);
-
-CreateImagePropertiesRecordEnd:
- if (EFI_ERROR (Status)) {
- // we failed to create a valid record, free the section memory that was allocated
- FreeImageRecordCodeSections (ImageRecord);
- }
-
- return Status;
-}
-
-/**
- Deleted an image properties record. The function will also call
- RemoveEntryList() on each code segment and the input ImageRecord before
- freeing each pool.
-
- @param[in] ImageRecord The IMAGE_PROPERTIES_RECORD to delete
-**/
-VOID
-EFIAPI
-DeleteImagePropertiesRecord (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- FreeImageRecordCodeSections (ImageRecord);
-
- if (!IsListEmpty (&ImageRecord->Link)) {
- RemoveEntryList (&ImageRecord->Link);
- }
-
- FreePool (ImageRecord);
-}
+/** @file
+
+ Provides definitions and functionality for manipulating IMAGE_PROPERTIES_RECORD.
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/ImagePropertiesRecordLib.h>
+
+#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
+
+#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
+
+/**
+ Converts a number of pages to a size in bytes.
+
+ NOTE: Do not use EFI_PAGES_TO_SIZE because it handles UINTN only.
+
+ @param[in] Pages The number of EFI_PAGES.
+
+ @retval The number of bytes associated with the input number of pages.
+**/
+STATIC
+UINT64
+EfiPagesToSize (
+ IN UINT64 Pages
+ )
+{
+ return LShiftU64 (Pages, EFI_PAGE_SHIFT);
+}
+
+/**
+ Converts a size, in bytes, to a number of EFI_PAGESs.
+
+ NOTE: Do not use EFI_SIZE_TO_PAGES because it handles UINTN only.
+
+ @param[in] Size A size in bytes.
+
+ @retval The number of pages associated with the input number of bytes.
+
+**/
+STATIC
+UINT64
+EfiSizeToPages (
+ IN UINT64 Size
+ )
+{
+ return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0);
+}
+
+/**
+ Frees the memory for each ImageRecordCodeSection within an ImageRecord
+ and removes the entries from the list. It does not free the ImageRecord
+ itself.
+
+ @param[in] ImageRecord The ImageRecord in which to free code sections
+**/
+STATIC
+VOID
+FreeImageRecordCodeSections (
+ IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+
+ if (ImageRecord == NULL) {
+ return;
+ }
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+}
+
+/**
+ Sort memory map entries based upon PhysicalStart from low to high.
+
+ @param[in, out] MemoryMap A pointer to the buffer in which firmware places
+ the current memory map.
+ @param[in] MemoryMapSize Size, in bytes, of the MemoryMap buffer.
+ @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+**/
+STATIC
+VOID
+SortMemoryMap (
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR TempMemoryMap;
+
+ MemoryMapEntry = MemoryMap;
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
+ while (MemoryMapEntry < MemoryMapEnd) {
+ while (NextMemoryMapEntry < MemoryMapEnd) {
+ if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
+ CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
+ }
+
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+
+ return;
+}
+
+/**
+ Return the first image record, whose [ImageBase, ImageSize] covered by [Buffer, Length].
+
+ @param[in] Buffer Starting Address
+ @param[in] Length Length to check
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries to check against
+ the memory range Buffer -> Buffer + Length
+
+ @retval The first image record covered by [Buffer, Length]
+**/
+STATIC
+IMAGE_PROPERTIES_RECORD *
+GetImageRecordByAddress (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink)
+ {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((Buffer <= ImageRecord->ImageBase) &&
+ (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize))
+ {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Break up the input OldRecord into multiple new records based on the code
+ and data sections in the input ImageRecord.
+
+ @param[in] ImageRecord An IMAGE_PROPERTIES_RECORD whose ImageBase and
+ ImageSize is covered by by OldRecord.
+ @param[in, out] NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be 1 +
+ (SplitRecordCount * DescriptorSize) calculated
+ below.
+ @param[in] OldRecord A pointer to one old memory map entry.
+ @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+
+ @retval The number of new descriptors created.
+**/
+STATIC
+UINTN
+SetNewRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN UINTN DescriptorSize
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+ UINTN NewRecordCount;
+ UINT64 PhysicalEnd;
+ UINT64 ImageEnd;
+
+ CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
+ NewRecordCount = 0;
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+
+ if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) {
+ //
+ // DATA
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount++;
+ }
+
+ //
+ // CODE
+ //
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize);
+ NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO;
+ if (NewRecord->NumberOfPages != 0) {
+ NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize);
+ NewRecordCount++;
+ }
+
+ TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize));
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - TempRecord.PhysicalStart);
+ if (TempRecord.NumberOfPages == 0) {
+ break;
+ }
+ }
+ }
+
+ ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
+
+ //
+ // Final DATA
+ //
+ if (TempRecord.PhysicalStart < ImageEnd) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP;
+ NewRecordCount++;
+ }
+
+ return NewRecordCount;
+}
+
+/**
+ Return the maximum number of new entries required to describe the code and data sections
+ of all images covered by the input OldRecord.
+
+ @param[in] OldRecord A pointer to one old memory map entry.
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
+ for an image record contained by the memory range described by
+ OldRecord
+
+ @retval The maximum number of new descriptors required to describe the code and data sections
+ of all images covered by OldRecord.
+**/
+STATIC
+UINTN
+GetMaxSplitRecordCount (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ UINTN SplitRecordCount;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+
+ SplitRecordCount = 0;
+ PhysicalStart = OldRecord->PhysicalStart;
+ PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize (OldRecord->NumberOfPages);
+
+ do {
+ ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
+ if (ImageRecord == NULL) {
+ break;
+ }
+
+ SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 3);
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ if (SplitRecordCount != 0) {
+ SplitRecordCount--;
+ }
+
+ return SplitRecordCount;
+}
+
+/**
+ Split the memory map into new entries based upon the PE code and data sections
+ in ImageRecordList covered by the input OldRecord.
+
+ @param[in] OldRecord A pointer to one old memory map entry.
+ @param[in, out] NewRecord A pointer to several new memory map entries.
+ The caller gurantee the buffer size be
+ (SplitRecordCount * DescriptorSize).
+ @param[in] MaxSplitRecordCount The maximum number of entries post-split.
+ @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
+ for an image record contained by the memory range described in
+ the existing EFI memory map descriptor OldRecord
+
+ @retval The number of split entries.
+**/
+STATIC
+UINTN
+SplitRecord (
+ IN EFI_MEMORY_DESCRIPTOR *OldRecord,
+ IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord,
+ IN UINTN MaxSplitRecordCount,
+ IN UINTN DescriptorSize,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ EFI_MEMORY_DESCRIPTOR TempRecord;
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NewImageRecord;
+ UINT64 PhysicalStart;
+ UINT64 PhysicalEnd;
+ UINTN NewRecordCount;
+ UINTN TotalNewRecordCount;
+
+ if (MaxSplitRecordCount == 0) {
+ CopyMem (NewRecord, OldRecord, DescriptorSize);
+ return 0;
+ }
+
+ TotalNewRecordCount = 0;
+
+ //
+ // Override previous record
+ //
+ CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR));
+ PhysicalStart = TempRecord.PhysicalStart;
+ PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages);
+
+ ImageRecord = NULL;
+ do {
+ NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList);
+ if (NewImageRecord == NULL) {
+ //
+ // No more images cover this range, check if we've reached the end of the old descriptor. If not,
+ // add the remaining range to the new descriptor list.
+ //
+ if (PhysicalEnd > PhysicalStart) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute;
+ TotalNewRecordCount++;
+ }
+
+ break;
+ }
+
+ ImageRecord = NewImageRecord;
+
+ //
+ // Update PhysicalStart to exclude the portion before the image buffer
+ //
+ if (TempRecord.PhysicalStart < ImageRecord->ImageBase) {
+ NewRecord->Type = TempRecord.Type;
+ NewRecord->PhysicalStart = TempRecord.PhysicalStart;
+ NewRecord->VirtualStart = 0;
+ NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->ImageBase - TempRecord.PhysicalStart);
+ NewRecord->Attribute = TempRecord.Attribute;
+ TotalNewRecordCount++;
+
+ PhysicalStart = ImageRecord->ImageBase;
+ TempRecord.PhysicalStart = PhysicalStart;
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + DescriptorSize);
+ }
+
+ //
+ // Set new record
+ //
+ NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize);
+ TotalNewRecordCount += NewRecordCount;
+ NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize);
+
+ //
+ // Update PhysicalStart, in order to exclude the image buffer already splitted.
+ //
+ PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize;
+ TempRecord.PhysicalStart = PhysicalStart;
+ TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart);
+ } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd));
+
+ //
+ // The logic in function SplitTable() ensures that TotalNewRecordCount will not be zero if the
+ // code reaches here.
+ //
+ ASSERT (TotalNewRecordCount != 0);
+ return TotalNewRecordCount - 1;
+}
+
+/**
+ Split the original memory map and add more entries to describe PE code
+ and data sections for each image in the input ImageRecordList.
+
+ NOTE: This function assumes PE code/data section are page aligned.
+ NOTE: This function assumes there are enough entries for the new memory map.
+
+ | | | | | | | |
+ | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE |
+ | | | | | | | |
+ Assume the above memory region is the result of one split memory map descriptor. It's unlikely
+ that a linker will orient an image this way, but the caller must assume the worst case scenario.
+ This image layout example contains code sections oriented in a way that maximizes the number of
+ descriptors which would be required to describe each section. To ensure we have enough space
+ for every descriptor of the broken up memory map, the caller must assume that every image will
+ have the maximum number of code sections oriented in a way which maximizes the number of data
+ sections with unrelated memory regions flanking each image within a single descriptor.
+
+ Given an image record list, the caller should use the following formula when allocating extra descriptors:
+ NumberOfAdditionalDescriptors = (MemoryMapSize / DescriptorSize) +
+ ((2 * <Most Code Segments in a Single Image> + 3) * <Number of Images>)
+
+ @param[in, out] MemoryMapSize IN: The size, in bytes, of the old memory map before the split.
+ OUT: The size, in bytes, of the used descriptors of the split
+ memory map
+ @param[in, out] MemoryMap IN: A pointer to the buffer containing the current memory map.
+ This buffer must have enough space to accomodate the "worst case"
+ scenario where every image in ImageRecordList needs a new descriptor
+ to describe its code and data sections.
+ OUT: A pointer to the updated memory map with separated image section
+ descriptors.
+ @param[in] DescriptorSize The size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries used when searching
+ for an image record contained by the memory range described in
+ EFI memory map descriptors.
+ @param[in] NumberOfAdditionalDescriptors The number of unused descriptors at the end of the input MemoryMap.
+ The formula in the description should be used to calculate this value.
+
+ @retval EFI_SUCCESS The memory map was successfully split.
+ @retval EFI_INVALID_PARAMETER MemoryMapSize, MemoryMap, or ImageRecordList was NULL.
+**/
+EFI_STATUS
+EFIAPI
+SplitTable (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN UINTN DescriptorSize,
+ IN LIST_ENTRY *ImageRecordList,
+ IN UINTN NumberOfAdditionalDescriptors
+ )
+{
+ INTN IndexOld;
+ INTN IndexNew;
+ INTN IndexNewStarting;
+ UINTN MaxSplitRecordCount;
+ UINTN RealSplitRecordCount;
+ UINTN TotalSkippedRecords;
+
+ if ((MemoryMapSize == NULL) || (MemoryMap == NULL) || (ImageRecordList == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TotalSkippedRecords = 0;
+ //
+ // Let old record point to end of valid MemoryMap buffer.
+ //
+ IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1;
+ //
+ // Let new record point to end of full MemoryMap buffer.
+ //
+ IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + NumberOfAdditionalDescriptors;
+ IndexNewStarting = IndexNew;
+ for ( ; IndexOld >= 0; IndexOld--) {
+ MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize), ImageRecordList);
+ //
+ // Split this MemoryMap record
+ //
+ IndexNew -= MaxSplitRecordCount;
+ RealSplitRecordCount = SplitRecord (
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize),
+ (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize),
+ MaxSplitRecordCount,
+ DescriptorSize,
+ ImageRecordList
+ );
+
+ // If we didn't utilize all the extra allocated descriptor slots, set the physical address of the unused slots
+ // to MAX_ADDRESS so they are moved to the bottom of the list when sorting.
+ for ( ; RealSplitRecordCount < MaxSplitRecordCount; RealSplitRecordCount++) {
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + ((IndexNew + RealSplitRecordCount + 1) * DescriptorSize)))->PhysicalStart = MAX_ADDRESS;
+ TotalSkippedRecords++;
+ }
+
+ IndexNew--;
+ }
+
+ //
+ // Move all records to the beginning.
+ //
+ CopyMem (
+ MemoryMap,
+ (UINT8 *)MemoryMap + ((IndexNew + 1) * DescriptorSize),
+ (IndexNewStarting - IndexNew) * DescriptorSize
+ );
+
+ //
+ // Sort from low to high to filter out the MAX_ADDRESS records.
+ //
+ SortMemoryMap (MemoryMap, (IndexNewStarting - IndexNew) * DescriptorSize, DescriptorSize);
+
+ *MemoryMapSize = (IndexNewStarting - IndexNew - TotalSkippedRecords) * DescriptorSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Swap two code sections in a single IMAGE_PROPERTIES_RECORD.
+
+ @param[in] FirstImageRecordCodeSection The first code section
+ @param[in] SecondImageRecordCodeSection The second code section
+
+ @retval EFI_SUCCESS The code sections were swapped successfully
+ @retval EFI_INVALID_PARAMETER FirstImageRecordCodeSection or SecondImageRecordCodeSection is NULL
+**/
+EFI_STATUS
+EFIAPI
+SwapImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection,
+ IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection;
+
+ if ((FirstImageRecordCodeSection == NULL) || (SecondImageRecordCodeSection == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase;
+ TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize;
+
+ FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase;
+ FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize;
+
+ SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase;
+ SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sort the code sections in the input ImageRecord based upon CodeSegmentBase from low to high.
+
+ @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be sorted
+
+ @retval EFI_SUCCESS The code sections in the input ImageRecord were sorted successfully
+ @retval EFI_ABORTED An error occurred while sorting the code sections in the input ImageRecord
+ @retval EFI_INVALID_PARAMETER ImageRecord is NULL
+**/
+EFI_STATUS
+EFIAPI
+SortImageRecordCodeSection (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ EFI_STATUS Status;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *NextImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ if (ImageRecord == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ NextImageRecordCodeSection = CR (
+ NextImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) {
+ Status = SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return EFI_ABORTED;
+ }
+ }
+
+ NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if the code sections in the input ImageRecord are valid.
+ The code sections are valid if they don't overlap, are contained
+ within the the ImageRecord's ImageBase and ImageSize, and are
+ contained within the MAX_ADDRESS.
+
+ @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be checked
+
+ @retval TRUE The code sections in the input ImageRecord are valid
+ @retval FALSE The code sections in the input ImageRecord are invalid
+**/
+BOOLEAN
+EFIAPI
+IsImageRecordCodeSectionValid (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ LIST_ENTRY *ImageRecordCodeSectionEndLink;
+ LIST_ENTRY *ImageRecordCodeSectionList;
+
+ if (ImageRecord == NULL) {
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount));
+
+ ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
+
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
+ ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
+ LastImageRecordCodeSection = NULL;
+ while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ if (ImageRecordCodeSection->CodeSegmentSize == 0) {
+ return FALSE;
+ }
+
+ if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) {
+ return FALSE;
+ }
+
+ if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) {
+ return FALSE;
+ }
+
+ if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ return FALSE;
+ }
+
+ if (LastImageRecordCodeSection != NULL) {
+ if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) {
+ return FALSE;
+ }
+ }
+
+ LastImageRecordCodeSection = ImageRecordCodeSection;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
+ }
+
+ return TRUE;
+}
+
+/**
+ Swap two image records.
+
+ @param[in] FirstImageRecord The first image record.
+ @param[in] SecondImageRecord The second image record.
+
+ @retval EFI_SUCCESS The image records were swapped successfully
+ @retval EFI_INVALID_PARAMETER FirstImageRecord or SecondImageRecord is NULL
+**/
+EFI_STATUS
+EFIAPI
+SwapImageRecord (
+ IN IMAGE_PROPERTIES_RECORD *FirstImageRecord,
+ IN IMAGE_PROPERTIES_RECORD *SecondImageRecord
+ )
+{
+ IMAGE_PROPERTIES_RECORD TempImageRecord;
+
+ if ((FirstImageRecord == NULL) || (SecondImageRecord == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempImageRecord.ImageBase = FirstImageRecord->ImageBase;
+ TempImageRecord.ImageSize = FirstImageRecord->ImageSize;
+ TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount;
+
+ FirstImageRecord->ImageBase = SecondImageRecord->ImageBase;
+ FirstImageRecord->ImageSize = SecondImageRecord->ImageSize;
+ FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount;
+
+ SecondImageRecord->ImageBase = TempImageRecord.ImageBase;
+ SecondImageRecord->ImageSize = TempImageRecord.ImageSize;
+ SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount;
+
+ SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList);
+ return EFI_SUCCESS;
+}
+
+/**
+ Sort the input ImageRecordList based upon the ImageBase from low to high.
+
+ @param[in] ImageRecordList Image record list to be sorted
+
+ @retval EFI_SUCCESS The image record list was sorted successfully
+ @retval EFI_ABORTED An error occurred while sorting the image record list
+ @retval EFI_INVALID_PARAMETER ImageRecordList is NULL
+**/
+EFI_STATUS
+EFIAPI
+SortImageRecord (
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD *NextImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *NextImageRecordLink;
+ LIST_ENTRY *ImageRecordEndLink;
+ EFI_STATUS Status;
+
+ if (ImageRecordList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ImageRecordLink = ImageRecordList->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ ImageRecordEndLink = ImageRecordList;
+ while (ImageRecordLink != ImageRecordEndLink) {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+ while (NextImageRecordLink != ImageRecordEndLink) {
+ NextImageRecord = CR (
+ NextImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+
+ );
+ if (ImageRecord->ImageBase > NextImageRecord->ImageBase) {
+ Status = SwapImageRecord (ImageRecord, NextImageRecord);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return EFI_ABORTED;
+ }
+ }
+
+ NextImageRecordLink = NextImageRecordLink->ForwardLink;
+ }
+
+ ImageRecordLink = ImageRecordLink->ForwardLink;
+ NextImageRecordLink = ImageRecordLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Extract the .efi filename out of the input PDB.
+
+ @param[in] PdbPointer Pointer to the PDB file path.
+ @param[out] EfiFileName Pointer to the .efi filename.
+ @param[in] EfiFileNameSize Size of the .efi filename buffer.
+**/
+STATIC
+VOID
+GetFilename (
+ IN CHAR8 *PdbPointer,
+ OUT CHAR8 *EfiFileName,
+ IN UINTN EfiFileNameSize
+ )
+{
+ UINTN Index;
+ UINTN StartIndex;
+
+ if ((PdbPointer == NULL) || (EfiFileNameSize < 5)) {
+ return;
+ }
+
+ // Print Module Name by Pdb file path.
+ StartIndex = 0;
+ for (Index = 0; PdbPointer[Index] != 0; Index++) {
+ if ((PdbPointer[Index] == '\\') || (PdbPointer[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+
+ // Copy the PDB file name to EfiFileName and replace .pdb with .efi
+ for (Index = 0; Index < EfiFileNameSize - 4; Index++) {
+ EfiFileName[Index] = PdbPointer[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+}
+
+/**
+ Debug dumps the input list of IMAGE_PROPERTIES_RECORD structs.
+
+ @param[in] ImageRecordList Head of the IMAGE_PROPERTIES_RECORD list
+**/
+VOID
+EFIAPI
+DumpImageRecords (
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ LIST_ENTRY *ImageRecordLink;
+ IMAGE_PROPERTIES_RECORD *CurrentImageRecord;
+ LIST_ENTRY *CodeSectionLink;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CurrentCodeSection;
+ CHAR8 *PdbPointer;
+ CHAR8 EfiFileName[256];
+
+ if (ImageRecordList == NULL) {
+ return;
+ }
+
+ ImageRecordLink = ImageRecordList->ForwardLink;
+
+ while (ImageRecordLink != ImageRecordList) {
+ CurrentImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)CurrentImageRecord->ImageBase);
+ if (PdbPointer != NULL) {
+ GetFilename (PdbPointer, EfiFileName, sizeof (EfiFileName));
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: 0x%llx - 0x%llx\n",
+ EfiFileName,
+ CurrentImageRecord->ImageBase,
+ CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
+ ));
+ } else {
+ DEBUG ((
+ DEBUG_INFO,
+ "Unknown Image: 0x%llx - 0x%llx\n",
+ CurrentImageRecord->ImageBase,
+ CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize
+ ));
+ }
+
+ CodeSectionLink = CurrentImageRecord->CodeSegmentList.ForwardLink;
+
+ while (CodeSectionLink != &CurrentImageRecord->CodeSegmentList) {
+ CurrentCodeSection = CR (
+ CodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+
+ DEBUG ((
+ DEBUG_INFO,
+ " Code Section: 0x%llx - 0x%llx\n",
+ CurrentCodeSection->CodeSegmentBase,
+ CurrentCodeSection->CodeSegmentBase + CurrentCodeSection->CodeSegmentSize
+ ));
+
+ CodeSectionLink = CodeSectionLink->ForwardLink;
+ }
+
+ ImageRecordLink = ImageRecordLink->ForwardLink;
+ }
+}
+
+/**
+ Find image record according to image base and size.
+
+ @param[in] ImageBase Base of PE image
+ @param[in] ImageSize Size of PE image
+ @param[in] ImageRecordList Image record list to be searched
+
+ @retval NULL No IMAGE_PROPERTIES_RECORD matches ImageBase
+ and ImageSize in the input ImageRecordList
+ @retval Other The found IMAGE_PROPERTIES_RECORD
+**/
+IMAGE_PROPERTIES_RECORD *
+EFIAPI
+FindImageRecord (
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ LIST_ENTRY *ImageRecordLink;
+
+ if (ImageRecordList == NULL) {
+ return NULL;
+ }
+
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink)
+ {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ if ((ImageBase == ImageRecord->ImageBase) &&
+ (ImageSize == ImageRecord->ImageSize))
+ {
+ return ImageRecord;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Creates an IMAGE_PROPERTIES_RECORD from a loaded PE image. The PE/COFF header will be found
+ and parsed to determine the number of code segments and their base addresses and sizes.
+
+ @param[in] ImageBase Base of the PE image
+ @param[in] ImageSize Size of the PE image
+ @param[in] RequiredAlignment If non-NULL, the alignment specified in the PE/COFF header
+ will be compared against this value.
+ @param[out] ImageRecord On out, a populated image properties record
+
+ @retval EFI_INVALID_PARAMETER This function ImageBase or ImageRecord was NULL, or the
+ image located at ImageBase was not a valid PE/COFF image
+ @retval EFI_OUT_OF_RESOURCES Failure to Allocate()
+ @retval EFI_ABORTED The input Alignment was non-NULL and did not match the
+ alignment specified in the PE/COFF header
+ @retval EFI_SUCCESS The image properties record was successfully created
+**/
+EFI_STATUS
+EFIAPI
+CreateImagePropertiesRecord (
+ IN CONST VOID *ImageBase,
+ IN CONST UINT64 ImageSize,
+ IN CONST UINT32 *RequiredAlignment OPTIONAL,
+ OUT IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ UINTN Index;
+ UINT8 *Name;
+ UINT32 SectionAlignment;
+ UINT32 PeCoffHeaderOffset;
+ CHAR8 *PdbPointer;
+
+ if ((ImageRecord == NULL) || (ImageBase == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "Creating Image Properties Record: 0x%016lx - 0x%016lx\n",
+ (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase,
+ ImageSize
+ ));
+
+ //
+ // Step 1: record whole region
+ //
+ Status = EFI_SUCCESS;
+ ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+ ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase;
+ ImageRecord->ImageSize = ImageSize;
+ ImageRecord->CodeSegmentCount = 0;
+ InitializeListHead (&ImageRecord->Link);
+ InitializeListHead (&ImageRecord->CodeSegmentList);
+
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase);
+ if (PdbPointer != NULL) {
+ DEBUG ((DEBUG_ERROR, " Image - %a\n", PdbPointer));
+ }
+
+ // Check PE/COFF image
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageBase + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get SectionAlignment
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ } else {
+ SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ }
+
+ // Check RequiredAlignment
+ if ((RequiredAlignment != NULL) && ((SectionAlignment & (*RequiredAlignment - 1)) != 0)) {
+ DEBUG ((
+ DEBUG_WARN,
+ "!!!!!!!! Image Section Alignment(0x%x) does not match Required Alignment (0x%x) !!!!!!!!\n",
+ SectionAlignment,
+ *RequiredAlignment
+ ));
+
+ return EFI_ABORTED;
+ }
+
+ Section = (EFI_IMAGE_SECTION_HEADER *)(
+ (UINT8 *)(UINTN)ImageBase +
+ PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Name = Section[Index].Name;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Section - '%c%c%c%c%c%c%c%c'\n",
+ Name[0],
+ Name[1],
+ Name[2],
+ Name[3],
+ Name[4],
+ Name[5],
+ Name[6],
+ Name[7]
+ ));
+
+ if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) {
+ DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize));
+ DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress));
+ DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData));
+ DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations));
+ DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations));
+ DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers));
+ DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics));
+
+ // Record code section(s)
+ ImageRecordCodeSection = AllocatePool (sizeof (*ImageRecordCodeSection));
+ if (ImageRecordCodeSection == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CreateImagePropertiesRecordEnd;
+ }
+
+ ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+
+ ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress;
+ // We still need to align the VirtualSize to the SectionAlignment because MSVC does not do
+ // this when creating a PE image. It expects the loader to do this.
+ ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].Misc.VirtualSize, SectionAlignment);
+
+ InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link);
+ ImageRecord->CodeSegmentCount++;
+ }
+ }
+
+ if (ImageRecord->CodeSegmentCount > 0) {
+ SortImageRecordCodeSection (ImageRecord);
+ }
+
+ //
+ // Check overlap all section in ImageBase/Size
+ //
+ if (!IsImageRecordCodeSectionValid (ImageRecord)) {
+ DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto CreateImagePropertiesRecordEnd;
+ }
+
+ //
+ // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned.
+ // Given that the loader always allocates full pages, we know the space after the image is not used.
+ //
+ ImageRecord->ImageSize = ALIGN_VALUE (ImageRecord->ImageSize, EFI_PAGE_SIZE);
+
+CreateImagePropertiesRecordEnd:
+ if (EFI_ERROR (Status)) {
+ // we failed to create a valid record, free the section memory that was allocated
+ FreeImageRecordCodeSections (ImageRecord);
+ }
+
+ return Status;
+}
+
+/**
+ Deleted an image properties record. The function will also call
+ RemoveEntryList() on each code segment and the input ImageRecord before
+ freeing each pool.
+
+ @param[in] ImageRecord The IMAGE_PROPERTIES_RECORD to delete
+**/
+VOID
+EFIAPI
+DeleteImagePropertiesRecord (
+ IN IMAGE_PROPERTIES_RECORD *ImageRecord
+ )
+{
+ FreeImageRecordCodeSections (ImageRecord);
+
+ if (!IsListEmpty (&ImageRecord->Link)) {
+ RemoveEntryList (&ImageRecord->Link);
+ }
+
+ FreePool (ImageRecord);
+}
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
index 1f82cc3e46..da99bd3a95 100644
--- a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
@@ -1,31 +1,31 @@
-## @file
-# Provides definitions and functionality for manipulating
-# IMAGE_PROPERTIES_RECORD.
-#
-# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-# Copyright (c) Microsoft Corporation.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = ImagePropertiesRecordLib
- FILE_GUID = 5CCA36C1-C430-4A90-8BF7-23D2719D5928
- MODULE_TYPE = BASE
- VERSION_STRING = 1.0
- LIBRARY_CLASS = ImagePropertiesRecordLib
-
-[Sources.common]
- ImagePropertiesRecordLib.c
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- DebugLib
- MemoryAllocationLib
- PeCoffGetEntryPointLib
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
+## @file
+# Provides definitions and functionality for manipulating
+# IMAGE_PROPERTIES_RECORD.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ImagePropertiesRecordLib
+ FILE_GUID = 5CCA36C1-C430-4A90-8BF7-23D2719D5928
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ImagePropertiesRecordLib
+
+[Sources.common]
+ ImagePropertiesRecordLib.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ PeCoffGetEntryPointLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c
index 8b0a55685c..ac4b80b7c5 100644
--- a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c
@@ -1,938 +1,938 @@
-/** @file
- Unit tests the SplitTable() ImagePropertiesRecordLib Logic
-
- Copyright (C) Microsoft Corporation.
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <setjmp.h>
-#include <cmocka.h>
-
-#include <Uefi.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UnitTestLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#define UNIT_TEST_APP_NAME "Image Properties Record Lib Unit Test"
-#define UNIT_TEST_APP_VERSION "1.0"
-
-#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
-
-// The starting memory map will contain 6 entries
-#define NUMBER_OF_MEMORY_MAP_DESCRIPTORS 6
-
-// Each memory map descriptor will be the sizeof(EFI_MEMORY_DESCRIPTOR) instead of a nonstandard size
-// to catch pointer math issues
-#define DESCRIPTOR_SIZE sizeof(EFI_MEMORY_DESCRIPTOR)
-
-// Each memory map descriptor will describe 12 pages
-#define BASE_DESCRIPTOR_NUMBER_OF_PAGES 0x0C
-
-// The size, in bytes, of each memory map descriptor range
-#define BASE_DESCRIPTOR_ENTRY_SIZE (EFI_PAGES_TO_SIZE(BASE_DESCRIPTOR_NUMBER_OF_PAGES))
-
-// MACRO to get the starting address of a descriptor's described range based on the index of that descriptor
-#define BASE_DESCRIPTOR_START_ADDRESS(DescriptorNumber) (DescriptorNumber * BASE_DESCRIPTOR_ENTRY_SIZE)
-
-// Virtual start must be zero
-#define BASE_DESCRIPTOR_VIRTUAL_START 0x0
-
-// Size of the default memory map
-#define BASE_MEMORY_MAP_SIZE (NUMBER_OF_MEMORY_MAP_DESCRIPTORS * DESCRIPTOR_SIZE)
-
-// Number of images in each test case
-#define NUMBER_OF_IMAGES_TO_SPLIT 3
-
-// Maximum number of descriptors required for each image (None->Data->Code->Data->Code->Data->None)
-#define MAX_DESCRIPTORS_PER_IMAGE 7
-
-// Number of unused additional descriptors in the starting memory map buffer which is used by the
-// SplitTable() logic
-#define NUMBER_OF_ADDITIONAL_DESCRIPTORS (NUMBER_OF_IMAGES_TO_SPLIT * MAX_DESCRIPTORS_PER_IMAGE)
-
-// Size of the memory map with enough space for the starting descriptors and the split descriptors
-#define SPLIT_MEMORY_MAP_SIZE (BASE_MEMORY_MAP_SIZE + (NUMBER_OF_ADDITIONAL_DESCRIPTORS * DESCRIPTOR_SIZE))
-
-typedef enum {
- SectionTypeCode,
- SectionTypeData,
- SectionTypeNotFound
-} SECTION_TYPE;
-
-typedef struct {
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- LIST_ENTRY ImageList;
-} IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT;
-
-EFI_MEMORY_DESCRIPTOR BaseMemoryMap[] = {
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (0), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- },
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (1), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- },
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (2), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- },
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (3), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- },
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (4), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- },
- {
- EfiConventionalMemory, // Type
- BASE_DESCRIPTOR_START_ADDRESS (5), // PhysicalStart
- BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
- BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
- 0 // Attribute
- }
-};
-
-/**
- Returns a bitmap where one bit is set for each section in the image list. For example, if
- there are 3 images and each image 3 sections the returned bitmap will be 111111111.
-
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries
-
- @retval A bitmap such that the most significant bit is the number of sections
- in all images and every bit between 0 -> MSB is set
-
-**/
-STATIC
-UINT64
-GetImageSectionBitmap (
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordLink;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- EFI_PHYSICAL_ADDRESS SectionBase;
- UINT64 ReturnBitmap;
- UINT64 Shift;
-
- if (ImageRecordList == NULL) {
- return 0;
- }
-
- ReturnBitmap = 0;
- Shift = 0;
-
- // Walk through each image record
- for (ImageRecordLink = ImageRecordList->ForwardLink;
- ImageRecordLink != ImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- SectionBase = ImageRecord->ImageBase;
-
- // Walk through each code entry
- for (ImageRecordCodeSectionLink = ImageRecord->CodeSegmentList.ForwardLink;
- ImageRecordCodeSectionLink != &ImageRecord->CodeSegmentList;
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink)
- {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
-
- // Check for data region before the code section base
- if (SectionBase < ImageRecordCodeSection->CodeSegmentBase) {
- ReturnBitmap |= LShiftU64 (1, Shift++);
- }
-
- // Code section
- ReturnBitmap |= LShiftU64 (1, Shift++);
- SectionBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
- }
-
- // Check for data region after the previous code section
- if (SectionBase < (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
- ReturnBitmap |= LShiftU64 (1, Shift++);
- }
- }
-
- return ReturnBitmap;
-}
-
-/**
- Searches the input image list for a section which exactly matches the memory range Buffer -> Buffer + Length.
-
- @param[in] Buffer Start Address to check
- @param[in] Length Length to check
- @param[out] Type The type of the section which corresponds with the memory
- range Buffer -> Buffer + Length (Code or Data) or SectionTypeNotFound
- if no image section matches the memory range
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries to check against
- the memory range Buffer -> Buffer + Length
-
- @retval A bitmap with a single bit set (1 << Shift) where Shift corresponds with the number of sections inspected
- in the image list before arriving at the section matching the memory range Buffer -> Buffer + Length
-**/
-STATIC
-UINT64
-MatchDescriptorToImageSection (
- IN EFI_PHYSICAL_ADDRESS Buffer,
- IN UINT64 Length,
- OUT SECTION_TYPE *Type,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordLink;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- EFI_PHYSICAL_ADDRESS SectionBase;
- UINT8 Shift;
-
- Shift = 0;
-
- if (ImageRecordList == NULL) {
- return 1;
- }
-
- // Walk through each image record
- for (ImageRecordLink = ImageRecordList->ForwardLink;
- ImageRecordLink != ImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- SectionBase = ImageRecord->ImageBase;
-
- // Walk through each code entry
- for (ImageRecordCodeSectionLink = ImageRecord->CodeSegmentList.ForwardLink;
- ImageRecordCodeSectionLink != &ImageRecord->CodeSegmentList;
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink)
- {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
-
- if (SectionBase < ImageRecordCodeSection->CodeSegmentBase) {
- // Check the data region before the code section base
- if ((Buffer == SectionBase) &&
- (Length == ImageRecordCodeSection->CodeSegmentBase - SectionBase))
- {
- *Type = SectionTypeData;
- return LShiftU64 (1, Shift);
- }
-
- Shift++;
- }
-
- // Check the code region
- if ((Buffer == ImageRecordCodeSection->CodeSegmentBase) &&
- (Length == ImageRecordCodeSection->CodeSegmentSize))
- {
- *Type = SectionTypeCode;
- return LShiftU64 (1, Shift);
- }
-
- Shift++;
- SectionBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
- }
-
- // Check the data region after the code section
- if (SectionBase < (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
- if ((Buffer == SectionBase) &&
- (Length == (ImageRecord->ImageBase + ImageRecord->ImageSize) - SectionBase))
- {
- *Type = SectionTypeData;
- return LShiftU64 (1, Shift);
- }
-
- Shift++;
- }
- }
-
- // No image sections match
- *Type = SectionTypeNotFound;
- return 0;
-}
-
-/**
- Walks through the input memory map and checks that every memory descriptor with an attribute matches
- an image in ImageRecordList.
-
- @param[in] MemoryMapSize The size, in bytes, of the memory map
- @param[in] MemoryMap A pointer to the buffer containing the memory map
- @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries
-
- @retval TRUE if all memory descriptors with attributes match an image section and have the correct attributes
-
-**/
-STATIC
-BOOLEAN
-IsMemoryMapValid (
- IN UINTN MemoryMapSize,
- IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN LIST_ENTRY *ImageRecordList
- )
-{
- UINT64 ImageSectionsBitmap;
- UINT64 ReturnSectionBitmask;
- UINT64 NumberOfDescriptors;
- UINT8 Index;
- SECTION_TYPE Type;
-
- Index = 0;
- NumberOfDescriptors = MemoryMapSize / DESCRIPTOR_SIZE;
-
- UT_ASSERT_EQUAL (MemoryMapSize % DESCRIPTOR_SIZE, 0);
- UT_ASSERT_NOT_NULL (MemoryMap);
- UT_ASSERT_NOT_NULL (ImageRecordList);
-
- // The returned bitmap will have one bit is set for each section in the image list.
- // If there are 3 images and 3 sections each image, the resulting bitmap will
- // be 0000000000000000000000000000000000000000000000000000000111111111. Flipping that bitmap
- // results in 1111111111111111111111111111111111111111111111111111111000000000. The return value
- // of each iteration through MatchDescriptorToImageSection() is one set bit corrosponding to the number
- // of sections before finding the section which matched the descriptor memory range which we
- // OR with ImageSectionsBitmap. If, at the end of the loop, every bit in ImageSectionsBitmap is set,
- // we must have matched every image in ImageRecordList with a descriptor in the memory map which has
- // nonzero attributes.
- ImageSectionsBitmap = ~GetImageSectionBitmap (ImageRecordList);
-
- // For each descriptor in the memory map
- for ( ; Index < NumberOfDescriptors; Index++) {
- if (MemoryMap[Index].Attribute != 0) {
- ReturnSectionBitmask = MatchDescriptorToImageSection (
- MemoryMap[Index].PhysicalStart,
- EFI_PAGES_TO_SIZE (MemoryMap[Index].NumberOfPages),
- &Type,
- ImageRecordList
- );
-
- // Make sure the attributes of the descriptor match the returned section type.
- // DATA sections should have execution protection and CODE sections should have
- // write protection.
- if ((Type == SectionTypeNotFound) ||
- ((Type == SectionTypeData) && (MemoryMap[Index].Attribute == EFI_MEMORY_RP)) ||
- ((Type == SectionTypeCode) && (MemoryMap[Index].Attribute == EFI_MEMORY_XP)))
- {
- return FALSE;
- }
-
- // If the bit associated with image found has already been set, then there must be a duplicate
- // in the memory map meaning it is invalid.
- UT_ASSERT_EQUAL (ImageSectionsBitmap & ReturnSectionBitmask, 0);
-
- ImageSectionsBitmap |= ReturnSectionBitmask;
- }
- }
-
- // If every bit in ImageSectionsBitmap is set, the return value will be TRUE
- return !(~ImageSectionsBitmap);
-}
-
-/**
- Separate the image sections in the memory map and run a check to ensure the output is valid.
-
- @param[in] Context Context containing the memory map and image record pointers
-
- @retval TRUE if the memory map is split correctly
-**/
-STATIC
-BOOLEAN
-SeparateAndCheck (
- IN IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context
- )
-{
- UINTN MemoryMapSize;
-
- MemoryMapSize = BASE_MEMORY_MAP_SIZE;
-
- // Separate the memory map so each image section has its own descriptor
- SplitTable (
- &MemoryMapSize,
- Context->MemoryMap,
- DESCRIPTOR_SIZE,
- &Context->ImageList,
- NUMBER_OF_ADDITIONAL_DESCRIPTORS
- );
-
- // Ensure the updated memory map is valid
- return IsMemoryMapValid (MemoryMapSize, Context->MemoryMap, &Context->ImageList);
-}
-
-/**
- Test the case where the image range contains multiple code sections and does not perfectly align with
- the existing memory descriptor.
-
- @param[in] Context Context containing the memory map and image record pointers
-
- @retval UNIT_TEST_PASSED The Unit test has completed and the test
- case was successful.
- @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
-**/
-UNIT_TEST_STATUS
-EFIAPI
-MaxOutAdditionalDescriptors (
- IN UNIT_TEST_CONTEXT Context
- )
-{
- IMAGE_PROPERTIES_RECORD *Image1;
- IMAGE_PROPERTIES_RECORD *Image2;
- IMAGE_PROPERTIES_RECORD *Image3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage3;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
-
- TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
-
- Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
-
- CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
-
- ///////////////
- // Descriptor 1
- ///////////////
- // | | | | | | | |
- // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
- // | | | | | | | |
-
- Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
- Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
- Image1->CodeSegmentCount = 2;
- CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
- TestContext->MemoryMap[1].Type = EfiBootServicesCode;
-
- AddCodeSectionInImage1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
- AddCodeSectionInImage1->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- AddCodeSectionInImage1->CodeSegmentBase = CodeSectionInImage1->CodeSegmentBase + CodeSectionInImage1->CodeSegmentSize + EFI_PAGE_SIZE;
- AddCodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
-
- InsertTailList (&Image1->CodeSegmentList, &AddCodeSectionInImage1->Link);
-
- ///////////////
- // Descriptor 2
- ///////////////
- // | | | | | | | |
- // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
- // | | | | | | | |
-
- Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (2) + EFI_PAGE_SIZE;
- Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
- Image2->CodeSegmentCount = 2;
- CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
- TestContext->MemoryMap[2].Type = EfiLoaderCode;
-
- AddCodeSectionInImage2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
- AddCodeSectionInImage2->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- AddCodeSectionInImage2->CodeSegmentBase = CodeSectionInImage2->CodeSegmentBase + CodeSectionInImage2->CodeSegmentSize + EFI_PAGE_SIZE;
- AddCodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
-
- InsertTailList (&Image2->CodeSegmentList, &AddCodeSectionInImage2->Link);
-
- ///////////////
- // Descriptor 3
- ///////////////
- // | | | | | | | |
- // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
- // | | | | | | | |
-
- Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3) + EFI_PAGE_SIZE;
- Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
- Image3->CodeSegmentCount = 2;
- CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
- TestContext->MemoryMap[3].Type = EfiRuntimeServicesCode;
-
- AddCodeSectionInImage3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
- AddCodeSectionInImage3->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- AddCodeSectionInImage3->CodeSegmentBase = CodeSectionInImage3->CodeSegmentBase + CodeSectionInImage3->CodeSegmentSize + EFI_PAGE_SIZE;
- AddCodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
-
- InsertTailList (&Image3->CodeSegmentList, &AddCodeSectionInImage3->Link);
-
- UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
-
- return UNIT_TEST_PASSED;
-}
-
-/**
- Test the case where multiple image ranges lie within an existing memory descriptor.
-
- @param[in] Context Context containing the memory map and image record pointers
-
- @retval UNIT_TEST_PASSED The Unit test has completed and the test
- case was successful.
- @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
-**/
-UNIT_TEST_STATUS
-EFIAPI
-MultipleImagesInOneDescriptor (
- IN UNIT_TEST_CONTEXT Context
- )
-{
- IMAGE_PROPERTIES_RECORD *Image1;
- IMAGE_PROPERTIES_RECORD *Image2;
- IMAGE_PROPERTIES_RECORD *Image3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
-
- TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
-
- Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
-
- CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
-
- ///////////////
- // Descriptor 1
- ///////////////
- // | | | | | | | | | | | | |
- // | 4K PAGE | DATA | CODE | DATA | 4K PAGE | DATA | CODE | DATA | DATA | CODE | DATA | 4K PAGE |
- // | | | | | | | | | | | | |
-
- Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
- Image1->ImageSize = EFI_PAGES_TO_SIZE (3);
- Image1->CodeSegmentCount = 1;
- CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
- TestContext->MemoryMap[1].Type = EfiBootServicesCode;
-
- Image2->ImageBase = Image1->ImageBase + Image1->ImageSize + EFI_PAGE_SIZE;
- Image2->ImageSize = EFI_PAGES_TO_SIZE (3);
- Image2->CodeSegmentCount = 1;
- CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
-
- Image3->ImageBase = Image2->ImageBase + Image2->ImageSize;
- Image3->ImageSize = EFI_PAGES_TO_SIZE (3);
- Image3->CodeSegmentCount = 1;
- CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
-
- UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
-
- return UNIT_TEST_PASSED;
-}
-
-/**
- Test the case where all image ranges do not fit perfectly within an existing memory descriptor.
-
- @param[in] Context Context containing the memory map and image record pointers
-
- @retval UNIT_TEST_PASSED The Unit test has completed and the test
- case was successful.
- @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
-**/
-UNIT_TEST_STATUS
-EFIAPI
-ImagesDontFitDescriptors (
- IN UNIT_TEST_CONTEXT Context
- )
-{
- IMAGE_PROPERTIES_RECORD *Image1;
- IMAGE_PROPERTIES_RECORD *Image2;
- IMAGE_PROPERTIES_RECORD *Image3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
-
- TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
-
- Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
-
- CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
-
- ///////////////
- // Descriptor 1
- ///////////////
- // | | | | |
- // | 4K PAGE | DATA | CODE * 2 | DATA * 8 |
- // | | | | |
-
- Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
- Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE;
- Image1->CodeSegmentCount = 1;
- CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage1->CodeSegmentSize = EFI_PAGES_TO_SIZE (2);
- TestContext->MemoryMap[1].Type = EfiBootServicesCode;
-
- ///////////////
- // Descriptor 3
- ///////////////
- // | | | | |
- // | DATA | CODE * 3 | DATA * 7 | 4K PAGE |
- // | | | | |
-
- Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3);
- Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE;
- Image2->CodeSegmentCount = 1;
- CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage2->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
- TestContext->MemoryMap[3].Type = EfiLoaderCode;
-
- ///////////////
- // Descriptor 4
- ///////////////
- // | | | | | |
- // | 4K PAGE | DATA | CODE * 2 | DATA * 7 | 4K PAGE |
- // | | | | | |
-
- Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (4) + EFI_PAGE_SIZE;
- Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
- Image3->CodeSegmentCount = 1;
- CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage3->CodeSegmentSize = EFI_PAGES_TO_SIZE (2);
- TestContext->MemoryMap[4].Type = EfiRuntimeServicesCode;
-
- UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
-
- return UNIT_TEST_PASSED;
-}
-
-/**
- Test the case where all image ranges fit perfectly within an existing memory descriptor.
-
- @param[in] Context Context containing the memory map and image record pointers
-
- @retval UNIT_TEST_PASSED The Unit test has completed and the test
- case was successful.
- @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
-**/
-UNIT_TEST_STATUS
-EFIAPI
-ImagesFitDescriptors (
- IN UNIT_TEST_CONTEXT Context
- )
-{
- IMAGE_PROPERTIES_RECORD *Image1;
- IMAGE_PROPERTIES_RECORD *Image2;
- IMAGE_PROPERTIES_RECORD *Image3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
-
- TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
-
- Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
- Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
-
- CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
- CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
-
- ///////////////
- // Descriptor 1
- ///////////////
- // | | | |
- // | DATA | CODE * 3 | DATA * 8 |
- // | | | |
-
- Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1);
- Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
- Image1->CodeSegmentCount = 1;
- CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage1->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
- TestContext->MemoryMap[1].Type = EfiBootServicesCode;
-
- ///////////////
- // Descriptor 2
- ///////////////
- // | | | |
- // | DATA | CODE * 4 | DATA * 7 |
- // | | | |
-
- Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (2);
- Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
- Image2->CodeSegmentCount = 1;
- CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage2->CodeSegmentSize = EFI_PAGES_TO_SIZE (4);
- TestContext->MemoryMap[2].Type = EfiLoaderCode;
-
- ///////////////
- // Descriptor 3
- ///////////////
- // | | | |
- // | DATA | CODE * 3 | DATA * 8 |
- // | | | |
-
- Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3);
- Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
- Image3->CodeSegmentCount = 1;
- CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
- CodeSectionInImage3->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
- TestContext->MemoryMap[3].Type = EfiRuntimeServicesCode;
-
- UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
-
- return UNIT_TEST_PASSED;
-}
-
-/**
- Free all allocated memory.
-
- @param[in] Context Context containing the memory map and image record pointers
-**/
-VOID
-EFIAPI
-TestCleanup (
- IN UNIT_TEST_CONTEXT Context
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordLink;
- LIST_ENTRY *CodeSegmentListHead;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
-
- TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
- ImageRecordLink = &TestContext->ImageList;
-
- while (!IsListEmpty (ImageRecordLink)) {
- ImageRecord = CR (
- ImageRecordLink->ForwardLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- CodeSegmentListHead = &ImageRecord->CodeSegmentList;
- while (!IsListEmpty (CodeSegmentListHead)) {
- ImageRecordCodeSection = CR (
- CodeSegmentListHead->ForwardLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- RemoveEntryList (&ImageRecordCodeSection->Link);
- FreePool (ImageRecordCodeSection);
- }
-
- RemoveEntryList (&ImageRecord->Link);
- FreePool (ImageRecord);
- }
-
- if (TestContext->MemoryMap != NULL) {
- FreePool (TestContext->MemoryMap);
- }
-}
-
-/**
- Create a generic image list with the proper signatures which will be customized for each test
- and allocate the default memory map.
-
- @param[out] TestContext Context which will be passed to the test cases
-**/
-STATIC
-VOID
-CreateBaseContextEntry (
- OUT IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext
- )
-{
- IMAGE_PROPERTIES_RECORD *Image1;
- IMAGE_PROPERTIES_RECORD *Image2;
- IMAGE_PROPERTIES_RECORD *Image3;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
-
- InitializeListHead (&TestContext->ImageList);
-
- Image1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
- CodeSectionInImage1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
-
- Image1->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
- CodeSectionInImage1->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- InitializeListHead (&Image1->CodeSegmentList);
-
- InsertTailList (&TestContext->ImageList, &Image1->Link);
- InsertTailList (&Image1->CodeSegmentList, &CodeSectionInImage1->Link);
-
- Image2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
- CodeSectionInImage2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
-
- Image2->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
- CodeSectionInImage2->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- InitializeListHead (&Image2->CodeSegmentList);
-
- InsertTailList (&TestContext->ImageList, &Image2->Link);
- InsertTailList (&Image2->CodeSegmentList, &CodeSectionInImage2->Link);
-
- Image3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
- CodeSectionInImage3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
-
- Image3->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
- CodeSectionInImage3->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
- InitializeListHead (&Image3->CodeSegmentList);
-
- InsertTailList (&TestContext->ImageList, &Image3->Link);
- InsertTailList (&Image3->CodeSegmentList, &CodeSectionInImage3->Link);
-
- TestContext->MemoryMap = AllocateZeroPool (SPLIT_MEMORY_MAP_SIZE);
- CopyMem (TestContext->MemoryMap, &BaseMemoryMap, BASE_MEMORY_MAP_SIZE);
-
- return;
-}
-
-/**
- Initialze the unit test framework, suite, and unit tests.
-
- @retval EFI_SUCCESS All test cases were dispatched.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
- initialize the unit tests.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-UnitTestingEntry (
- VOID
- )
-{
- EFI_STATUS Status;
- UNIT_TEST_FRAMEWORK_HANDLE Framework;
- UNIT_TEST_SUITE_HANDLE ImagePropertiesRecordTests;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context1;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context2;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context3;
- IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context4;
-
- DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
-
- Framework = NULL;
-
- Context1 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
- Context2 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
- Context3 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
- Context4 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
-
- CreateBaseContextEntry (Context1);
- CreateBaseContextEntry (Context2);
- CreateBaseContextEntry (Context3);
- CreateBaseContextEntry (Context4);
-
- //
- // Start setting up the test framework for running the tests.
- //
- Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
- goto EXIT;
- }
-
- //
- // Populate the Unit Test Suite.
- //
- Status = CreateUnitTestSuite (&ImagePropertiesRecordTests, Framework, "Image Properties Record Tests", "ImagePropertiesRecordLib.SplitTable", NULL, NULL);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for the Image Properties Record Tests\n"));
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- //
- // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context-----------
- //
- AddTestCase (ImagePropertiesRecordTests, "All images fit perfectly into existing descriptors", "ImagesFitDescriptors", ImagesFitDescriptors, NULL, TestCleanup, Context1);
- AddTestCase (ImagePropertiesRecordTests, "All images don't fit perfectly into existing descriptors", "ImagesDontFitDescriptors", ImagesDontFitDescriptors, NULL, TestCleanup, Context2);
- AddTestCase (ImagePropertiesRecordTests, "All Images are contined In single descriptor", "MultipleImagesInOneDescriptor", MultipleImagesInOneDescriptor, NULL, TestCleanup, Context3);
- AddTestCase (ImagePropertiesRecordTests, "Multiple code sections each image", "MaxOutAdditionalDescriptors", MaxOutAdditionalDescriptors, NULL, TestCleanup, Context4);
-
- //
- // Execute the tests.
- //
- Status = RunAllTestSuites (Framework);
-
-EXIT:
- if (Framework) {
- FreeUnitTestFramework (Framework);
- }
-
- return Status;
-}
-
-///
-/// Avoid ECC error for function name that starts with lower case letter
-///
-#define ImagePropertiesRecordLibUnitTestMain main
-
-/**
- Standard POSIX C entry point for host based unit test execution.
-
- @param[in] Argc Number of arguments
- @param[in] Argv Array of pointers to arguments
-
- @retval 0 Success
- @retval other Error
-**/
-INT32
-ImagePropertiesRecordLibUnitTestMain (
- IN INT32 Argc,
- IN CHAR8 *Argv[]
- )
-{
- return UnitTestingEntry ();
-}
+/** @file
+ Unit tests the SplitTable() ImagePropertiesRecordLib Logic
+
+ Copyright (C) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UnitTestLib.h>
+#include <Library/ImagePropertiesRecordLib.h>
+
+#define UNIT_TEST_APP_NAME "Image Properties Record Lib Unit Test"
+#define UNIT_TEST_APP_VERSION "1.0"
+
+#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
+ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
+
+// The starting memory map will contain 6 entries
+#define NUMBER_OF_MEMORY_MAP_DESCRIPTORS 6
+
+// Each memory map descriptor will be the sizeof(EFI_MEMORY_DESCRIPTOR) instead of a nonstandard size
+// to catch pointer math issues
+#define DESCRIPTOR_SIZE sizeof(EFI_MEMORY_DESCRIPTOR)
+
+// Each memory map descriptor will describe 12 pages
+#define BASE_DESCRIPTOR_NUMBER_OF_PAGES 0x0C
+
+// The size, in bytes, of each memory map descriptor range
+#define BASE_DESCRIPTOR_ENTRY_SIZE (EFI_PAGES_TO_SIZE(BASE_DESCRIPTOR_NUMBER_OF_PAGES))
+
+// MACRO to get the starting address of a descriptor's described range based on the index of that descriptor
+#define BASE_DESCRIPTOR_START_ADDRESS(DescriptorNumber) (DescriptorNumber * BASE_DESCRIPTOR_ENTRY_SIZE)
+
+// Virtual start must be zero
+#define BASE_DESCRIPTOR_VIRTUAL_START 0x0
+
+// Size of the default memory map
+#define BASE_MEMORY_MAP_SIZE (NUMBER_OF_MEMORY_MAP_DESCRIPTORS * DESCRIPTOR_SIZE)
+
+// Number of images in each test case
+#define NUMBER_OF_IMAGES_TO_SPLIT 3
+
+// Maximum number of descriptors required for each image (None->Data->Code->Data->Code->Data->None)
+#define MAX_DESCRIPTORS_PER_IMAGE 7
+
+// Number of unused additional descriptors in the starting memory map buffer which is used by the
+// SplitTable() logic
+#define NUMBER_OF_ADDITIONAL_DESCRIPTORS (NUMBER_OF_IMAGES_TO_SPLIT * MAX_DESCRIPTORS_PER_IMAGE)
+
+// Size of the memory map with enough space for the starting descriptors and the split descriptors
+#define SPLIT_MEMORY_MAP_SIZE (BASE_MEMORY_MAP_SIZE + (NUMBER_OF_ADDITIONAL_DESCRIPTORS * DESCRIPTOR_SIZE))
+
+typedef enum {
+ SectionTypeCode,
+ SectionTypeData,
+ SectionTypeNotFound
+} SECTION_TYPE;
+
+typedef struct {
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ LIST_ENTRY ImageList;
+} IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT;
+
+EFI_MEMORY_DESCRIPTOR BaseMemoryMap[] = {
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (0), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ },
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (1), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ },
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (2), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ },
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (3), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ },
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (4), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ },
+ {
+ EfiConventionalMemory, // Type
+ BASE_DESCRIPTOR_START_ADDRESS (5), // PhysicalStart
+ BASE_DESCRIPTOR_VIRTUAL_START, // VirtualStart
+ BASE_DESCRIPTOR_NUMBER_OF_PAGES, // Number of Pages
+ 0 // Attribute
+ }
+};
+
+/**
+ Returns a bitmap where one bit is set for each section in the image list. For example, if
+ there are 3 images and each image 3 sections the returned bitmap will be 111111111.
+
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries
+
+ @retval A bitmap such that the most significant bit is the number of sections
+ in all images and every bit between 0 -> MSB is set
+
+**/
+STATIC
+UINT64
+GetImageSectionBitmap (
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ EFI_PHYSICAL_ADDRESS SectionBase;
+ UINT64 ReturnBitmap;
+ UINT64 Shift;
+
+ if (ImageRecordList == NULL) {
+ return 0;
+ }
+
+ ReturnBitmap = 0;
+ Shift = 0;
+
+ // Walk through each image record
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink)
+ {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ SectionBase = ImageRecord->ImageBase;
+
+ // Walk through each code entry
+ for (ImageRecordCodeSectionLink = ImageRecord->CodeSegmentList.ForwardLink;
+ ImageRecordCodeSectionLink != &ImageRecord->CodeSegmentList;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink)
+ {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+
+ // Check for data region before the code section base
+ if (SectionBase < ImageRecordCodeSection->CodeSegmentBase) {
+ ReturnBitmap |= LShiftU64 (1, Shift++);
+ }
+
+ // Code section
+ ReturnBitmap |= LShiftU64 (1, Shift++);
+ SectionBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
+ }
+
+ // Check for data region after the previous code section
+ if (SectionBase < (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ ReturnBitmap |= LShiftU64 (1, Shift++);
+ }
+ }
+
+ return ReturnBitmap;
+}
+
+/**
+ Searches the input image list for a section which exactly matches the memory range Buffer -> Buffer + Length.
+
+ @param[in] Buffer Start Address to check
+ @param[in] Length Length to check
+ @param[out] Type The type of the section which corresponds with the memory
+ range Buffer -> Buffer + Length (Code or Data) or SectionTypeNotFound
+ if no image section matches the memory range
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries to check against
+ the memory range Buffer -> Buffer + Length
+
+ @retval A bitmap with a single bit set (1 << Shift) where Shift corresponds with the number of sections inspected
+ in the image list before arriving at the section matching the memory range Buffer -> Buffer + Length
+**/
+STATIC
+UINT64
+MatchDescriptorToImageSection (
+ IN EFI_PHYSICAL_ADDRESS Buffer,
+ IN UINT64 Length,
+ OUT SECTION_TYPE *Type,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *ImageRecordCodeSectionLink;
+ EFI_PHYSICAL_ADDRESS SectionBase;
+ UINT8 Shift;
+
+ Shift = 0;
+
+ if (ImageRecordList == NULL) {
+ return 1;
+ }
+
+ // Walk through each image record
+ for (ImageRecordLink = ImageRecordList->ForwardLink;
+ ImageRecordLink != ImageRecordList;
+ ImageRecordLink = ImageRecordLink->ForwardLink)
+ {
+ ImageRecord = CR (
+ ImageRecordLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ SectionBase = ImageRecord->ImageBase;
+
+ // Walk through each code entry
+ for (ImageRecordCodeSectionLink = ImageRecord->CodeSegmentList.ForwardLink;
+ ImageRecordCodeSectionLink != &ImageRecord->CodeSegmentList;
+ ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink)
+ {
+ ImageRecordCodeSection = CR (
+ ImageRecordCodeSectionLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+
+ if (SectionBase < ImageRecordCodeSection->CodeSegmentBase) {
+ // Check the data region before the code section base
+ if ((Buffer == SectionBase) &&
+ (Length == ImageRecordCodeSection->CodeSegmentBase - SectionBase))
+ {
+ *Type = SectionTypeData;
+ return LShiftU64 (1, Shift);
+ }
+
+ Shift++;
+ }
+
+ // Check the code region
+ if ((Buffer == ImageRecordCodeSection->CodeSegmentBase) &&
+ (Length == ImageRecordCodeSection->CodeSegmentSize))
+ {
+ *Type = SectionTypeCode;
+ return LShiftU64 (1, Shift);
+ }
+
+ Shift++;
+ SectionBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
+ }
+
+ // Check the data region after the code section
+ if (SectionBase < (ImageRecord->ImageBase + ImageRecord->ImageSize)) {
+ if ((Buffer == SectionBase) &&
+ (Length == (ImageRecord->ImageBase + ImageRecord->ImageSize) - SectionBase))
+ {
+ *Type = SectionTypeData;
+ return LShiftU64 (1, Shift);
+ }
+
+ Shift++;
+ }
+ }
+
+ // No image sections match
+ *Type = SectionTypeNotFound;
+ return 0;
+}
+
+/**
+ Walks through the input memory map and checks that every memory descriptor with an attribute matches
+ an image in ImageRecordList.
+
+ @param[in] MemoryMapSize The size, in bytes, of the memory map
+ @param[in] MemoryMap A pointer to the buffer containing the memory map
+ @param[in] ImageRecordList A list of IMAGE_PROPERTIES_RECORD entries
+
+ @retval TRUE if all memory descriptors with attributes match an image section and have the correct attributes
+
+**/
+STATIC
+BOOLEAN
+IsMemoryMapValid (
+ IN UINTN MemoryMapSize,
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ IN LIST_ENTRY *ImageRecordList
+ )
+{
+ UINT64 ImageSectionsBitmap;
+ UINT64 ReturnSectionBitmask;
+ UINT64 NumberOfDescriptors;
+ UINT8 Index;
+ SECTION_TYPE Type;
+
+ Index = 0;
+ NumberOfDescriptors = MemoryMapSize / DESCRIPTOR_SIZE;
+
+ UT_ASSERT_EQUAL (MemoryMapSize % DESCRIPTOR_SIZE, 0);
+ UT_ASSERT_NOT_NULL (MemoryMap);
+ UT_ASSERT_NOT_NULL (ImageRecordList);
+
+ // The returned bitmap will have one bit is set for each section in the image list.
+ // If there are 3 images and 3 sections each image, the resulting bitmap will
+ // be 0000000000000000000000000000000000000000000000000000000111111111. Flipping that bitmap
+ // results in 1111111111111111111111111111111111111111111111111111111000000000. The return value
+ // of each iteration through MatchDescriptorToImageSection() is one set bit corrosponding to the number
+ // of sections before finding the section which matched the descriptor memory range which we
+ // OR with ImageSectionsBitmap. If, at the end of the loop, every bit in ImageSectionsBitmap is set,
+ // we must have matched every image in ImageRecordList with a descriptor in the memory map which has
+ // nonzero attributes.
+ ImageSectionsBitmap = ~GetImageSectionBitmap (ImageRecordList);
+
+ // For each descriptor in the memory map
+ for ( ; Index < NumberOfDescriptors; Index++) {
+ if (MemoryMap[Index].Attribute != 0) {
+ ReturnSectionBitmask = MatchDescriptorToImageSection (
+ MemoryMap[Index].PhysicalStart,
+ EFI_PAGES_TO_SIZE (MemoryMap[Index].NumberOfPages),
+ &Type,
+ ImageRecordList
+ );
+
+ // Make sure the attributes of the descriptor match the returned section type.
+ // DATA sections should have execution protection and CODE sections should have
+ // write protection.
+ if ((Type == SectionTypeNotFound) ||
+ ((Type == SectionTypeData) && (MemoryMap[Index].Attribute == EFI_MEMORY_RP)) ||
+ ((Type == SectionTypeCode) && (MemoryMap[Index].Attribute == EFI_MEMORY_XP)))
+ {
+ return FALSE;
+ }
+
+ // If the bit associated with image found has already been set, then there must be a duplicate
+ // in the memory map meaning it is invalid.
+ UT_ASSERT_EQUAL (ImageSectionsBitmap & ReturnSectionBitmask, 0);
+
+ ImageSectionsBitmap |= ReturnSectionBitmask;
+ }
+ }
+
+ // If every bit in ImageSectionsBitmap is set, the return value will be TRUE
+ return !(~ImageSectionsBitmap);
+}
+
+/**
+ Separate the image sections in the memory map and run a check to ensure the output is valid.
+
+ @param[in] Context Context containing the memory map and image record pointers
+
+ @retval TRUE if the memory map is split correctly
+**/
+STATIC
+BOOLEAN
+SeparateAndCheck (
+ IN IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context
+ )
+{
+ UINTN MemoryMapSize;
+
+ MemoryMapSize = BASE_MEMORY_MAP_SIZE;
+
+ // Separate the memory map so each image section has its own descriptor
+ SplitTable (
+ &MemoryMapSize,
+ Context->MemoryMap,
+ DESCRIPTOR_SIZE,
+ &Context->ImageList,
+ NUMBER_OF_ADDITIONAL_DESCRIPTORS
+ );
+
+ // Ensure the updated memory map is valid
+ return IsMemoryMapValid (MemoryMapSize, Context->MemoryMap, &Context->ImageList);
+}
+
+/**
+ Test the case where the image range contains multiple code sections and does not perfectly align with
+ the existing memory descriptor.
+
+ @param[in] Context Context containing the memory map and image record pointers
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+MaxOutAdditionalDescriptors (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ IMAGE_PROPERTIES_RECORD *Image1;
+ IMAGE_PROPERTIES_RECORD *Image2;
+ IMAGE_PROPERTIES_RECORD *Image3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *AddCodeSectionInImage3;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
+
+ TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
+
+ Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+
+ CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+
+ ///////////////
+ // Descriptor 1
+ ///////////////
+ // | | | | | | | |
+ // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
+ // | | | | | | | |
+
+ Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
+ Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
+ Image1->CodeSegmentCount = 2;
+ CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
+ TestContext->MemoryMap[1].Type = EfiBootServicesCode;
+
+ AddCodeSectionInImage1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+ AddCodeSectionInImage1->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ AddCodeSectionInImage1->CodeSegmentBase = CodeSectionInImage1->CodeSegmentBase + CodeSectionInImage1->CodeSegmentSize + EFI_PAGE_SIZE;
+ AddCodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
+
+ InsertTailList (&Image1->CodeSegmentList, &AddCodeSectionInImage1->Link);
+
+ ///////////////
+ // Descriptor 2
+ ///////////////
+ // | | | | | | | |
+ // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
+ // | | | | | | | |
+
+ Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (2) + EFI_PAGE_SIZE;
+ Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
+ Image2->CodeSegmentCount = 2;
+ CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
+ TestContext->MemoryMap[2].Type = EfiLoaderCode;
+
+ AddCodeSectionInImage2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+ AddCodeSectionInImage2->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ AddCodeSectionInImage2->CodeSegmentBase = CodeSectionInImage2->CodeSegmentBase + CodeSectionInImage2->CodeSegmentSize + EFI_PAGE_SIZE;
+ AddCodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
+
+ InsertTailList (&Image2->CodeSegmentList, &AddCodeSectionInImage2->Link);
+
+ ///////////////
+ // Descriptor 3
+ ///////////////
+ // | | | | | | | |
+ // | 4K PAGE | DATA | CODE | DATA | CODE | DATA | 4K PAGE * 5 |
+ // | | | | | | | |
+
+ Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3) + EFI_PAGE_SIZE;
+ Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
+ Image3->CodeSegmentCount = 2;
+ CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
+ TestContext->MemoryMap[3].Type = EfiRuntimeServicesCode;
+
+ AddCodeSectionInImage3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+ AddCodeSectionInImage3->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ AddCodeSectionInImage3->CodeSegmentBase = CodeSectionInImage3->CodeSegmentBase + CodeSectionInImage3->CodeSegmentSize + EFI_PAGE_SIZE;
+ AddCodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
+
+ InsertTailList (&Image3->CodeSegmentList, &AddCodeSectionInImage3->Link);
+
+ UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Test the case where multiple image ranges lie within an existing memory descriptor.
+
+ @param[in] Context Context containing the memory map and image record pointers
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+MultipleImagesInOneDescriptor (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ IMAGE_PROPERTIES_RECORD *Image1;
+ IMAGE_PROPERTIES_RECORD *Image2;
+ IMAGE_PROPERTIES_RECORD *Image3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
+
+ TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
+
+ Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+
+ CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+
+ ///////////////
+ // Descriptor 1
+ ///////////////
+ // | | | | | | | | | | | | |
+ // | 4K PAGE | DATA | CODE | DATA | 4K PAGE | DATA | CODE | DATA | DATA | CODE | DATA | 4K PAGE |
+ // | | | | | | | | | | | | |
+
+ Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
+ Image1->ImageSize = EFI_PAGES_TO_SIZE (3);
+ Image1->CodeSegmentCount = 1;
+ CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage1->CodeSegmentSize = EFI_PAGE_SIZE;
+ TestContext->MemoryMap[1].Type = EfiBootServicesCode;
+
+ Image2->ImageBase = Image1->ImageBase + Image1->ImageSize + EFI_PAGE_SIZE;
+ Image2->ImageSize = EFI_PAGES_TO_SIZE (3);
+ Image2->CodeSegmentCount = 1;
+ CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage2->CodeSegmentSize = EFI_PAGE_SIZE;
+
+ Image3->ImageBase = Image2->ImageBase + Image2->ImageSize;
+ Image3->ImageSize = EFI_PAGES_TO_SIZE (3);
+ Image3->CodeSegmentCount = 1;
+ CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage3->CodeSegmentSize = EFI_PAGE_SIZE;
+
+ UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Test the case where all image ranges do not fit perfectly within an existing memory descriptor.
+
+ @param[in] Context Context containing the memory map and image record pointers
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ImagesDontFitDescriptors (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ IMAGE_PROPERTIES_RECORD *Image1;
+ IMAGE_PROPERTIES_RECORD *Image2;
+ IMAGE_PROPERTIES_RECORD *Image3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
+
+ TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
+
+ Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+
+ CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+
+ ///////////////
+ // Descriptor 1
+ ///////////////
+ // | | | | |
+ // | 4K PAGE | DATA | CODE * 2 | DATA * 8 |
+ // | | | | |
+
+ Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1) + EFI_PAGE_SIZE;
+ Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE;
+ Image1->CodeSegmentCount = 1;
+ CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage1->CodeSegmentSize = EFI_PAGES_TO_SIZE (2);
+ TestContext->MemoryMap[1].Type = EfiBootServicesCode;
+
+ ///////////////
+ // Descriptor 3
+ ///////////////
+ // | | | | |
+ // | DATA | CODE * 3 | DATA * 7 | 4K PAGE |
+ // | | | | |
+
+ Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3);
+ Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE;
+ Image2->CodeSegmentCount = 1;
+ CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage2->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
+ TestContext->MemoryMap[3].Type = EfiLoaderCode;
+
+ ///////////////
+ // Descriptor 4
+ ///////////////
+ // | | | | | |
+ // | 4K PAGE | DATA | CODE * 2 | DATA * 7 | 4K PAGE |
+ // | | | | | |
+
+ Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (4) + EFI_PAGE_SIZE;
+ Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE - EFI_PAGE_SIZE - EFI_PAGE_SIZE;
+ Image3->CodeSegmentCount = 1;
+ CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage3->CodeSegmentSize = EFI_PAGES_TO_SIZE (2);
+ TestContext->MemoryMap[4].Type = EfiRuntimeServicesCode;
+
+ UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Test the case where all image ranges fit perfectly within an existing memory descriptor.
+
+ @param[in] Context Context containing the memory map and image record pointers
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+ImagesFitDescriptors (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ IMAGE_PROPERTIES_RECORD *Image1;
+ IMAGE_PROPERTIES_RECORD *Image2;
+ IMAGE_PROPERTIES_RECORD *Image3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
+
+ TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
+
+ Image1 = CR (TestContext->ImageList.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image2 = CR (Image1->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+ Image3 = CR (Image2->Link.ForwardLink, IMAGE_PROPERTIES_RECORD, Link, IMAGE_PROPERTIES_RECORD_SIGNATURE);
+
+ CodeSectionInImage1 = CR (Image1->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage2 = CR (Image2->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+ CodeSectionInImage3 = CR (Image3->CodeSegmentList.ForwardLink, IMAGE_PROPERTIES_RECORD_CODE_SECTION, Link, IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE);
+
+ ///////////////
+ // Descriptor 1
+ ///////////////
+ // | | | |
+ // | DATA | CODE * 3 | DATA * 8 |
+ // | | | |
+
+ Image1->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (1);
+ Image1->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
+ Image1->CodeSegmentCount = 1;
+ CodeSectionInImage1->CodeSegmentBase = Image1->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage1->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
+ TestContext->MemoryMap[1].Type = EfiBootServicesCode;
+
+ ///////////////
+ // Descriptor 2
+ ///////////////
+ // | | | |
+ // | DATA | CODE * 4 | DATA * 7 |
+ // | | | |
+
+ Image2->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (2);
+ Image2->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
+ Image2->CodeSegmentCount = 1;
+ CodeSectionInImage2->CodeSegmentBase = Image2->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage2->CodeSegmentSize = EFI_PAGES_TO_SIZE (4);
+ TestContext->MemoryMap[2].Type = EfiLoaderCode;
+
+ ///////////////
+ // Descriptor 3
+ ///////////////
+ // | | | |
+ // | DATA | CODE * 3 | DATA * 8 |
+ // | | | |
+
+ Image3->ImageBase = BASE_DESCRIPTOR_START_ADDRESS (3);
+ Image3->ImageSize = BASE_DESCRIPTOR_ENTRY_SIZE;
+ Image3->CodeSegmentCount = 1;
+ CodeSectionInImage3->CodeSegmentBase = Image3->ImageBase + EFI_PAGE_SIZE;
+ CodeSectionInImage3->CodeSegmentSize = EFI_PAGES_TO_SIZE (3);
+ TestContext->MemoryMap[3].Type = EfiRuntimeServicesCode;
+
+ UT_ASSERT_TRUE (SeparateAndCheck (TestContext));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Free all allocated memory.
+
+ @param[in] Context Context containing the memory map and image record pointers
+**/
+VOID
+EFIAPI
+TestCleanup (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ IMAGE_PROPERTIES_RECORD *ImageRecord;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
+ LIST_ENTRY *ImageRecordLink;
+ LIST_ENTRY *CodeSegmentListHead;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext;
+
+ TestContext = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)Context;
+ ImageRecordLink = &TestContext->ImageList;
+
+ while (!IsListEmpty (ImageRecordLink)) {
+ ImageRecord = CR (
+ ImageRecordLink->ForwardLink,
+ IMAGE_PROPERTIES_RECORD,
+ Link,
+ IMAGE_PROPERTIES_RECORD_SIGNATURE
+ );
+
+ CodeSegmentListHead = &ImageRecord->CodeSegmentList;
+ while (!IsListEmpty (CodeSegmentListHead)) {
+ ImageRecordCodeSection = CR (
+ CodeSegmentListHead->ForwardLink,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION,
+ Link,
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
+ );
+ RemoveEntryList (&ImageRecordCodeSection->Link);
+ FreePool (ImageRecordCodeSection);
+ }
+
+ RemoveEntryList (&ImageRecord->Link);
+ FreePool (ImageRecord);
+ }
+
+ if (TestContext->MemoryMap != NULL) {
+ FreePool (TestContext->MemoryMap);
+ }
+}
+
+/**
+ Create a generic image list with the proper signatures which will be customized for each test
+ and allocate the default memory map.
+
+ @param[out] TestContext Context which will be passed to the test cases
+**/
+STATIC
+VOID
+CreateBaseContextEntry (
+ OUT IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *TestContext
+ )
+{
+ IMAGE_PROPERTIES_RECORD *Image1;
+ IMAGE_PROPERTIES_RECORD *Image2;
+ IMAGE_PROPERTIES_RECORD *Image3;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage1;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage2;
+ IMAGE_PROPERTIES_RECORD_CODE_SECTION *CodeSectionInImage3;
+
+ InitializeListHead (&TestContext->ImageList);
+
+ Image1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
+ CodeSectionInImage1 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+
+ Image1->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+ CodeSectionInImage1->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ InitializeListHead (&Image1->CodeSegmentList);
+
+ InsertTailList (&TestContext->ImageList, &Image1->Link);
+ InsertTailList (&Image1->CodeSegmentList, &CodeSectionInImage1->Link);
+
+ Image2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
+ CodeSectionInImage2 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+
+ Image2->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+ CodeSectionInImage2->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ InitializeListHead (&Image2->CodeSegmentList);
+
+ InsertTailList (&TestContext->ImageList, &Image2->Link);
+ InsertTailList (&Image2->CodeSegmentList, &CodeSectionInImage2->Link);
+
+ Image3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD));
+ CodeSectionInImage3 = AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_CODE_SECTION));
+
+ Image3->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE;
+ CodeSectionInImage3->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE;
+ InitializeListHead (&Image3->CodeSegmentList);
+
+ InsertTailList (&TestContext->ImageList, &Image3->Link);
+ InsertTailList (&Image3->CodeSegmentList, &CodeSectionInImage3->Link);
+
+ TestContext->MemoryMap = AllocateZeroPool (SPLIT_MEMORY_MAP_SIZE);
+ CopyMem (TestContext->MemoryMap, &BaseMemoryMap, BASE_MEMORY_MAP_SIZE);
+
+ return;
+}
+
+/**
+ Initialze the unit test framework, suite, and unit tests.
+
+ @retval EFI_SUCCESS All test cases were dispatched.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ initialize the unit tests.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UnitTestingEntry (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE ImagePropertiesRecordTests;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context1;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context2;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context3;
+ IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *Context4;
+
+ DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
+
+ Framework = NULL;
+
+ Context1 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
+ Context2 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
+ Context3 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
+ Context4 = (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT *)AllocateZeroPool (sizeof (IMAGE_PROPERTIES_RECORD_HOST_TEST_CONTEXT));
+
+ CreateBaseContextEntry (Context1);
+ CreateBaseContextEntry (Context2);
+ CreateBaseContextEntry (Context3);
+ CreateBaseContextEntry (Context4);
+
+ //
+ // Start setting up the test framework for running the tests.
+ //
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Populate the Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (&ImagePropertiesRecordTests, Framework, "Image Properties Record Tests", "ImagePropertiesRecordLib.SplitTable", NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for the Image Properties Record Tests\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context-----------
+ //
+ AddTestCase (ImagePropertiesRecordTests, "All images fit perfectly into existing descriptors", "ImagesFitDescriptors", ImagesFitDescriptors, NULL, TestCleanup, Context1);
+ AddTestCase (ImagePropertiesRecordTests, "All images don't fit perfectly into existing descriptors", "ImagesDontFitDescriptors", ImagesDontFitDescriptors, NULL, TestCleanup, Context2);
+ AddTestCase (ImagePropertiesRecordTests, "All Images are contined In single descriptor", "MultipleImagesInOneDescriptor", MultipleImagesInOneDescriptor, NULL, TestCleanup, Context3);
+ AddTestCase (ImagePropertiesRecordTests, "Multiple code sections each image", "MaxOutAdditionalDescriptors", MaxOutAdditionalDescriptors, NULL, TestCleanup, Context4);
+
+ //
+ // Execute the tests.
+ //
+ Status = RunAllTestSuites (Framework);
+
+EXIT:
+ if (Framework) {
+ FreeUnitTestFramework (Framework);
+ }
+
+ return Status;
+}
+
+///
+/// Avoid ECC error for function name that starts with lower case letter
+///
+#define ImagePropertiesRecordLibUnitTestMain main
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+
+ @param[in] Argc Number of arguments
+ @param[in] Argv Array of pointers to arguments
+
+ @retval 0 Success
+ @retval other Error
+**/
+INT32
+ImagePropertiesRecordLibUnitTestMain (
+ IN INT32 Argc,
+ IN CHAR8 *Argv[]
+ )
+{
+ return UnitTestingEntry ();
+}
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf
index cbc64a14bd..9bceb89ded 100644
--- a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf
@@ -1,35 +1,35 @@
-## @file
-# Unit tests the SplitTable() ImagePropertiesRecordLib Logic
-#
-# Copyright (C) Microsoft Corporation.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-[Defines]
- INF_VERSION = 0x00010006
- BASE_NAME = ImagePropertiesRecordLibUnitTestHost
- FILE_GUID = 45B39FAA-E25D-4724-A6F4-93C0C8588A80
- MODULE_TYPE = HOST_APPLICATION
- VERSION_STRING = 1.0
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 AARCH64
-#
-
-[Sources]
- ImagePropertiesRecordLibUnitTestHost.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- DebugLib
- MemoryAllocationLib
- UnitTestLib
- ImagePropertiesRecordLib
+## @file
+# Unit tests the SplitTable() ImagePropertiesRecordLib Logic
+#
+# Copyright (C) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = ImagePropertiesRecordLibUnitTestHost
+ FILE_GUID = 45B39FAA-E25D-4724-A6F4-93C0C8588A80
+ MODULE_TYPE = HOST_APPLICATION
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ ImagePropertiesRecordLibUnitTestHost.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UnitTestLib
+ ImagePropertiesRecordLib