public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Taylor Beebe" <taylor.d.beebe@gmail.com>
To: devel@edk2.groups.io
Cc: Jian J Wang <jian.j.wang@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Dandan Bi <dandan.bi@intel.com>
Subject: [edk2-devel] [PATCH v4 08/14] MdeModulePkg: Add ImagePropertiesRecordLib Host-Based Unit Test
Date: Fri,  3 Nov 2023 10:17:00 -0700	[thread overview]
Message-ID: <20231103171706.148-9-taylor.d.beebe@gmail.com> (raw)
In-Reply-To: <20231103171706.148-1-taylor.d.beebe@gmail.com>

Create a host-based unit test for the ImagePropertiesRecordLib
SplitTable() logic. This test has 4 cases which tests different
potential image and memory map layouts. 3/4 of these tests fail
with the logic in its current state to provide proof of the bugs
in the current MAT logic.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Dandan Bi <dandan.bi@intel.com>
Signed-off-by: Taylor Beebe <taylor.d.beebe@gmail.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
---
 MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c   | 938 ++++++++++++++++++++
 MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf |  35 +
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc                                                      |   5 +
 3 files changed, 978 insertions(+)

diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c
new file mode 100644
index 000000000000..8b0a55685ce3
--- /dev/null
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.c
@@ -0,0 +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 ();
+}
diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf
new file mode 100644
index 000000000000..cbc64a14bde7
--- /dev/null
+++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf
@@ -0,0 +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
diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 8fb982a2703d..2b8cbb867a73 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -54,6 +54,11 @@ [Components]
       DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
   }
 
+  MdeModulePkg/Library/ImagePropertiesRecordLib/UnitTest/ImagePropertiesRecordLibUnitTestHost.inf {
+    <LibraryClasses>
+      ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
+  }
+
   #
   # Build HOST_APPLICATION Libraries
   #
-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#110656): https://edk2.groups.io/g/devel/message/110656
Mute This Topic: https://groups.io/mt/102368848/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2023-11-03 17:17 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-03 17:16 [edk2-devel] [PATCH v4 00/14] Add ImagePropertiesRecordLib and Fix MAT Bugs Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 01/14] MdeModulePkg: Add ImagePropertiesRecordLib Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 02/14] ArmVirtPkg: Add ImagePropertiesRecordLib Instance Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 03/14] EmulatorPkg: " Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 04/14] OvmfPkg: " Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 05/14] UefiPayloadPkg: " Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 06/14] MdeModulePkg: Update MemoryAttributesTable.c to Reduce Global Variable Use Taylor Beebe
2023-11-03 17:16 ` [edk2-devel] [PATCH v4 07/14] MdeModulePkg: Move Some DXE MAT Logic to ImagePropertiesRecordLib Taylor Beebe
2023-11-03 17:17 ` Taylor Beebe [this message]
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 09/14] MdeModulePkg: Fix Bugs in MAT Logic Taylor Beebe
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 10/14] MdeModulePkg: Add NULL checks and Return Status to ImagePropertiesRecordLib Taylor Beebe
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 11/14] UefiCpuPkg: Use Attribute From SMM MemoryAttributesTable if Nonzero Taylor Beebe
2023-11-08 21:57   ` Laszlo Ersek
2023-11-20 22:57     ` Taylor Beebe
2023-11-23  9:54       ` Laszlo Ersek
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 12/14] MdeModulePkg: Transition SMM MAT Logic to Use ImagePropertiesRecordLib Taylor Beebe
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 13/14] MdeModulePkg: Add Logic to Create/Delete Image Properties Records Taylor Beebe
2023-11-03 17:17 ` [edk2-devel] [PATCH v4 14/14] MdeModulePkg: Update DumpImageRecord() in ImagePropertiesRecordLib Taylor Beebe
  -- strict thread matches above, loose matches on Subject: below --
2023-08-04 19:46 [edk2-devel] [PATCH v4 00/14] Add ImagePropertiesRecordLib and Fix MAT Bugs Taylor Beebe
2023-08-04 19:46 ` [edk2-devel] [PATCH v4 08/14] MdeModulePkg: Add ImagePropertiesRecordLib Host-Based Unit Test Taylor Beebe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231103171706.148-9-taylor.d.beebe@gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox