diff options
Diffstat (limited to 'MdeModulePkg/Library/ImagePropertiesRecordLib')
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 |
