public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Michael D Kinney" <michael.d.kinney@intel.com>
To: devel@edk2.groups.io
Cc: Sean Brogan <sean.brogan@microsoft.com>,
	Bret Barkelew <Bret.Barkelew@microsoft.com>
Subject: [Patch 05/11] UnitTestFrameworkPkg/Library: Add library instances
Date: Thu, 23 Jan 2020 18:10:26 -0800	[thread overview]
Message-ID: <20200124021032.13808-6-michael.d.kinney@intel.com> (raw)
In-Reply-To: <20200124021032.13808-1-michael.d.kinney@intel.com>

Add the following library instances that are used to
build unit tests for host and target environments.

* CmockaLib with cmocka submodule to:

  https://git.cryptomilk.org/projects/cmocka.git

* DebugLibPosix - Instance of DebugLib based on POSIX
  APIs (e.g. printf).
* MemoryAllocationLibPosix - Instance of MemoryAllocationLib
  based on POSIX APIs (e.g. malloc/free).
* UnitTestBootLibNull - Null instance of the UnitTestBootLib
* UnitTestBootLibUsbClass - UnitTestBootLib instances that
  supports setting boot next to a USB device.
* UnitTestLib - UnitTestLib instance that is designed to work
  with PEI, DXE, SMM, and UEFI Shell target environments.
* UnitTestLibCmocka - UintTestLib instance that uses cmocka
  APIs and can only be use in a host environment.
* UnitTestPersistenceLibNull - Null instance of the
  UnitTestPersistenceLib
* UnitTestPersistenceLibSimpleFileSystem - UnitTestPersistenceLib
  instance that can safe the unit test framework state to a
  media device that supports the UEFI Simple File System
  Protocol.
* UnitTestResultReportLibConOut - UnitTestResultReportLib
  instance that sends report results to the UEFI standard
  output console.
* UnitTestResultReportLibDebugLib - UnitTestResultReportLib
  instance that sends report results to a DebugLib using
  DEBUG() macros.

Cc: Sean Brogan <sean.brogan@microsoft.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
---
 .gitmodules                                   |   3 +
 .../Library/CmockaLib/CmockaLib.inf           |  35 +
 .../Library/CmockaLib/CmockaLib.uni           |  14 +
 UnitTestFrameworkPkg/Library/CmockaLib/cmocka |   1 +
 .../Posix/DebugLibPosix/DebugLibPosix.c       | 279 ++++++
 .../Posix/DebugLibPosix/DebugLibPosix.inf     |  35 +
 .../Posix/DebugLibPosix/DebugLibPosix.uni     |  14 +
 .../MemoryAllocationLibPosix.c                | 631 +++++++++++++
 .../MemoryAllocationLibPosix.inf              |  27 +
 .../MemoryAllocationLibPosix.uni              |  14 +
 .../UnitTestBootLibNull/UnitTestBootLibNull.c |  26 +
 .../UnitTestBootLibNull.inf                   |  23 +
 .../UnitTestBootLibNull.uni                   |  11 +
 .../UnitTestBootLibUsbClass.c                 | 127 +++
 .../UnitTestBootLibUsbClass.inf               |  34 +
 .../UnitTestBootLibUsbClass.uni               |  12 +
 .../Library/UnitTestLib/Assert.c              | 491 ++++++++++
 .../Library/UnitTestLib/AssertCmocka.c        | 335 +++++++
 .../Library/UnitTestLib/Log.c                 | 200 ++++
 .../Library/UnitTestLib/RunTests.c            | 171 ++++
 .../Library/UnitTestLib/RunTestsCmocka.c      | 278 ++++++
 .../Library/UnitTestLib/UnitTestLib.c         | 853 ++++++++++++++++++
 .../Library/UnitTestLib/UnitTestLib.inf       |  37 +
 .../Library/UnitTestLib/UnitTestLib.uni       |  11 +
 .../Library/UnitTestLib/UnitTestLibCmocka.inf |  38 +
 .../Library/UnitTestLib/UnitTestLibCmocka.uni |  11 +
 .../UnitTestPersistenceLibNull.c              |  75 ++
 .../UnitTestPersistenceLibNull.inf            |  28 +
 .../UnitTestPersistenceLibNull.uni            |  11 +
 .../UnitTestPersistenceLibSimpleFileSystem.c  | 416 +++++++++
 ...UnitTestPersistenceLibSimpleFileSystem.inf |  47 +
 ...UnitTestPersistenceLibSimpleFileSystem.uni |  15 +
 .../UnitTestResultReportLib.c                 | 216 +++++
 .../UnitTestResultReportLibConOut.c           |  48 +
 .../UnitTestResultReportLibConOut.inf         |  29 +
 .../UnitTestResultReportLibConOut.uni         |  11 +
 .../UnitTestResultReportLibDebugLib.c         |  47 +
 .../UnitTestResultReportLibDebugLib.inf       |  28 +
 .../UnitTestResultReportLibDebugLib.uni       |  11 +
 39 files changed, 4693 insertions(+)
 create mode 100644 UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
 create mode 100644 UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni
 create mode 160000 UnitTestFrameworkPkg/Library/CmockaLib/cmocka
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
 create mode 100644 UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/Log.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf
 create mode 100644 UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni

diff --git a/.gitmodules b/.gitmodules
index 508f0c1828..b30f5bf136 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "SoftFloat"]
 	path = ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
 	url = https://github.com/ucb-bar/berkeley-softfloat-3.git
+[submodule "UnitTestFrameworkPkg/Library/CmockaLib/cmocka"]
+	path = UnitTestFrameworkPkg/Library/CmockaLib/cmocka
+	url = https://git.cryptomilk.org/projects/cmocka.git
diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
new file mode 100644
index 0000000000..07da7a88e9
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.inf
@@ -0,0 +1,35 @@
+## @file
+#  This module provides Cmocka Library implementation.
+#
+#  Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = CmockaLib
+  MODULE_UNI_FILE = CmockaLib.uni
+  FILE_GUID       = F1662152-3399-49AC-BE44-CAA97575FACE
+  MODULE_TYPE     = BASE
+  VERSION_STRING  = 0.1
+  LIBRARY_CLASS   = CmockaLib|HOST_APPLICATION
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  cmocka/src/cmocka.c
+
+[Packages]
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[BuildOptions]
+  MSFT:*_*_*_CC_FLAGS     == /c -DHAVE_VSNPRINTF -DHAVE_SNPRINTF
+  MSFT:NOOPT_*_*_CC_FLAGS =  /Od
+
+  GCC:*_*_*_CC_FLAGS     == -g -DHAVE_SIGNAL_H
+  GCC:NOOPT_*_*_CC_FLAGS =  -O0
+  GCC:*_*_IA32_CC_FLAGS  =  -m32
+  GCC:*_*_X64_CC_FLAGS   =  -m64
diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni
new file mode 100644
index 0000000000..acdb72d075
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/CmockaLib/CmockaLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// This module provides Cmocka Library implementation.
+//
+// This module provides Cmocka Library implementation.
+//
+// Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Cmocka Library implementation"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This module provides Cmocka Library implementation."
diff --git a/UnitTestFrameworkPkg/Library/CmockaLib/cmocka b/UnitTestFrameworkPkg/Library/CmockaLib/cmocka
new file mode 160000
index 0000000000..1cc9cde344
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/CmockaLib/cmocka
@@ -0,0 +1 @@
+Subproject commit 1cc9cde3448cdd2e000886a26acf1caac2db7cf1
diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c
new file mode 100644
index 0000000000..0daea00728
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.c
@@ -0,0 +1,279 @@
+/** @file
+  Instance of Debug Library based on POSIX APIs
+
+  Uses Print Library to produce formatted output strings sent to printf().
+
+  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <stdio.h>
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+
+///
+/// Define the maximum debug and assert message length that this library supports
+///
+#define MAX_DEBUG_MESSAGE_LENGTH  0x100
+
+/**
+  Prints a debug message to the debug output device if the specified error level is enabled.
+
+  If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+  GetDebugPrintErrorLevel (), then print the message specified by Format and the
+  associated variable argument list to the debug output device.
+
+  If Format is NULL, then ASSERT().
+
+  @param  ErrorLevel  The error level of the debug message.
+  @param  Format      The format string for the debug message to print.
+  @param  ...         The variable argument list whose contents are accessed
+                      based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugPrint (
+  IN  UINTN        ErrorLevel,
+  IN  CONST CHAR8  *Format,
+  ...
+  )
+{
+  VA_LIST  Marker;
+
+  VA_START (Marker, Format);
+  DebugVPrint (ErrorLevel, Format, Marker);
+  VA_END (Marker);
+}
+
+/**
+  Prints a debug message to the debug output device if the specified
+  error level is enabled.
+
+  If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+  GetDebugPrintErrorLevel (), then print the message specified by Format and
+  the associated variable argument list to the debug output device.
+
+  If Format is NULL, then ASSERT().
+
+  @param  ErrorLevel    The error level of the debug message.
+  @param  Format        Format string for the debug message to print.
+  @param  VaListMarker  VA_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugVPrint (
+  IN  UINTN         ErrorLevel,
+  IN  CONST CHAR8   *Format,
+  IN  VA_LIST       VaListMarker
+  )
+{
+  CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+
+  AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);
+  printf ("%s", Buffer);
+}
+
+/**
+  Prints a debug message to the debug output device if the specified
+  error level is enabled.
+  This function use BASE_LIST which would provide a more compatible
+  service than VA_LIST.
+
+  If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+  GetDebugPrintErrorLevel (), then print the message specified by Format and
+  the associated variable argument list to the debug output device.
+
+  If Format is NULL, then ASSERT().
+
+  @param  ErrorLevel      The error level of the debug message.
+  @param  Format          Format string for the debug message to print.
+  @param  BaseListMarker  BASE_LIST marker for the variable argument list.
+
+**/
+VOID
+EFIAPI
+DebugBPrint (
+  IN  UINTN         ErrorLevel,
+  IN  CONST CHAR8   *Format,
+  IN  BASE_LIST     BaseListMarker
+  )
+{
+  CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+
+  AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);
+  printf ("%s", Buffer);
+}
+
+/**
+  Prints an assert message containing a filename, line number, and description.
+  This may be followed by a breakpoint or a dead loop.
+
+  Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
+  to the debug output device.  If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
+  PcdDebugPropertyMask is set then CpuBreakpoint() is called. Otherwise, if
+  DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugPropertyMask is set then
+  CpuDeadLoop() is called.  If neither of these bits are set, then this function
+  returns immediately after the message is printed to the debug output device.
+  DebugAssert() must actively prevent recursion.  If DebugAssert() is called while
+  processing another DebugAssert(), then DebugAssert() must return immediately.
+
+  If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
+  If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
+
+  @param  FileName     The pointer to the name of the source file that generated the assert condition.
+  @param  LineNumber   The line number in the source file that generated the assert condition
+  @param  Description  The pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+DebugAssert (
+  IN CONST CHAR8  *FileName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *Description
+  )
+{
+  printf ("ASSERT: %s(%d): %s\n", FileName, (INT32)(UINT32)LineNumber, Description);
+
+  //
+  // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
+  //
+  if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
+    CpuBreakpoint ();
+  } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
+    CpuDeadLoop ();
+  }
+}
+
+/**
+  Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with the value specified by
+  PcdDebugClearMemoryValue, and returns Buffer.
+
+  If Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param   Buffer  The pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
+  @param   Length  The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
+
+  @return  Buffer  The pointer to the target buffer filled with PcdDebugClearMemoryValue.
+
+**/
+VOID *
+EFIAPI
+DebugClearMemory (
+  OUT VOID  *Buffer,
+  IN UINTN  Length
+  )
+{
+  //
+  // If Buffer is NULL, then ASSERT().
+  //
+  ASSERT (Buffer != NULL);
+
+  //
+  // SetMem() checks for the the ASSERT() condition on Length and returns Buffer
+  //
+  return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue));
+}
+
+/**
+  Returns TRUE if ASSERT() macros are enabled.
+
+  This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
+  PcdDebugPropertyMask is set.  Otherwise FALSE is returned.
+
+  @retval  TRUE    The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is set.
+  @retval  FALSE   The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugAssertEnabled (
+  VOID
+  )
+{
+  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
+}
+
+/**
+  Returns TRUE if DEBUG() macros are enabled.
+
+  This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
+  PcdDebugPropertyMask is set.  Otherwise FALSE is returned.
+
+  @retval  TRUE    The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is set.
+  @retval  FALSE   The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintEnabled (
+  VOID
+  )
+{
+  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
+}
+
+/**
+  Returns TRUE if DEBUG_CODE() macros are enabled.
+
+  This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
+  PcdDebugPropertyMask is set.  Otherwise FALSE is returned.
+
+  @retval  TRUE    The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is set.
+  @retval  FALSE   The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugCodeEnabled (
+  VOID
+  )
+{
+  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
+
+/**
+  Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
+
+  This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
+  PcdDebugPropertyMask is set.  Otherwise FALSE is returned.
+
+  @retval  TRUE    The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is set.
+  @retval  FALSE   The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugClearMemoryEnabled (
+  VOID
+  )
+{
+  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
+}
+
+/**
+  Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+  This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+  @retval  TRUE    Current ErrorLevel is supported.
+  @retval  FALSE   Current ErrorLevel is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintLevelEnabled (
+  IN  CONST UINTN        ErrorLevel
+  )
+{
+  return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
+}
diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
new file mode 100644
index 0000000000..5babbca3b0
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.inf
@@ -0,0 +1,35 @@
+## @file
+#  Instance of Debug Library based on POSIX APIs
+#
+#  Uses Print Library to produce formatted output strings sent to printf().
+#
+#  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = DebugLibPosix
+  MODULE_UNI_FILE = DebugLibPosix.uni
+  FILE_GUID       = 6A77CE89-C1B6-4A6B-9561-07D7127514A7
+  MODULE_TYPE     = BASE
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = DebugLib|HOST_APPLICATION
+
+[Sources]
+  DebugLibPosix.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  PcdLib
+  PrintLib
+  BaseLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue     ## SOMETIMES_CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask         ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES
diff --git a/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni
new file mode 100644
index 0000000000..d34f1a05be
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/DebugLibPosix/DebugLibPosix.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Instance of Debug Library based on POSIX APIs
+//
+// Uses Print Library to produce formatted output strings sent to printf().
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Instance of Debug Library based on POSIX APIs"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Uses Print Library to produce formatted output strings sent to printf()."
diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c
new file mode 100644
index 0000000000..1f590524d8
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.c
@@ -0,0 +1,631 @@
+/** @file
+  Instance of Memory Allocation Library based on POSIX APIs
+
+  Uses POSIX APIs malloc() and free() to allocate and free memory.
+
+  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <Uefi.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+///
+/// Signature for PAGE_HEAD structure
+/// Used to verify that buffer being freed was allocated by this library.
+///
+#define PAGE_HEAD_PRIVATE_SIGNATURE  SIGNATURE_32 ('P', 'H', 'D', 'R')
+
+///
+/// Structure placed immediately before an aligned allocation to store the
+/// information required to free the entire buffer allocated to support then
+/// aligned allocation.
+///
+typedef struct {
+  UINT32  Signature;
+  VOID    *AllocatedBufffer;
+  UINTN   TotalPages;
+  VOID    *AlignedBuffer;
+  UINTN   AlignedPages;
+} PAGE_HEAD;
+
+/**
+  Allocates one or more 4KB pages of type EfiBootServicesData.
+
+  Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+  allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
+  is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
+  returned.
+
+  @param  Pages  The number of 4 KB pages to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+  IN UINTN  Pages
+  )
+{
+  return AllocateAlignedPages (Pages, SIZE_4KB);
+}
+
+/**
+  Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+  Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+  allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
+  is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
+  returned.
+
+  @param  Pages  The number of 4 KB pages to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+  IN UINTN  Pages
+  )
+{
+  return AllocatePages (Pages);
+}
+
+/**
+  Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+  Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+  allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
+  is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
+  returned.
+
+  @param  Pages  The number of 4 KB pages to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+  IN UINTN  Pages
+  )
+{
+  return AllocatePages (Pages);
+}
+
+/**
+  Frees one or more 4KB pages that were previously allocated with one of the page allocation
+  functions in the Memory Allocation Library.
+
+  Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer.  Buffer
+  must have been allocated on a previous call to the page allocation services of the Memory
+  Allocation Library.  If it is not possible to free allocated pages, then this function will
+  perform no actions.
+
+  If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+  then ASSERT().
+  If Pages is zero, then ASSERT().
+
+  @param  Buffer  The pointer to the buffer of pages to free.
+  @param  Pages   The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+  IN VOID   *Buffer,
+  IN UINTN  Pages
+  )
+{
+  FreeAlignedPages (Buffer, Pages);
+}
+
+/**
+  Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+  Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+  alignment specified by Alignment.  The allocated buffer is returned.  If Pages is 0, then NULL is
+  returned.  If there is not enough memory at the specified alignment remaining to satisfy the
+  request, then NULL is returned.
+
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+  @param  Pages      The number of 4 KB pages to allocate.
+  @param  Alignment  The requested alignment of the allocation.  Must be a power of two.
+                     If Alignment is zero, then byte alignment is used.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/VOID *
+EFIAPI
+AllocateAlignedPages (
+  IN UINTN  Pages,
+  IN UINTN  Alignment
+  )
+{
+  PAGE_HEAD  PageHead;
+  PAGE_HEAD  *PageHeadPtr;
+  UINTN      AlignmentMask;
+
+  ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+  if (Alignment < SIZE_4KB) {
+    Alignment = SIZE_4KB;
+  }
+  AlignmentMask  = Alignment - 1;
+
+  //
+  // We need reserve Alignment pages for PAGE_HEAD, as meta data.
+  //
+  PageHead.Signature = PAGE_HEAD_PRIVATE_SIGNATURE;
+  PageHead.TotalPages = Pages + EFI_SIZE_TO_PAGES (Alignment) * 2;
+  PageHead.AlignedPages = Pages;
+  PageHead.AllocatedBufffer = malloc (EFI_PAGES_TO_SIZE (PageHead.TotalPages));
+  if (PageHead.AllocatedBufffer == NULL) {
+    return NULL;
+  }
+  PageHead.AlignedBuffer = (VOID *)(((UINTN) PageHead.AllocatedBufffer + AlignmentMask) & ~AlignmentMask);
+  if ((UINTN)PageHead.AlignedBuffer - (UINTN)PageHead.AllocatedBufffer < sizeof(PAGE_HEAD)) {
+    PageHead.AlignedBuffer = (VOID *)((UINTN)PageHead.AlignedBuffer + Alignment);
+  }
+
+  PageHeadPtr = (VOID *)((UINTN)PageHead.AlignedBuffer - sizeof(PAGE_HEAD));
+  memcpy (PageHeadPtr, &PageHead, sizeof(PAGE_HEAD));
+
+  return PageHead.AlignedBuffer;
+}
+
+/**
+  Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+  Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+  alignment specified by Alignment.  The allocated buffer is returned.  If Pages is 0, then NULL is
+  returned.  If there is not enough memory at the specified alignment remaining to satisfy the
+  request, then NULL is returned.
+
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+  @param  Pages      The number of 4 KB pages to allocate.
+  @param  Alignment  The requested alignment of the allocation.  Must be a power of two.
+                     If Alignment is zero, then byte alignment is used.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+  IN UINTN  Pages,
+  IN UINTN  Alignment
+  )
+{
+  return AllocateAlignedPages (Pages, Alignment);
+}
+
+/**
+  Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+  Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+  alignment specified by Alignment.  The allocated buffer is returned.  If Pages is 0, then NULL is
+  returned.  If there is not enough memory at the specified alignment remaining to satisfy the
+  request, then NULL is returned.
+
+  If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+  If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+  @param  Pages      The number of 4 KB pages to allocate.
+  @param  Alignment  The requested alignment of the allocation.  Must be a power of two.
+                     If Alignment is zero, then byte alignment is used.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+  IN UINTN  Pages,
+  IN UINTN  Alignment
+  )
+{
+  return AllocateAlignedPages (Pages, Alignment);
+}
+
+/**
+  Frees one or more 4KB pages that were previously allocated with one of the aligned page
+  allocation functions in the Memory Allocation Library.
+
+  Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer.  Buffer
+  must have been allocated on a previous call to the aligned page allocation services of the Memory
+  Allocation Library.  If it is not possible to free allocated pages, then this function will
+  perform no actions.
+
+  If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+  Library, then ASSERT().
+  If Pages is zero, then ASSERT().
+
+  @param  Buffer  The pointer to the buffer of pages to free.
+  @param  Pages   The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+  IN VOID   *Buffer,
+  IN UINTN  Pages
+  )
+{
+  PAGE_HEAD  *PageHeadPtr;
+
+  //
+  // NOTE: Partial free is not supported. Just keep it.
+  //
+  PageHeadPtr = (VOID *)((UINTN)Buffer - sizeof(PAGE_HEAD));
+  if (PageHeadPtr->Signature != PAGE_HEAD_PRIVATE_SIGNATURE) {
+    return;
+  }
+  if (PageHeadPtr->AlignedPages != Pages) {
+    return;
+  }
+
+  PageHeadPtr->Signature = 0;
+  free (PageHeadPtr->AllocatedBufffer);
+}
+
+/**
+  Allocates a buffer of type EfiBootServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+  pointer to the allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is
+  returned.  If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/VOID *
+EFIAPI
+AllocatePool (
+  IN UINTN  AllocationSize
+  )
+{
+  return malloc (AllocationSize);
+}
+
+/**
+  Allocates a buffer of type EfiRuntimeServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+  a pointer to the allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is
+  returned.  If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+  IN UINTN  AllocationSize
+  )
+{
+  return AllocatePool (AllocationSize);
+}
+
+/**
+  Allocates a buffer of type EfiReservedMemoryType.
+
+  Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+  a pointer to the allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is
+  returned.  If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+  IN UINTN  AllocationSize
+  )
+{
+  return AllocatePool (AllocationSize);
+}
+
+/**
+  Allocates and zeros a buffer of type EfiBootServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+  buffer with zeros, and returns a pointer to the allocated buffer.  If AllocationSize is 0, then a
+  valid buffer of 0 size is returned.  If there is not enough memory remaining to satisfy the
+  request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+  IN UINTN  AllocationSize
+  )
+{
+  VOID  *Buffer;
+
+  Buffer = malloc (AllocationSize);
+  if (Buffer == NULL) {
+    return NULL;
+  }
+  memset (Buffer, 0, AllocationSize);
+  return Buffer;
+}
+
+/**
+  Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+  buffer with zeros, and returns a pointer to the allocated buffer.  If AllocationSize is 0, then a
+  valid buffer of 0 size is returned.  If there is not enough memory remaining to satisfy the
+  request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+  IN UINTN  AllocationSize
+  )
+{
+  return AllocateZeroPool (AllocationSize);
+}
+
+/**
+  Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+  Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+  buffer with zeros, and returns a pointer to the allocated buffer.  If AllocationSize is 0, then a
+  valid buffer of 0 size is returned.  If there is not enough memory remaining to satisfy the
+  request, then NULL is returned.
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+  IN UINTN  AllocationSize
+  )
+{
+  return AllocateZeroPool (AllocationSize);
+}
+
+/**
+  Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+  AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+  allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there
+  is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+  @param  Buffer          The buffer to copy to the allocated buffer.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+  IN UINTN       AllocationSize,
+  IN CONST VOID  *Buffer
+  )
+{
+  VOID  *Memory;
+
+  Memory = malloc (AllocationSize);
+  if (Memory == NULL) {
+    return NULL;
+  }
+  memcpy (Memory, Buffer, AllocationSize);
+  return Memory;
+}
+
+/**
+  Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+  Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+  AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+  allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there
+  is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+  @param  Buffer          The buffer to copy to the allocated buffer.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+  IN UINTN       AllocationSize,
+  IN CONST VOID  *Buffer
+  )
+{
+  return AllocateCopyPool (AllocationSize, Buffer);
+}
+
+/**
+  Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+  Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+  AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+  allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there
+  is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  AllocationSize  The number of bytes to allocate and zero.
+  @param  Buffer          The buffer to copy to the allocated buffer.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+  IN UINTN       AllocationSize,
+  IN CONST VOID  *Buffer
+  )
+{
+  return AllocateCopyPool (AllocationSize, Buffer);
+}
+
+/**
+  Reallocates a buffer of type EfiBootServicesData.
+
+  Allocates and zeros the number bytes specified by NewSize from memory of type
+  EfiBootServicesData.  If OldBuffer is not NULL, then the smaller of OldSize and
+  NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+  OldBuffer is freed.  A pointer to the newly allocated buffer is returned.
+  If NewSize is 0, then a valid buffer of 0 size is  returned.  If there is not
+  enough memory remaining to satisfy the request, then NULL is returned.
+
+  If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+  is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+  @param  OldSize    The size, in bytes, of OldBuffer.
+  @param  NewSize    The size, in bytes, of the buffer to reallocate.
+  @param  OldBuffer  The buffer to copy to the allocated buffer.  This is an optional
+                     parameter that may be NULL.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+  IN UINTN  OldSize,
+  IN UINTN  NewSize,
+  IN VOID   *OldBuffer   OPTIONAL
+  )
+{
+  VOID  *NewBuffer;
+
+  NewBuffer = malloc (NewSize);
+  if (NewBuffer != NULL && OldBuffer != NULL) {
+    memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+  }
+  if (OldBuffer != NULL) {
+    FreePool(OldBuffer);
+  }
+  return NewBuffer;
+}
+
+/**
+  Reallocates a buffer of type EfiRuntimeServicesData.
+
+  Allocates and zeros the number bytes specified by NewSize from memory of type
+  EfiRuntimeServicesData.  If OldBuffer is not NULL, then the smaller of OldSize and
+  NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+  OldBuffer is freed.  A pointer to the newly allocated buffer is returned.
+  If NewSize is 0, then a valid buffer of 0 size is  returned.  If there is not
+  enough memory remaining to satisfy the request, then NULL is returned.
+
+  If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+  is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+  @param  OldSize    The size, in bytes, of OldBuffer.
+  @param  NewSize    The size, in bytes, of the buffer to reallocate.
+  @param  OldBuffer  The buffer to copy to the allocated buffer.  This is an optional
+                     parameter that may be NULL.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+  IN UINTN  OldSize,
+  IN UINTN  NewSize,
+  IN VOID   *OldBuffer   OPTIONAL
+  )
+{
+  return ReallocatePool (OldSize, NewSize, OldBuffer);
+}
+
+/**
+  Reallocates a buffer of type EfiReservedMemoryType.
+
+  Allocates and zeros the number bytes specified by NewSize from memory of type
+  EfiReservedMemoryType.  If OldBuffer is not NULL, then the smaller of OldSize and
+  NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+  OldBuffer is freed.  A pointer to the newly allocated buffer is returned.
+  If NewSize is 0, then a valid buffer of 0 size is  returned.  If there is not
+  enough memory remaining to satisfy the request, then NULL is returned.
+
+  If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+  is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+  @param  OldSize    The size, in bytes, of OldBuffer.
+  @param  NewSize    The size, in bytes, of the buffer to reallocate.
+  @param  OldBuffer  The buffer to copy to the allocated buffer.  This is an optional
+                     parameter that may be NULL.
+
+  @return  A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+  IN UINTN  OldSize,
+  IN UINTN  NewSize,
+  IN VOID   *OldBuffer   OPTIONAL
+  )
+{
+  return ReallocatePool (OldSize, NewSize, OldBuffer);
+}
+
+/**
+  Frees a buffer that was previously allocated with one of the pool allocation functions in the
+  Memory Allocation Library.
+
+  Frees the buffer specified by Buffer.  Buffer must have been allocated on a previous call to the
+  pool allocation services of the Memory Allocation Library.  If it is not possible to free pool
+  resources, then this function will perform no actions.
+
+  If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+  then ASSERT().
+
+  @param  Buffer  The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+  IN VOID  *Buffer
+  )
+{
+  free (Buffer);
+}
diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
new file mode 100644
index 0000000000..44ec3fd517
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.inf
@@ -0,0 +1,27 @@
+## @file
+#  Instance of Memory Allocation Library based on POSIX APIs
+#
+#  Uses POSIX APIs malloc() and free() to allocate and free memory.
+#
+#  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION     = 0x00010005
+  BASE_NAME       = MemoryAllocationLibPosix
+  MODULE_UNI_FILE = MemoryAllocationLibPosix.uni
+  FILE_GUID       = A1672454-A3D3-4AAC-A86B-8D63132BBB91
+  MODULE_TYPE     = UEFI_DRIVER
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = MemoryAllocationLib|HOST_APPLICATION
+
+[Sources]
+  MemoryAllocationLibPosix.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
diff --git a/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni
new file mode 100644
index 0000000000..854b427976
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/Posix/MemoryAllocationLibPosix/MemoryAllocationLibPosix.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Instance of Memory Allocation Library based on POSIX APIs
+//
+// Uses POSIX APIs malloc() and free() to allocate and free memory.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Instance of Memory Allocation Library based on POSIX APIs"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Uses POSIX APIs malloc() and free() to allocate and free memory."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c
new file mode 100644
index 0000000000..c5a5162c58
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.c
@@ -0,0 +1,26 @@
+/**
+  NULL implementation for UnitTestBootLib to allow simple compilation
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+
+/**
+  Set the boot manager to boot from a specific device on the next boot. This
+  should be set only for the next boot and shouldn't require any manual clean up
+
+  @retval EFI_SUCCESS      Boot device for next boot was set.
+  @retval EFI_UNSUPPORTED  Setting the boot device for the next boot is not
+                           supportted.
+  @retval Other            Boot device for next boot can not be set.
+**/
+EFI_STATUS
+EFIAPI
+SetBootNextDevice(
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf
new file mode 100644
index 0000000000..a4a907b65b
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.inf
@@ -0,0 +1,23 @@
+## @file
+# NULL library for UnitTestBootUsb
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestBootLibNull
+  MODULE_UNI_FILE = UnitTestBootLibNull.uni
+  FILE_GUID       = f143e75d-76e1-4040-b134-8f4f0bd5e3bd
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = DXE_DRIVER
+  LIBRARY_CLASS   = UnitTestBootLib
+
+[Sources]
+  UnitTestBootLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni
new file mode 100644
index 0000000000..1ed3b20544
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibNull/UnitTestBootLibNull.uni
@@ -0,0 +1,11 @@
+// /** @file
+// NULL library for UnitTestBootUsb
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "NULL library for UnitTestBootUsb"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "NULL library for UnitTestBootUsb."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c
new file mode 100644
index 0000000000..4ce48bd233
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.c
@@ -0,0 +1,127 @@
+/**
+  Implement UnitTestBootLib using USB Class Boot option.  This should be
+  industry standard and should work on all platforms
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Protocol/DevicePath.h>
+#include <Library/MemoryAllocationLib.h>
+
+/**
+  Set the boot manager to boot from a specific device on the next boot. This
+  should be set only for the next boot and shouldn't require any manual clean up
+
+  @retval EFI_SUCCESS      Boot device for next boot was set.
+  @retval EFI_UNSUPPORTED  Setting the boot device for the next boot is not
+                           supportted.
+  @retval Other            Boot device for next boot can not be set.
+**/
+EFI_STATUS
+EFIAPI
+SetBootNextDevice (
+   VOID
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_BOOT_MANAGER_LOAD_OPTION  NewOption;
+  UINT32                        Attributes;
+  UINT8                         *OptionalData;
+  UINT32                        OptionalDataSize;
+  UINT16                        BootNextValue;
+  USB_CLASS_DEVICE_PATH         UsbDp;
+  EFI_DEVICE_PATH_PROTOCOL      *DpEnd;
+  EFI_DEVICE_PATH_PROTOCOL      *Dp;
+  BOOLEAN                       NewOptionValid;
+
+  OptionalData     = NULL;
+  OptionalDataSize = 0;
+  BootNextValue    = 0xABCD;  // this should be a safe number...
+  DpEnd            = NULL;
+  Dp               = NULL;
+  NewOptionValid   = FALSE;
+
+  UsbDp.Header.Length[0] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff);
+  UsbDp.Header.Length[1] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8);
+  UsbDp.Header.Type      = MESSAGING_DEVICE_PATH;
+  UsbDp.Header.SubType   = MSG_USB_CLASS_DP;
+  UsbDp.VendorId         = 0xFFFF;
+  UsbDp.ProductId        = 0xFFFF;
+  UsbDp.DeviceClass      = 0xFF;
+  UsbDp.DeviceSubClass   = 0xFF;
+  UsbDp.DeviceProtocol   = 0xFF;
+
+  Attributes = LOAD_OPTION_ACTIVE;
+
+  DpEnd = AppendDevicePathNode (NULL, NULL);
+  if (DpEnd == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Unable to create device path.  DpEnd is NULL.\n", __FUNCTION__));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto CLEANUP;
+  }
+
+  //@MRT --- Is this memory leak because we lose the old Dp memory
+  Dp = AppendDevicePathNode (
+         DpEnd,
+         (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp
+         );
+  if (Dp == NULL) {
+    DEBUG((DEBUG_ERROR, "%a: Unable to create device path.  Dp is NULL.\n", __FUNCTION__));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto CLEANUP;
+  }
+
+  Status = EfiBootManagerInitializeLoadOption (
+             &NewOption,
+             (UINTN) BootNextValue,
+             LoadOptionTypeBoot,
+             Attributes,
+             L"Generic USB Class Device",
+             Dp,
+             OptionalData,
+             OptionalDataSize
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Error creating load option.  Status = %r\n", __FUNCTION__, Status));
+    goto CLEANUP;
+  }
+
+  NewOptionValid = TRUE;
+  DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created.\n", __FUNCTION__));
+  Status = EfiBootManagerLoadOptionToVariable (&NewOption);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status = %r\n", __FUNCTION__, Status));
+    goto CLEANUP;
+  }
+
+  //
+  // Set Boot Next
+  //
+  Status = gRT->SetVariable (
+                  L"BootNext",
+                  &gEfiGlobalVariableGuid,
+                  (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE),
+                  sizeof(BootNextValue),
+                  &(BootNextValue)
+                  );
+
+  DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, Status));
+
+CLEANUP:
+  if (Dp != NULL) {
+    FreePool (Dp);
+  }
+  if (DpEnd != NULL) {
+    FreePool (DpEnd);
+  }
+  if (NewOptionValid) {
+    EfiBootManagerFreeLoadOption (&NewOption);
+  }
+  return Status;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf
new file mode 100644
index 0000000000..80c4e4f111
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.inf
@@ -0,0 +1,34 @@
+## @file
+# Library to support booting to USB on the next boot
+# This instance uses the industry standard usb class boot option.
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestBootLibUsbClass
+  MODULE_UNI_FILE = UnitTestBootLibUsbClass.uni
+  FILE_GUID       = DFADE2A2-DB69-47DE-A37A-40FB6D52E844
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_APPLICATION
+  LIBRARY_CLASS   = UnitTestBootLib
+
+[Sources]
+  UnitTestBootLibUsbClass.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiRuntimeServicesTableLib
+  MemoryAllocationLib
+  DevicePathLib
+  UefiBootManagerLib
+
+[Guids]
+  gEfiGlobalVariableGuid  ## CONSUMES ## Used to probe boot options and set BootNext.
diff --git a/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni
new file mode 100644
index 0000000000..8468b3537c
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestBootLibUsbClass/UnitTestBootLibUsbClass.uni
@@ -0,0 +1,12 @@
+// /** @file
+// Library to support booting to USB on the next boot
+// This instance uses the industry standard usb class boot option.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Library to support booting to USB on the next boot"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This instance uses the industry standard usb class boot option.."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
new file mode 100644
index 0000000000..dd85b84b08
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Assert.c
@@ -0,0 +1,491 @@
+/**
+  Implement UnitTestLib assert services
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <UnitTestFrameworkTypes.h>
+#include <Library/UnitTestLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+
+STATIC
+EFI_STATUS
+AddUnitTestFailure (
+  IN OUT UNIT_TEST     *UnitTest,
+  IN     CONST CHAR8   *FailureMessage,
+  IN     FAILURE_TYPE  FailureType
+  )
+{
+  //
+  // Make sure that you're cooking with gas.
+  //
+  if (UnitTest == NULL || FailureMessage == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  UnitTest->FailureType = FailureType;
+  AsciiStrCpyS (
+    &UnitTest->FailureMessage[0],
+    UNIT_TEST_TESTFAILUREMSG_LENGTH,
+    FailureMessage
+    );
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+UnitTestLogFailure (
+  IN FAILURE_TYPE  FailureType,
+  IN CONST CHAR8   *Format,
+  ...
+  )
+{
+  UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle;
+  CHAR8                       LogString[UNIT_TEST_TESTFAILUREMSG_LENGTH];
+  VA_LIST                     Marker;
+
+  //
+  // Get active Framework handle
+  //
+  FrameworkHandle = GetActiveFrameworkHandle ();
+
+  //
+  // Convert the message to an ASCII String
+  //
+  VA_START (Marker, Format);
+  AsciiVSPrint (LogString, sizeof (LogString), Format, Marker);
+  VA_END (Marker);
+
+  //
+  // Finally, add the string to the log.
+  //
+  AddUnitTestFailure (
+    ((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest,
+    LogString,
+    FailureType
+    );
+
+  return;
+}
+
+/**
+  If Expression is TRUE, then TRUE is returned.
+  If Expression is FALSE, then an assert is triggered and the location of the
+  assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the expression being
+                            evaluated.
+
+  @retval  TRUE   Expression is TRUE.
+  @retval  FALSE  Expression is FALSE.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertTrue (
+  IN BOOLEAN      Expression,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  if (!Expression) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTTRUE,
+      "%a::%d Expression (%a) is not TRUE!\n",
+      FunctionName,
+      LineNumber,
+      Description
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Expression (%a) is not TRUE!\n",
+      FunctionName,
+      LineNumber,
+      Description
+      );
+  }
+  return Expression;
+}
+
+/**
+  If Expression is FALSE, then TRUE is returned.
+  If Expression is TRUE, then an assert is triggered and the location of the
+  assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the expression being
+                            evaluated.
+
+  @retval  TRUE   Expression is FALSE.
+  @retval  FALSE  Expression is TRUE.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertFalse (
+  IN BOOLEAN      Expression,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  if (Expression) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTFALSE,
+      "%a::%d Expression(%a) is not FALSE!\n",
+      FunctionName,
+      LineNumber,
+      Description
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Expression (%a) is not FALSE!\n",
+      FunctionName,
+      LineNumber,
+      Description
+      );
+  }
+  return !Expression;
+}
+
+/**
+  If Status is not an EFI_ERROR(), then TRUE is returned.
+  If Status is an EFI_ERROR(), then an assert is triggered and the location of
+  the assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Status        The EFI_STATUS value to evaluate.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the status
+                            expression being evaluated.
+
+  @retval  TRUE   Status is not an EFI_ERROR().
+  @retval  FALSE  Status is an EFI_ERROR().
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotEfiError (
+  IN EFI_STATUS   Status,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  if (EFI_ERROR (Status)) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTNOTEFIERROR,
+      "%a::%d Status '%a' is EFI_ERROR (%r)!\n",
+      FunctionName,
+      LineNumber,
+      Description,
+      Status
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Status '%a' is EFI_ERROR (%r)!\n",
+      FunctionName,
+      LineNumber,
+      Description,
+      Status
+      );
+  }
+  return !EFI_ERROR( Status );
+}
+
+/**
+  If ValueA is equal ValueB, then TRUE is returned.
+  If ValueA is not equal to ValueB, then an assert is triggered and the location
+  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
+  and DescriptionB are recorded and FALSE is returned.
+
+  @param[in]  ValueA        64-bit value.
+  @param[in]  ValueB        64-bit value.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of ValueA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of ValueB.
+
+  @retval  TRUE   ValueA is equal to ValueB.
+  @retval  FALSE  ValueA is not equal to ValueB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertEqual (
+  IN UINT64       ValueA,
+  IN UINT64       ValueB,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  if ((ValueA != ValueB)) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTEQUAL,
+      "%a::%d Value %a != %a (%d != %d)!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      ValueA,
+      ValueB
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Value %a != %a (%d != %d)!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      ValueA,
+      ValueB
+      );
+  }
+  return (ValueA == ValueB);
+}
+
+/**
+  If the contents of BufferA are identical to the contents of BufferB, then TRUE
+  is returned.  If the contents of BufferA are not identical to the contents of
+  BufferB, then an assert is triggered and the location of the assert provided
+  by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
+  recorded and FALSE is returned.
+
+  @param[in]  BufferA       Pointer to a buffer for comparison.
+  @param[in]  BufferB       Pointer to a buffer for comparison.
+  @param[in]  Length        Number of bytes to compare in BufferA and BufferB.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of BufferA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of BufferB.
+
+  @retval  TRUE   The contents of BufferA are identical to the contents of
+                  BufferB.
+  @retval  FALSE  The contents of BufferA are not identical to the contents of
+                  BufferB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertMemEqual (
+  IN VOID         *BufferA,
+  IN VOID         *BufferB,
+  IN UINTN        Length,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  if (CompareMem(BufferA, BufferB, Length) != 0) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTEQUAL,
+      "%a::%d Memory at %a != %a for length %d bytes!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      Length
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Value %a != %a for length %d bytes!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      Length
+      );
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  If ValueA is not equal ValueB, then TRUE is returned.
+  If ValueA is equal to ValueB, then an assert is triggered and the location
+  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
+  and DescriptionB are recorded and FALSE is returned.
+
+  @param[in]  ValueA        64-bit value.
+  @param[in]  ValueB        64-bit value.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of ValueA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of ValueB.
+
+  @retval  TRUE   ValueA is not equal to ValueB.
+  @retval  FALSE  ValueA is equal to ValueB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotEqual (
+  IN UINT64       ValueA,
+  IN UINT64       ValueB,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  if ((ValueA == ValueB)) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTNOTEQUAL,
+      "%a::%d Value %a == %a (%d == %d)!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      ValueA,
+      ValueB
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Value %a == %a (%d == %d)!\n",
+      FunctionName,
+      LineNumber,
+      DescriptionA,
+      DescriptionB,
+      ValueA,
+      ValueB
+      );
+  }
+  return (ValueA != ValueB);
+}
+
+/**
+  If Status is equal to Expected, then TRUE is returned.
+  If Status is not equal to Expected, then an assert is triggered and the
+  location of the assert provided by FunctionName, LineNumber, FileName, and
+  Description are recorded and FALSE is returned.
+
+  @param[in]  Status        EFI_STATUS value returned from an API under test.
+  @param[in]  Expected      The expected EFI_STATUS return value from an API
+                            under test.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string that is a description
+                            of Status.
+
+  @retval  TRUE   Status is equal to Expected.
+  @retval  FALSE  Status is not equal to Expected.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertStatusEqual (
+  IN EFI_STATUS   Status,
+  IN EFI_STATUS   Expected,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  if ((Status != Expected)) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTSTATUSEQUAL,
+      "%a::%d Status '%a' is %r, should be %r!\n",
+      FunctionName,
+      LineNumber,
+      Description,
+      Status,
+      Expected
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Status '%a' is %r, should be %r!\n",
+      FunctionName,
+      LineNumber,
+      Description,
+      Status,
+      Expected
+      );
+  }
+  return (Status == Expected);
+}
+
+/**
+  If Pointer is not equal to NULL, then TRUE is returned.
+  If Pointer is equal to NULL, then an assert is triggered and the location of
+  the assert provided by FunctionName, LineNumber, FileName, and PointerName
+  are recorded and FALSE is returned.
+
+  @param[in]  Pointer       Pointer value to be checked against NULL.
+  @param[in]  Expected      The expected EFI_STATUS return value from a function
+                            under test.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  PointerName   Null-terminated ASCII string that is a description
+                            of Pointer.
+
+  @retval  TRUE   Pointer is not equal to NULL.
+  @retval  FALSE  Pointer is equal to NULL.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotNull (
+  IN VOID         *Pointer,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *PointerName
+  )
+{
+  if (Pointer == NULL) {
+    UnitTestLogFailure (
+      FAILURETYPE_ASSERTNOTNULL,
+      "%a::%d Pointer (%a) is NULL!\n",
+      FunctionName,
+      LineNumber,
+      PointerName
+      );
+    UT_LOG_ERROR (
+      "[ASSERT FAIL] %a::%d Pointer (%a) is NULL!\n",
+      FunctionName,
+      LineNumber,
+      PointerName
+      );
+  }
+  return (Pointer != NULL);
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
new file mode 100644
index 0000000000..e48d614976
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/AssertCmocka.c
@@ -0,0 +1,335 @@
+/** @file
+  Implement UnitTestLib assert services using cmocka services
+
+  Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+  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/BaseMemoryLib.h>
+#include <Library/UnitTestLib.h>
+
+#define MAX_STRING_SIZE  1025
+
+/**
+  If Expression is TRUE, then TRUE is returned.
+  If Expression is FALSE, then an assert is triggered and the location of the
+  assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the expression being
+                            evaluated.
+
+  @retval  TRUE   Expression is TRUE.
+  @retval  FALSE  Expression is FALSE.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertTrue (
+  IN BOOLEAN      Expression,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_TRUE(%s:%x)", Description, Expression);
+  _assert_true (Expression, TempStr, FileName, (INT32)LineNumber);
+
+  return Expression;
+}
+
+/**
+  If Expression is FALSE, then TRUE is returned.
+  If Expression is TRUE, then an assert is triggered and the location of the
+  assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Expression    The BOOLEAN result of the expression evaluation.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the expression being
+                            evaluated.
+
+  @retval  TRUE   Expression is FALSE.
+  @retval  FALSE  Expression is TRUE.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertFalse (
+  IN BOOLEAN      Expression,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_FALSE(%s:%x)", Description, Expression);
+  _assert_true (!Expression, TempStr, FileName, (INT32)LineNumber);
+
+  return !Expression;
+}
+
+/**
+  If Status is not an EFI_ERROR(), then TRUE is returned.
+  If Status is an EFI_ERROR(), then an assert is triggered and the location of
+  the assert provided by FunctionName, LineNumber, FileName, and Description are
+  recorded and FALSE is returned.
+
+  @param[in]  Status        The EFI_STATUS value to evaluate.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string of the status
+                            expression being evaluated.
+
+  @retval  TRUE   Status is not an EFI_ERROR().
+  @retval  FALSE  Status is an EFI_ERROR().
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotEfiError (
+  IN EFI_STATUS   Status,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EFI_ERROR(%s:%p)", Description, (void *)Status);
+  _assert_true (!EFI_ERROR (Status), TempStr, FileName, (INT32)LineNumber);
+
+  return !EFI_ERROR (Status);
+}
+
+/**
+  If ValueA is equal ValueB, then TRUE is returned.
+  If ValueA is not equal to ValueB, then an assert is triggered and the location
+  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA,
+  and DescriptionB are recorded and FALSE is returned.
+
+  @param[in]  ValueA        64-bit value.
+  @param[in]  ValueB        64-bit value.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of ValueA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of ValueB.
+
+  @retval  TRUE   ValueA is equal to ValueB.
+  @retval  FALSE  ValueA is not equal to ValueB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertEqual (
+  IN UINT64       ValueA,
+  IN UINT64       ValueB,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);
+  _assert_true ((ValueA == ValueB), TempStr, FileName, (INT32)LineNumber);
+
+  return (ValueA == ValueB);
+}
+
+/**
+  If the contents of BufferA are identical to the contents of BufferB, then TRUE
+  is returned.  If the contents of BufferA are not identical to the contents of
+  BufferB, then an assert is triggered and the location of the assert provided
+  by FunctionName, LineNumber, FileName, DescriptionA, and DescriptionB are
+  recorded and FALSE is returned.
+
+  @param[in]  BufferA       Pointer to a buffer for comparison.
+  @param[in]  BufferB       Pointer to a buffer for comparison.
+  @param[in]  Length        Number of bytes to compare in BufferA and BufferB.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of BufferA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of BufferB.
+
+  @retval  TRUE   The contents of BufferA are identical to the contents of
+                  BufferB.
+  @retval  FALSE  The contents of BufferA are not identical to the contents of
+                  BufferB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertMemEqual (
+  IN VOID         *BufferA,
+  IN VOID         *BufferB,
+  IN UINTN        Length,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  CHAR8    TempStr[MAX_STRING_SIZE];
+  BOOLEAN  Result;
+
+  Result = (CompareMem(BufferA, BufferB, Length) == 0);
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_MEM_EQUAL(%s:%p, %s:%p)", DescriptionA, BufferA, DescriptionB, BufferB);
+  _assert_true (Result, TempStr, FileName, (INT32)LineNumber);
+
+  return Result;
+}
+
+/**
+  If ValueA is not equal ValueB, then TRUE is returned.
+  If ValueA is equal to ValueB, then an assert is triggered and the location
+  of the assert provided by FunctionName, LineNumber, FileName, DescriptionA
+  and DescriptionB are recorded and FALSE is returned.
+
+  @param[in]  ValueA        64-bit value.
+  @param[in]  ValueB        64-bit value.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  DescriptionA  Null-terminated ASCII string that is a description
+                            of ValueA.
+  @param[in]  DescriptionB  Null-terminated ASCII string that is a description
+                            of ValueB.
+
+  @retval  TRUE   ValueA is not equal to ValueB.
+  @retval  FALSE  ValueA is equal to ValueB.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotEqual (
+  IN UINT64       ValueA,
+  IN UINT64       ValueB,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *DescriptionA,
+  IN CONST CHAR8  *DescriptionB
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_EQUAL(%s:%llx, %s:%llx)", DescriptionA, ValueA, DescriptionB, ValueB);
+  _assert_true ((ValueA != ValueB), TempStr, FileName, (INT32)LineNumber);
+
+  return (ValueA != ValueB);
+}
+
+/**
+  If Status is equal to Expected, then TRUE is returned.
+  If Status is not equal to Expected, then an assert is triggered and the
+  location of the assert provided by FunctionName, LineNumber, FileName, and
+  Description are recorded and FALSE is returned.
+
+  @param[in]  Status        EFI_STATUS value returned from an API under test.
+  @param[in]  Expected      The expected EFI_STATUS return value from an API
+                            under test.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  Description   Null-terminated ASCII string that is a description
+                            of Status.
+
+  @retval  TRUE   Status is equal to Expected.
+  @retval  FALSE  Status is not equal to Expected.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertStatusEqual (
+  IN EFI_STATUS   Status,
+  IN EFI_STATUS   Expected,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *Description
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_STATUS_EQUAL(%s:%p)", Description, (VOID *)Status);
+  _assert_true ((Status == Expected), TempStr, FileName, (INT32)LineNumber);
+
+  return (Status == Expected);
+}
+
+/**
+  If Pointer is not equal to NULL, then TRUE is returned.
+  If Pointer is equal to NULL, then an assert is triggered and the location of
+  the assert provided by FunctionName, LineNumber, FileName, and PointerName
+  are recorded and FALSE is returned.
+
+  @param[in]  Pointer       Pointer value to be checked against NULL.
+  @param[in]  Expected      The expected EFI_STATUS return value from a function
+                            under test.
+  @param[in]  FunctionName  Null-terminated ASCII string of the function
+                            executing the assert macro.
+  @param[in]  LineNumber    The source file line number of the assert macro.
+  @param[in]  FileName      Null-terminated ASCII string of the filename
+                            executing the assert macro.
+  @param[in]  PointerName   Null-terminated ASCII string that is a description
+                            of Pointer.
+
+  @retval  TRUE   Pointer is not equal to NULL.
+  @retval  FALSE  Pointer is equal to NULL.
+**/
+BOOLEAN
+EFIAPI
+UnitTestAssertNotNull (
+  IN VOID         *Pointer,
+  IN CONST CHAR8  *FunctionName,
+  IN UINTN        LineNumber,
+  IN CONST CHAR8  *FileName,
+  IN CONST CHAR8  *PointerName
+  )
+{
+  CHAR8  TempStr[MAX_STRING_SIZE];
+
+  snprintf (TempStr, sizeof(TempStr), "UT_ASSERT_NOT_NULL(%s:%p)", PointerName, Pointer);
+  _assert_true ((Pointer != NULL), TempStr, FileName, (INT32)LineNumber);
+
+  return (Pointer != NULL);
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c
new file mode 100644
index 0000000000..78df086a28
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/Log.c
@@ -0,0 +1,200 @@
+/**
+  Implemnet UnitTestLib log services
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <UnitTestFrameworkTypes.h>
+#include <Library/UnitTestLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+
+#define UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH  (512)
+#define UNIT_TEST_MAX_LOG_BUFFER                SIZE_16KB
+
+struct _UNIT_TEST_LOG_PREFIX_STRING {
+  UNIT_TEST_STATUS  LogLevel;
+  CHAR8             *String;
+};
+
+struct _UNIT_TEST_LOG_PREFIX_STRING  mLogPrefixStrings[] = {
+  { UNIT_TEST_LOG_LEVEL_ERROR,   "[ERROR]       " },
+  { UNIT_TEST_LOG_LEVEL_WARN,    "[WARNING]     " },
+  { UNIT_TEST_LOG_LEVEL_INFO,    "[INFO]        " },
+  { UNIT_TEST_LOG_LEVEL_VERBOSE, "[VERBOSE]     " }
+};
+
+//
+// Unit-Test Log helper functions
+//
+
+STATIC
+CONST CHAR8*
+GetStringForStatusLogPrefix (
+  IN UINTN  LogLevel
+  )
+{
+  UINTN  Index;
+  CHAR8  *Result;
+
+  Result = NULL;
+  for (Index = 0; Index < ARRAY_SIZE (mLogPrefixStrings); Index++) {
+    if (mLogPrefixStrings[Index].LogLevel == LogLevel) {
+      Result = mLogPrefixStrings[Index].String;
+      break;
+    }
+  }
+  return Result;
+}
+
+STATIC
+EFI_STATUS
+AddStringToUnitTestLog (
+  IN OUT UNIT_TEST    *UnitTest,
+  IN     CONST CHAR8  *String
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Make sure that you're cooking with gas.
+  //
+  if (UnitTest == NULL || String == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // If this is the first log for the test allocate log space
+  if (UnitTest->Log == NULL) {
+    UnitTestLogInit (UnitTest, NULL, 0);
+  }
+
+  if (UnitTest->Log == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate space for unit test log\n"));
+    ASSERT (UnitTest->Log != NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = AsciiStrnCatS (
+             UnitTest->Log,
+             UNIT_TEST_MAX_LOG_BUFFER / sizeof (CHAR8),
+             String,
+             UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH
+             );
+  if(EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to add unit test log string.  Status = %r\n", Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is responsible for initializing the log buffer for a single test. It can
+  be used internally, but may also be consumed by the test framework to add pre-existing
+  data to a log before it's used.
+
+  @param[in,out]  TestHandle    A handle to the test being initialized.
+  @param[in]      Buffer        [Optional] A pointer to pre-existing log data that should
+                                be used to initialize the log. Should include a NULL terminator.
+  @param[in]      BufferSize    [Optional] The size of the pre-existing log data.
+
+**/
+VOID
+EFIAPI
+UnitTestLogInit (
+  IN OUT UNIT_TEST  *Test,
+  IN     UINT8      *Buffer,     OPTIONAL
+  IN     UINTN      BufferSize   OPTIONAL
+  )
+{
+  //
+  // Make sure that you're cooking with gas.
+  //
+  if (Test == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a called with invalid Test parameter\n", __FUNCTION__));
+    return;
+  }
+
+  //
+  // If this is the first log for the test allocate log space
+  //
+  if (Test->Log == NULL) {
+    Test->Log = AllocateZeroPool (UNIT_TEST_MAX_LOG_BUFFER);
+  }
+
+  //
+  //check again to make sure allocate worked
+  //
+  if(Test->Log == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate memory for the log\n"));
+    return;
+  }
+
+  if((Buffer != NULL) && (BufferSize > 0) && ((BufferSize <= UNIT_TEST_MAX_LOG_BUFFER))) {
+    CopyMem (Test->Log, Buffer, BufferSize);
+  }
+}
+
+/**
+  Test logging function that records a messages in the test framework log.
+  Record is associated with the currently executing test case.
+
+  @param[in]  ErrorLevel  The error level of the unit test log message.
+  @param[in]  Format      Formatting string following the format defined in the
+                          MdePkg/Include/Library/PrintLib.h.
+  @param[in]  ...         Print args.
+**/
+VOID
+EFIAPI
+UnitTestLog (
+  IN  UINTN        ErrorLevel,
+  IN  CONST CHAR8  *Format,
+  ...
+  )
+{
+  UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle;
+  CHAR8                       NewFormatString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
+  CHAR8                       LogString[UNIT_TEST_MAX_SINGLE_LOG_STRING_LENGTH];
+  CONST CHAR8                 *LogTypePrefix;
+  VA_LIST                     Marker;
+
+  FrameworkHandle = GetActiveFrameworkHandle ();
+
+  LogTypePrefix = NULL;
+
+  //
+  // Make sure that this unit test log level is enabled.
+  //
+  if ((ErrorLevel & (UINTN)PcdGet32 (PcdUnitTestLogLevel)) == 0) {
+    return;
+  }
+
+  //
+  // If we need to define a new format string...
+  // well... get to it.
+  //
+  LogTypePrefix = GetStringForStatusLogPrefix (ErrorLevel);
+  if (LogTypePrefix != NULL) {
+    AsciiSPrint (NewFormatString, sizeof (NewFormatString), "%a%a", LogTypePrefix, Format);
+  } else {
+    AsciiStrCpyS (NewFormatString, sizeof (NewFormatString), Format);
+  }
+
+  //
+  // Convert the message to an ASCII String
+  //
+  VA_START (Marker, Format);
+  AsciiVSPrint (LogString, sizeof (LogString), NewFormatString, Marker);
+  VA_END (Marker);
+
+  //
+  // Finally, add the string to the log.
+  //
+  AddStringToUnitTestLog (((UNIT_TEST_FRAMEWORK *)FrameworkHandle)->CurrentTest, LogString);
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
new file mode 100644
index 0000000000..d66382e2d3
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTests.c
@@ -0,0 +1,171 @@
+/**
+  UnitTestLib APIs to run unit tests
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UnitTestLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UnitTestResultReportLib.h>
+
+STATIC UNIT_TEST_FRAMEWORK_HANDLE  mFrameworkHandle = NULL;
+
+UNIT_TEST_FRAMEWORK_HANDLE
+GetActiveFrameworkHandle (
+  VOID
+  )
+{
+  ASSERT (mFrameworkHandle != NULL);
+  return mFrameworkHandle;
+}
+
+STATIC
+EFI_STATUS
+RunTestSuite (
+  IN UNIT_TEST_SUITE  *Suite
+  )
+{
+  UNIT_TEST_LIST_ENTRY  *TestEntry;
+  UNIT_TEST             *Test;
+  UNIT_TEST_FRAMEWORK   *ParentFramework;
+
+  TestEntry       = NULL;
+  ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
+
+  if (Suite == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+
+  if (Suite->Setup != NULL) {
+    Suite->Setup ();
+  }
+
+  //
+  // Iterate all tests within the suite
+  //
+  for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));
+       (LIST_ENTRY*)TestEntry != &(Suite->TestCaseList);
+       TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) {
+    Test                         = &TestEntry->UT;
+    ParentFramework->CurrentTest = Test;
+
+    DEBUG ((DEBUG_VERBOSE, "*********************************************************\n"));
+    DEBUG ((DEBUG_VERBOSE, " RUNNING TEST: %a:\n", Test->Description));
+    DEBUG ((DEBUG_VERBOSE, "**********************************************************\n"));
+
+    //
+    // First, check to see whether the test has already been run.
+    // NOTE: This would generally only be the case if a saved state was detected and loaded.
+    //
+    if (Test->Result != UNIT_TEST_PENDING && Test->Result != UNIT_TEST_RUNNING) {
+      DEBUG ((DEBUG_VERBOSE, "Test was run on a previous pass. Skipping.\n"));
+      ParentFramework->CurrentTest = NULL;
+      continue;
+    }
+
+    //
+    // Next, if we're still running, make sure that our test prerequisites are in place.
+    if (Test->Result == UNIT_TEST_PENDING && Test->Prerequisite != NULL) {
+      DEBUG ((DEBUG_VERBOSE, "PREREQ\n"));
+      if (Test->Prerequisite (Test->Context) != UNIT_TEST_PASSED) {
+        DEBUG ((DEBUG_ERROR, "Prerequisite Not Met\n"));
+        Test->Result = UNIT_TEST_ERROR_PREREQUISITE_NOT_MET;
+        ParentFramework->CurrentTest  = NULL;
+        continue;
+      }
+    }
+
+    //
+    // Now we should be ready to call the actual test.
+    // We set the status to UNIT_TEST_RUNNING in case the test needs to reboot
+    // or quit. The UNIT_TEST_RUNNING state will allow the test to resume
+    // but will prevent the Prerequisite from being dispatched a second time.
+    Test->Result = UNIT_TEST_RUNNING;
+    Test->Result = Test->RunTest (Test->Context);
+
+    //
+    // Finally, clean everything up, if need be.
+    if (Test->CleanUp != NULL) {
+      DEBUG ((DEBUG_VERBOSE, "CLEANUP\n"));
+      Test->CleanUp (Test->Context);
+    }
+
+    //
+    // End the test.
+    //
+    ParentFramework->CurrentTest = NULL;
+  }
+
+  if (Suite->Teardown != NULL) {
+    Suite->Teardown ();
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Execute all unit test cases in all unit test suites added to a Framework.
+
+  Once a unit test framework is initialized and all unit test suites and unit
+  test cases are registered, this function will cause the unit test framework to
+  dispatch all unit test cases in sequence and record the results for reporting.
+
+  @param[in]  FrameworkHandle  A handle to the current running framework that
+                               dispatched the test.  Necessary for recording
+                               certain test events with the framework.
+
+  @retval  EFI_SUCCESS            All test cases were dispached.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+**/
+EFI_STATUS
+EFIAPI
+RunAllTestSuites (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  UNIT_TEST_FRAMEWORK         *Framework;
+  UNIT_TEST_SUITE_LIST_ENTRY  *Suite;
+  EFI_STATUS                  Status;
+
+  Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
+  Suite     = NULL;
+
+  if (Framework == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  DEBUG ((DEBUG_VERBOSE, "------------     RUNNING ALL TEST SUITES   --------------\n"));
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  mFrameworkHandle = FrameworkHandle;
+
+  //
+  // Iterate all suites
+  //
+  for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);
+    (LIST_ENTRY *)Suite != &Framework->TestSuiteList;
+    Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) {
+    Status = RunTestSuite (&(Suite->UTS));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error.  %r\n", Status));
+    }
+  }
+
+  //
+  // Save current state so if test is started again it doesn't have to run.  It will just report
+  //
+  SaveFrameworkState (FrameworkHandle, NULL, 0);
+  OutputUnitTestFrameworkReport (FrameworkHandle);
+
+  mFrameworkHandle = NULL;
+
+  return EFI_SUCCESS;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c
new file mode 100644
index 0000000000..cb9c881723
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/RunTestsCmocka.c
@@ -0,0 +1,278 @@
+/** @file
+  UnitTestLib APIs to run unit tests using cmocka
+
+  Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+  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 <UnitTestFrameworkTypes.h>
+#include <Library/UnitTestLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+STATIC UNIT_TEST_FRAMEWORK_HANDLE  mFrameworkHandle = NULL;
+
+UNIT_TEST_FRAMEWORK_HANDLE
+GetActiveFrameworkHandle (
+  VOID
+  )
+{
+  ASSERT (mFrameworkHandle != NULL);
+  return mFrameworkHandle;
+}
+
+//
+// The currently active test suite
+//
+UNIT_TEST_SUITE  *mActiveUnitTestSuite = NULL;
+
+void
+CmockaUnitTestFunctionRunner (
+  void **state
+  )
+{
+  UNIT_TEST            *UnitTest;
+  UNIT_TEST_SUITE      *Suite;
+  UNIT_TEST_FRAMEWORK  *Framework;
+
+  UnitTest  = (UNIT_TEST *)(*state);
+  Suite     = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
+  Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
+
+  if (UnitTest->RunTest == NULL) {
+    UnitTest->Result = UNIT_TEST_SKIPPED;
+  } else {
+    UnitTest->Result = UNIT_TEST_RUNNING;
+
+    Framework->CurrentTest = UnitTest;
+    UnitTest->Result = UnitTest->RunTest (UnitTest->Context);
+    Framework->CurrentTest = NULL;
+
+    // Print out the log messages - This is a partial solution as it
+    // does not get the log into the XML.  Need cmocka changes to support
+    // stdout and stderr in their xml format
+    //
+    if (UnitTest->Log != NULL) {
+      print_message("UnitTest: %s - %s\n", UnitTest->Name, UnitTest->Description);
+      print_message("Log Output Start\n");
+      print_message("%s", UnitTest->Log);
+      print_message("Log Output End\n");
+    }
+  }
+}
+
+int
+CmockaUnitTestSetupFunctionRunner (
+  void **state
+  )
+{
+  UNIT_TEST            *UnitTest;
+  UNIT_TEST_SUITE      *Suite;
+  UNIT_TEST_FRAMEWORK  *Framework;
+  UNIT_TEST_STATUS     Result;
+
+  UnitTest  = (UNIT_TEST *)(*state);
+  Suite     = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
+  Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
+
+  if (UnitTest->Prerequisite == NULL) {
+    return 0;
+  }
+
+  Framework->CurrentTest = UnitTest;
+  Result = UnitTest->Prerequisite (UnitTest->Context);
+  Framework->CurrentTest = NULL;
+
+  //
+  // Return 0 for success.  Non-zero for error.
+  //
+  return (int)Result;
+}
+
+int
+CmockaUnitTestTeardownFunctionRunner (
+  void **state
+  )
+{
+  UNIT_TEST            *UnitTest;
+  UNIT_TEST_SUITE      *Suite;
+  UNIT_TEST_FRAMEWORK  *Framework;
+
+  UnitTest  = (UNIT_TEST *)(*state);
+  Suite     = (UNIT_TEST_SUITE *)(UnitTest->ParentSuite);
+  Framework = (UNIT_TEST_FRAMEWORK *)(Suite->ParentFramework);
+
+  if (UnitTest->CleanUp == NULL) {
+    return 0;
+  }
+
+  Framework->CurrentTest = UnitTest;
+  UnitTest->CleanUp (UnitTest->Context);
+  Framework->CurrentTest = NULL;
+  //
+  // Return 0 for success.  Non-zero for error.
+  //
+  return 0;
+}
+
+int
+CmockaUnitTestSuiteSetupFunctionRunner (
+  void **state
+  )
+{
+  if (mActiveUnitTestSuite == NULL) {
+    return -1;
+  }
+  if (mActiveUnitTestSuite->Setup == NULL) {
+    return 0;
+  }
+
+  mActiveUnitTestSuite->Setup ();
+  //
+  // Always succeed
+  //
+  return 0;
+}
+
+int
+CmockaUnitTestSuiteTeardownFunctionRunner (
+  void **state
+  )
+{
+  if (mActiveUnitTestSuite == NULL) {
+    return -1;
+  }
+  if (mActiveUnitTestSuite->Teardown == NULL) {
+    return 0;
+  }
+
+  mActiveUnitTestSuite->Teardown ();
+  //
+  // Always succeed
+  //
+  return 0;
+}
+
+STATIC
+EFI_STATUS
+RunTestSuite (
+  IN UNIT_TEST_SUITE  *Suite
+  )
+{
+  UNIT_TEST_LIST_ENTRY  *TestEntry;
+  UNIT_TEST             *UnitTest;
+  struct CMUnitTest     *Tests;
+  UINTN                 Index;
+
+  TestEntry       = NULL;
+
+  if (Suite == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  DEBUG ((DEBUG_VERBOSE, "RUNNING TEST SUITE: %a\n", Suite->Title));
+  DEBUG ((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+
+  //
+  // Allocate buffer of CMUnitTest entries
+  //
+  Tests = AllocateZeroPool (Suite->NumTests * sizeof (struct CMUnitTest));
+  ASSERT (Tests != NULL);
+
+  //
+  // Populate buffer of CMUnitTest entries
+  //
+  Index = 0;
+  for (TestEntry = (UNIT_TEST_LIST_ENTRY *)GetFirstNode (&(Suite->TestCaseList));
+       (LIST_ENTRY *)TestEntry != &(Suite->TestCaseList);
+       TestEntry = (UNIT_TEST_LIST_ENTRY *)GetNextNode (&(Suite->TestCaseList), (LIST_ENTRY *)TestEntry)) {
+    UnitTest                   = &TestEntry->UT;
+    Tests[Index].name          = UnitTest->Description;
+    Tests[Index].test_func     = CmockaUnitTestFunctionRunner;
+    Tests[Index].setup_func    = CmockaUnitTestSetupFunctionRunner;
+    Tests[Index].teardown_func = CmockaUnitTestTeardownFunctionRunner;
+    Tests[Index].initial_state = UnitTest;
+    Index++;
+  }
+  ASSERT (Index == Suite->NumTests);
+
+  //
+  // Run all unit tests in a test suite
+  //
+  mActiveUnitTestSuite = Suite;
+  _cmocka_run_group_tests (
+    Suite->Title,
+    Tests,
+    Suite->NumTests,
+    CmockaUnitTestSuiteSetupFunctionRunner,
+    CmockaUnitTestSuiteTeardownFunctionRunner
+    );
+  mActiveUnitTestSuite = NULL;
+  FreePool (Tests);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Execute all unit test cases in all unit test suites added to a Framework.
+
+  Once a unit test framework is initialized and all unit test suites and unit
+  test cases are registered, this function will cause the unit test framework to
+  dispatch all unit test cases in sequence and record the results for reporting.
+
+  @param[in]  FrameworkHandle  A handle to the current running framework that
+                               dispatched the test.  Necessary for recording
+                               certain test events with the framework.
+
+  @retval  EFI_SUCCESS            All test cases were dispached.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+**/
+EFI_STATUS
+EFIAPI
+RunAllTestSuites (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  UNIT_TEST_FRAMEWORK         *Framework;
+  UNIT_TEST_SUITE_LIST_ENTRY  *Suite;
+  EFI_STATUS                  Status;
+
+  Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
+  Suite     = NULL;
+
+  if (Framework == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  DEBUG((DEBUG_VERBOSE, "------------     RUNNING ALL TEST SUITES   --------------\n"));
+  DEBUG((DEBUG_VERBOSE, "---------------------------------------------------------\n"));
+  mFrameworkHandle = FrameworkHandle;
+
+  //
+  // Iterate all suites
+  //
+  for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetFirstNode (&Framework->TestSuiteList);
+    (LIST_ENTRY *)Suite != &Framework->TestSuiteList;
+    Suite = (UNIT_TEST_SUITE_LIST_ENTRY *)GetNextNode (&Framework->TestSuiteList, (LIST_ENTRY *)Suite)) {
+    Status = RunTestSuite (&(Suite->UTS));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Test Suite Failed with Error.  %r\n", Status));
+    }
+  }
+
+  mFrameworkHandle = NULL;
+
+  return EFI_SUCCESS;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c
new file mode 100644
index 0000000000..e37c78a41d
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.c
@@ -0,0 +1,853 @@
+/**
+  Implement UnitTestLib
+
+  Copyright (c) Microsoft Corporation.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UnitTestLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UnitTestPersistenceLib.h>
+#include <Library/UnitTestResultReportLib.h>
+
+///
+/// Forward declaration of prototype
+///
+STATIC
+VOID
+UpdateTestFromSave (
+  IN OUT UNIT_TEST              *Test,
+  IN     UNIT_TEST_SAVE_HEADER  *SavedState
+  );
+
+/**
+  This function will determine whether the short name violates any rules that would
+  prevent it from being used as a reporting name or as a serialization name.
+
+  Example: If the name cannot be serialized to a filesystem file name.
+
+  @param[in]  ShortTitleString  A pointer to the short title string to be evaluated.
+
+  @retval  TRUE   The string is acceptable.
+  @retval  FALSE  The string should not be used.
+
+**/
+STATIC
+BOOLEAN
+IsFrameworkShortNameValid (
+  IN CHAR8  *ShortTitleString
+  )
+{
+  // TODO: Finish this function.
+  return TRUE;
+}
+
+STATIC
+CHAR8*
+AllocateAndCopyString (
+  IN CHAR8  *StringToCopy
+  )
+{
+  CHAR8  *NewString;
+  UINTN  NewStringLength;
+
+  NewString = NULL;
+  NewStringLength = AsciiStrnLenS (StringToCopy, UNIT_TEST_MAX_STRING_LENGTH) + 1;
+  NewString = AllocatePool (NewStringLength * sizeof( CHAR8 ));
+  if (NewString != NULL) {
+    AsciiStrCpyS (NewString, NewStringLength, StringToCopy);
+  }
+  return NewString;
+}
+
+STATIC
+VOID
+SetFrameworkFingerprint (
+  OUT UINT8                *Fingerprint,
+  IN  UNIT_TEST_FRAMEWORK  *Framework
+  )
+{
+  UINT32  NewFingerprint;
+
+  // For this one we'll just use the title and version as the unique fingerprint.
+  NewFingerprint = CalculateCrc32( Framework->Title, (AsciiStrLen( Framework->Title ) * sizeof( CHAR8 )) );
+  NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Framework->VersionString, (AsciiStrLen( Framework->VersionString ) * sizeof( CHAR8 )) );
+
+  CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );
+  return;
+}
+
+STATIC
+VOID
+SetSuiteFingerprint (
+  OUT UINT8                *Fingerprint,
+  IN  UNIT_TEST_FRAMEWORK  *Framework,
+  IN  UNIT_TEST_SUITE      *Suite
+  )
+{
+  UINT32  NewFingerprint;
+
+  // For this one, we'll use the fingerprint from the framework, and the title of the suite.
+  NewFingerprint = CalculateCrc32( &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE );
+  NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Title, (AsciiStrLen( Suite->Title ) * sizeof( CHAR8 )) );
+  NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Suite->Name, (AsciiStrLen(Suite->Name) * sizeof(CHAR8)) );
+
+  CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );
+  return;
+}
+
+STATIC
+VOID
+SetTestFingerprint (
+  OUT UINT8            *Fingerprint,
+  IN  UNIT_TEST_SUITE  *Suite,
+  IN  UNIT_TEST        *Test
+  )
+{
+  UINT32  NewFingerprint;
+
+  // For this one, we'll use the fingerprint from the suite, and the description and classname of the test.
+  NewFingerprint = CalculateCrc32( &Suite->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE );
+  NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Description, (AsciiStrLen( Test->Description ) * sizeof( CHAR8 )) );
+  NewFingerprint = (NewFingerprint >> 8) ^ CalculateCrc32( Test->Name, (AsciiStrLen(Test->Name) * sizeof(CHAR8)) );
+
+  CopyMem( Fingerprint, &NewFingerprint, UNIT_TEST_FINGERPRINT_SIZE );
+  return;
+}
+
+STATIC
+BOOLEAN
+CompareFingerprints (
+  IN UINT8  *FingerprintA,
+  IN UINT8  *FingerprintB
+  )
+{
+  return (CompareMem( FingerprintA, FingerprintB, UNIT_TEST_FINGERPRINT_SIZE ) == 0);
+}
+
+/**
+  Cleanup a test framework.
+
+  After tests are run, this will teardown the entire framework and free all
+  allocated data within.
+
+  @param[in]  FrameworkHandle  A handle to the current running framework that
+                               dispatched the test.  Necessary for recording
+                               certain test events with the framework.
+
+  @retval  EFI_SUCCESS            All resources associated with framework were
+                                  freed.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+**/
+EFI_STATUS
+EFIAPI
+FreeUnitTestFramework (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  // TODO: Finish this function.
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FreeUnitTestSuiteEntry (
+  IN UNIT_TEST_SUITE_LIST_ENTRY  *SuiteEntry
+  )
+{
+  // TODO: Finish this function.
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FreeUnitTestTestEntry (
+  IN UNIT_TEST_LIST_ENTRY  *TestEntry
+  )
+{
+  // TODO: Finish this function.
+  return EFI_SUCCESS;
+}
+
+/**
+  Method to Initialize the Unit Test framework.  This function registers the
+  test name and also initializes the internal state of the test framework to
+  receive any new suites and tests.
+
+  @param[out]  FrameworkHandle  Unit test framework to be created.
+  @param[in]   Title            Null-terminated ASCII string that is the user
+                                friendly name of the framework. String is
+                                copied.
+  @param[in]   ShortTitle       Null-terminaled ASCII short string that is the
+                                short name of the framework with no spaces.
+                                String is copied.
+  @param[in]   VersionString    Null-terminaled ASCII version string for the
+                                framework. String is copied.
+
+  @retval  EFI_SUCCESS            The unit test framework was initialized.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+  @retval  EFI_INVALID_PARAMETER  Title is NULL.
+  @retval  EFI_INVALID_PARAMETER  ShortTitle is NULL.
+  @retval  EFI_INVALID_PARAMETER  VersionString is NULL.
+  @retval  EFI_INVALID_PARAMETER  ShortTitle is invalid.
+  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
+                                  initialize the unit test framework.
+**/
+EFI_STATUS
+EFIAPI
+InitUnitTestFramework (
+  OUT UNIT_TEST_FRAMEWORK_HANDLE  *FrameworkHandle,
+  IN  CHAR8                       *Title,
+  IN  CHAR8                       *ShortTitle,
+  IN  CHAR8                       *VersionString
+  )
+{
+  EFI_STATUS                  Status;
+  UNIT_TEST_FRAMEWORK_HANDLE  NewFrameworkHandle;
+  UNIT_TEST_FRAMEWORK         *NewFramework;
+  UNIT_TEST_SAVE_HEADER       *SavedState;
+
+  Status       = EFI_SUCCESS;
+  NewFramework = NULL;
+
+  //
+  // First, check all pointers and make sure nothing's broked.
+  //
+  if (FrameworkHandle == NULL || Title == NULL ||
+      ShortTitle == NULL || VersionString == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Next, determine whether all of the strings are good to use.
+  //
+  if (!IsFrameworkShortNameValid (ShortTitle)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Next, set aside some space to start messing with the framework.
+  //
+  NewFramework = AllocateZeroPool (sizeof (UNIT_TEST_FRAMEWORK));
+  if (NewFramework == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Next, set up all the test data.
+  //
+  NewFrameworkHandle          = (UNIT_TEST_FRAMEWORK_HANDLE)NewFramework;
+  NewFramework->Title         = AllocateAndCopyString (Title);
+  NewFramework->ShortTitle    = AllocateAndCopyString (ShortTitle);
+  NewFramework->VersionString = AllocateAndCopyString (VersionString);
+  NewFramework->Log           = NULL;
+  NewFramework->CurrentTest   = NULL;
+  NewFramework->SavedState    = NULL;
+  if (NewFramework->Title == NULL ||
+      NewFramework->ShortTitle == NULL ||
+      NewFramework->VersionString == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  InitializeListHead (&(NewFramework->TestSuiteList));
+
+  //
+  // Create the framework fingerprint.
+  //
+  SetFrameworkFingerprint (&NewFramework->Fingerprint[0], NewFramework);
+
+  //
+  // If there is a persisted context, load it now.
+  //
+  if (DoesCacheExist (NewFrameworkHandle)) {
+    SavedState = (UNIT_TEST_SAVE_HEADER *)NewFramework->SavedState;
+    Status = LoadUnitTestCache (NewFrameworkHandle, &SavedState);
+    if (EFI_ERROR (Status)) {
+      //
+      // Don't actually report it as an error, but emit a warning.
+      //
+      DEBUG (( DEBUG_ERROR, "%a - Cache was detected, but failed to load.\n", __FUNCTION__ ));
+      Status = EFI_SUCCESS;
+    }
+  }
+
+Exit:
+  //
+  // If we're good, then let's copy the framework.
+  //
+  if (!EFI_ERROR (Status)) {
+    *FrameworkHandle = NewFrameworkHandle;
+  } else {
+    //
+    // Otherwise, we need to undo this horrible thing that we've done.
+    //
+    FreeUnitTestFramework (NewFrameworkHandle);
+  }
+
+  return Status;
+}
+
+/**
+  Registers a Unit Test Suite in the Unit Test Framework.
+  At least one test suite must be registered, because all test cases must be
+  within a unit test suite.
+
+  @param[out]  SuiteHandle      Unit test suite to create
+  @param[in]   FrameworkHandle  Unit test framework to add unit test suite to
+  @param[in]   Title            Null-terminated ASCII string that is the user
+                                friendly name of the test suite.  String is
+                                copied.
+  @param[in]   Name             Null-terminated ASCII string that is the short
+                                name of the test suite with no spaces.  String
+                                is copied.
+  @param[in]   Setup            Setup function, runs before suite.  This is an
+                                optional parameter that may be NULL.
+  @param[in]   Teardown         Teardown function, runs after suite.  This is an
+                                optional parameter that may be NULL.
+
+  @retval  EFI_SUCCESS            The unit test suite was created.
+  @retval  EFI_INVALID_PARAMETER  SuiteHandle is NULL.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+  @retval  EFI_INVALID_PARAMETER  Title is NULL.
+  @retval  EFI_INVALID_PARAMETER  Name is NULL.
+  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
+                                  initialize the unit test suite.
+**/
+EFI_STATUS
+EFIAPI
+CreateUnitTestSuite (
+  OUT UNIT_TEST_SUITE_HANDLE      *SuiteHandle,
+  IN  UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  IN  CHAR8                       *Title,
+  IN  CHAR8                       *Name,
+  IN  UNIT_TEST_SUITE_SETUP       Setup     OPTIONAL,
+  IN  UNIT_TEST_SUITE_TEARDOWN    Teardown  OPTIONAL
+  )
+{
+  EFI_STATUS                  Status;
+  UNIT_TEST_SUITE_LIST_ENTRY  *NewSuiteEntry;
+  UNIT_TEST_FRAMEWORK         *Framework;
+
+  Status = EFI_SUCCESS;
+  Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
+
+  //
+  // First, let's check to make sure that our parameters look good.
+  //
+  if ((SuiteHandle == NULL) || (Framework == NULL) || (Title == NULL) || (Name == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create the new entry.
+  //
+  NewSuiteEntry = AllocateZeroPool (sizeof (UNIT_TEST_SUITE_LIST_ENTRY));
+  if (NewSuiteEntry == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Copy the fields we think we need.
+  //
+  NewSuiteEntry->UTS.NumTests         = 0;
+  NewSuiteEntry->UTS.Title            = AllocateAndCopyString (Title);
+  NewSuiteEntry->UTS.Name             = AllocateAndCopyString (Name);
+  NewSuiteEntry->UTS.Setup            = Setup;
+  NewSuiteEntry->UTS.Teardown         = Teardown;
+  NewSuiteEntry->UTS.ParentFramework  = FrameworkHandle;
+  InitializeListHead (&(NewSuiteEntry->Entry));             // List entry for sibling suites.
+  InitializeListHead (&(NewSuiteEntry->UTS.TestCaseList));  // List entry for child tests.
+  if (NewSuiteEntry->UTS.Title == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  if (NewSuiteEntry->UTS.Name == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Create the suite fingerprint.
+  //
+  SetSuiteFingerprint( &NewSuiteEntry->UTS.Fingerprint[0], Framework, &NewSuiteEntry->UTS );
+
+Exit:
+  //
+  // If everything is going well, add the new suite to the tail list for the framework.
+  //
+  if (!EFI_ERROR( Status )) {
+    InsertTailList (&(Framework->TestSuiteList), (LIST_ENTRY *)NewSuiteEntry);
+    *SuiteHandle = (UNIT_TEST_SUITE_HANDLE)(&NewSuiteEntry->UTS);
+  } else {
+    //
+    // Otherwise, make with the destruction.
+    //
+    FreeUnitTestSuiteEntry (NewSuiteEntry);
+  }
+
+  return Status;
+}
+
+/**
+  Adds test case to Suite
+
+  @param[in]  SuiteHandle   Unit test suite to add test to.
+  @param[in]  Description   Null-terminated ASCII string that is the user
+                            friendly description of a test.  String is copied.
+  @param[in]  Name          Null-terminated ASCII string that is the short name
+                            of the test with no spaces.  String is copied.
+  @param[in]  Function      Unit test function.
+  @param[in]  Prerequisite  Prerequisite function, runs before test.  This is
+                            an optional parameter that may be NULL.
+  @param[in]  CleanUp       Clean up function, runs after test.  This is an
+                            optional parameter that may be NULL.
+  @param[in]  Context       Pointer to context.    This is an optional parameter
+                            that may be NULL.
+
+  @retval  EFI_SUCCESS            The unit test case was added to Suite.
+  @retval  EFI_INVALID_PARAMETER  SuiteHandle is NULL.
+  @retval  EFI_INVALID_PARAMETER  Description is NULL.
+  @retval  EFI_INVALID_PARAMETER  Name is NULL.
+  @retval  EFI_INVALID_PARAMETER  Function is NULL.
+  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
+                                  add the unit test case to Suite.
+**/
+EFI_STATUS
+EFIAPI
+AddTestCase (
+  IN UNIT_TEST_SUITE_HANDLE  SuiteHandle,
+  IN CHAR8                   *Description,
+  IN CHAR8                   *Name,
+  IN UNIT_TEST_FUNCTION      Function,
+  IN UNIT_TEST_PREREQUISITE  Prerequisite  OPTIONAL,
+  IN UNIT_TEST_CLEANUP       CleanUp       OPTIONAL,
+  IN UNIT_TEST_CONTEXT       Context       OPTIONAL
+  )
+{
+  EFI_STATUS            Status;
+  UNIT_TEST_LIST_ENTRY  *NewTestEntry;
+  UNIT_TEST_FRAMEWORK   *ParentFramework;
+  UNIT_TEST_SUITE       *Suite;
+
+  Status          = EFI_SUCCESS;
+  Suite           = (UNIT_TEST_SUITE *)SuiteHandle;
+  ParentFramework = (UNIT_TEST_FRAMEWORK *)Suite->ParentFramework;
+
+  //
+  // First, let's check to make sure that our parameters look good.
+  //
+  if ((Suite == NULL) || (Description == NULL) || (Name == NULL) || (Function == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create the new entry.
+  NewTestEntry = AllocateZeroPool (sizeof( UNIT_TEST_LIST_ENTRY ));
+  if (NewTestEntry == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Copy the fields we think we need.
+  NewTestEntry->UT.Description       = AllocateAndCopyString (Description);
+  NewTestEntry->UT.Name              = AllocateAndCopyString (Name);
+  NewTestEntry->UT.FailureType       = FAILURETYPE_NOFAILURE;
+  NewTestEntry->UT.FailureMessage[0] = '\0';
+  NewTestEntry->UT.Log               = NULL;
+  NewTestEntry->UT.Prerequisite      = Prerequisite;
+  NewTestEntry->UT.CleanUp           = CleanUp;
+  NewTestEntry->UT.RunTest           = Function;
+  NewTestEntry->UT.Context           = Context;
+  NewTestEntry->UT.Result            = UNIT_TEST_PENDING;
+  NewTestEntry->UT.ParentSuite       = SuiteHandle;
+  InitializeListHead (&(NewTestEntry->Entry));  // List entry for sibling tests.
+  if (NewTestEntry->UT.Description == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  if (NewTestEntry->UT.Name == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Create the test fingerprint.
+  //
+  SetTestFingerprint (&NewTestEntry->UT.Fingerprint[0], Suite, &NewTestEntry->UT);
+
+  // TODO: Make sure that duplicate fingerprints cannot be created.
+
+  //
+  // If there is saved test data, update this record.
+  //
+  if (ParentFramework->SavedState != NULL) {
+    UpdateTestFromSave (&NewTestEntry->UT, ParentFramework->SavedState);
+  }
+
+Exit:
+  //
+  // If everything is going well, add the new suite to the tail list for the framework.
+  //
+  if (!EFI_ERROR (Status)) {
+    InsertTailList (&(Suite->TestCaseList), (LIST_ENTRY*)NewTestEntry);
+    Suite->NumTests++;
+  } else {
+    //
+    // Otherwise, make with the destruction.
+    //
+    FreeUnitTestTestEntry (NewTestEntry);
+  }
+
+  return Status;
+}
+
+STATIC
+VOID
+UpdateTestFromSave (
+  IN OUT UNIT_TEST              *Test,
+  IN     UNIT_TEST_SAVE_HEADER  *SavedState
+  )
+{
+  UNIT_TEST_SAVE_TEST     *CurrentTest;
+  UNIT_TEST_SAVE_TEST     *MatchingTest;
+  UINT8                   *FloatingPointer;
+  UNIT_TEST_SAVE_CONTEXT  *SavedContext;
+  UINTN                   Index;
+
+  //
+  // First, evaluate the inputs.
+  //
+  if (Test == NULL || SavedState == NULL) {
+    return;
+  }
+  if (SavedState->TestCount == 0) {
+    return;
+  }
+
+  //
+  // Next, determine whether a matching test can be found.
+  // Start at the beginning.
+  //
+  MatchingTest    = NULL;
+  FloatingPointer = (UINT8 *)SavedState + sizeof (*SavedState);
+  for (Index = 0; Index < SavedState->TestCount; Index++) {
+    CurrentTest = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
+    if (CompareFingerprints (&Test->Fingerprint[0], &CurrentTest->Fingerprint[0])) {
+      MatchingTest = CurrentTest;
+      //
+      // If there's a saved context, it's important that we iterate through the entire list.
+      //
+      if (!SavedState->HasSavedContext) {
+        break;
+      }
+    }
+
+    //
+    // If we didn't find it, we have to increment to the next test.
+    //
+    FloatingPointer = (UINT8 *)CurrentTest + CurrentTest->Size;
+  }
+
+  //
+  // If a matching test was found, copy the status.
+  //
+  if (MatchingTest) {
+    //
+    // Override the test status with the saved status.
+    //
+    Test->Result = MatchingTest->Result;
+
+    Test->FailureType = MatchingTest->FailureType;
+    AsciiStrnCpyS (
+      &Test->FailureMessage[0],
+      UNIT_TEST_TESTFAILUREMSG_LENGTH,
+      &MatchingTest->FailureMessage[0],
+      UNIT_TEST_TESTFAILUREMSG_LENGTH
+      );
+
+    //
+    // If there is a log string associated, grab that.
+    // We can tell that there's a log string because the "size" will be larger than
+    // the structure size.
+    // IMPORTANT NOTE: There are security implications here.
+    //                 This data is user-supplied and we're about to play kinda
+    //                 fast and loose with data buffers.
+    //
+    if (MatchingTest->Size > sizeof (UNIT_TEST_SAVE_TEST)) {
+      UnitTestLogInit (Test, (UINT8 *)MatchingTest->Log, MatchingTest->Size - sizeof (UNIT_TEST_SAVE_TEST));
+    }
+  }
+
+  //
+  // If the saved context exists and matches this test, grab it, too.
+  //
+  if (SavedState->HasSavedContext) {
+    //
+    // If there was a saved context, the "matching test" loop will have placed the FloatingPointer
+    // at the beginning of the context structure.
+    //
+    SavedContext = (UNIT_TEST_SAVE_CONTEXT *)FloatingPointer;
+    if ((SavedContext->Size - sizeof (UNIT_TEST_SAVE_CONTEXT)) > 0 &&
+        CompareFingerprints (&Test->Fingerprint[0], &SavedContext->Fingerprint[0])) {
+      //
+      // Override the test context with the saved context.
+      //
+      Test->Context = (VOID*)SavedContext->Data;
+    }
+  }
+}
+
+STATIC
+UNIT_TEST_SAVE_HEADER*
+SerializeState (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  IN UNIT_TEST_CONTEXT           ContextToSave,      OPTIONAL
+  IN UINTN                       ContextToSaveSize
+  )
+{
+  UNIT_TEST_FRAMEWORK     *Framework;
+  UNIT_TEST_SAVE_HEADER   *Header;
+  LIST_ENTRY              *SuiteListHead;
+  LIST_ENTRY              *Suite;
+  LIST_ENTRY              *TestListHead;
+  LIST_ENTRY              *Test;
+  UINT32                  TestCount;
+  UINT32                  TotalSize;
+  UINTN                   LogSize;
+  UNIT_TEST_SAVE_TEST     *TestSaveData;
+  UNIT_TEST_SAVE_CONTEXT  *TestSaveContext;
+  UNIT_TEST               *UnitTest;
+  UINT8                   *FloatingPointer;
+
+  Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
+  Header    = NULL;
+
+  //
+  // First, let's not make assumptions about the parameters.
+  //
+  if (Framework == NULL ||
+      (ContextToSave != NULL && ContextToSaveSize == 0) ||
+      ContextToSaveSize > MAX_UINT32) {
+    return NULL;
+  }
+
+  //
+  // Next, we've gotta figure out the resources that will be required to serialize the
+  // the framework state so that we can persist it.
+  // To start with, we're gonna need a header.
+  //
+  TotalSize = sizeof (UNIT_TEST_SAVE_HEADER);
+  //
+  // Now we need to figure out how many tests there are.
+  //
+  TestCount = 0;
+  //
+  // Iterate all suites.
+  //
+  SuiteListHead = &Framework->TestSuiteList;
+  for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
+    //
+    // Iterate all tests within the suite.
+    //
+    TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
+    for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
+      UnitTest = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
+      //
+      // Account for the size of a test structure.
+      //
+      TotalSize += sizeof( UNIT_TEST_SAVE_TEST );
+      //
+      // If there's a log, make sure to account for the log size.
+      //
+      if (UnitTest->Log != NULL)     {
+        //
+        // The +1 is for the NULL character. Can't forget the NULL character.
+        //
+        LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
+        ASSERT (LogSize < MAX_UINT32);
+        TotalSize += (UINT32)LogSize;
+      }
+      //
+      // Increment the test count.
+      //
+      TestCount++;
+    }
+  }
+  //
+  // If there are no tests, we're done here.
+  //
+  if (TestCount == 0) {
+    return NULL;
+  }
+  //
+  // Add room for the context, if there is one.
+  //
+  if (ContextToSave != NULL) {
+    TotalSize += sizeof (UNIT_TEST_SAVE_CONTEXT) + (UINT32)ContextToSaveSize;
+  }
+
+  //
+  // Now that we know the size, we need to allocate space for the serialized output.
+  //
+  Header = AllocateZeroPool (TotalSize);
+  if (Header == NULL) {
+    return NULL;
+  }
+
+  //
+  // Alright, let's start setting up some data.
+  //
+  Header->Version         = UNIT_TEST_PERSISTENCE_LIB_VERSION;
+  Header->SaveStateSize   = TotalSize;
+  CopyMem (&Header->Fingerprint[0], &Framework->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
+  CopyMem (&Header->StartTime, &Framework->StartTime, sizeof (EFI_TIME));
+  Header->TestCount       = TestCount;
+  Header->HasSavedContext = FALSE;
+
+  //
+  // Start adding all of the test cases.
+  // Set the floating pointer to the start of the current test save buffer.
+  //
+  FloatingPointer = (UINT8*)Header + sizeof( UNIT_TEST_SAVE_HEADER );
+  //
+  // Iterate all suites.
+  //
+  SuiteListHead = &Framework->TestSuiteList;
+  for (Suite = GetFirstNode (SuiteListHead); Suite != SuiteListHead; Suite = GetNextNode (SuiteListHead, Suite)) {
+    //
+    // Iterate all tests within the suite.
+    //
+    TestListHead = &((UNIT_TEST_SUITE_LIST_ENTRY *)Suite)->UTS.TestCaseList;
+    for (Test = GetFirstNode (TestListHead); Test != TestListHead; Test = GetNextNode (TestListHead, Test)) {
+      TestSaveData  = (UNIT_TEST_SAVE_TEST *)FloatingPointer;
+      UnitTest      = &((UNIT_TEST_LIST_ENTRY *)Test)->UT;
+
+      //
+      // Save the fingerprint.
+      //
+      CopyMem (&TestSaveData->Fingerprint[0], &UnitTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
+
+      //
+      // Save the result.
+      //
+      TestSaveData->Result = UnitTest->Result;
+      TestSaveData->FailureType = UnitTest->FailureType;
+      AsciiStrnCpyS (&TestSaveData->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH, &UnitTest->FailureMessage[0], UNIT_TEST_TESTFAILUREMSG_LENGTH);
+
+
+      //
+      // If there is a log, save the log.
+      //
+      FloatingPointer += sizeof (UNIT_TEST_SAVE_TEST);
+      if (UnitTest->Log != NULL) {
+        //
+        // The +1 is for the NULL character. Can't forget the NULL character.
+        //
+        LogSize = (AsciiStrLen (UnitTest->Log) + 1) * sizeof (CHAR8);
+        CopyMem (FloatingPointer, UnitTest->Log, LogSize);
+        FloatingPointer += LogSize;
+      }
+
+      //
+      // Update the size once the structure is complete.
+      // NOTE: Should this be a straight cast without validation?
+      //
+      TestSaveData->Size = (UINT32)(FloatingPointer - (UINT8 *)TestSaveData);
+    }
+  }
+
+  //
+  // If there is a context to save, let's do that now.
+  //
+  if (ContextToSave != NULL && Framework->CurrentTest != NULL) {
+    TestSaveContext         = (UNIT_TEST_SAVE_CONTEXT*)FloatingPointer;
+    TestSaveContext->Size   = (UINT32)ContextToSaveSize + sizeof (UNIT_TEST_SAVE_CONTEXT);
+    CopyMem (&TestSaveContext->Fingerprint[0], &Framework->CurrentTest->Fingerprint[0], UNIT_TEST_FINGERPRINT_SIZE);
+    CopyMem (((UINT8 *)TestSaveContext + sizeof (UNIT_TEST_SAVE_CONTEXT)), ContextToSave, ContextToSaveSize);
+    Header->HasSavedContext = TRUE;
+  }
+
+  return Header;
+}
+
+/**
+  Leverages a framework-specific mechanism (see UnitTestPersistenceLib if you're
+  a framework author) to save the state of the executing framework along with
+  any allocated data so that the test may be resumed upon reentry. A test case
+  should pass any needed context (which, to prevent an infinite loop, should be
+  at least the current execution count) which will be saved by the framework and
+  passed to the test case upon resume.
+
+  Generally called from within a test case prior to quitting or rebooting.
+
+  @param[in]  FrameworkHandle    A handle to the current running framework that
+                                 dispatched the test.  Necessary for recording
+                                 certain test events with the framework.
+  @param[in]  ContextToSave      A buffer of test case-specific data to be saved
+                                 along with framework state.  Will be passed as
+                                 "Context" to the test case upon resume.  This
+                                 is an optional parameter that may be NULL.
+  @param[in]  ContextToSaveSize  Size of the ContextToSave buffer.
+
+  @retval  EFI_SUCCESS            The framework state and context were saved.
+  @retval  EFI_INVALID_PARAMETER  FrameworkHandle is NULL.
+  @retval  EFI_INVALID_PARAMETER  ContextToSave is not NULL and
+                                  ContextToSaveSize is 0.
+  @retval  EFI_INVALID_PARAMETER  ContextToSave is >= 4GB.
+  @retval  EFI_OUT_OF_RESOURCES   There are not enough resources available to
+                                  save the framework and context state.
+  @retval  EFI_DEVICE_ERROR       The framework and context state could not be
+                                  saved to a persistent storage device due to a
+                                  device error.
+**/
+EFI_STATUS
+EFIAPI
+SaveFrameworkState (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  IN UNIT_TEST_CONTEXT           ContextToSave     OPTIONAL,
+  IN UINTN                       ContextToSaveSize
+  )
+{
+  EFI_STATUS             Status;
+  UNIT_TEST_SAVE_HEADER  *Header;
+
+  Header = NULL;
+
+  //
+  // First, let's not make assumptions about the parameters.
+  //
+  if (FrameworkHandle == NULL ||
+      (ContextToSave != NULL && ContextToSaveSize == 0) ||
+      ContextToSaveSize > MAX_UINT32) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Now, let's package up all the data for saving.
+  //
+  Header = SerializeState (FrameworkHandle, ContextToSave, ContextToSaveSize);
+  if (Header == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // All that should be left to do is save it using the associated persistence lib.
+  //
+  Status = SaveUnitTestCache (FrameworkHandle, Header);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Could not save state! %r\n", __FUNCTION__, Status));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Free data that was used.
+  //
+  FreePool (Header);
+
+  return Status;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
new file mode 100644
index 0000000000..96e40e973c
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestLib
+  MODULE_UNI_FILE = UnitTestLib.uni
+  FILE_GUID       = 98CEF9CA-15CE-40A3-ADE8-C299953CD0F6
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_DRIVER
+  LIBRARY_CLASS   = UnitTestLib|PEIM DXE_DRIVER DXE_SMM_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+[Sources]
+  UnitTestLib.c
+  RunTests.c
+  Assert.c
+  Log.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  PcdLib
+  DebugLib
+  MemoryAllocationLib
+  UnitTestPersistenceLib
+  UnitTestResultReportLib
+
+[Pcd]
+  gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel  ## CONSUMES
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni
new file mode 100644
index 0000000000..fe7c9c7f71
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.uni
@@ -0,0 +1,11 @@
+// /** @file
+// Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Library to support Unit Testing from PEI, DXE, SMM, and UEFI Applications."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
new file mode 100644
index 0000000000..b12af91576
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.inf
@@ -0,0 +1,38 @@
+## @file
+# Library to support Unit Testing from host environments using Cmocka services.
+#
+# Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestLibCmocka
+  MODULE_UNI_FILE = UnitTestLibCmocka.uni
+  FILE_GUID       = C800595F-45A3-45A1-8B50-28F01C2A5A4F
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_DRIVER
+  LIBRARY_CLASS   = UnitTestLib|HOST_APPLICATION
+
+[Sources]
+  UnitTestLib.c
+  RunTestsCmocka.c
+  AssertCmocka.c
+  Log.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  PcdLib
+  DebugLib
+  MemoryAllocationLib
+  UnitTestPersistenceLib
+  UnitTestResultReportLib
+  CmockaLib
+
+[Pcd]
+  gUnitTestFrameworkPkgTokenSpaceGuid.PcdUnitTestLogLevel  ## CONSUMES
diff --git a/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni
new file mode 100644
index 0000000000..aa25a44e35
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLibCmocka.uni
@@ -0,0 +1,11 @@
+// /** @file
+// Library to support Unit Testing from host environments using Cmocka services.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Library to support Unit Testing from host environments using Cmocka services"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Library to support Unit Testing from host environments using Cmocka services."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c
new file mode 100644
index 0000000000..e28327652e
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.c
@@ -0,0 +1,75 @@
+/** @file
+  This is an instance of the Unit Test Persistence Lib that does nothing.
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UnitTestPersistenceLib.h>
+
+/**
+  Determines whether a persistence cache already exists for
+  the given framework.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+
+  @retval  TRUE
+  @retval  FALSE  Cache doesn't exist or an error occurred.
+
+**/
+BOOLEAN
+EFIAPI
+DoesCacheExist (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  return FALSE;
+}
+
+/**
+  Will save the data associated with an internal Unit Test Framework
+  state in a manner that can persist a Unit Test Application quit or
+  even a system reboot.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+  @param[in]  SaveData         A pointer to the buffer containing the serialized
+                               framework internal state.
+
+  @retval  EFI_SUCCESS  Data is persisted and the test can be safely quit.
+  @retval  Others       Data is not persisted and test cannot be resumed upon exit.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveUnitTestCache (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  IN UNIT_TEST_SAVE_HEADER       *SaveData
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Will retrieve any cached state associated with the given framework.
+  Will allocate a buffer to hold the loaded data.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+  @param[in]  SaveData         A pointer pointer that will be updated with the address
+                               of the loaded data buffer.
+
+  @retval  EFI_SUCCESS  Data has been loaded successfully and SaveData is updated
+                        with a pointer to the buffer.
+  @retval  Others       An error has occurred and no data has been loaded. SaveData
+                        is set to NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadUnitTestCache (
+  IN  UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  OUT UNIT_TEST_SAVE_HEADER       **SaveData
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf
new file mode 100644
index 0000000000..1175772662
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf
@@ -0,0 +1,28 @@
+## @file
+# This is an instance of the Unit Test Persistence Lib does nothing.
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestPersistenceLibNull
+  MODULE_UNI_FILE = UnitTestPersistenceLibNull.uni
+  FILE_GUID       = B8553C7A-0B0B-4BBD-9DF3-825804BF26AB
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_DRIVER
+  LIBRARY_CLASS   = UnitTestPersistenceLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  UnitTestPersistenceLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni
new file mode 100644
index 0000000000..00f7d8d7f0
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.uni
@@ -0,0 +1,11 @@
+// /** @file
+// NULL library for Unit Test Persistence Lib.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "NULL library for Unit Test Persistence Lib"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "NULL library for Unit Test Persistence Lib."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
new file mode 100644
index 0000000000..ccca9bfacb
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
@@ -0,0 +1,416 @@
+/** @file
+  This is an instance of the Unit Test Persistence Lib that will utilize
+  the filesystem that a test application is running from to save a serialized
+  version of the internal test state in case the test needs to quit and restore.
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include <Library/UnitTestPersistenceLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/ShellLib.h>
+#include <Protocol/LoadedImage.h>
+
+#define CACHE_FILE_SUFFIX  L"_Cache.dat"
+
+/**
+  Generate the device path to the cache file.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+
+  @retval  !NULL  A pointer to the EFI_FILE protocol instance for the filesystem.
+  @retval  NULL   Filesystem could not be found or an error occurred.
+
+**/
+STATIC
+EFI_DEVICE_PATH_PROTOCOL*
+GetCacheFileDevicePath (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  EFI_STATUS                 Status;
+  UNIT_TEST_FRAMEWORK        *Framework;
+  EFI_LOADED_IMAGE_PROTOCOL  *LoadedImage;
+  CHAR16                     *AppPath;
+  CHAR16                     *CacheFilePath;
+  CHAR16                     *TestName;
+  UINTN                      DirectorySlashOffset;
+  UINTN                      CacheFilePathLength;
+  EFI_DEVICE_PATH_PROTOCOL   *CacheFileDevicePath;
+
+  Framework           = (UNIT_TEST_FRAMEWORK*)FrameworkHandle;
+  AppPath             = NULL;
+  CacheFilePath       = NULL;
+  TestName            = NULL;
+  CacheFileDevicePath = NULL;
+
+  //
+  // First, we need to get some information from the loaded image.
+  //
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID**)&LoadedImage
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_WARN, "%a - Failed to locate DevicePath for loaded image. %r\n", __FUNCTION__, Status));
+    return NULL;
+  }
+
+  //
+  // Before we can start, change test name from ASCII to Unicode.
+  //
+  CacheFilePathLength = AsciiStrLen (Framework->ShortTitle) + 1;
+  TestName = AllocatePool (CacheFilePathLength);
+  if (!TestName) {
+    goto Exit;
+  }
+  AsciiStrToUnicodeStrS (Framework->ShortTitle, TestName, CacheFilePathLength);
+
+  //
+  // Now we should have the device path of the root device and a file path for the rest.
+  // In order to target the directory for the test application, we must process
+  // the file path a little.
+  //
+  // NOTE: This may not be necessary... Path processing functions exist...
+  // PathCleanUpDirectories (FileNameCopy);
+  //     if (PathRemoveLastItem (FileNameCopy)) {
+  //
+  AppPath = ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);    // NOTE: This must be freed.
+  DirectorySlashOffset = StrLen (AppPath);
+  //
+  // Make sure we didn't get any weird data.
+  //
+  if (DirectorySlashOffset == 0) {
+    DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing app path.\n", __FUNCTION__));
+    goto Exit;
+  }
+
+  //
+  // Now that we know we have a decent string, let's take a deeper look.
+  //
+  do {
+    if (AppPath[DirectorySlashOffset] == L'\\') {
+      break;
+    }
+    DirectorySlashOffset--;
+  } while (DirectorySlashOffset > 0);
+
+  //
+  // After that little maneuver, DirectorySlashOffset should be pointing at the last '\' in AppString.
+  // That would be the path to the parent directory that the test app is executing from.
+  // Let's check and make sure that's right.
+  //
+  if (AppPath[DirectorySlashOffset] != L'\\') {
+    DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory separator in app path.\n", __FUNCTION__));
+    goto Exit;
+  }
+
+  //
+  // Now we know some things, we're ready to produce our output string, I think.
+  //
+  CacheFilePathLength = DirectorySlashOffset + 1;
+  CacheFilePathLength += StrLen (TestName);
+  CacheFilePathLength += StrLen (CACHE_FILE_SUFFIX);
+  CacheFilePathLength += 1;   // Don't forget the NULL terminator.
+  CacheFilePath       = AllocateZeroPool (CacheFilePathLength * sizeof (CHAR16));
+  if (!CacheFilePath) {
+    goto Exit;
+  }
+
+  //
+  // Let's produce our final path string, shall we?
+  //
+  StrnCpyS (CacheFilePath, CacheFilePathLength, AppPath, DirectorySlashOffset + 1);  // Copy the path for the parent directory.
+  StrCatS (CacheFilePath, CacheFilePathLength, TestName);                            // Copy the base name for the test cache.
+  StrCatS (CacheFilePath, CacheFilePathLength, CACHE_FILE_SUFFIX);                          // Copy the file suffix.
+
+  //
+  // Finally, try to create the device path for the thing thing.
+  //
+  CacheFileDevicePath = FileDevicePath (LoadedImage->DeviceHandle, CacheFilePath);
+
+Exit:
+  //
+  // Free allocated buffers.
+  //
+  if (AppPath != NULL) {
+    FreePool (AppPath);
+  }
+  if (CacheFilePath != NULL) {
+    FreePool (CacheFilePath);
+  }
+  if (TestName != NULL) {
+    FreePool (TestName);
+  }
+
+  return CacheFileDevicePath;
+}
+
+/**
+  Determines whether a persistence cache already exists for
+  the given framework.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+
+  @retval  TRUE
+  @retval  FALSE  Cache doesn't exist or an error occurred.
+
+**/
+BOOLEAN
+EFIAPI
+DoesCacheExist (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *FileDevicePath;
+  EFI_STATUS                Status;
+  SHELL_FILE_HANDLE         FileHandle;
+
+  //
+  // NOTE: This devpath is allocated and must be freed.
+  //
+  FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
+
+  //
+  // Check to see whether the file exists.  If the file can be opened for
+  // reading, it exists.  Otherwise, probably not.
+  //
+  Status = ShellOpenFileByDevicePath (
+             &FileDevicePath,
+             &FileHandle,
+             EFI_FILE_MODE_READ,
+             0
+             );
+  if (!EFI_ERROR (Status)) {
+    ShellCloseFile (&FileHandle);
+  }
+
+  if (FileDevicePath != NULL) {
+    FreePool (FileDevicePath);
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __FUNCTION__, !EFI_ERROR (Status)));
+
+  return (!EFI_ERROR (Status));
+}
+
+/**
+  Will save the data associated with an internal Unit Test Framework
+  state in a manner that can persist a Unit Test Application quit or
+  even a system reboot.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+  @param[in]  SaveData         A pointer to the buffer containing the serialized
+                               framework internal state.
+
+  @retval  EFI_SUCCESS  Data is persisted and the test can be safely quit.
+  @retval  Others       Data is not persisted and test cannot be resumed upon exit.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveUnitTestCache (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  IN UNIT_TEST_SAVE_HEADER       *SaveData
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL  *FileDevicePath;
+  EFI_STATUS                Status;
+  SHELL_FILE_HANDLE         FileHandle;
+  UINTN                     WriteCount;
+
+  //
+  // Check the inputs for sanity.
+  //
+  if (FrameworkHandle == NULL || SaveData == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Determine the path for the cache file.
+  // NOTE: This devpath is allocated and must be freed.
+  //
+  FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
+
+  //
+  //First lets open the file if it exists so we can delete it...This is the work around for truncation
+  //
+  Status = ShellOpenFileByDevicePath (
+             &FileDevicePath,
+             &FileHandle,
+             (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE),
+             0
+             );
+
+  if (!EFI_ERROR (Status)) {
+    //
+    // If file handle above was opened it will be closed by the delete.
+    //
+    Status = ShellDeleteFile (&FileHandle);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a failed to delete file %r\n", __FUNCTION__, Status));
+    }
+  }
+
+  //
+  // Now that we know the path to the file... let's open it for writing.
+  //
+  Status = ShellOpenFileByDevicePath (
+             &FileDevicePath,
+             &FileHandle,
+             (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE),
+             0
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));
+    goto Exit;
+  }
+
+  //
+  // Write the data to the file.
+  //
+  WriteCount = SaveData->SaveStateSize;
+  DEBUG ((DEBUG_INFO, "%a - Writing %d bytes to file...\n", __FUNCTION__, WriteCount));
+  Status = ShellWriteFile (
+             FileHandle,
+             &WriteCount,
+             SaveData
+             );
+
+  if (EFI_ERROR (Status) || WriteCount != SaveData->SaveStateSize) {
+    DEBUG ((DEBUG_ERROR, "%a - Writing to file failed! %r\n", __FUNCTION__, Status));
+  } else {
+    DEBUG ((DEBUG_INFO, "%a - SUCCESS!\n", __FUNCTION__));
+  }
+
+  //
+  // No matter what, we should probably close the file.
+  //
+  ShellCloseFile (&FileHandle);
+
+Exit:
+  if (FileDevicePath != NULL) {
+    FreePool (FileDevicePath);
+  }
+
+  return Status;
+}
+
+/**
+  Will retrieve any cached state associated with the given framework.
+  Will allocate a buffer to hold the loaded data.
+
+  @param[in]  FrameworkHandle  A pointer to the framework that is being persisted.
+  @param[in]  SaveData         A pointer pointer that will be updated with the address
+                               of the loaded data buffer.
+
+  @retval  EFI_SUCCESS  Data has been loaded successfully and SaveData is updated
+                        with a pointer to the buffer.
+  @retval  Others       An error has occurred and no data has been loaded. SaveData
+                        is set to NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadUnitTestCache (
+  IN  UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle,
+  OUT UNIT_TEST_SAVE_HEADER       **SaveData
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *FileDevicePath;
+  SHELL_FILE_HANDLE         FileHandle;
+  BOOLEAN                   IsFileOpened;
+  UINT64                    LargeFileSize;
+  UINTN                     FileSize;
+  UNIT_TEST_SAVE_HEADER     *Buffer;
+
+  IsFileOpened = FALSE;
+  Buffer       = NULL;
+
+  //
+  // Check the inputs for sanity.
+  //
+  if (FrameworkHandle == NULL || SaveData == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Determine the path for the cache file.
+  // NOTE: This devpath is allocated and must be freed.
+  //
+  FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
+
+  //
+  // Now that we know the path to the file... let's open it for writing.
+  //
+  Status = ShellOpenFileByDevicePath (
+             &FileDevicePath,
+             &FileHandle,
+             EFI_FILE_MODE_READ,
+             0
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Opening file for writing failed! %r\n", __FUNCTION__, Status));
+    goto Exit;
+  } else {
+    IsFileOpened = TRUE;
+  }
+
+  //
+  // Now that the file is opened, we need to determine how large a buffer we need.
+  //
+  Status = ShellGetFileSize (FileHandle, &LargeFileSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to determine file size! %r\n", __FUNCTION__, Status));
+    goto Exit;
+  }
+
+  //
+  // Now that we know the size, let's allocated a buffer to hold the contents.
+  //
+  FileSize = (UINTN)LargeFileSize;    // You know what... if it's too large, this lib don't care.
+  Buffer = AllocatePool (FileSize);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to allocate a pool to hold the file contents! %r\n", __FUNCTION__, Status));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Finally, let's read the data.
+  //
+  Status = ShellReadFile (FileHandle, &FileSize, Buffer);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to read the file contents! %r\n", __FUNCTION__, Status));
+  }
+
+Exit:
+  //
+  // Free allocated buffers
+  //
+  if (FileDevicePath != NULL) {
+    FreePool (FileDevicePath);
+  }
+  if (IsFileOpened) {
+    ShellCloseFile (&FileHandle);
+  }
+
+  //
+  // If we're returning an error, make sure
+  // the state is sane.
+  if (EFI_ERROR (Status) && Buffer != NULL) {
+    FreePool (Buffer);
+    Buffer = NULL;
+  }
+
+  *SaveData = Buffer;
+  return Status;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf
new file mode 100644
index 0000000000..c518c4e5ce
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.inf
@@ -0,0 +1,47 @@
+## @file
+# UEFI Simple File System based version of the Unit Test Persistence Lib
+#
+# Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem
+# that a test application is running from to save a serialized version of the
+# internal test state in case the test needs to quit and restore.
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestPersistenceLibSimpleFileSystem
+  MODULE_UNI_FILE = UnitTestPersistenceLibSimpleFileSystem.uni
+  FILE_GUID       = 9200844A-CDFD-4368-B4BD-106354702605
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_APPLICATION
+  LIBRARY_CLASS   = UnitTestPersistenceLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  UnitTestPersistenceLibSimpleFileSystem.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+  ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiBootServicesTableLib
+  BaseLib
+  ShellLib
+
+[Protocols]
+  gEfiLoadedImageProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
diff --git a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni
new file mode 100644
index 0000000000..e6593be137
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.uni
@@ -0,0 +1,15 @@
+// /** @file
+// UEFI Simple File System based version of the Unit Test Persistence Lib
+//
+// Instance of the Unit Test Persistence Lib that utilizes the UEFI filesystem
+// that a test application is running from to save a serialized version of the
+// internal test state in case the test needs to quit and restore.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "UEFI Simple File System based version of the Unit Test Persistence Lib."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c
new file mode 100644
index 0000000000..687a04f55d
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLib.c
@@ -0,0 +1,216 @@
+/** @file
+  Implement UnitTestResultReportLib doing plain txt out to console
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/UnitTestResultReportLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+VOID
+ReportPrint (
+  IN CONST CHAR8  *Format,
+  ...
+  );
+
+VOID
+ReportOutput (
+  IN CONST CHAR8  *Output
+  );
+
+struct _UNIT_TEST_STATUS_STRING {
+  UNIT_TEST_STATUS  Status;
+  CHAR8             *String;
+};
+
+struct _UNIT_TEST_FAILURE_TYPE_STRING {
+  FAILURE_TYPE  Type;
+  CHAR8         *String;
+};
+
+struct _UNIT_TEST_STATUS_STRING  mStatusStrings[] = {
+  { UNIT_TEST_PASSED,                     "PASSED"},
+  { UNIT_TEST_ERROR_PREREQUISITE_NOT_MET, "NOT RUN - PREREQUISITE FAILED"},
+  { UNIT_TEST_ERROR_TEST_FAILED,          "FAILED"},
+  { UNIT_TEST_RUNNING,                    "RUNNING"},
+  { UNIT_TEST_PENDING,                    "PENDING"},
+  { 0,                                    "**UNKNOWN**"}
+};
+
+struct _UNIT_TEST_FAILURE_TYPE_STRING mFailureTypeStrings[] = {
+  { FAILURETYPE_NOFAILURE,         "NO FAILURE"},
+  { FAILURETYPE_OTHER,             "OTHER FAILURE"},
+  { FAILURETYPE_ASSERTTRUE,        "ASSERT_TRUE FAILURE"},
+  { FAILURETYPE_ASSERTFALSE,       "ASSERT_FALSE FAILURE"},
+  { FAILURETYPE_ASSERTEQUAL,       "ASSERT_EQUAL FAILURE"},
+  { FAILURETYPE_ASSERTNOTEQUAL,    "ASSERT_NOTEQUAL FAILURE"},
+  { FAILURETYPE_ASSERTNOTEFIERROR, "ASSERT_NOTEFIERROR FAILURE"},
+  { FAILURETYPE_ASSERTSTATUSEQUAL, "ASSERT_STATUSEQUAL FAILURE"},
+  { FAILURETYPE_ASSERTNOTNULL ,    "ASSERT_NOTNULL FAILURE"},
+  { 0,                             "*UNKNOWN* Failure"}
+};
+
+//
+// TEST REPORTING FUNCTIONS
+//
+
+STATIC
+CONST CHAR8*
+GetStringForUnitTestStatus (
+  IN UNIT_TEST_STATUS  Status
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < ARRAY_SIZE (mStatusStrings); Index++) {
+    if (mStatusStrings[Index].Status == Status) {
+      //
+      // Return string from matching entry
+      //
+      return mStatusStrings[Index].String;
+    }
+  }
+  //
+  // Return last entry if no match found.
+  //
+  return mStatusStrings[Index].String;
+}
+
+STATIC
+CONST CHAR8*
+GetStringForFailureType (
+  IN FAILURE_TYPE  Failure
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < ARRAY_SIZE (mFailureTypeStrings); Index++) {
+    if (mFailureTypeStrings[Index].Type == Failure) {
+      //
+      // Return string from matching entry
+      //
+      return mFailureTypeStrings[Index].String;
+    }
+  }
+  //
+  // Return last entry if no match found.
+  //
+  DEBUG((DEBUG_INFO, "%a Failure Type does not have string defined 0x%X\n", __FUNCTION__, (UINT32)Failure));
+  return mFailureTypeStrings[Index].String;
+}
+
+/*
+  Method to print the Unit Test run results
+
+  @retval  Success
+*/
+EFI_STATUS
+EFIAPI
+OutputUnitTestFrameworkReport (
+  IN UNIT_TEST_FRAMEWORK_HANDLE  FrameworkHandle
+  )
+{
+  UNIT_TEST_FRAMEWORK         *Framework;
+  INTN                        Passed;
+  INTN                        Failed;
+  INTN                        NotRun;
+  UNIT_TEST_SUITE_LIST_ENTRY  *Suite;
+  UNIT_TEST_LIST_ENTRY        *Test;
+  INTN                        SPassed;
+  INTN                        SFailed;
+  INTN                        SNotRun;
+
+  Passed = 0;
+  Failed = 0;
+  NotRun = 0;
+  Suite = NULL;
+
+  Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
+  if (Framework == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ReportPrint ("---------------------------------------------------------\n");
+  ReportPrint ("------------- UNIT TEST FRAMEWORK RESULTS ---------------\n");
+  ReportPrint ("---------------------------------------------------------\n");
+
+  //print the version and time
+
+  //
+  // Iterate all suites
+  //
+  for (Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetFirstNode(&Framework->TestSuiteList);
+    (LIST_ENTRY*)Suite != &Framework->TestSuiteList;
+    Suite = (UNIT_TEST_SUITE_LIST_ENTRY*)GetNextNode(&Framework->TestSuiteList, (LIST_ENTRY*)Suite)) {
+
+    Test = NULL;
+    SPassed = 0;
+    SFailed = 0;
+    SNotRun = 0;
+
+    ReportPrint ("/////////////////////////////////////////////////////////\n");
+    ReportPrint ("  SUITE: %a\n", Suite->UTS.Title);
+    ReportPrint ("   PACKAGE: %a\n", Suite->UTS.Name);
+    ReportPrint ("/////////////////////////////////////////////////////////\n");
+
+    //
+    // Iterate all tests within the suite
+    //
+    for (Test = (UNIT_TEST_LIST_ENTRY*)GetFirstNode(&(Suite->UTS.TestCaseList));
+      (LIST_ENTRY*)Test != &(Suite->UTS.TestCaseList);
+      Test = (UNIT_TEST_LIST_ENTRY*)GetNextNode(&(Suite->UTS.TestCaseList), (LIST_ENTRY*)Test)) {
+
+      ReportPrint ("*********************************************************\n");
+      ReportPrint ("  CLASS NAME: %a\n", Test->UT.Name);
+      ReportPrint ("  TEST:    %a\n", Test->UT.Description);
+      ReportPrint ("  STATUS:  %a\n", GetStringForUnitTestStatus (Test->UT.Result));
+      ReportPrint ("  FAILURE: %a\n", GetStringForFailureType (Test->UT.FailureType));
+      ReportPrint ("  FAILURE MESSAGE:\n%a\n", Test->UT.FailureMessage);
+
+      if (Test->UT.Log != NULL) {
+        ReportPrint ("  LOG:\n");
+        ReportOutput (Test->UT.Log);
+      }
+
+      switch (Test->UT.Result) {
+      case UNIT_TEST_PASSED:
+        SPassed++;
+        break;
+      case UNIT_TEST_ERROR_TEST_FAILED:
+        SFailed++;
+        break;
+      case UNIT_TEST_PENDING:               // Fall through...
+      case UNIT_TEST_RUNNING:               // Fall through...
+      case UNIT_TEST_ERROR_PREREQUISITE_NOT_MET:
+        SNotRun++;
+        break;
+      default:
+        break;
+      }
+      ReportPrint ("**********************************************************\n");
+    } //End Test iteration
+
+    ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+    ReportPrint ("Suite Stats\n");
+    ReportPrint (" Passed:  %d  (%d%%)\n", SPassed, (SPassed * 100)/(SPassed+SFailed+SNotRun));
+    ReportPrint (" Failed:  %d  (%d%%)\n", SFailed, (SFailed * 100) / (SPassed + SFailed + SNotRun));
+    ReportPrint (" Not Run: %d  (%d%%)\n", SNotRun, (SNotRun * 100) / (SPassed + SFailed + SNotRun));
+    ReportPrint ("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" );
+
+    Passed += SPassed;  //add to global counters
+    Failed += SFailed;  //add to global counters
+    NotRun += SNotRun;  //add to global counters
+  }//End Suite iteration
+
+  ReportPrint ("=========================================================\n");
+  ReportPrint ("Total Stats\n");
+  ReportPrint (" Passed:  %d  (%d%%)\n", Passed, (Passed * 100) / (Passed + Failed + NotRun));
+  ReportPrint (" Failed:  %d  (%d%%)\n", Failed, (Failed * 100) / (Passed + Failed + NotRun));
+  ReportPrint (" Not Run: %d  (%d%%)\n", NotRun, (NotRun * 100) / (Passed + Failed + NotRun));
+  ReportPrint ("=========================================================\n" );
+
+  return EFI_SUCCESS;
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c
new file mode 100644
index 0000000000..139360ee16
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.c
@@ -0,0 +1,48 @@
+/** @file
+  Implement UnitTestResultReportLib doing plain txt out to console
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+VOID
+ReportPrint (
+  IN CONST CHAR8  *Format,
+  ...
+  )
+{
+  VA_LIST  Marker;
+  CHAR16   String[256];
+  UINTN    Length;
+
+  VA_START (Marker, Format);
+  Length = UnicodeVSPrintAsciiFormat (String, sizeof (String), Format, Marker);
+  if (Length == 0) {
+    DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));
+  } else {
+    gST->ConOut->OutputString (gST->ConOut, String);
+  }
+  VA_END (Marker);
+}
+
+VOID
+ReportOutput (
+  IN CONST CHAR8  *Output
+  )
+{
+  CHAR8  AsciiString[128];
+  UINTN  Length;
+  UINTN  Index;
+
+  Length = AsciiStrLen (Output);
+  for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {
+    AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);
+    ReportPrint ("%a", AsciiString);
+  }
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf
new file mode 100644
index 0000000000..4382199fbc
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.inf
@@ -0,0 +1,29 @@
+## @file
+# Library to support printing out the unit test report to a UEFI console
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestResultReportLibConOut
+  MODULE_UNI_FILE = UnitTestResultReportLibConOut.uni
+  FILE_GUID       = C659641D-BA1F-4B58-946E-B1E1103903F9
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_DRIVER
+  LIBRARY_CLASS   = UnitTestResultReportLib
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  UefiBootServicesTableLib
+  PrintLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[Sources]
+  UnitTestResultReportLib.c
+  UnitTestResultReportLibConOut.c
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni
new file mode 100644
index 0000000000..92ba1b84da
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibConOut.uni
@@ -0,0 +1,11 @@
+// /** @file
+// Library to support printing out the unit test report to a UEFI console
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Library to support printing out the unit test report to a UEFI console"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Library to support printing out the unit test report to a UEFI console."
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c
new file mode 100644
index 0000000000..743aad2958
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.c
@@ -0,0 +1,47 @@
+/** @file
+  Implement UnitTestResultReportLib doing plain txt out to console
+
+  Copyright (c) Microsoft Corporation.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+
+VOID
+ReportPrint (
+  IN CONST CHAR8  *Format,
+  ...
+  )
+{
+  VA_LIST  Marker;
+  CHAR8    String[256];
+  UINTN    Length;
+
+  VA_START (Marker, Format);
+  Length = AsciiVSPrint (String, sizeof (String), Format, Marker);
+  if (Length == 0) {
+    DEBUG ((DEBUG_ERROR, "%a formatted string is too long\n", __FUNCTION__));
+  } else {
+    DEBUG ((DEBUG_INFO, String));
+  }
+  VA_END (Marker);
+}
+
+VOID
+ReportOutput (
+  IN CONST CHAR8  *Output
+  )
+{
+  CHAR8  AsciiString[128];
+  UINTN  Length;
+  UINTN  Index;
+
+  Length = AsciiStrLen (Output);
+  for (Index = 0; Index < Length; Index += (sizeof (AsciiString) - 1)) {
+    AsciiStrCpyS (AsciiString, sizeof (AsciiString), &Output[Index]);
+    DEBUG ((DEBUG_INFO, AsciiString));
+  }
+}
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf
new file mode 100644
index 0000000000..a1c786a700
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf
@@ -0,0 +1,28 @@
+## @file
+# Library to support printing out the unit test report using DEBUG() macros.
+#
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = UnitTestResultReportLibDebugLib
+  MODULE_UNI_FILE = UnitTestResultReportLibDebugLib.uni
+  FILE_GUID       = BED736D4-D197-475F-B7CE-0D828FF2C9A6
+  VERSION_STRING  = 1.0
+  MODULE_TYPE     = UEFI_DRIVER
+  LIBRARY_CLASS   = UnitTestResultReportLib
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  PrintLib
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[Sources]
+  UnitTestResultReportLib.c
+  UnitTestResultReportLibDebugLib.c
diff --git a/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni
new file mode 100644
index 0000000000..4f1993417a
--- /dev/null
+++ b/UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.uni
@@ -0,0 +1,11 @@
+// /** @file
+// Library to support printing out the unit test report using DEBUG() macros.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "Library to support printing out the unit test report using DEBUG() macros"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Library to support printing out the unit test report using DEBUG() macros."
-- 
2.21.0.windows.1


  parent reply	other threads:[~2020-01-24  2:10 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-24  2:10 [Patch 00/11] Add Unit Test Framework Michael D Kinney
2020-01-24  2:10 ` [Patch 01/11] .pytool: Add CI support for host based unit tests with results Michael D Kinney
2020-01-27 23:28   ` [edk2-devel] " brbarkel
2020-01-24  2:10 ` [Patch 02/11] BaseTools/Plugin: Add HostBasedUnitTestRunner plugin Michael D Kinney
2020-01-27 23:29   ` [edk2-devel] " brbarkel
2020-02-07  2:32   ` Bob Feng
2020-01-24  2:10 ` [Patch 03/11] MdePkg/Include/Library: Add UnitTestLib class Michael D Kinney
2020-01-27 23:42   ` [edk2-devel] " brbarkel
2020-02-07  0:49   ` Michael D Kinney
2020-02-07  1:22   ` Wu, Hao A
2020-02-07  5:43     ` Bret Barkelew
2020-01-24  2:10 ` [Patch 04/11] UnitTestFrameworkPkg: Add public and private interfaces Michael D Kinney
2020-01-27 23:42   ` [edk2-devel] " brbarkel
2020-01-24  2:10 ` Michael D Kinney [this message]
2020-01-27 23:43   ` [edk2-devel] [Patch 05/11] UnitTestFrameworkPkg/Library: Add library instances brbarkel
2020-01-24  2:10 ` [Patch 06/11] UnitTestFrameworkPkg/Test: Add unit test samples Michael D Kinney
2020-01-27 23:43   ` [edk2-devel] " brbarkel
2020-01-24  2:10 ` [Patch 07/11] UnitTestFrameworkPkg: Add DSC, DSC INC, and YAML files Michael D Kinney
2020-01-27 23:43   ` [edk2-devel] " brbarkel
2020-01-24  2:10 ` [Patch 08/11] MdePkg/Test: Add SafeIntLib and BaseLib Base64 unit tests Michael D Kinney
2020-01-27 23:43   ` [edk2-devel] " brbarkel
2020-02-07  1:27   ` Wu, Hao A
2020-02-07  7:56   ` Liming Gao
2020-02-07 16:05     ` Michael D Kinney
2020-01-24  2:10 ` [Patch 09/11] MdeModulePkg: Add DxeResetSystemLib unit test Michael D Kinney
2020-01-27 23:43   ` [edk2-devel] " brbarkel
2020-02-07  1:25   ` Wu, Hao A
2020-01-24  2:10 ` [Patch 10/11] .azurepipelines: Enable CI for UnitTestFrameworkPkg and host tests Michael D Kinney
2020-01-27 23:44   ` [edk2-devel] " brbarkel
2020-01-24  2:10 ` [Patch 11/11] Maintainers.txt: Add UnitTestFrameworkPkg Michael D Kinney
2020-01-24 10:22   ` Laszlo Ersek
2020-01-27 23:44     ` [edk2-devel] " brbarkel
2020-01-27 23:28 ` [edk2-devel] [Patch 00/11] Add Unit Test Framework brbarkel

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=20200124021032.13808-6-michael.d.kinney@intel.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