[edk2-devel] [edk2-platform patch 1/2] Silicon/Intel: Import IntelSiliconPkg from edk2 repo master

Liming Gao liming.gao at intel.com
Mon Jun 10 15:36:26 UTC 2019


BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1890

Signed-off-by: Liming Gao <liming.gao at intel.com>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Ray Ni <ray.ni at intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty at intel.com>
---
 .../MicrocodeFlashAccessLibNull.c                  |   36 +
 .../Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c      |  979 +++++++++++++++
 .../Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c   | 1326 ++++++++++++++++++++
 .../Feature/VTd/IntelVTdDxe/BmDma.c                |  538 ++++++++
 .../Feature/VTd/IntelVTdDxe/DmaProtection.c        |  683 ++++++++++
 .../Feature/VTd/IntelVTdDxe/DmarAcpiTable.c        |  890 +++++++++++++
 .../Feature/VTd/IntelVTdDxe/IntelVTdDxe.c          |  400 ++++++
 .../Feature/VTd/IntelVTdDxe/PciInfo.c              |  373 ++++++
 .../Feature/VTd/IntelVTdDxe/TranslationTable.c     | 1026 +++++++++++++++
 .../Feature/VTd/IntelVTdDxe/TranslationTableEx.c   |  152 +++
 .../Feature/VTd/IntelVTdDxe/VtdReg.c               |  561 +++++++++
 .../Feature/VTd/IntelVTdPmrPei/DmarTable.c         |  578 +++++++++
 .../Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c       |  420 +++++++
 .../Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c    |  810 ++++++++++++
 .../Feature/VTd/IntelVTdPmrPei/VtdReg.c            |  287 +++++
 .../PlatformVTdInfoSamplePei.c                     |  361 ++++++
 .../PlatformVTdSampleDxe/PlatformVTdSampleDxe.c    |  407 ++++++
 .../DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.c      |   81 ++
 .../MicrocodeFlashAccessLibNull.inf                |   34 +
 .../MicrocodeFlashAccessLibNull.uni                |   16 +
 .../MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc    |   27 +
 .../MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf    |   26 +
 .../Feature/Capsule/MicrocodeCapsulePdb/Readme.md  |   20 +
 .../MicrocodeCapsuleTxt/Microcode/Microcode.inf    |   21 +
 .../MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc    |   33 +
 .../MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf    |   26 +
 .../Feature/Capsule/MicrocodeCapsuleTxt/Readme.md  |   33 +
 .../Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h   |  499 ++++++++
 .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf      |   67 +
 .../MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni      |   15 +
 .../MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni |   14 +
 .../Feature/VTd/IntelVTdDxe/DmaProtection.h        |  632 ++++++++++
 .../Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf        |   83 ++
 .../Feature/VTd/IntelVTdDxe/IntelVTdDxe.uni        |   14 +
 .../Feature/VTd/IntelVTdDxe/IntelVTdDxeExtra.uni   |   14 +
 .../Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h    |  159 +++
 .../Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf  |   60 +
 .../Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.uni  |   14 +
 .../VTd/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni     |   14 +
 .../PlatformVTdInfoSamplePei.inf                   |   48 +
 .../PlatformVTdInfoSamplePei.uni                   |   14 +
 .../PlatformVTdInfoSamplePeiExtra.uni              |   14 +
 .../PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf  |   56 +
 .../PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni  |   14 +
 .../PlatformVTdSampleDxeExtra.uni                  |   14 +
 .../IntelSiliconPkg/Include/Guid/MicrocodeFmp.h    |   15 +
 .../IndustryStandard/FirmwareInterfaceTable.h      |   69 +
 .../Include/IndustryStandard/FirmwareVersionInfo.h |   54 +
 .../Include/IndustryStandard/IgdOpRegion.h         |  149 +++
 .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h |  355 ++++++
 .../Include/Library/MicrocodeFlashAccessLib.h      |   33 +
 .../Intel/IntelSiliconPkg/Include/Ppi/VtdInfo.h    |   37 +
 .../Include/Protocol/PlatformVtdPolicy.h           |  143 +++
 Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec  |   80 ++
 Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc  |   86 ++
 .../DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf    |   38 +
 56 files changed, 12948 insertions(+)
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTable.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTableEx.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.c
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxeExtra.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePeiExtra.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Guid/MicrocodeFmp.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareInterfaceTable.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareVersionInfo.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/IgdOpRegion.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Library/MicrocodeFlashAccessLib.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Ppi/VtdInfo.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
 create mode 100644 Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec
 create mode 100644 Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc
 create mode 100644 Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c
new file mode 100644
index 0000000000..9fc10c398b
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.c
@@ -0,0 +1,36 @@
+/** @file
+  Microcode flash device access library NULL instance.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MicrocodeFlashAccessLib.h>
+
+/**
+  Perform microcode write opreation.
+
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFlashWrite (
+  IN EFI_PHYSICAL_ADDRESS         FlashAddress,
+  IN VOID                         *Buffer,
+  IN UINTN                        Length
+  )
+{
+  CopyMem((VOID *)(UINTN)(FlashAddress), Buffer, Length);
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
new file mode 100644
index 0000000000..40d302425d
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
@@ -0,0 +1,979 @@
+/** @file
+  Produce FMP instance for Microcode.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MicrocodeUpdate.h"
+
+//
+// MicrocodeFmp driver private data
+//
+MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate = NULL;
+
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = {
+  FmpGetImageInfo,
+  FmpGetImage,
+  FmpSetImage,
+  FmpCheckImage,
+  FmpGetPackageInfo,
+  FmpSetPackageInfo
+};
+
+/**
+  Initialize Microcode Descriptor.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS Microcode Descriptor is initialized.
+**/
+EFI_STATUS
+InitializeMicrocodeDescriptor (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  );
+
+/**
+  Returns information about the current firmware image(s) of the device.
+
+  This function allows a copy of the current firmware image to be created and saved.
+  The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+  @param[in]      This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in, out] ImageInfoSize      A pointer to the size, in bytes, of the ImageInfo buffer.
+                                     On input, this is the size of the buffer allocated by the caller.
+                                     On output, it is the size of the buffer returned by the firmware
+                                     if the buffer was large enough, or the size of the buffer needed
+                                     to contain the image(s) information if the buffer was too small.
+  @param[in, out] ImageInfo          A pointer to the buffer in which firmware places the current image(s)
+                                     information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+  @param[out]     DescriptorVersion  A pointer to the location in which firmware returns the version number
+                                     associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]     DescriptorCount    A pointer to the location in which firmware returns the number of
+                                     descriptors or firmware images within this device.
+  @param[out]     DescriptorSize     A pointer to the location in which firmware returns the size, in bytes,
+                                     of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]     PackageVersion     A version number that represents all the firmware images in the device.
+                                     The format is vendor specific and new version must have a greater value
+                                     than the old version. If PackageVersion is not supported, the value is
+                                     0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
+                                     is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
+                                     that package version update is in progress.
+  @param[out]     PackageVersionName A pointer to a pointer to a null-terminated string representing the
+                                     package version name. The buffer is allocated by this function with
+                                     AllocatePool(), and it is the caller's responsibility to free it with a call
+                                     to FreePool().
+
+  @retval EFI_SUCCESS                The device was successfully updated with the new image.
+  @retval EFI_BUFFER_TOO_SMALL       The ImageInfo buffer was too small. The current buffer size
+                                     needed to hold the image(s) information is returned in ImageInfoSize.
+  @retval EFI_INVALID_PARAMETER      ImageInfoSize is NULL.
+  @retval EFI_DEVICE_ERROR           Valid information could not be returned. Possible corrupted image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImageInfo (
+  IN        EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
+  IN OUT    UINTN                             *ImageInfoSize,
+  IN OUT    EFI_FIRMWARE_IMAGE_DESCRIPTOR     *ImageInfo,
+  OUT       UINT32                            *DescriptorVersion,
+  OUT       UINT8                             *DescriptorCount,
+  OUT       UINTN                             *DescriptorSize,
+  OUT       UINT32                            *PackageVersion,
+  OUT       CHAR16                            **PackageVersionName
+  )
+{
+  MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+  UINTN                      Index;
+
+  MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+
+  if(ImageInfoSize == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount) {
+    *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  if (ImageInfo == NULL ||
+      DescriptorVersion == NULL ||
+      DescriptorCount == NULL ||
+      DescriptorSize == NULL ||
+      PackageVersion == NULL ||
+      PackageVersionName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *ImageInfoSize      = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount;
+  *DescriptorSize     = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+  *DescriptorCount    = MicrocodeFmpPrivate->DescriptorCount;
+  *DescriptorVersion  = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+
+  //
+  // supports 1 ImageInfo descriptor
+  //
+  CopyMem(&ImageInfo[0], MicrocodeFmpPrivate->ImageDescriptor, sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount);
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    if ((ImageInfo[Index].AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0) {
+      ImageInfo[Index].LastAttemptVersion = MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion;
+      ImageInfo[Index].LastAttemptStatus = MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus;
+    }
+  }
+
+  //
+  // package version
+  //
+  *PackageVersion = MicrocodeFmpPrivate->PackageVersion;
+  if (MicrocodeFmpPrivate->PackageVersionName != NULL) {
+    *PackageVersionName = AllocateCopyPool(StrSize(MicrocodeFmpPrivate->PackageVersionName), MicrocodeFmpPrivate->PackageVersionName);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves a copy of the current firmware image of the device.
+
+  This function allows a copy of the current firmware image to be created and saved.
+  The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+  @param[in]     This            A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]     ImageIndex      A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in,out] Image           Points to the buffer where the current image is copied to.
+  @param[in,out] ImageSize       On entry, points to the size of the buffer pointed to by Image, in bytes.
+                                 On return, points to the length of the image, in bytes.
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new image.
+  @retval EFI_BUFFER_TOO_SMALL   The buffer specified by ImageSize is too small to hold the
+                                 image. The current buffer size needed to hold the image is returned
+                                 in ImageSize.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_NOT_FOUND          The current image is not copied to the buffer.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
+  IN  UINT8                             ImageIndex,
+  IN  OUT  VOID                         *Image,
+  IN  OUT  UINTN                        *ImageSize
+  )
+{
+  MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+  MICROCODE_INFO             *MicrocodeInfo;
+
+  if (Image == NULL || ImageSize == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+
+  if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || ImageSize == NULL || Image == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[ImageIndex - 1];
+
+  if (*ImageSize < MicrocodeInfo->TotalSize) {
+    *ImageSize = MicrocodeInfo->TotalSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  *ImageSize = MicrocodeInfo->TotalSize;
+  CopyMem (Image, MicrocodeInfo->MicrocodeEntryPoint, MicrocodeInfo->TotalSize);
+  return EFI_SUCCESS;
+}
+
+/**
+  Updates the firmware image of the device.
+
+  This function updates the hardware with the new firmware image.
+  This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
+  If the firmware image is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+  - Validate the image authentication if image has attribute
+    IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
+    EFI_SECURITY_VIOLATION if the validation fails.
+  - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
+    the image is unsupported. The function can optionally provide more detailed information on
+    why the image is not a supported image.
+  - Validate the data from VendorCode if not null. Image validation must be performed before
+    VendorCode data validation. VendorCode data is ignored or considered invalid if image
+    validation failed. The function returns EFI_ABORTED if the data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
+  the caller did not specify the policy or use the default policy. As an example, vendor can implement
+  a policy to allow an option to force a firmware image update when the abort reason is due to the new
+  firmware image version is older than the current firmware image version or bad image checksum.
+  Sensitive operations such as those wiping the entire firmware image and render the device to be
+  non-functional should be encoded in the image itself rather than passed with the VendorCode.
+  AbortReason enables vendor to have the option to provide a more detailed description of the abort
+  reason to the caller.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in]  Image              Points to the new image.
+  @param[in]  ImageSize          Size of the new image in bytes.
+  @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware image update policy.
+                                 Null indicates the caller did not specify the policy or use the default policy.
+  @param[in]  Progress           A function used by the driver to report the progress of the firmware update.
+  @param[out] AbortReason        A pointer to a pointer to a null-terminated string providing more
+                                 details for the aborted operation. The buffer is allocated by this function
+                                 with AllocatePool(), and it is the caller's responsibility to free it with a
+                                 call to FreePool().
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new image.
+  @retval EFI_ABORTED            The operation is aborted.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL                 *This,
+  IN  UINT8                                            ImageIndex,
+  IN  CONST VOID                                       *Image,
+  IN  UINTN                                            ImageSize,
+  IN  CONST VOID                                       *VendorCode,
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS    Progress,
+  OUT CHAR16                                           **AbortReason
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_STATUS                 VarStatus;
+  MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
+
+  if (Image == NULL || AbortReason == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This);
+  *AbortReason     = NULL;
+
+  if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || Image == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = MicrocodeWrite(MicrocodeFmpPrivate, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);
+  DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, Status - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
+  VarStatus = gRT->SetVariable(
+                     MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
+                     &gEfiCallerIdGuid,
+                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                     sizeof(MicrocodeFmpPrivate->LastAttempt),
+                     &MicrocodeFmpPrivate->LastAttempt
+                     );
+  DEBUG((DEBUG_INFO, "SetLastAttempt - %r\n", VarStatus));
+
+  if (!EFI_ERROR(Status)) {
+    InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+    DumpPrivateInfo (MicrocodeFmpPrivate);
+  }
+
+  return Status;
+}
+
+/**
+  Checks if the firmware image is valid for the device.
+
+  This function allows firmware update application to validate the firmware image without
+  invoking the SetImage() first.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in]  Image              Points to the new image.
+  @param[in]  ImageSize          Size of the new image in bytes.
+  @param[out] ImageUpdatable     Indicates if the new image is valid for update. It also provides,
+                                 if available, additional information if the image is invalid.
+
+  @retval EFI_SUCCESS            The image was successfully checked.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpCheckImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
+  IN  UINT8                             ImageIndex,
+  IN  CONST VOID                        *Image,
+  IN  UINTN                             ImageSize,
+  OUT UINT32                            *ImageUpdatable
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Returns information about the firmware package.
+
+  This function returns package information.
+
+  @param[in]  This                     A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[out] PackageVersion           A version number that represents all the firmware images in the device.
+                                       The format is vendor specific and new version must have a greater value
+                                       than the old version. If PackageVersion is not supported, the value is
+                                       0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
+                                       comparison is to be performed using PackageVersionName. A value of
+                                       0xFFFFFFFD indicates that package version update is in progress.
+  @param[out] PackageVersionName       A pointer to a pointer to a null-terminated string representing
+                                       the package version name. The buffer is allocated by this function with
+                                       AllocatePool(), and it is the caller's responsibility to free it with a
+                                       call to FreePool().
+  @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
+                                       package version name. A value of 0 indicates the device does not support
+                                       update of package version name. Length is the number of Unicode characters,
+                                       including the terminating null character.
+  @param[out] AttributesSupported      Package attributes that are supported by this device. See 'Package Attribute
+                                       Definitions' for possible returned values of this parameter. A value of 1
+                                       indicates the attribute is supported and the current setting value is
+                                       indicated in AttributesSetting. A value of 0 indicates the attribute is not
+                                       supported and the current setting value in AttributesSetting is meaningless.
+  @param[out] AttributesSetting        Package attributes. See 'Package Attribute Definitions' for possible returned
+                                       values of this parameter
+
+  @retval EFI_SUCCESS                  The package information was successfully returned.
+  @retval EFI_UNSUPPORTED              The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetPackageInfo (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+  OUT UINT32                           *PackageVersion,
+  OUT CHAR16                           **PackageVersionName,
+  OUT UINT32                           *PackageVersionNameMaxLen,
+  OUT UINT64                           *AttributesSupported,
+  OUT UINT64                           *AttributesSetting
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Updates information about the firmware package.
+
+  This function updates package information.
+  This function returns EFI_UNSUPPORTED if the package information is not updatable.
+  VendorCode enables vendor to implement vendor-specific package information update policy.
+  Null if the caller did not specify this policy or use the default policy.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  Image              Points to the authentication image.
+                                 Null if authentication is not required.
+  @param[in]  ImageSize          Size of the authentication image in bytes.
+                                 0 if authentication is not required.
+  @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware
+                                 image update policy.
+                                 Null indicates the caller did not specify this policy or use
+                                 the default policy.
+  @param[in]  PackageVersion     The new package version.
+  @param[in]  PackageVersionName A pointer to the new null-terminated Unicode string representing
+                                 the package version name.
+                                 The string length is equal to or less than the value returned in
+                                 PackageVersionNameMaxLen.
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new package
+                                 information.
+  @retval EFI_INVALID_PARAMETER  The PackageVersionName length is longer than the value
+                                 returned in PackageVersionNameMaxLen.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetPackageInfo (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL   *This,
+  IN  CONST VOID                         *Image,
+  IN  UINTN                              ImageSize,
+  IN  CONST VOID                         *VendorCode,
+  IN  UINT32                             PackageVersion,
+  IN  CONST CHAR16                       *PackageVersionName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Sort FIT microcode entries based upon MicrocodeEntryPoint, from low to high.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+**/
+VOID
+SortFitMicrocodeInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate
+  )
+{
+  FIT_MICROCODE_INFO        *FitMicrocodeEntry;
+  FIT_MICROCODE_INFO        *NextFitMicrocodeEntry;
+  FIT_MICROCODE_INFO        TempFitMicrocodeEntry;
+  FIT_MICROCODE_INFO        *FitMicrocodeEntryEnd;
+
+  FitMicrocodeEntry = MicrocodeFmpPrivate->FitMicrocodeInfo;
+  NextFitMicrocodeEntry = FitMicrocodeEntry + 1;
+  FitMicrocodeEntryEnd = MicrocodeFmpPrivate->FitMicrocodeInfo + MicrocodeFmpPrivate->FitMicrocodeEntryCount;
+  while (FitMicrocodeEntry < FitMicrocodeEntryEnd) {
+    while (NextFitMicrocodeEntry < FitMicrocodeEntryEnd) {
+      if (FitMicrocodeEntry->MicrocodeEntryPoint > NextFitMicrocodeEntry->MicrocodeEntryPoint) {
+        CopyMem (&TempFitMicrocodeEntry, FitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
+        CopyMem (FitMicrocodeEntry, NextFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
+        CopyMem (NextFitMicrocodeEntry, &TempFitMicrocodeEntry, sizeof (FIT_MICROCODE_INFO));
+      }
+
+      NextFitMicrocodeEntry = NextFitMicrocodeEntry + 1;
+    }
+
+    FitMicrocodeEntry     = FitMicrocodeEntry + 1;
+    NextFitMicrocodeEntry = FitMicrocodeEntry + 1;
+  }
+}
+
+/**
+  Initialize FIT microcode information.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS           FIT microcode information is initialized.
+  @return EFI_OUT_OF_RESOURCES  No enough resource for the initialization.
+  @return EFI_DEVICE_ERROR      There is something wrong in FIT microcode entry.
+**/
+EFI_STATUS
+InitializeFitMicrocodeInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate
+  )
+{
+  UINT64                            FitPointer;
+  FIRMWARE_INTERFACE_TABLE_ENTRY    *FitEntry;
+  UINT32                            EntryNum;
+  UINT32                            MicrocodeEntryNum;
+  UINT32                            Index;
+  UINTN                             Address;
+  VOID                              *MicrocodePatchAddress;
+  UINTN                             MicrocodePatchRegionSize;
+  FIT_MICROCODE_INFO                *FitMicrocodeInfo;
+  FIT_MICROCODE_INFO                *FitMicrocodeInfoNext;
+  CPU_MICROCODE_HEADER              *MicrocodeEntryPoint;
+  CPU_MICROCODE_HEADER              *MicrocodeEntryPointNext;
+  UINTN                             FitMicrocodeIndex;
+  MICROCODE_INFO                    *MicrocodeInfo;
+  UINTN                             MicrocodeIndex;
+
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {
+    FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);
+    MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;
+    MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;
+  }
+
+  FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS;
+  if ((FitPointer == 0) ||
+      (FitPointer == 0xFFFFFFFFFFFFFFFF) ||
+      (FitPointer == 0xEEEEEEEEEEEEEEEE)) {
+    //
+    // No FIT table.
+    //
+    return EFI_SUCCESS;
+  }
+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer;
+  if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) ||
+      (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) {
+    //
+    // Invalid FIT table, treat it as no FIT table.
+    //
+    return EFI_SUCCESS;
+  }
+
+  EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
+
+  //
+  // Calculate microcode entry number.
+  //
+  MicrocodeEntryNum = 0;
+  for (Index = 0; Index < EntryNum; Index++) {
+    if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
+      MicrocodeEntryNum++;
+    }
+  }
+  if (MicrocodeEntryNum == 0) {
+    //
+    // No FIT microcode entry.
+    //
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Allocate buffer.
+  //
+  MicrocodeFmpPrivate->FitMicrocodeInfo = AllocateZeroPool (MicrocodeEntryNum * sizeof (FIT_MICROCODE_INFO));
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  MicrocodeFmpPrivate->FitMicrocodeEntryCount = MicrocodeEntryNum;
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  //
+  // Collect microcode entry info.
+  //
+  MicrocodeEntryNum = 0;
+  for (Index = 0; Index < EntryNum; Index++) {
+    if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
+      Address = (UINTN) FitEntry[Index].Address;
+      if ((Address < (UINTN) MicrocodePatchAddress) ||
+          (Address >= ((UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize))) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "InitializeFitMicrocodeInfo - Address (0x%x) is not in Microcode Region\n",
+          Address
+          ));
+        goto ErrorExit;
+      }
+      FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[MicrocodeEntryNum];
+      FitMicrocodeInfo->MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) Address;
+      if ((*(UINT32 *) Address) == 0xFFFFFFFF) {
+        //
+        // It is the empty slot as long as the first dword is 0xFFFF_FFFF.
+        //
+        FitMicrocodeInfo->Empty = TRUE;
+      } else {
+        FitMicrocodeInfo->Empty = FALSE;
+      }
+      MicrocodeEntryNum++;
+    }
+  }
+
+  //
+  // Every microcode should have a FIT microcode entry.
+  //
+  for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
+    MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex];
+    for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount; FitMicrocodeIndex++) {
+      FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];
+      if (MicrocodeInfo->MicrocodeEntryPoint == FitMicrocodeInfo->MicrocodeEntryPoint) {
+        FitMicrocodeInfo->TotalSize = MicrocodeInfo->TotalSize;
+        FitMicrocodeInfo->InUse = MicrocodeInfo->InUse;
+        break;
+      }
+    }
+    if (FitMicrocodeIndex >= MicrocodeFmpPrivate->FitMicrocodeEntryCount) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "InitializeFitMicrocodeInfo - There is no FIT microcode entry for Microcode (0x%x)\n",
+        MicrocodeInfo->MicrocodeEntryPoint
+        ));
+      goto ErrorExit;
+    }
+  }
+
+  SortFitMicrocodeInfo (MicrocodeFmpPrivate);
+
+  //
+  // Check overlap.
+  //
+  for (FitMicrocodeIndex = 0; FitMicrocodeIndex < MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1; FitMicrocodeIndex++) {
+    FitMicrocodeInfo = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex];
+    MicrocodeEntryPoint = FitMicrocodeInfo->MicrocodeEntryPoint;
+    FitMicrocodeInfoNext = &MicrocodeFmpPrivate->FitMicrocodeInfo[FitMicrocodeIndex + 1];
+    MicrocodeEntryPointNext = FitMicrocodeInfoNext->MicrocodeEntryPoint;
+    if ((MicrocodeEntryPoint >= MicrocodeEntryPointNext) ||
+        ((FitMicrocodeInfo->TotalSize != 0) &&
+         ((UINTN) MicrocodeEntryPoint + FitMicrocodeInfo->TotalSize) >
+          (UINTN) MicrocodeEntryPointNext)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "InitializeFitMicrocodeInfo - There is overlap between FIT microcode entries (0x%x 0x%x)\n",
+        MicrocodeEntryPoint,
+        MicrocodeEntryPointNext
+        ));
+      goto ErrorExit;
+    }
+  }
+
+  return EFI_SUCCESS;
+
+ErrorExit:
+  FreePool (MicrocodeFmpPrivate->FitMicrocodeInfo);
+  MicrocodeFmpPrivate->FitMicrocodeInfo = NULL;
+  MicrocodeFmpPrivate->FitMicrocodeEntryCount = 0;
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  Initialize Processor Microcode Index.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+**/
+VOID
+InitializedProcessorMicrocodeIndex (
+  IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+  )
+{
+  UINTN       CpuIndex;
+  UINTN       MicrocodeIndex;
+  UINTN       TargetCpuIndex;
+  UINT32      AttemptStatus;
+  EFI_STATUS  Status;
+
+  for (CpuIndex = 0; CpuIndex < MicrocodeFmpPrivate->ProcessorCount; CpuIndex++) {
+    if (MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex != (UINTN)-1) {
+      continue;
+    }
+    for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
+      if (!MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].InUse) {
+        continue;
+      }
+      TargetCpuIndex = CpuIndex;
+      Status = VerifyMicrocode(
+                 MicrocodeFmpPrivate,
+                 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].MicrocodeEntryPoint,
+                 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].TotalSize,
+                 FALSE,
+                 &AttemptStatus,
+                 NULL,
+                 &TargetCpuIndex
+                 );
+      if (!EFI_ERROR(Status)) {
+        MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex = MicrocodeIndex;
+      }
+    }
+  }
+}
+
+/**
+  Initialize Microcode Descriptor.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS           Microcode Descriptor is initialized.
+  @return EFI_OUT_OF_RESOURCES  No enough resource for the initialization.
+**/
+EFI_STATUS
+InitializeMicrocodeDescriptor (
+  IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+  )
+{
+  EFI_STATUS Status;
+  UINT8      CurrentMicrocodeCount;
+
+  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);
+
+  if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) {
+    if (MicrocodeFmpPrivate->ImageDescriptor != NULL) {
+      FreePool(MicrocodeFmpPrivate->ImageDescriptor);
+      MicrocodeFmpPrivate->ImageDescriptor = NULL;
+    }
+    if (MicrocodeFmpPrivate->MicrocodeInfo != NULL) {
+      FreePool(MicrocodeFmpPrivate->MicrocodeInfo);
+      MicrocodeFmpPrivate->MicrocodeInfo = NULL;
+    }
+  } else {
+    ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+    ZeroMem(MicrocodeFmpPrivate->MicrocodeInfo, MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
+  }
+
+  MicrocodeFmpPrivate->DescriptorCount = CurrentMicrocodeCount;
+
+  if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
+    MicrocodeFmpPrivate->ImageDescriptor = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+    if (MicrocodeFmpPrivate->ImageDescriptor == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+  if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+    MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
+    if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+      FreePool (MicrocodeFmpPrivate->ImageDescriptor);
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, MicrocodeFmpPrivate->DescriptorCount, MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->MicrocodeInfo);
+  ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount);
+
+  InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);
+
+  Status = InitializeFitMicrocodeInfo (MicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    FreePool (MicrocodeFmpPrivate->ImageDescriptor);
+    FreePool (MicrocodeFmpPrivate->MicrocodeInfo);
+    DEBUG((DEBUG_ERROR, "InitializeFitMicrocodeInfo - %r\n", Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize MicrocodeFmpDriver multiprocessor information.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS           Processor information is initialized.
+  @return EFI_OUT_OF_RESOURCES  No enough resource for the initialization.
+**/
+EFI_STATUS
+InitializeProcessorInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  UINTN                                NumberOfProcessors;
+  UINTN                                NumberOfEnabledProcessors;
+  UINTN                                Index;
+  UINTN                                BspIndex;
+
+  Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
+  ASSERT_EFI_ERROR(Status);
+
+  MicrocodeFmpPrivate->MpService = MpService;
+  MicrocodeFmpPrivate->ProcessorCount = 0;
+  MicrocodeFmpPrivate->ProcessorInfo = NULL;
+
+  Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
+  ASSERT_EFI_ERROR(Status);
+  MicrocodeFmpPrivate->ProcessorCount = NumberOfProcessors;
+
+  Status = MpService->WhoAmI (MpService, &BspIndex);
+  ASSERT_EFI_ERROR(Status);
+  MicrocodeFmpPrivate->BspIndex = BspIndex;
+
+  MicrocodeFmpPrivate->ProcessorInfo = AllocateZeroPool (sizeof(PROCESSOR_INFO) * MicrocodeFmpPrivate->ProcessorCount);
+  if (MicrocodeFmpPrivate->ProcessorInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < NumberOfProcessors; Index++) {
+    MicrocodeFmpPrivate->ProcessorInfo[Index].CpuIndex = Index;
+    MicrocodeFmpPrivate->ProcessorInfo[Index].MicrocodeIndex = (UINTN)-1;
+    if (Index == BspIndex) {
+      CollectProcessorInfo (&MicrocodeFmpPrivate->ProcessorInfo[Index]);
+    } else {
+      Status = MpService->StartupThisAP (
+                            MpService,
+                            CollectProcessorInfo,
+                            Index,
+                            NULL,
+                            0,
+                            &MicrocodeFmpPrivate->ProcessorInfo[Index],
+                            NULL
+                            );
+      ASSERT_EFI_ERROR(Status);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump private information.
+
+  @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  )
+{
+  UINTN                                Index;
+  PROCESSOR_INFO                       *ProcessorInfo;
+  MICROCODE_INFO                       *MicrocodeInfo;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR        *ImageDescriptor;
+  FIT_MICROCODE_INFO                   *FitMicrocodeInfo;
+
+  DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));
+  DEBUG ((DEBUG_INFO, "  ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));
+  DEBUG ((DEBUG_INFO, "  BspIndex - 0x%x\n", MicrocodeFmpPrivate->BspIndex));
+
+  ProcessorInfo = MicrocodeFmpPrivate->ProcessorInfo;
+  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "  ProcessorInfo[0x%x] - 0x%08x, 0x%02x, 0x%08x, (0x%x)\n",
+      ProcessorInfo[Index].CpuIndex,
+      ProcessorInfo[Index].ProcessorSignature,
+      ProcessorInfo[Index].PlatformId,
+      ProcessorInfo[Index].MicrocodeRevision,
+      ProcessorInfo[Index].MicrocodeIndex
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO, "MicrocodeInfo:\n"));
+  MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+  DEBUG ((DEBUG_INFO, "  MicrocodeRegion - 0x%x - 0x%x\n", MicrocodeFmpPrivate->MicrocodePatchAddress, MicrocodeFmpPrivate->MicrocodePatchRegionSize));
+  DEBUG ((DEBUG_INFO, "  MicrocodeCount - 0x%x\n", MicrocodeFmpPrivate->DescriptorCount));
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "  MicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x)\n",
+      Index,
+      MicrocodeInfo[Index].MicrocodeEntryPoint,
+      MicrocodeInfo[Index].TotalSize,
+      MicrocodeInfo[Index].InUse
+      ));
+  }
+
+  ImageDescriptor = MicrocodeFmpPrivate->ImageDescriptor;
+  DEBUG ((DEBUG_VERBOSE, "ImageDescriptor:\n"));
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    DEBUG((DEBUG_VERBOSE, "  ImageDescriptor (%d)\n", Index));
+    DEBUG((DEBUG_VERBOSE, "    ImageIndex                  - 0x%x\n", ImageDescriptor[Index].ImageIndex));
+    DEBUG((DEBUG_VERBOSE, "    ImageTypeId                 - %g\n", &ImageDescriptor[Index].ImageTypeId));
+    DEBUG((DEBUG_VERBOSE, "    ImageId                     - 0x%lx\n", ImageDescriptor[Index].ImageId));
+    DEBUG((DEBUG_VERBOSE, "    ImageIdName                 - %s\n", ImageDescriptor[Index].ImageIdName));
+    DEBUG((DEBUG_VERBOSE, "    Version                     - 0x%x\n", ImageDescriptor[Index].Version));
+    DEBUG((DEBUG_VERBOSE, "    VersionName                 - %s\n", ImageDescriptor[Index].VersionName));
+    DEBUG((DEBUG_VERBOSE, "    Size                        - 0x%x\n", ImageDescriptor[Index].Size));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSupported         - 0x%lx\n", ImageDescriptor[Index].AttributesSupported));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSetting           - 0x%lx\n", ImageDescriptor[Index].AttributesSetting));
+    DEBUG((DEBUG_VERBOSE, "    Compatibilities             - 0x%lx\n", ImageDescriptor[Index].Compatibilities));
+    DEBUG((DEBUG_VERBOSE, "    LowestSupportedImageVersion - 0x%x\n", ImageDescriptor[Index].LowestSupportedImageVersion));
+    DEBUG((DEBUG_VERBOSE, "    LastAttemptVersion          - 0x%x\n", ImageDescriptor[Index].LastAttemptVersion));
+    DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));
+    DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));
+  }
+
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {
+    DEBUG ((DEBUG_INFO, "FitMicrocodeInfo:\n"));
+    FitMicrocodeInfo = MicrocodeFmpPrivate->FitMicrocodeInfo;
+    DEBUG ((DEBUG_INFO, "  FitMicrocodeEntryCount - 0x%x\n", MicrocodeFmpPrivate->FitMicrocodeEntryCount));
+    for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {
+      DEBUG ((
+        DEBUG_INFO,
+        "  FitMicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x, 0x%x)\n",
+        Index,
+        FitMicrocodeInfo[Index].MicrocodeEntryPoint,
+        FitMicrocodeInfo[Index].TotalSize,
+        FitMicrocodeInfo[Index].InUse,
+        FitMicrocodeInfo[Index].Empty
+        ));
+    }
+  }
+}
+
+/**
+  Initialize MicrocodeFmpDriver private data structure.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS private data is initialized.
+**/
+EFI_STATUS
+InitializePrivateData (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  )
+{
+  EFI_STATUS       Status;
+  EFI_STATUS       VarStatus;
+  UINTN            VarSize;
+  BOOLEAN          Result;
+
+  MicrocodeFmpPrivate->Signature       = MICROCODE_FMP_PRIVATE_DATA_SIGNATURE;
+  MicrocodeFmpPrivate->Handle          = NULL;
+  CopyMem(&MicrocodeFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL));
+
+  MicrocodeFmpPrivate->PackageVersion = 0x1;
+  MicrocodeFmpPrivate->PackageVersionName = L"Microcode";
+
+  MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion = 0x0;
+  MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus = 0x0;
+  VarSize = sizeof(MicrocodeFmpPrivate->LastAttempt);
+  VarStatus = gRT->GetVariable(
+                     MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME,
+                     &gEfiCallerIdGuid,
+                     NULL,
+                     &VarSize,
+                     &MicrocodeFmpPrivate->LastAttempt
+                     );
+  DEBUG((DEBUG_INFO, "GetLastAttempt - %r\n", VarStatus));
+  DEBUG((DEBUG_INFO, "GetLastAttempt Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
+
+  Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);
+  if (!Result) {
+    DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  Status = InitializeProcessorInfo (MicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "InitializeProcessorInfo - %r\n", Status));
+    return Status;
+  }
+
+  Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    FreePool (MicrocodeFmpPrivate->ProcessorInfo);
+    DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));
+    return Status;
+  }
+
+  DumpPrivateInfo (MicrocodeFmpPrivate);
+
+  return Status;
+}
+
+/**
+  Microcode FMP module entrypoint
+
+  @param[in]  ImageHandle       The firmware allocated handle for the EFI image.
+  @param[in]  SystemTable       A pointer to the EFI System Table.
+
+  @return EFI_SUCCESS Microcode FMP module is initialized.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFmpMain (
+  IN EFI_HANDLE                         ImageHandle,
+  IN EFI_SYSTEM_TABLE                   *SystemTable
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Initialize MicrocodeFmpPrivateData
+  //
+  mMicrocodeFmpPrivate = AllocateZeroPool (sizeof(MICROCODE_FMP_PRIVATE_DATA));
+  if (mMicrocodeFmpPrivate == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = InitializePrivateData(mMicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    FreePool(mMicrocodeFmpPrivate);
+    mMicrocodeFmpPrivate = NULL;
+    return Status;
+  }
+
+  //
+  // Install FMP protocol.
+  //
+  Status = gBS->InstallProtocolInterface (
+                  &mMicrocodeFmpPrivate->Handle,
+                  &gEfiFirmwareManagementProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &mMicrocodeFmpPrivate->Fmp
+                  );
+  if (EFI_ERROR (Status)) {
+    FreePool(mMicrocodeFmpPrivate);
+    mMicrocodeFmpPrivate = NULL;
+    return Status;
+  }
+
+  return Status;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
new file mode 100644
index 0000000000..84914973b9
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
@@ -0,0 +1,1326 @@
+/** @file
+  SetImage instance to update Microcode.
+
+  Caution: This module requires additional review when modified.
+  This module will have external input - capsule image.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MicrocodeUpdate.h"
+
+/**
+  Get Microcode Region.
+
+  @param[out] MicrocodePatchAddress      The address of Microcode
+  @param[out] MicrocodePatchRegionSize   The region size of Microcode
+
+  @retval TRUE   The Microcode region is returned.
+  @retval FALSE  No Microcode region.
+**/
+BOOLEAN
+GetMicrocodeRegion (
+  OUT VOID     **MicrocodePatchAddress,
+  OUT UINTN    *MicrocodePatchRegionSize
+  )
+{
+  *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
+  *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
+
+  if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Get Microcode update signature of currently loaded Microcode update.
+
+  @return  Microcode signature.
+
+**/
+UINT32
+GetCurrentMicrocodeSignature (
+  VOID
+  )
+{
+  UINT64 Signature;
+
+  AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);
+  AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+  Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);
+  return (UINT32)RShiftU64(Signature, 32);
+}
+
+/**
+  Get current processor signature.
+
+  @return current processor signature.
+**/
+UINT32
+GetCurrentProcessorSignature (
+  VOID
+  )
+{
+  UINT32                                  RegEax;
+  AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+  return RegEax;
+}
+
+/**
+  Get current platform ID.
+
+  @return current platform ID.
+**/
+UINT8
+GetCurrentPlatformId (
+  VOID
+  )
+{
+  UINT8                                   PlatformId;
+
+  PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);
+  return PlatformId;
+}
+
+/**
+  Load new Microcode.
+
+  @param[in] Address  The address of new Microcode.
+
+  @return  Loaded Microcode signature.
+
+**/
+UINT32
+LoadMicrocode (
+  IN UINT64  Address
+  )
+{
+  AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);
+  return GetCurrentMicrocodeSignature();
+}
+
+/**
+  Load Microcode on an Application Processor.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+MicrocodeLoadAp (
+  IN OUT VOID  *Buffer
+  )
+{
+  MICROCODE_LOAD_BUFFER                *MicrocodeLoadBuffer;
+
+  MicrocodeLoadBuffer = Buffer;
+  MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
+}
+
+/**
+  Load new Microcode on this processor
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  CpuIndex                   The index of the processor.
+  @param[in]  Address                    The address of new Microcode.
+
+  @return  Loaded Microcode signature.
+
+**/
+UINT32
+LoadMicrocodeOnThis (
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  UINTN                       CpuIndex,
+  IN  UINT64                      Address
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  MICROCODE_LOAD_BUFFER                MicrocodeLoadBuffer;
+
+  if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
+    return LoadMicrocode (Address);
+  } else {
+    MpService = MicrocodeFmpPrivate->MpService;
+    MicrocodeLoadBuffer.Address = Address;
+    MicrocodeLoadBuffer.Revision = 0;
+    Status = MpService->StartupThisAP (
+                          MpService,
+                          MicrocodeLoadAp,
+                          CpuIndex,
+                          NULL,
+                          0,
+                          &MicrocodeLoadBuffer,
+                          NULL
+                          );
+    ASSERT_EFI_ERROR(Status);
+    return MicrocodeLoadBuffer.Revision;
+  }
+}
+
+/**
+  Collect processor information.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+  IN OUT VOID  *Buffer
+  )
+{
+  PROCESSOR_INFO  *ProcessorInfo;
+
+  ProcessorInfo = Buffer;
+  ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
+  ProcessorInfo->PlatformId = GetCurrentPlatformId();
+  ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
+}
+
+/**
+  Get current Microcode information.
+
+  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+  in MicrocodeFmpPrivate must be initialized.
+
+  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+  in MicrocodeFmpPrivate may not be avaiable in this function.
+
+  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
+  @param[out]  ImageDescriptor            Microcode ImageDescriptor
+  @param[out]  MicrocodeInfo              Microcode information
+
+  @return Microcode count
+**/
+UINTN
+GetMicrocodeInfo (
+  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
+  IN  UINTN                          DescriptorCount,  OPTIONAL
+  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
+  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
+  )
+{
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
+  UINTN                                   MicrocodeEnd;
+  UINTN                                   TotalSize;
+  UINTN                                   Count;
+  UINT64                                  ImageAttributes;
+  BOOLEAN                                 IsInUse;
+  EFI_STATUS                              Status;
+  UINT32                                  AttemptStatus;
+  UINTN                                   TargetCpuIndex;
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
+
+  Count = 0;
+
+  MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+  do {
+    if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
+      //
+      // It is the microcode header. It is not the padding data between microcode patches
+      // becasue the padding data should not include 0x00000001 and it should be the repeated
+      // byte format (like 0xXYXYXYXY....).
+      //
+      if (MicrocodeEntryPoint->DataSize == 0) {
+        TotalSize = 2048;
+      } else {
+        TotalSize = MicrocodeEntryPoint->TotalSize;
+      }
+
+      TargetCpuIndex = (UINTN)-1;
+      Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
+      if (!EFI_ERROR(Status)) {
+        IsInUse = TRUE;
+        ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+        MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
+      } else {
+        IsInUse = FALSE;
+      }
+
+      if (ImageDescriptor != NULL && DescriptorCount > Count) {
+        ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
+        CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
+        ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;
+        ImageDescriptor[Count].ImageIdName = NULL;
+        ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;
+        ImageDescriptor[Count].VersionName = NULL;
+        ImageDescriptor[Count].Size = TotalSize;
+        ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
+        if (IsInUse) {
+          ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
+        }
+        ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
+        ImageDescriptor[Count].AttributesSetting = ImageAttributes;
+        ImageDescriptor[Count].Compatibilities = 0;
+        ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback
+        ImageDescriptor[Count].LastAttemptVersion = 0;
+        ImageDescriptor[Count].LastAttemptStatus = 0;
+        ImageDescriptor[Count].HardwareInstance = 0;
+      }
+      if (MicrocodeInfo != NULL && DescriptorCount > Count) {
+        MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
+        MicrocodeInfo[Count].TotalSize = TotalSize;
+        MicrocodeInfo[Count].InUse = IsInUse;
+      }
+    } else {
+      //
+      // It is the padding data between the microcode patches for microcode patches alignment.
+      // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+      // find the next possible microcode patch header.
+      //
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+      continue;
+    }
+
+    Count++;
+    ASSERT(Count < 0xFF);
+
+    //
+    // Get the next patch.
+    //
+    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
+
+  return Count;
+}
+
+/**
+  Return matched processor information.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  ProcessorSignature         The processor signature to be matched
+  @param[in]  ProcessorFlags             The processor flags to be matched
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
+
+  @return matched processor information.
+**/
+PROCESSOR_INFO *
+GetMatchedProcessor (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN UINT32                      ProcessorSignature,
+  IN UINT32                      ProcessorFlags,
+  IN OUT UINTN                   *TargetCpuIndex
+  )
+{
+  UINTN  Index;
+
+  if (*TargetCpuIndex != (UINTN)-1) {
+    Index = *TargetCpuIndex;
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+    } else {
+      return NULL;
+    }
+  }
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+      *TargetCpuIndex = Index;
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+    }
+  }
+  return NULL;
+}
+
+/**
+  Verify Microcode.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  Image                      The Microcode image buffer.
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[in]  TryLoad                    Try to load Microcode or not.
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out] AbortReason                A pointer to a pointer to a null-terminated string providing more
+                                         details for the aborted operation. The buffer is allocated by this function
+                                         with AllocatePool(), and it is the caller's responsibility to free it with a
+                                         call to FreePool().
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
+
+  @retval EFI_SUCCESS               The Microcode image passes verification.
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupted.
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
+  @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
+**/
+EFI_STATUS
+VerifyMicrocode (
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  VOID                        *Image,
+  IN  UINTN                       ImageSize,
+  IN  BOOLEAN                     TryLoad,
+  OUT UINT32                      *LastAttemptStatus,
+  OUT CHAR16                      **AbortReason,   OPTIONAL
+  IN OUT UINTN                    *TargetCpuIndex
+  )
+{
+  UINTN                                   Index;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
+  UINTN                                   TotalSize;
+  UINTN                                   DataSize;
+  UINT32                                  CurrentRevision;
+  PROCESSOR_INFO                          *ProcessorInfo;
+  UINT32                                  InCompleteCheckSum32;
+  UINT32                                  CheckSum32;
+  UINTN                                   ExtendedTableLength;
+  UINT32                                  ExtendedTableCount;
+  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;
+  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;
+  BOOLEAN                                 CorrectMicrocode;
+
+  //
+  // Check HeaderVersion
+  //
+  MicrocodeEntryPoint = Image;
+  if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");
+    }
+    return EFI_INCOMPATIBLE_VERSION;
+  }
+  //
+  // Check LoaderRevision
+  //
+  if (MicrocodeEntryPoint->LoaderRevision != 0x1) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");
+    }
+    return EFI_INCOMPATIBLE_VERSION;
+  }
+  //
+  // Check TotalSize
+  //
+  if (MicrocodeEntryPoint->DataSize == 0) {
+    TotalSize = 2048;
+  } else {
+    TotalSize = MicrocodeEntryPoint->TotalSize;
+  }
+  if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  if ((TotalSize & (SIZE_1KB - 1)) != 0) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  if (TotalSize != ImageSize) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  //
+  // Check DataSize
+  //
+  if (MicrocodeEntryPoint->DataSize == 0) {
+    DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);
+  } else {
+    DataSize = MicrocodeEntryPoint->DataSize;
+  }
+  if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  if ((DataSize & 0x3) != 0) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  //
+  // Check CheckSum32
+  //
+  CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));
+  if (CheckSum32 != 0) {
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");
+    }
+    return EFI_VOLUME_CORRUPTED;
+  }
+  InCompleteCheckSum32 = CheckSum32;
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
+  InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
+
+  //
+  // Check ProcessorSignature/ProcessorFlags
+  //
+
+  ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
+  if (ProcessorInfo == NULL) {
+    CorrectMicrocode = FALSE;
+    ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));
+    if (ExtendedTableLength != 0) {
+      //
+      // Extended Table exist, check if the CPU in support list
+      //
+      ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));
+      //
+      // Calculate Extended Checksum
+      //
+      if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {
+        CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+        if (CheckSum32 != 0) {
+          //
+          // Checksum incorrect
+          //
+          DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));
+        } else {
+          //
+          // Checksum correct
+          //
+          ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+          if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {
+            DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount));
+          } else {
+            ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+            for (Index = 0; Index < ExtendedTableCount; Index++) {
+              CheckSum32 = InCompleteCheckSum32;
+              CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
+              CheckSum32 += ExtendedTable->ProcessorFlag;
+              CheckSum32 += ExtendedTable->Checksum;
+              if (CheckSum32 != 0) {
+                DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));
+              } else {
+                //
+                // Verify Header
+                //
+                ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
+                if (ProcessorInfo != NULL) {
+                  //
+                  // Find one
+                  //
+                  CorrectMicrocode = TRUE;
+                  break;
+                }
+              }
+              ExtendedTable++;
+            }
+          }
+        }
+      }
+    }
+    if (!CorrectMicrocode) {
+      if (TryLoad) {
+        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));
+      }
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
+      if (AbortReason != NULL) {
+        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");
+      }
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Check UpdateRevision
+  //
+  CurrentRevision = ProcessorInfo->MicrocodeRevision;
+  if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
+      (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
+    if (TryLoad) {
+      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
+    }
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
+    if (AbortReason != NULL) {
+      *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");
+    }
+    return EFI_INCOMPATIBLE_VERSION;
+  }
+
+  //
+  // try load MCU
+  //
+  if (TryLoad) {
+    CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
+    if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {
+      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
+      if (AbortReason != NULL) {
+        *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");
+      }
+      return EFI_SECURITY_VIOLATION;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get next Microcode entrypoint.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint
+
+  @return next Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+GetNextMicrocode (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
+  )
+{
+  UINTN                                   Index;
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
+      if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
+        // it is last one
+        return NULL;
+      } else {
+        // return next one
+        return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
+      }
+    }
+  }
+
+  ASSERT(FALSE);
+  return NULL;
+}
+
+/**
+  Get next FIT Microcode entrypoint.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint
+
+  @return next FIT Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+GetNextFitMicrocode (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
+  )
+{
+  UINTN                                   Index;
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {
+    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint) {
+      if (Index == (UINTN) MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1) {
+        // it is last one
+        return NULL;
+      } else {
+        // return next one
+        return MicrocodeFmpPrivate->FitMicrocodeInfo[Index + 1].MicrocodeEntryPoint;
+      }
+    }
+  }
+
+  ASSERT(FALSE);
+  return NULL;
+}
+
+/**
+  Find empty FIT Microcode entrypoint.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[out] AvailableSize              Available size of the empty FIT Microcode entrypoint.
+
+  @return Empty FIT Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+FindEmptyFitMicrocode (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN UINTN                                   ImageSize,
+  OUT UINTN                                  *AvailableSize
+  )
+{
+  UINTN                                   Index;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
+  CPU_MICROCODE_HEADER                    *NextMicrocodeEntryPoint;
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {
+    if (MicrocodeFmpPrivate->FitMicrocodeInfo[Index].Empty) {
+      MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;
+      NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);
+      if (NextMicrocodeEntryPoint != NULL) {
+        *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;
+      } else {
+        *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;
+      }
+      if (*AvailableSize >= ImageSize) {
+        return MicrocodeEntryPoint;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  Find unused FIT Microcode entrypoint.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[out] AvailableSize              Available size of the unused FIT Microcode entrypoint.
+
+  @return Unused FIT Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+FindUnusedFitMicrocode (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN UINTN                                   ImageSize,
+  OUT UINTN                                  *AvailableSize
+  )
+{
+  UINTN                                   Index;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
+  CPU_MICROCODE_HEADER                    *NextMicrocodeEntryPoint;
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {
+    if (!MicrocodeFmpPrivate->FitMicrocodeInfo[Index].InUse) {
+      MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;
+      NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);
+      if (NextMicrocodeEntryPoint != NULL) {
+        *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;
+      } else {
+        *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;
+      }
+      if (*AvailableSize >= ImageSize) {
+        return MicrocodeEntryPoint;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  Get current Microcode used region size.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+
+  @return current Microcode used region size.
+**/
+UINTN
+GetCurrentMicrocodeUsedRegionSize (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
+  )
+{
+  if (MicrocodeFmpPrivate->DescriptorCount == 0) {
+    return 0;
+  }
+
+  return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
+         + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
+         - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
+}
+
+/**
+  Update Microcode.
+
+  @param[in]   Address            The flash address of Microcode.
+  @param[in]   Image              The Microcode image buffer.
+  @param[in]   ImageSize          The size of Microcode image buffer in bytes.
+  @param[out]  LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+  @retval EFI_SUCCESS           The Microcode image is updated.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+**/
+EFI_STATUS
+UpdateMicrocode (
+  IN UINT64   Address,
+  IN VOID     *Image,
+  IN UINTN    ImageSize,
+  OUT UINT32  *LastAttemptStatus
+  )
+{
+  EFI_STATUS  Status;
+
+  DEBUG((DEBUG_INFO, "PlatformUpdate:"));
+  DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address));
+  DEBUG((DEBUG_INFO, "  Length - 0x%x\n", ImageSize));
+
+  Status = MicrocodeFlashWrite (
+             Address,
+             Image,
+             ImageSize
+             );
+  if (!EFI_ERROR(Status)) {
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+  } else {
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+  }
+  return Status;
+}
+
+/**
+  Update Microcode flash region with FIT.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated
+  @param[in]  Image                      The Microcode image buffer.
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+  @retval EFI_SUCCESS             The Microcode image is written.
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.
+**/
+EFI_STATUS
+UpdateMicrocodeFlashRegionWithFit (
+  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,
+  IN  VOID                                    *Image,
+  IN  UINTN                                   ImageSize,
+  OUT UINT32                                  *LastAttemptStatus
+  )
+{
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
+  UINTN                                   TargetTotalSize;
+  EFI_STATUS                              Status;
+  VOID                                    *MicrocodePatchScratchBuffer;
+  UINT8                                   *ScratchBufferPtr;
+  UINTN                                   ScratchBufferSize;
+  UINTN                                   RestSize;
+  UINTN                                   AvailableSize;
+  VOID                                    *NextMicrocodeEntryPoint;
+  VOID                                    *EmptyFitMicrocodeEntry;
+  VOID                                    *UnusedFitMicrocodeEntry;
+
+  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
+  if (MicrocodePatchScratchBuffer == NULL) {
+    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ScratchBufferPtr = MicrocodePatchScratchBuffer;
+  ScratchBufferSize = 0;
+
+  //
+  // Target data collection
+  //
+  TargetTotalSize = 0;
+  AvailableSize = 0;
+  if (TargetMicrocodeEntryPoint != NULL) {
+    if (TargetMicrocodeEntryPoint->DataSize == 0) {
+      TargetTotalSize = 2048;
+    } else {
+      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
+    }
+    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));
+    NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
+    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
+    if (NextMicrocodeEntryPoint != NULL) {
+      ASSERT ((UINTN) NextMicrocodeEntryPoint >= ((UINTN) TargetMicrocodeEntryPoint + TargetTotalSize));
+      AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) TargetMicrocodeEntryPoint;
+    } else {
+      AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) TargetMicrocodeEntryPoint;
+    }
+    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
+    ASSERT (AvailableSize >= TargetTotalSize);
+  }
+  //
+  // Total Size means the Microcode size.
+  // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.
+  //
+  // (1)
+  // +------+-----------+-----+------+===================+
+  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |
+  // +------+-----------+-----+------+===================+
+  //        | TotalSize |
+  //        |<-AvailableSize->|
+  //
+  // (2)
+  // +------+-----------+===================+
+  // | MCU  | Microcode |      Empty        |
+  // +------+-----------+===================+
+  //        | TotalSize |
+  //        |<-      AvailableSize        ->|
+  //
+
+  //
+  // Update based on policy
+  //
+
+  //
+  // 1. If there is enough space to update old one in situ, replace old microcode in situ.
+  //
+  if (AvailableSize >= ImageSize) {
+    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
+    //
+    // +------+------------+------+===================+
+    // |Other | Old Image  | ...  |      Empty        |
+    // +------+------------+------+===================+
+    //
+    // +------+---------+--+------+===================+
+    // |Other |New Image|FF| ...  |      Empty        |
+    // +------+---------+--+------+===================+
+    //
+    // 1.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    // 1.2. Pad 0xFF
+    RestSize = AvailableSize - ImageSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    return Status;
+  }
+
+  //
+  // 2. If there is empty FIT microcode entry with enough space, use it.
+  //
+  EmptyFitMicrocodeEntry = FindEmptyFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);
+  if (EmptyFitMicrocodeEntry != NULL) {
+    DEBUG((DEBUG_INFO, "Use empty FIT microcode entry\n"));
+    // 2.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    // 2.2. Pad 0xFF
+    RestSize = AvailableSize - ImageSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode ((UINTN) EmptyFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {
+      //
+      // Empty old microcode.
+      //
+      ScratchBufferPtr = MicrocodePatchScratchBuffer;
+      SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);
+      ScratchBufferSize = TargetTotalSize;
+      ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;
+      UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    }
+    return Status;
+  }
+
+  //
+  // 3. If there is unused microcode entry with enough space, use it.
+  //
+  UnusedFitMicrocodeEntry = FindUnusedFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);
+  if (UnusedFitMicrocodeEntry != NULL) {
+    DEBUG((DEBUG_INFO, "Use unused FIT microcode entry\n"));
+    // 3.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    // 3.2. Pad 0xFF
+    RestSize = AvailableSize - ImageSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode ((UINTN) UnusedFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {
+      //
+      // Empty old microcode.
+      //
+      ScratchBufferPtr = MicrocodePatchScratchBuffer;
+      SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);
+      ScratchBufferSize = TargetTotalSize;
+      ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;
+      UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    }
+    return Status;
+  }
+
+  //
+  // 4. No usable FIT microcode entry.
+  //
+  DEBUG((DEBUG_ERROR, "No usable FIT microcode entry\n"));
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+  Status = EFI_OUT_OF_RESOURCES;
+
+  return Status;
+}
+
+/**
+  Update Microcode flash region.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated
+  @param[in]  Image                      The Microcode image buffer.
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+  @retval EFI_SUCCESS             The Microcode image is written.
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.
+**/
+EFI_STATUS
+UpdateMicrocodeFlashRegion (
+  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,
+  IN  VOID                                    *Image,
+  IN  UINTN                                   ImageSize,
+  OUT UINT32                                  *LastAttemptStatus
+  )
+{
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
+  UINTN                                   TargetTotalSize;
+  UINTN                                   UsedRegionSize;
+  EFI_STATUS                              Status;
+  VOID                                    *MicrocodePatchScratchBuffer;
+  UINT8                                   *ScratchBufferPtr;
+  UINTN                                   ScratchBufferSize;
+  UINTN                                   RestSize;
+  UINTN                                   AvailableSize;
+  VOID                                    *NextMicrocodeEntryPoint;
+  MICROCODE_INFO                          *MicrocodeInfo;
+  UINTN                                   MicrocodeCount;
+  UINTN                                   Index;
+
+  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
+
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
+  if (MicrocodePatchScratchBuffer == NULL) {
+    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ScratchBufferPtr = MicrocodePatchScratchBuffer;
+  ScratchBufferSize = 0;
+
+  //
+  // Target data collection
+  //
+  TargetTotalSize = 0;
+  AvailableSize = 0;
+  NextMicrocodeEntryPoint = NULL;
+  if (TargetMicrocodeEntryPoint != NULL) {
+    if (TargetMicrocodeEntryPoint->DataSize == 0) {
+      TargetTotalSize = 2048;
+    } else {
+      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
+    }
+    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));
+    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
+    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
+    if (NextMicrocodeEntryPoint != NULL) {
+      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
+      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
+    } else {
+      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
+    }
+    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
+    ASSERT (AvailableSize >= TargetTotalSize);
+  }
+  UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
+  DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));
+  ASSERT (UsedRegionSize >= TargetTotalSize);
+  if (TargetMicrocodeEntryPoint != NULL) {
+    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
+  }
+  //
+  // Total Size means the Microcode size.
+  // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.
+  //
+  // (1)
+  // +------+-----------+-----+------+===================+
+  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |
+  // +------+-----------+-----+------+===================+
+  //        | TotalSize |
+  //        |<-AvailableSize->|
+  // |<-        UsedRegionSize     ->|
+  //
+  // (2)
+  // +------+-----------+===================+
+  // | MCU  | Microcode |      Empty        |
+  // +------+-----------+===================+
+  //        | TotalSize |
+  //        |<-      AvailableSize        ->|
+  // |<-UsedRegionSize->|
+  //
+
+  //
+  // Update based on policy
+  //
+
+  //
+  // 1. If there is enough space to update old one in situ, replace old microcode in situ.
+  //
+  if (AvailableSize >= ImageSize) {
+    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
+    //
+    // +------+------------+------+===================+
+    // |Other | Old Image  | ...  |      Empty        |
+    // +------+------------+------+===================+
+    //
+    // +------+---------+--+------+===================+
+    // |Other |New Image|FF| ...  |      Empty        |
+    // +------+---------+--+------+===================+
+    //
+    // 1.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    // 1.2. Pad 0xFF
+    RestSize = AvailableSize - ImageSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    return Status;
+  }
+
+  //
+  // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
+  //
+  if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
+    if (TargetMicrocodeEntryPoint == NULL) {
+      DEBUG((DEBUG_INFO, "Append new microcode\n"));
+      //
+      // +------+------------+------+===================+
+      // |Other1|   Other    |Other2|      Empty        |
+      // +------+------------+------+===================+
+      //
+      // +------+------------+------+-----------+=======+
+      // |Other1|   Other    |Other2| New Image | Empty |
+      // +------+------------+------+-----------+=======+
+      //
+      Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
+    } else {
+      DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
+      //
+      // +------+------------+------+===================+
+      // |Other | Old Image  | ...  |      Empty        |
+      // +------+------------+------+===================+
+      //
+      // +------+---------------+------+================+
+      // |Other |   New Image   | ...  |      Empty     |
+      // +------+---------------+------+================+
+      //
+      // 2.1. Copy new image
+      CopyMem (ScratchBufferPtr, Image, ImageSize);
+      ScratchBufferSize += ImageSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+      // 2.2. Copy rest images after the old image.
+      if (NextMicrocodeEntryPoint != 0) {
+        RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
+        CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);
+        ScratchBufferSize += RestSize;
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+      }
+      Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    }
+    return Status;
+  }
+
+  //
+  // 3. The new image can be put in MCU region, but not all others can be put.
+  //    So all the unused MCU is removed.
+  //
+  if (MicrocodePatchRegionSize >= ImageSize) {
+    //
+    // +------+------------+------+===================+
+    // |Other1| Old Image  |Other2|      Empty        |
+    // +------+------------+------+===================+
+    //
+    // +-------------------------------------+--------+
+    // |        New Image                    | Other  |
+    // +-------------------------------------+--------+
+    //
+    DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
+
+    MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
+    MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+
+    // 3.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    // 3.2. Copy some others to rest buffer
+    for (Index = 0; Index < MicrocodeCount; Index++) {
+      if (!MicrocodeInfo[Index].InUse) {
+        continue;
+      }
+      if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
+        continue;
+      }
+      if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
+        CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
+        ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+      }
+    }
+    // 3.3. Pad 0xFF
+    RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    return Status;
+  }
+
+  //
+  // 4. The new image size is bigger than the whole MCU region.
+  //
+  DEBUG((DEBUG_ERROR, "Microcode too big\n"));
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+  Status = EFI_OUT_OF_RESOURCES;
+
+  return Status;
+}
+
+/**
+  Write Microcode.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]   MicrocodeFmpPrivate The Microcode driver private data
+  @param[in]   Image               The Microcode image buffer.
+  @param[in]   ImageSize           The size of Microcode image buffer in bytes.
+  @param[out]  LastAttemptVersion  The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]  LastAttemptStatus   The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]  AbortReason         A pointer to a pointer to a null-terminated string providing more
+                                   details for the aborted operation. The buffer is allocated by this function
+                                   with AllocatePool(), and it is the caller's responsibility to free it with a
+                                   call to FreePool().
+
+  @retval EFI_SUCCESS               The Microcode image is written.
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupted.
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
+  @retval EFI_WRITE_PROTECTED       The flash device is read only.
+**/
+EFI_STATUS
+MicrocodeWrite (
+  IN  MICROCODE_FMP_PRIVATE_DATA   *MicrocodeFmpPrivate,
+  IN  VOID                         *Image,
+  IN  UINTN                        ImageSize,
+  OUT UINT32                       *LastAttemptVersion,
+  OUT UINT32                       *LastAttemptStatus,
+  OUT CHAR16                       **AbortReason
+  )
+{
+  EFI_STATUS                              Status;
+  VOID                                    *AlignedImage;
+  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint;
+  UINTN                                   TargetCpuIndex;
+  UINTN                                   TargetMicrcodeIndex;
+
+  //
+  // MCU must be 16 bytes aligned
+  //
+  AlignedImage = AllocateCopyPool(ImageSize, Image);
+  if (AlignedImage == NULL) {
+    DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  TargetCpuIndex = (UINTN)-1;
+  Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
+    FreePool(AlignedImage);
+    return Status;
+  }
+  DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
+  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
+
+  DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));
+  ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+  TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
+  DEBUG((DEBUG_INFO, "  TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
+  if (TargetMicrcodeIndex != (UINTN)-1) {
+    ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
+    TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
+  } else {
+    TargetMicrocodeEntryPoint = NULL;
+  }
+  DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
+
+  if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {
+    Status = UpdateMicrocodeFlashRegionWithFit (
+               MicrocodeFmpPrivate,
+               TargetMicrocodeEntryPoint,
+               AlignedImage,
+               ImageSize,
+               LastAttemptStatus
+               );
+  } else {
+    Status = UpdateMicrocodeFlashRegion (
+               MicrocodeFmpPrivate,
+               TargetMicrocodeEntryPoint,
+               AlignedImage,
+               ImageSize,
+               LastAttemptStatus
+               );
+  }
+
+  FreePool(AlignedImage);
+
+  return Status;
+}
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c
new file mode 100644
index 0000000000..0bd4e818ab
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c
@@ -0,0 +1,538 @@
+/** @file
+  BmDma related function
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+// TBD: May make it a policy
+#define DMA_MEMORY_TOP          MAX_UINTN
+//#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL
+
+#define MAP_HANDLE_INFO_SIGNATURE  SIGNATURE_32 ('H', 'M', 'A', 'P')
+typedef struct {
+  UINT32                                    Signature;
+  LIST_ENTRY                                Link;
+  EFI_HANDLE                                DeviceHandle;
+  UINT64                                    IoMmuAccess;
+} MAP_HANDLE_INFO;
+#define MAP_HANDLE_INFO_FROM_LINK(a) CR (a, MAP_HANDLE_INFO, Link, MAP_HANDLE_INFO_SIGNATURE)
+
+#define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')
+typedef struct {
+  UINT32                                    Signature;
+  LIST_ENTRY                                Link;
+  EDKII_IOMMU_OPERATION                     Operation;
+  UINTN                                     NumberOfBytes;
+  UINTN                                     NumberOfPages;
+  EFI_PHYSICAL_ADDRESS                      HostAddress;
+  EFI_PHYSICAL_ADDRESS                      DeviceAddress;
+  LIST_ENTRY                                HandleList;
+} MAP_INFO;
+#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
+
+LIST_ENTRY                        gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);
+
+/**
+  This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,
+  based upon the DeviceAddress.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  DeviceAddress     The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+**/
+VOID
+SyncDeviceHandleToMapInfo (
+  IN EFI_HANDLE            DeviceHandle,
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  )
+{
+  MAP_INFO                 *MapInfo;
+  MAP_HANDLE_INFO          *MapHandleInfo;
+  LIST_ENTRY               *Link;
+  EFI_TPL                  OriginalTpl;
+
+  //
+  // Find MapInfo according to DeviceAddress
+  //
+  OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);
+  MapInfo = NULL;
+  for (Link = GetFirstNode (&gMaps)
+       ; !IsNull (&gMaps, Link)
+       ; Link = GetNextNode (&gMaps, Link)
+       ) {
+    MapInfo = MAP_INFO_FROM_LINK (Link);
+    if (MapInfo->DeviceAddress == DeviceAddress) {
+      break;
+    }
+  }
+  if ((MapInfo == NULL) || (MapInfo->DeviceAddress != DeviceAddress)) {
+    DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: DeviceAddress(0x%lx) - not found\n", DeviceAddress));
+    gBS->RestoreTPL (OriginalTpl);
+    return ;
+  }
+
+  //
+  // Find MapHandleInfo according to DeviceHandle
+  //
+  MapHandleInfo = NULL;
+  for (Link = GetFirstNode (&MapInfo->HandleList)
+       ; !IsNull (&MapInfo->HandleList, Link)
+       ; Link = GetNextNode (&MapInfo->HandleList, Link)
+       ) {
+    MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (Link);
+    if (MapHandleInfo->DeviceHandle == DeviceHandle) {
+      break;
+    }
+  }
+  if ((MapHandleInfo != NULL) && (MapHandleInfo->DeviceHandle == DeviceHandle)) {
+    MapHandleInfo->IoMmuAccess       = IoMmuAccess;
+    gBS->RestoreTPL (OriginalTpl);
+    return ;
+  }
+
+  //
+  // No DeviceHandle
+  // Initialize and insert the MAP_HANDLE_INFO structure
+  //
+  MapHandleInfo = AllocatePool (sizeof (MAP_HANDLE_INFO));
+  if (MapHandleInfo == NULL) {
+    DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: %r\n", EFI_OUT_OF_RESOURCES));
+    gBS->RestoreTPL (OriginalTpl);
+    return ;
+  }
+
+  MapHandleInfo->Signature         = MAP_HANDLE_INFO_SIGNATURE;
+  MapHandleInfo->DeviceHandle      = DeviceHandle;
+  MapHandleInfo->IoMmuAccess       = IoMmuAccess;
+
+  InsertTailList (&MapInfo->HandleList, &MapHandleInfo->Link);
+  gBS->RestoreTPL (OriginalTpl);
+
+  return ;
+}
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  The protocol instance pointer.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuMap (
+  IN     EDKII_IOMMU_PROTOCOL                       *This,
+  IN     EDKII_IOMMU_OPERATION                      Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  )
+{
+  EFI_STATUS                                        Status;
+  EFI_PHYSICAL_ADDRESS                              PhysicalAddress;
+  MAP_INFO                                          *MapInfo;
+  EFI_PHYSICAL_ADDRESS                              DmaMemoryTop;
+  BOOLEAN                                           NeedRemap;
+  EFI_TPL                                           OriginalTpl;
+
+  if (NumberOfBytes == NULL || DeviceAddress == NULL ||
+      Mapping == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress, *NumberOfBytes, Operation));
+
+  //
+  // Make sure that Operation is valid
+  //
+  if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+  NeedRemap = FALSE;
+  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+
+  DmaMemoryTop = DMA_MEMORY_TOP;
+
+  //
+  // Alignment check
+  //
+  if ((*NumberOfBytes != ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||
+      (PhysicalAddress != ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {
+    if ((Operation == EdkiiIoMmuOperationBusMasterCommonBuffer) ||
+        (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64)) {
+      //
+      // The input buffer might be a subset from IoMmuAllocateBuffer.
+      // Skip the check.
+      //
+    } else {
+      NeedRemap = TRUE;
+    }
+  }
+
+  if ((PhysicalAddress + *NumberOfBytes) >= DMA_MEMORY_TOP) {
+    NeedRemap = TRUE;
+  }
+
+  if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&
+        Operation != EdkiiIoMmuOperationBusMasterWrite64 &&
+        Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&
+      ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {
+    //
+    // If the root bridge or the device cannot handle performing DMA above
+    // 4GB but any part of the DMA transfer being mapped is above 4GB, then
+    // map the DMA transfer to a buffer below 4GB.
+    //
+    NeedRemap = TRUE;
+    DmaMemoryTop = MIN (DmaMemoryTop, SIZE_4GB - 1);
+  }
+
+  if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
+      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
+    if (NeedRemap) {
+      //
+      // Common Buffer operations can not be remapped.  If the common buffer
+      // is above 4GB, then it is not possible to generate a mapping, so return
+      // an error.
+      //
+      DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  //
+  // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
+  // called later.
+  //
+  MapInfo = AllocatePool (sizeof (MAP_INFO));
+  if (MapInfo == NULL) {
+    *NumberOfBytes = 0;
+    DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the MAP_INFO structure
+  //
+  MapInfo->Signature         = MAP_INFO_SIGNATURE;
+  MapInfo->Operation         = Operation;
+  MapInfo->NumberOfBytes     = *NumberOfBytes;
+  MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
+  MapInfo->HostAddress       = PhysicalAddress;
+  MapInfo->DeviceAddress     = DmaMemoryTop;
+  InitializeListHead(&MapInfo->HandleList);
+
+  //
+  // Allocate a buffer below 4GB to map the transfer to.
+  //
+  if (NeedRemap) {
+    Status = gBS->AllocatePages (
+                    AllocateMaxAddress,
+                    EfiBootServicesData,
+                    MapInfo->NumberOfPages,
+                    &MapInfo->DeviceAddress
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (MapInfo);
+      *NumberOfBytes = 0;
+      DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));
+      return Status;
+    }
+
+    //
+    // If this is a read operation from the Bus Master's point of view,
+    // then copy the contents of the real buffer into the mapped buffer
+    // so the Bus Master can read the contents of the real buffer.
+    //
+    if (Operation == EdkiiIoMmuOperationBusMasterRead ||
+        Operation == EdkiiIoMmuOperationBusMasterRead64) {
+      CopyMem (
+        (VOID *) (UINTN) MapInfo->DeviceAddress,
+        (VOID *) (UINTN) MapInfo->HostAddress,
+        MapInfo->NumberOfBytes
+        );
+    }
+  } else {
+    MapInfo->DeviceAddress = MapInfo->HostAddress;
+  }
+
+  OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);
+  InsertTailList (&gMaps, &MapInfo->Link);
+  gBS->RestoreTPL (OriginalTpl);
+
+  //
+  // The DeviceAddress is the address of the maped buffer below 4GB
+  //
+  *DeviceAddress = MapInfo->DeviceAddress;
+  //
+  // Return a pointer to the MAP_INFO structure in Mapping
+  //
+  *Mapping       = MapInfo;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress, *Mapping));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  The protocol instance pointer.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IoMmuUnmap (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  VOID                                     *Mapping
+  )
+{
+  MAP_INFO                 *MapInfo;
+  MAP_HANDLE_INFO          *MapHandleInfo;
+  LIST_ENTRY               *Link;
+  EFI_TPL                  OriginalTpl;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));
+
+  if (Mapping == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);
+  MapInfo = NULL;
+  for (Link = GetFirstNode (&gMaps)
+       ; !IsNull (&gMaps, Link)
+       ; Link = GetNextNode (&gMaps, Link)
+       ) {
+    MapInfo = MAP_INFO_FROM_LINK (Link);
+    if (MapInfo == Mapping) {
+      break;
+    }
+  }
+  //
+  // Mapping is not a valid value returned by Map()
+  //
+  if (MapInfo != Mapping) {
+    gBS->RestoreTPL (OriginalTpl);
+    DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+  RemoveEntryList (&MapInfo->Link);
+  gBS->RestoreTPL (OriginalTpl);
+
+  //
+  // remove all nodes in MapInfo->HandleList
+  //
+  while (!IsListEmpty (&MapInfo->HandleList)) {
+    MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (MapInfo->HandleList.ForwardLink);
+    RemoveEntryList (&MapHandleInfo->Link);
+    FreePool (MapHandleInfo);
+  }
+
+  if (MapInfo->DeviceAddress != MapInfo->HostAddress) {
+    //
+    // If this is a write operation from the Bus Master's point of view,
+    // then copy the contents of the mapped buffer into the real buffer
+    // so the processor can read the contents of the real buffer.
+    //
+    if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
+        MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
+      CopyMem (
+        (VOID *) (UINTN) MapInfo->HostAddress,
+        (VOID *) (UINTN) MapInfo->DeviceAddress,
+        MapInfo->NumberOfBytes
+        );
+    }
+
+    //
+    // Free the mapped buffer and the MAP_INFO structure.
+    //
+    gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);
+  }
+
+  FreePool (Mapping);
+  return EFI_SUCCESS;
+}
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  The protocol instance pointer.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuAllocateBuffer (
+  IN     EDKII_IOMMU_PROTOCOL                     *This,
+  IN     EFI_ALLOCATE_TYPE                        Type,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  )
+{
+  EFI_STATUS                Status;
+  EFI_PHYSICAL_ADDRESS      PhysicalAddress;
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages));
+
+  //
+  // Validate Attributes
+  //
+  if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check for invalid inputs
+  //
+  if (HostAddress == NULL) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The only valid memory types are EfiBootServicesData and
+  // EfiRuntimeServicesData
+  //
+  if (MemoryType != EfiBootServicesData &&
+      MemoryType != EfiRuntimeServicesData) {
+    DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PhysicalAddress = DMA_MEMORY_TOP;
+  if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+    //
+    // Limit allocations to memory below 4GB
+    //
+    PhysicalAddress = MIN (PhysicalAddress, SIZE_4GB - 1);
+  }
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  MemoryType,
+                  Pages,
+                  &PhysicalAddress
+                  );
+  if (!EFI_ERROR (Status)) {
+    *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress));
+
+  return Status;
+}
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  The protocol instance pointer.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuFreeBuffer (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));
+  return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
+}
+
+/**
+  Get device information from mapping.
+
+  @param[in]  Mapping        The mapping.
+  @param[out] DeviceAddress  The device address of the mapping.
+  @param[out] NumberOfPages  The number of pages of the mapping.
+
+  @retval EFI_SUCCESS            The device information is returned.
+  @retval EFI_INVALID_PARAMETER  The mapping is invalid.
+**/
+EFI_STATUS
+GetDeviceInfoFromMapping (
+  IN  VOID                                     *Mapping,
+  OUT EFI_PHYSICAL_ADDRESS                     *DeviceAddress,
+  OUT UINTN                                    *NumberOfPages
+  )
+{
+  MAP_INFO                 *MapInfo;
+  LIST_ENTRY               *Link;
+
+  if (Mapping == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MapInfo = NULL;
+  for (Link = GetFirstNode (&gMaps)
+       ; !IsNull (&gMaps, Link)
+       ; Link = GetNextNode (&gMaps, Link)
+       ) {
+    MapInfo = MAP_INFO_FROM_LINK (Link);
+    if (MapInfo == Mapping) {
+      break;
+    }
+  }
+  //
+  // Mapping is not a valid value returned by Map()
+  //
+  if (MapInfo != Mapping) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DeviceAddress = MapInfo->DeviceAddress;
+  *NumberOfPages = MapInfo->NumberOfPages;
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
new file mode 100644
index 0000000000..956ebb2d3d
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
@@ -0,0 +1,683 @@
+/** @file
+
+  Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+UINT64                                  mBelow4GMemoryLimit;
+UINT64                                  mAbove4GMemoryLimit;
+
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL      *mPlatformVTdPolicy;
+
+VTD_ACCESS_REQUEST                      *mAccessRequest = NULL;
+UINTN                                   mAccessRequestCount = 0;
+UINTN                                   mAccessRequestMaxCount = 0;
+
+/**
+  Append VTd Access Request to global.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS           The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER Length is 0.
+  @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED       The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED       The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR      The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+RequestAccessAttribute (
+  IN UINT16                 Segment,
+  IN VTD_SOURCE_ID          SourceId,
+  IN UINT64                 BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 IoMmuAccess
+  )
+{
+  VTD_ACCESS_REQUEST        *NewAccessRequest;
+  UINTN                     Index;
+
+  //
+  // Optimization for memory.
+  //
+  // If the last record is to IoMmuAccess=0,
+  // Check previous records and remove the matched entry.
+  //
+  if (IoMmuAccess == 0) {
+    for (Index = 0; Index < mAccessRequestCount; Index++) {
+      if ((mAccessRequest[Index].Segment == Segment) &&
+          (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) &&
+          (mAccessRequest[Index].BaseAddress == BaseAddress) &&
+          (mAccessRequest[Index].Length == Length) &&
+          (mAccessRequest[Index].IoMmuAccess != 0)) {
+        //
+        // Remove this record [Index].
+        // No need to add the new record.
+        //
+        if (Index != mAccessRequestCount - 1) {
+          CopyMem (
+            &mAccessRequest[Index],
+            &mAccessRequest[Index + 1],
+            sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index)
+            );
+        }
+        ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST));
+        mAccessRequestCount--;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  if (mAccessRequestCount >= mAccessRequestMaxCount) {
+    NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));
+    if (NewAccessRequest == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST;
+    if (mAccessRequest != NULL) {
+      CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount);
+      FreePool (mAccessRequest);
+    }
+    mAccessRequest = NewAccessRequest;
+  }
+
+  ASSERT (mAccessRequestCount < mAccessRequestMaxCount);
+
+  mAccessRequest[mAccessRequestCount].Segment = Segment;
+  mAccessRequest[mAccessRequestCount].SourceId = SourceId;
+  mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress;
+  mAccessRequest[mAccessRequestCount].Length = Length;
+  mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess;
+
+  mAccessRequestCount++;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Process Access Requests from before DMAR table is installed.
+
+**/
+VOID
+ProcessRequestedAccessAttribute (
+  VOID
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));
+
+  for (Index = 0; Index < mAccessRequestCount; Index++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "PCI(S%x.B%x.D%x.F%x) ",
+      mAccessRequest[Index].Segment,
+      mAccessRequest[Index].SourceId.Bits.Bus,
+      mAccessRequest[Index].SourceId.Bits.Device,
+      mAccessRequest[Index].SourceId.Bits.Function
+      ));
+    DEBUG ((
+      DEBUG_INFO,
+      "(0x%lx~0x%lx) - %lx\n",
+      mAccessRequest[Index].BaseAddress,
+      mAccessRequest[Index].Length,
+      mAccessRequest[Index].IoMmuAccess
+      ));
+    Status = SetAccessAttribute (
+               mAccessRequest[Index].Segment,
+               mAccessRequest[Index].SourceId,
+               mAccessRequest[Index].BaseAddress,
+               mAccessRequest[Index].Length,
+               mAccessRequest[Index].IoMmuAccess
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));
+    }
+  }
+
+  if (mAccessRequest != NULL) {
+    FreePool (mAccessRequest);
+  }
+  mAccessRequest = NULL;
+  mAccessRequestCount = 0;
+  mAccessRequestMaxCount = 0;
+
+  DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));
+}
+
+/**
+  return the UEFI memory information.
+
+  @param[out] Below4GMemoryLimit  The below 4GiB memory limit
+  @param[out] Above4GMemoryLimit  The above 4GiB memory limit
+**/
+VOID
+ReturnUefiMemoryMap (
+  OUT UINT64   *Below4GMemoryLimit,
+  OUT UINT64   *Above4GMemoryLimit
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMap;
+  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMapEnd;
+  EFI_MEMORY_DESCRIPTOR       *EfiEntry;
+  EFI_MEMORY_DESCRIPTOR       *NextEfiEntry;
+  EFI_MEMORY_DESCRIPTOR       TempEfiEntry;
+  UINTN                       EfiMemoryMapSize;
+  UINTN                       EfiMapKey;
+  UINTN                       EfiDescriptorSize;
+  UINT32                      EfiDescriptorVersion;
+  UINT64                      MemoryBlockLength;
+
+  *Below4GMemoryLimit = 0;
+  *Above4GMemoryLimit = 0;
+
+  //
+  // Get the EFI memory map.
+  //
+  EfiMemoryMapSize  = 0;
+  EfiMemoryMap      = NULL;
+  Status = gBS->GetMemoryMap (
+                  &EfiMemoryMapSize,
+                  EfiMemoryMap,
+                  &EfiMapKey,
+                  &EfiDescriptorSize,
+                  &EfiDescriptorVersion
+                  );
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+  do {
+    //
+    // Use size returned back plus 1 descriptor for the AllocatePool.
+    // We don't just multiply by 2 since the "for" loop below terminates on
+    // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
+    // we process bogus entries and create bogus E820 entries.
+    //
+    EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
+    ASSERT (EfiMemoryMap != NULL);
+    Status = gBS->GetMemoryMap (
+                    &EfiMemoryMapSize,
+                    EfiMemoryMap,
+                    &EfiMapKey,
+                    &EfiDescriptorSize,
+                    &EfiDescriptorVersion
+                    );
+    if (EFI_ERROR (Status)) {
+      FreePool (EfiMemoryMap);
+    }
+  } while (Status == EFI_BUFFER_TOO_SMALL);
+
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Sort memory map from low to high
+  //
+  EfiEntry        = EfiMemoryMap;
+  NextEfiEntry    = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+  while (EfiEntry < EfiMemoryMapEnd) {
+    while (NextEfiEntry < EfiMemoryMapEnd) {
+      if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
+        CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+        CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+        CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+      }
+
+      NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
+    }
+
+    EfiEntry      = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+    NextEfiEntry  = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  }
+
+  //
+  //
+  //
+  DEBUG ((DEBUG_INFO, "MemoryMap:\n"));
+  EfiEntry        = EfiMemoryMap;
+  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+  while (EfiEntry < EfiMemoryMapEnd) {
+    MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
+    DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));
+    switch (EfiEntry->Type) {
+    case EfiLoaderCode:
+    case EfiLoaderData:
+    case EfiBootServicesCode:
+    case EfiBootServicesData:
+    case EfiConventionalMemory:
+    case EfiRuntimeServicesCode:
+    case EfiRuntimeServicesData:
+    case EfiACPIReclaimMemory:
+    case EfiACPIMemoryNVS:
+    case EfiReservedMemoryType:
+      if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {
+        //
+        // Skip the memory block is under 1MB
+        //
+      } else if (EfiEntry->PhysicalStart >= BASE_4GB) {
+        if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
+          *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
+        }
+      } else {
+        if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
+          *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
+        }
+      }
+      break;
+    }
+    EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+  }
+
+  FreePool (EfiMemoryMap);
+
+  DEBUG ((DEBUG_INFO, "Result:\n"));
+  DEBUG ((DEBUG_INFO, "Below4GMemoryLimit:  0x%016lx\n", *Below4GMemoryLimit));
+  DEBUG ((DEBUG_INFO, "Above4GMemoryLimit:  0x%016lx\n", *Above4GMemoryLimit));
+
+  return ;
+}
+
+/**
+  The scan bus callback function to always enable page attribute.
+
+  @param[in]  Context               The context of the callback.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Device                The device of the source.
+  @param[in]  Function              The function of the source.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+EFIAPI
+ScanBusCallbackAlwaysEnablePageAttribute (
+  IN VOID           *Context,
+  IN UINT16         Segment,
+  IN UINT8          Bus,
+  IN UINT8          Device,
+  IN UINT8          Function
+  )
+{
+  VTD_SOURCE_ID           SourceId;
+  EFI_STATUS              Status;
+
+  SourceId.Bits.Bus = Bus;
+  SourceId.Bits.Device = Device;
+  SourceId.Bits.Function = Function;
+  Status = AlwaysEnablePageAttribute (Segment, SourceId);
+  return Status;
+}
+
+/**
+  Always enable the VTd page attribute for the device in the DeviceScope.
+
+  @param[in]  DeviceScope  the input device scope data structure
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
+**/
+EFI_STATUS
+AlwaysEnablePageAttributeDeviceScope (
+  IN  EDKII_PLATFORM_VTD_DEVICE_SCOPE   *DeviceScope
+  )
+{
+  UINT8                             Bus;
+  UINT8                             Device;
+  UINT8                             Function;
+  VTD_SOURCE_ID                     SourceId;
+  UINT8                             SecondaryBusNumber;
+  EFI_STATUS                        Status;
+
+  Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);
+
+  if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {
+    //
+    // Need scan the bridge and add all devices.
+    //
+    SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+    Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);
+    return Status;
+  } else {
+    SourceId.Bits.Bus      = Bus;
+    SourceId.Bits.Device   = Device;
+    SourceId.Bits.Function = Function;
+    Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);
+    return Status;
+  }
+}
+
+/**
+  Always enable the VTd page attribute for the device matching DeviceId.
+
+  @param[in]  PciDeviceId  the input PCI device ID
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.
+**/
+EFI_STATUS
+AlwaysEnablePageAttributePciDeviceId (
+  IN  EDKII_PLATFORM_VTD_PCI_DEVICE_ID   *PciDeviceId
+  )
+{
+  UINTN            VtdIndex;
+  UINTN            PciIndex;
+  PCI_DEVICE_DATA  *PciDeviceData;
+  EFI_STATUS       Status;
+
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {
+      PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];
+
+      if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&
+          ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&
+          ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&
+          ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&
+          ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {
+        Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);
+        if (EFI_ERROR(Status)) {
+          continue;
+        }
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Always enable the VTd page attribute for the device.
+
+  @param[in]  DeviceInfo  the exception device information
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device in the device info.
+**/
+EFI_STATUS
+AlwaysEnablePageAttributeExceptionDeviceInfo (
+  IN  EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO   *DeviceInfo
+  )
+{
+  switch (DeviceInfo->Type) {
+  case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:
+    return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));
+  case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:
+    return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));
+  default:
+    return EFI_UNSUPPORTED;
+  }
+}
+
+/**
+  Initialize platform VTd policy.
+**/
+VOID
+InitializePlatformVTdPolicy (
+  VOID
+  )
+{
+  EFI_STATUS                               Status;
+  UINTN                                    DeviceInfoCount;
+  VOID                                     *DeviceInfo;
+  EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;
+  UINTN                                    Index;
+
+  //
+  // It is optional.
+  //
+  Status = gBS->LocateProtocol (
+                  &gEdkiiPlatformVTdPolicyProtocolGuid,
+                  NULL,
+                  (VOID **)&mPlatformVTdPolicy
+                  );
+  if (!EFI_ERROR(Status)) {
+    DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));
+    Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);
+    if (!EFI_ERROR(Status)) {
+      ThisDeviceInfo = DeviceInfo;
+      for (Index = 0; Index < DeviceInfoCount; Index++) {
+        if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {
+          break;
+        }
+        AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);
+        ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);
+      }
+      FreePool (DeviceInfo);
+    }
+  }
+}
+
+/**
+  Setup VTd engine.
+**/
+VOID
+SetupVtd (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  VOID            *PciEnumerationComplete;
+  UINTN           Index;
+  UINT64          Below4GMemoryLimit;
+  UINT64          Above4GMemoryLimit;
+
+  //
+  // PCI Enumeration must be done
+  //
+  Status = gBS->LocateProtocol (
+                  &gEfiPciEnumerationCompleteProtocolGuid,
+                  NULL,
+                  &PciEnumerationComplete
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);
+  Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);
+  DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));
+
+  mBelow4GMemoryLimit = Below4GMemoryLimit;
+  mAbove4GMemoryLimit = Above4GMemoryLimit;
+
+  //
+  // 1. setup
+  //
+  DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));
+  Status = ParseDmarAcpiTableDrhd ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
+  PrepareVtdConfig ();
+
+  //
+  // 2. initialization
+  //
+  DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));
+  Status = SetupTranslationTable ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  InitializePlatformVTdPolicy ();
+
+  ParseDmarAcpiTableRmrr ();
+
+  if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) == 0) {
+    //
+    // Support IOMMU access attribute request recording before DMAR table is installed.
+    // Here is to process the requests.
+    //
+    ProcessRequestedAccessAttribute ();
+  }
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));
+    if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
+      DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);
+    }
+    if (mVtdUnitInformation[Index].RootEntryTable != NULL) {
+      DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);
+    }
+  }
+
+  //
+  // 3. enable
+  //
+  DEBUG ((DEBUG_INFO, "EnableDmar\n"));
+  Status = EnableDmar ();
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+  DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));
+  DumpVtdRegsAll ();
+}
+
+/**
+  Notification function of ACPI Table change.
+
+  This is a notification function registered on ACPI Table change event.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+AcpiNotificationFunc (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  EFI_STATUS          Status;
+
+  Status = GetDmarAcpiTable ();
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_ALREADY_STARTED) {
+      gBS->CloseEvent (Event);
+    }
+    return;
+  }
+  SetupVtd ();
+  gBS->CloseEvent (Event);
+}
+
+/**
+  Exit boot service callback function.
+
+  @param[in]  Event    The event handle.
+  @param[in]  Context  The event content.
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+  IN EFI_EVENT                               Event,
+  IN VOID                                    *Context
+  )
+{
+  UINTN   VtdIndex;
+
+  DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));
+  DumpVtdRegsAll ();
+
+  DEBUG ((DEBUG_INFO, "Invalidate all\n"));
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    FlushWriteBuffer (VtdIndex);
+
+    InvalidateContextCache (VtdIndex);
+
+    InvalidateIOTLB (VtdIndex);
+  }
+
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
+    DisableDmar ();
+    DumpVtdRegsAll ();
+  }
+}
+
+/**
+  Legacy boot callback function.
+
+  @param[in]  Event    The event handle.
+  @param[in]  Context  The event content.
+**/
+VOID
+EFIAPI
+OnLegacyBoot (
+  EFI_EVENT                               Event,
+  VOID                                    *Context
+  )
+{
+  DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));
+  DumpVtdRegsAll ();
+  DisableDmar ();
+  DumpVtdRegsAll ();
+}
+
+/**
+  Initialize DMA protection.
+**/
+VOID
+InitializeDmaProtection (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   ExitBootServicesEvent;
+  EFI_EVENT   LegacyBootEvent;
+  EFI_EVENT   EventAcpi10;
+  EFI_EVENT   EventAcpi20;
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  VTD_TPL_LEVEL,
+                  AcpiNotificationFunc,
+                  NULL,
+                  &gEfiAcpi10TableGuid,
+                  &EventAcpi10
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  VTD_TPL_LEVEL,
+                  AcpiNotificationFunc,
+                  NULL,
+                  &gEfiAcpi20TableGuid,
+                  &EventAcpi20
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Signal the events initially for the case
+  // that DMAR table has been installed.
+  //
+  gBS->SignalEvent (EventAcpi20);
+  gBS->SignalEvent (EventAcpi10);
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  OnExitBootServices,
+                  NULL,
+                  &gEfiEventExitBootServicesGuid,
+                  &ExitBootServicesEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = EfiCreateEventLegacyBootEx (
+             TPL_CALLBACK,
+             OnLegacyBoot,
+             NULL,
+             &LegacyBootEvent
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return ;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c
new file mode 100644
index 0000000000..52bc189078
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmarAcpiTable.c
@@ -0,0 +1,890 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+#pragma pack(1)
+
+typedef struct {
+  EFI_ACPI_DESCRIPTION_HEADER  Header;
+  UINT32                       Entry;
+} RSDT_TABLE;
+
+typedef struct {
+  EFI_ACPI_DESCRIPTION_HEADER  Header;
+  UINT64                       Entry;
+} XSDT_TABLE;
+
+#pragma pack()
+
+EFI_ACPI_DMAR_HEADER  *mAcpiDmarTable = NULL;
+
+/**
+  Dump DMAR DeviceScopeEntry.
+
+  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
+**/
+VOID
+DumpDmarDeviceScopeEntry (
+  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+  )
+{
+  UINTN   PciPathNumber;
+  UINTN   PciPathIndex;
+  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
+
+  if (DmarDeviceScopeEntry == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
+    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
+    DmarDeviceScopeEntry
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Device Scope Entry Type ............................ 0x%02x\n",
+    DmarDeviceScopeEntry->Type
+    ));
+  switch (DmarDeviceScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Endpoint Device\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Sub-hierachy\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+    DEBUG ((DEBUG_INFO,
+      "        IOAPIC\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+    DEBUG ((DEBUG_INFO,
+      "        MSI Capable HPET\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+    DEBUG ((DEBUG_INFO,
+      "        ACPI Namespace Device\n"
+      ));
+    break;
+  default:
+    break;
+  }
+  DEBUG ((DEBUG_INFO,
+    "      Length ............................................. 0x%02x\n",
+    DmarDeviceScopeEntry->Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Enumeration ID ..................................... 0x%02x\n",
+    DmarDeviceScopeEntry->EnumerationId
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Starting Bus Number ................................ 0x%02x\n",
+    DmarDeviceScopeEntry->StartBusNumber
+    ));
+
+  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
+  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
+  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
+    DEBUG ((DEBUG_INFO,
+      "      Device ............................................. 0x%02x\n",
+      PciPath[PciPathIndex].Device
+      ));
+    DEBUG ((DEBUG_INFO,
+      "      Function ........................................... 0x%02x\n",
+      PciPath[PciPathIndex].Function
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ANDD table.
+
+  @param[in]  Andd  DMAR ANDD table
+**/
+VOID
+DumpDmarAndd (
+  IN EFI_ACPI_DMAR_ANDD_HEADER *Andd
+  )
+{
+  if (Andd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       ACPI Name-space Device Declaration Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  ANDD address ........................................... 0x%016lx\n" :
+    "  ANDD address ........................................... 0x%08x\n",
+    Andd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Andd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Andd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    ACPI Device Number ................................... 0x%02x\n",
+    Andd->AcpiDeviceNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    ACPI Object Name ..................................... '%a'\n",
+    (Andd + 1)
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RHSA table.
+
+  @param[in]  Rhsa  DMAR RHSA table
+**/
+VOID
+DumpDmarRhsa (
+  IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa
+  )
+{
+  if (Rhsa == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Remapping Hardware Status Affinity Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RHSA address ........................................... 0x%016lx\n" :
+    "  RHSA address ........................................... 0x%08x\n",
+    Rhsa
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rhsa->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rhsa->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Rhsa->RegisterBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Proximity Domain ..................................... 0x%08x\n",
+    Rhsa->ProximityDomain
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ATSR table.
+
+  @param[in]  Atsr  DMAR ATSR table
+**/
+VOID
+DumpDmarAtsr (
+  IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    AtsrLen;
+
+  if (Atsr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Root Port ATS Capability Reporting Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  ATSR address ........................................... 0x%016lx\n" :
+    "  ATSR address ........................................... 0x%08x\n",
+    Atsr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Atsr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Atsr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Atsr->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      ALL_PORTS .......................................... 0x%02x\n",
+    Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Atsr->SegmentNumber
+    ));
+
+  AtsrLen  = Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Atsr + 1);
+  while (AtsrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    AtsrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RMRR table.
+
+  @param[in]  Rmrr  DMAR RMRR table
+**/
+VOID
+DumpDmarRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    RmrrLen;
+
+  if (Rmrr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Reserved Memory Region Reporting Structure                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RMRR address ........................................... 0x%016lx\n" :
+    "  RMRR address ........................................... 0x%08x\n",
+    Rmrr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rmrr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rmrr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Rmrr->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionLimitAddress
+    ));
+
+  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
+  while (RmrrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    RmrrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR DRHD table.
+
+  @param[in]  Drhd  DMAR DRHD table
+**/
+VOID
+DumpDmarDrhd (
+  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    DrhdLen;
+
+  if (Drhd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  DRHD address ........................................... 0x%016lx\n" :
+    "  DRHD address ........................................... 0x%08x\n",
+    Drhd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Drhd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Drhd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Drhd->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
+    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Drhd->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Drhd->RegisterBaseAddress
+    ));
+
+  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
+  while (DrhdLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    DrhdLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+  INTN                  DmarLen;
+
+  if (Dmar == NULL) {
+    return;
+  }
+
+  //
+  // Dump Dmar table
+  //
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*         DMAR Table                                                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "DMAR address ............................................. 0x%016lx\n" :
+    "DMAR address ............................................. 0x%08x\n",
+    Dmar
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  Table Contents:\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Host Address Width ................................... 0x%02x\n",
+    Dmar->HostAddressWidth
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Dmar->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INTR_REMAP ......................................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
+    ));
+
+  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
+  while (DmarLen > 0) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_ATSR:
+      DumpDmarAtsr ((EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RHSA:
+      DumpDmarRhsa ((EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_ANDD:
+      DumpDmarAndd ((EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarLen -= DmarHeader->Length;
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+**/
+VOID
+VtdDumpDmarTable (
+  VOID
+  )
+{
+  DumpAcpiDMAR ((EFI_ACPI_DMAR_HEADER *)(UINTN)mAcpiDmarTable);
+}
+
+/**
+  Get PCI device information from DMAR DevScopeEntry.
+
+  @param[in]  Segment               The segment number.
+  @param[in]  DmarDevScopeEntry     DMAR DevScopeEntry
+  @param[out] Bus                   The bus number.
+  @param[out] Device                The device number.
+  @param[out] Function              The function number.
+
+  @retval EFI_SUCCESS  The PCI device information is returned.
+**/
+EFI_STATUS
+GetPciBusDeviceFunction (
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,
+  OUT UINT8                                       *Bus,
+  OUT UINT8                                       *Device,
+  OUT UINT8                                       *Function
+  )
+{
+  EFI_ACPI_DMAR_PCI_PATH                     *DmarPciPath;
+  UINT8                                      MyBus;
+  UINT8                                      MyDevice;
+  UINT8                                      MyFunction;
+
+  DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1));
+  MyBus = DmarDevScopeEntry->StartBusNumber;
+  MyDevice = DmarPciPath->Device;
+  MyFunction = DmarPciPath->Function;
+
+  switch (DmarDevScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    while ((UINTN)DmarPciPath + sizeof(EFI_ACPI_DMAR_PCI_PATH) < (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length) {
+      MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+      DmarPciPath ++;
+      MyDevice = DmarPciPath->Device;
+      MyFunction = DmarPciPath->Function;
+    }
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+    break;
+  }
+
+  *Bus = MyBus;
+  *Device = MyDevice;
+  *Function = MyFunction;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Process DMAR DHRD table.
+
+  @param[in]  VtdIndex  The index of VTd engine.
+  @param[in]  DmarDrhd  The DRHD table.
+
+  @retval EFI_SUCCESS The DRHD table is processed.
+**/
+EFI_STATUS
+ProcessDhrd (
+  IN UINTN                      VtdIndex,
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINT8                                             Bus;
+  UINT8                                             Device;
+  UINT8                                             Function;
+  UINT8                                             SecondaryBusNumber;
+  EFI_STATUS                                        Status;
+  VTD_SOURCE_ID                                     SourceId;
+
+  mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress = (UINTN)DmarDrhd->RegisterBaseAddress;
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+
+  mVtdUnitInformation[VtdIndex].Segment = DmarDrhd->SegmentNumber;
+
+  if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) {
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = TRUE;
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: with INCLUDE ALL\n"));
+
+    Status = ScanPciBus((VOID *)VtdIndex, DmarDrhd->SegmentNumber, 0, ScanBusCallbackRegisterPciDevice);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = FALSE;
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: without INCLUDE ALL\n"));
+  }
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+
+    Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG ((DEBUG_INFO,"  ProcessDhrd: "));
+    switch (DmarDevScopeEntry->Type) {
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+      DEBUG ((DEBUG_INFO,"PCI Endpoint"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+      DEBUG ((DEBUG_INFO,"PCI-PCI bridge"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC:
+      DEBUG ((DEBUG_INFO,"IOAPIC"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET:
+      DEBUG ((DEBUG_INFO,"MSI Capable HPET"));
+      break;
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE:
+      DEBUG ((DEBUG_INFO,"ACPI Namespace Device"));
+      break;
+    }
+    DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function));
+
+    SourceId.Bits.Bus = Bus;
+    SourceId.Bits.Device = Device;
+    SourceId.Bits.Function = Function;
+
+    Status = RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE);
+    if (EFI_ERROR (Status)) {
+      //
+      // There might be duplication for special device other than standard PCI device.
+      //
+      switch (DmarDevScopeEntry->Type) {
+      case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+      case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+        return Status;
+      }
+    }
+
+    switch (DmarDevScopeEntry->Type) {
+    case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+      SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DmarDrhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+      Status = ScanPciBus ((VOID *)VtdIndex, DmarDrhd->SegmentNumber, SecondaryBusNumber, ScanBusCallbackRegisterPciDevice);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    default:
+      break;
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Process DMAR RMRR table.
+
+  @param[in]  DmarRmrr  The RMRR table.
+
+  @retval EFI_SUCCESS The RMRR table is processed.
+**/
+EFI_STATUS
+ProcessRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINT8                                             Bus;
+  UINT8                                             Device;
+  UINT8                                             Function;
+  EFI_STATUS                                        Status;
+  VTD_SOURCE_ID                                     SourceId;
+
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+    if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
+      DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type));
+      return EFI_DEVICE_ERROR;
+    }
+
+    Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function));
+
+    SourceId.Bits.Bus = Bus;
+    SourceId.Bits.Device = Device;
+    SourceId.Bits.Function = Function;
+    Status = SetAccessAttribute (
+               DmarRmrr->SegmentNumber,
+               SourceId,
+               DmarRmrr->ReservedMemoryRegionBaseAddress,
+               DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->ReservedMemoryRegionBaseAddress,
+               EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get VTd engine number.
+**/
+UINTN
+GetVtdEngineNumber (
+  VOID
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      VtdIndex++;
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return VtdIndex ;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  VOID
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  EFI_STATUS                                        Status;
+  UINTN                                             VtdIndex;
+
+  mVtdUnitNumber = GetVtdEngineNumber ();
+  DEBUG ((DEBUG_INFO,"  VtdUnitNumber - %d\n", mVtdUnitNumber));
+  ASSERT (mVtdUnitNumber > 0);
+  if (mVtdUnitNumber == 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  mVtdUnitInformation = AllocateZeroPool (sizeof(*mVtdUnitInformation) * mVtdUnitNumber);
+  ASSERT (mVtdUnitInformation != NULL);
+  if (mVtdUnitInformation == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      ASSERT (VtdIndex < mVtdUnitNumber);
+      Status = ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      VtdIndex++;
+
+      break;
+
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  ASSERT (VtdIndex == mVtdUnitNumber);
+
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    DumpPciDeviceInfo (VtdIndex);
+  }
+  return EFI_SUCCESS ;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableRmrr (
+  VOID
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  EFI_STATUS                                        Status;
+
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      Status = ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return EFI_SUCCESS ;
+}
+
+/**
+  Get the DMAR ACPI table.
+
+  @retval EFI_SUCCESS           The DMAR ACPI table is got.
+  @retval EFI_ALREADY_STARTED   The DMAR ACPI table has been got previously.
+  @retval EFI_NOT_FOUND         The DMAR ACPI table is not found.
+**/
+EFI_STATUS
+GetDmarAcpiTable (
+  VOID
+  )
+{
+  if (mAcpiDmarTable != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  mAcpiDmarTable = (EFI_ACPI_DMAR_HEADER *) EfiLocateFirstAcpiTable (
+                                              EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE
+                                              );
+  if (mAcpiDmarTable == NULL) {
+    return EFI_NOT_FOUND;
+  }
+  DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable));
+  VtdDumpDmarTable();
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c
new file mode 100644
index 0000000000..a6287be2cf
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.c
@@ -0,0 +1,400 @@
+/** @file
+  Intel VTd driver.
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  The protocol instance pointer.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuMap (
+  IN     EDKII_IOMMU_PROTOCOL                       *This,
+  IN     EDKII_IOMMU_OPERATION                      Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  );
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  The protocol instance pointer.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IoMmuUnmap (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  VOID                                     *Mapping
+  );
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  The protocol instance pointer.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuAllocateBuffer (
+  IN     EDKII_IOMMU_PROTOCOL                     *This,
+  IN     EFI_ALLOCATE_TYPE                        Type,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  );
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  The protocol instance pointer.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuFreeBuffer (
+  IN  EDKII_IOMMU_PROTOCOL                     *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  );
+
+/**
+  This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,
+  based upon the DeviceAddress.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  DeviceAddress     The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+**/
+VOID
+SyncDeviceHandleToMapInfo (
+  IN EFI_HANDLE            DeviceHandle,
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  );
+
+/**
+  Convert the DeviceHandle to SourceId and Segment.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[out] Segment           The Segment used to identify a VTd engine.
+  @param[out] SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS            The Segment and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+**/
+EFI_STATUS
+DeviceHandleToSourceId (
+  IN EFI_HANDLE            DeviceHandle,
+  OUT UINT16               *Segment,
+  OUT VTD_SOURCE_ID        *SourceId
+  )
+{
+  EFI_PCI_IO_PROTOCOL                      *PciIo;
+  UINTN                                    Seg;
+  UINTN                                    Bus;
+  UINTN                                    Dev;
+  UINTN                                    Func;
+  EFI_STATUS                               Status;
+  EDKII_PLATFORM_VTD_DEVICE_INFO           DeviceInfo;
+
+  Status = EFI_NOT_FOUND;
+  if (mPlatformVTdPolicy != NULL) {
+    Status = mPlatformVTdPolicy->GetDeviceId (mPlatformVTdPolicy, DeviceHandle, &DeviceInfo);
+    if (!EFI_ERROR(Status)) {
+      *Segment  = DeviceInfo.Segment;
+      *SourceId = DeviceInfo.SourceId;
+      return EFI_SUCCESS;
+    }
+  }
+
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+  Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+  *Segment = (UINT16)Seg;
+  SourceId->Bits.Bus = (UINT8)Bus;
+  SourceId->Bits.Device = (UINT8)Dev;
+  SourceId->Bits.Function = (UINT8)Func;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set IOMMU attribute for a system memory.
+
+  If the IOMMU protocol exists, the system memory cannot be used
+  for DMA by default.
+
+  When a device requests a DMA access for a system memory,
+  the device driver need use SetAttribute() to update the IOMMU
+  attribute to request DMA access (read and/or write).
+
+  The DeviceHandle is used to identify which device submits the request.
+  The IOMMU implementation need translate the device path to an IOMMU device ID,
+  and set IOMMU hardware register accordingly.
+  1) DeviceHandle can be a standard PCI device.
+     The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+     The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+     The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+     After the memory is used, the memory need set 0 to keep it being protected.
+  2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+     The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDKII_IOMMU_ACCESS_WRITE.
+
+  @param[in]  This              The protocol instance pointer.
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  DeviceAddress     The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_INVALID_PARAMETER  DeviceAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by DeviceAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+VTdSetAttribute (
+  IN EDKII_IOMMU_PROTOCOL  *This,
+  IN EFI_HANDLE            DeviceHandle,
+  IN EFI_PHYSICAL_ADDRESS  DeviceAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  )
+{
+  EFI_STATUS           Status;
+  UINT16               Segment;
+  VTD_SOURCE_ID        SourceId;
+  CHAR8                PerfToken[sizeof("VTD(S0000.B00.D00.F00)")];
+  UINT32               Identifier;
+
+  DumpVtdIfError ();
+
+  Status = DeviceHandleToSourceId (DeviceHandle, &Segment, &SourceId);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "IoMmuSetAttribute: "));
+  DEBUG ((DEBUG_VERBOSE, "PCI(S%x.B%x.D%x.F%x) ", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+  DEBUG ((DEBUG_VERBOSE, "(0x%lx~0x%lx) - %lx\n", DeviceAddress, Length, IoMmuAccess));
+
+  if (mAcpiDmarTable == NULL) {
+    //
+    // Record the entry to driver global variable.
+    // As such once VTd is activated, the setting can be adopted.
+    //
+    if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) != 0) {
+      //
+      // Force no IOMMU access attribute request recording before DMAR table is installed.
+      //
+      ASSERT_EFI_ERROR (EFI_NOT_READY);
+      return EFI_NOT_READY;
+    }
+    Status = RequestAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);
+  } else {
+    PERF_CODE (
+      AsciiSPrint (PerfToken, sizeof(PerfToken), "S%04xB%02xD%02xF%01x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function);
+      Identifier = (Segment << 16) | SourceId.Uint16;
+      PERF_START_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);
+    );
+
+    Status = SetAccessAttribute (Segment, SourceId, DeviceAddress, Length, IoMmuAccess);
+
+    PERF_CODE (
+      Identifier = (Segment << 16) | SourceId.Uint16;
+      PERF_END_EX (gImageHandle, PerfToken, "IntelVTD", 0, Identifier);
+    );
+  }
+
+  if (!EFI_ERROR(Status)) {
+    SyncDeviceHandleToMapInfo (
+      DeviceHandle,
+      DeviceAddress,
+      Length,
+      IoMmuAccess
+      );
+  }
+
+  return Status;
+}
+
+/**
+  Set IOMMU attribute for a system memory.
+
+  If the IOMMU protocol exists, the system memory cannot be used
+  for DMA by default.
+
+  When a device requests a DMA access for a system memory,
+  the device driver need use SetAttribute() to update the IOMMU
+  attribute to request DMA access (read and/or write).
+
+  The DeviceHandle is used to identify which device submits the request.
+  The IOMMU implementation need translate the device path to an IOMMU device ID,
+  and set IOMMU hardware register accordingly.
+  1) DeviceHandle can be a standard PCI device.
+     The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+     The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+     The memory for BusMasterCommonBuffer need set EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+     After the memory is used, the memory need set 0 to keep it being protected.
+  2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+     The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or EDKII_IOMMU_ACCESS_WRITE.
+
+  @param[in]  This              The protocol instance pointer.
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[in]  Mapping           The mapping value returned from Map().
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by Map().
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by Mapping.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+EFIAPI
+IoMmuSetAttribute (
+  IN EDKII_IOMMU_PROTOCOL  *This,
+  IN EFI_HANDLE            DeviceHandle,
+  IN VOID                  *Mapping,
+  IN UINT64                IoMmuAccess
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  DeviceAddress;
+  UINTN                 NumberOfPages;
+  EFI_TPL               OriginalTpl;
+
+  OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);
+
+  Status = GetDeviceInfoFromMapping (Mapping, &DeviceAddress, &NumberOfPages);
+  if (!EFI_ERROR(Status)) {
+    Status = VTdSetAttribute (
+               This,
+               DeviceHandle,
+               DeviceAddress,
+               EFI_PAGES_TO_SIZE(NumberOfPages),
+               IoMmuAccess
+               );
+  }
+
+  gBS->RestoreTPL (OriginalTpl);
+
+  return Status;
+}
+
+EDKII_IOMMU_PROTOCOL  mIntelVTd = {
+  EDKII_IOMMU_PROTOCOL_REVISION,
+  IoMmuSetAttribute,
+  IoMmuMap,
+  IoMmuUnmap,
+  IoMmuAllocateBuffer,
+  IoMmuFreeBuffer,
+};
+
+/**
+  Initialize the VTd driver.
+
+  @param[in]  ImageHandle  ImageHandle of the loaded driver
+  @param[in]  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           The Protocol is installed.
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IntelVTdInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  InitializeDmaProtection ();
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEdkiiIoMmuProtocolGuid, &mIntelVTd,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
new file mode 100644
index 0000000000..4af376b350
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/PciInfo.c
@@ -0,0 +1,373 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+/**
+  Return the index of PCI data.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @return The index of the PCI data.
+  @retval (UINTN)-1  The PCI data is not found.
+**/
+UINTN
+GetPciDataIndex (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId
+  )
+{
+  UINTN          Index;
+  VTD_SOURCE_ID  *PciSourceId;
+
+  if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+    return (UINTN)-1;
+  }
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+    if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&
+        (PciSourceId->Bits.Device == SourceId.Bits.Device) &&
+        (PciSourceId->Bits.Function == SourceId.Bits.Function) ) {
+      return Index;
+    }
+  }
+
+  return (UINTN)-1;
+}
+
+/**
+  Register PCI device to VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[in]  DeviceType            The DMAR device scope type.
+  @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
+                                    FALSE: SUCCESS will be returned if the PCI device is registered.
+
+  @retval EFI_SUCCESS           The PCI device is registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+  @retval EFI_ALREADY_STARTED   The device is already registered.
+**/
+EFI_STATUS
+RegisterPciDevice (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId,
+  IN UINT8          DeviceType,
+  IN BOOLEAN        CheckExist
+  )
+{
+  PCI_DEVICE_INFORMATION           *PciDeviceInfo;
+  VTD_SOURCE_ID                    *PciSourceId;
+  UINTN                            PciDataIndex;
+  UINTN                            Index;
+  PCI_DEVICE_DATA                  *NewPciDeviceData;
+  EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;
+
+  PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;
+
+  if (PciDeviceInfo->IncludeAllFlag) {
+    //
+    // Do not register device in other VTD Unit
+    //
+    for (Index = 0; Index < VtdIndex; Index++) {
+      PciDataIndex = GetPciDataIndex (Index, Segment, SourceId);
+      if (PciDataIndex != (UINTN)-1) {
+        DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, Index));
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
+  if (PciDataIndex == (UINTN)-1) {
+    //
+    // Register new
+    //
+
+    if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {
+      //
+      // Reallocate
+      //
+      NewPciDeviceData = AllocateZeroPool (sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER));
+      if (NewPciDeviceData == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;
+      if (PciDeviceInfo->PciDeviceData != NULL) {
+        CopyMem (NewPciDeviceData, PciDeviceInfo->PciDeviceData, sizeof(*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);
+        FreePool (PciDeviceInfo->PciDeviceData);
+      }
+      PciDeviceInfo->PciDeviceData = NewPciDeviceData;
+    }
+
+    ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);
+
+    PciSourceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;
+    PciSourceId->Bits.Bus = SourceId.Bits.Bus;
+    PciSourceId->Bits.Device = SourceId.Bits.Device;
+    PciSourceId->Bits.Function = SourceId.Bits.Function;
+
+    DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    PciDeviceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciDeviceId;
+    if ((DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) ||
+        (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
+      PciDeviceId->VendorId   = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_VENDOR_ID_OFFSET));
+      PciDeviceId->DeviceId   = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_DEVICE_ID_OFFSET));
+      PciDeviceId->RevisionId = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_REVISION_ID_OFFSET));
+
+      DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDeviceId->DeviceId, PciDeviceId->RevisionId));
+
+      if (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
+        PciDeviceId->SubsystemVendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));
+        PciDeviceId->SubsystemDeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_ID_OFFSET));
+        DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, PciDeviceId->SubsystemDeviceId));
+      }
+      DEBUG ((DEBUG_INFO, ")"));
+    }
+
+    PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;
+
+    if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&
+        (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
+      DEBUG ((DEBUG_INFO, " (*)"));
+    }
+    DEBUG ((DEBUG_INFO, "\n"));
+
+    PciDeviceInfo->PciDeviceDataNumber++;
+  } else {
+    if (CheckExist) {
+      DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      return EFI_ALREADY_STARTED;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The scan bus callback function to register PCI device.
+
+  @param[in]  Context               The context of the callback.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Device                The device of the source.
+  @param[in]  Function              The function of the source.
+
+  @retval EFI_SUCCESS           The PCI device is registered.
+**/
+EFI_STATUS
+EFIAPI
+ScanBusCallbackRegisterPciDevice (
+  IN VOID           *Context,
+  IN UINT16         Segment,
+  IN UINT8          Bus,
+  IN UINT8          Device,
+  IN UINT8          Function
+  )
+{
+  VTD_SOURCE_ID           SourceId;
+  UINTN                   VtdIndex;
+  UINT8                   BaseClass;
+  UINT8                   SubClass;
+  UINT8                   DeviceType;
+  EFI_STATUS              Status;
+
+  VtdIndex = (UINTN)Context;
+  SourceId.Bits.Bus = Bus;
+  SourceId.Bits.Device = Device;
+  SourceId.Bits.Function = Function;
+
+  DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;
+  BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
+  if (BaseClass == PCI_CLASS_BRIDGE) {
+    SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
+    if (SubClass == PCI_CLASS_BRIDGE_P2P) {
+      DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;
+    }
+  }
+
+  Status = RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, FALSE);
+  return Status;
+}
+
+/**
+  Scan PCI bus and invoke callback function for each PCI devices under the bus.
+
+  @param[in]  Context               The context of the callback function.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Callback              The callback function in PCI scan.
+
+  @retval EFI_SUCCESS           The PCI devices under the bus are scaned.
+**/
+EFI_STATUS
+ScanPciBus (
+  IN VOID                         *Context,
+  IN UINT16                       Segment,
+  IN UINT8                        Bus,
+  IN SCAN_BUS_FUNC_CALLBACK_FUNC  Callback
+  )
+{
+  UINT8                   Device;
+  UINT8                   Function;
+  UINT8                   SecondaryBusNumber;
+  UINT8                   HeaderType;
+  UINT8                   BaseClass;
+  UINT8                   SubClass;
+  UINT16                  VendorID;
+  UINT16                  DeviceID;
+  EFI_STATUS              Status;
+
+  // Scan the PCI bus for devices
+  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+    for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
+      VendorID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
+      DeviceID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
+      if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
+        if (Function == 0) {
+          //
+          // If function 0 is not implemented, do not scan other functions.
+          //
+          break;
+        }
+        continue;
+      }
+
+      Status = Callback (Context, Segment, Bus, Device, Function);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
+      if (BaseClass == PCI_CLASS_BRIDGE) {
+        SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
+        if (SubClass == PCI_CLASS_BRIDGE_P2P) {
+          SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
+          DEBUG ((DEBUG_INFO,"  ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
+          if (SecondaryBusNumber != 0) {
+            Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);
+            if (EFI_ERROR (Status)) {
+              return Status;
+            }
+          }
+        }
+      }
+
+      if (Function == 0) {
+        HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
+        if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
+          //
+          // It is not a multi-function device, do not scan other functions.
+          //
+          break;
+        }
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump the PCI device information managed by this VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpPciDeviceInfo (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN  Index;
+
+  DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
+    mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
+    ));
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    DEBUG ((DEBUG_INFO,"  S%04x B%02x D%02x F%02x\n",
+      mVtdUnitInformation[VtdIndex].Segment,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
+      mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function
+      ));
+  }
+}
+
+/**
+  Find the VTd index by the Segment and SourceId.
+
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[out] ExtContextEntry       The ExtContextEntry of the source.
+  @param[out] ContextEntry          The ContextEntry of the source.
+
+  @return The index of the VTd engine.
+  @retval (UINTN)-1  The VTd engine is not found.
+**/
+UINTN
+FindVtdIndexByPciDevice (
+  IN  UINT16                  Segment,
+  IN  VTD_SOURCE_ID           SourceId,
+  OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
+  OUT VTD_CONTEXT_ENTRY       **ContextEntry
+  )
+{
+  UINTN                   VtdIndex;
+  VTD_ROOT_ENTRY          *RootEntry;
+  VTD_CONTEXT_ENTRY       *ContextEntryTable;
+  VTD_CONTEXT_ENTRY       *ThisContextEntry;
+  VTD_EXT_ROOT_ENTRY      *ExtRootEntry;
+  VTD_EXT_CONTEXT_ENTRY   *ExtContextEntryTable;
+  VTD_EXT_CONTEXT_ENTRY   *ThisExtContextEntry;
+  UINTN                   PciDataIndex;
+
+  for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
+    if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
+      continue;
+    }
+
+    PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
+    if (PciDataIndex == (UINTN)-1) {
+      continue;
+    }
+
+//    DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
+      ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
+      ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
+      ThisExtContextEntry  = &ExtContextEntryTable[SourceId.Index.ContextIndex];
+      if (ThisExtContextEntry->Bits.AddressWidth == 0) {
+        continue;
+      }
+      *ExtContextEntry = ThisExtContextEntry;
+      *ContextEntry    = NULL;
+    } else {
+      RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
+      ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
+      ThisContextEntry  = &ContextEntryTable[SourceId.Index.ContextIndex];
+      if (ThisContextEntry->Bits.AddressWidth == 0) {
+        continue;
+      }
+      *ExtContextEntry = NULL;
+      *ContextEntry    = ThisContextEntry;
+    }
+
+    return VtdIndex;
+  }
+
+  return (UINTN)-1;
+}
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTable.c
new file mode 100644
index 0000000000..fcff0925b8
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTable.c
@@ -0,0 +1,1026 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+/**
+  Create extended context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The extended context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create extended context entry.
+**/
+EFI_STATUS
+CreateExtContextEntry (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Allocate zero pages.
+
+  @param[in]  Pages the number of pages.
+
+  @return the page address.
+  @retval NULL No resource to allocate pages.
+**/
+VOID *
+EFIAPI
+AllocateZeroPages (
+  IN UINTN  Pages
+  )
+{
+  VOID *Addr;
+
+  Addr = AllocatePages (Pages);
+  if (Addr == NULL) {
+    return NULL;
+  }
+  ZeroMem (Addr, EFI_PAGES_TO_SIZE(Pages));
+  return Addr;
+}
+
+/**
+  Set second level paging entry attribute based upon IoMmuAccess.
+
+  @param[in]  PtEntry      The paging entry.
+  @param[in]  IoMmuAccess  The IOMMU access.
+**/
+VOID
+SetSecondLevelPagingEntryAttribute (
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY  *PtEntry,
+  IN UINT64                         IoMmuAccess
+  )
+{
+  PtEntry->Bits.Read  = ((IoMmuAccess & EDKII_IOMMU_ACCESS_READ) != 0);
+  PtEntry->Bits.Write = ((IoMmuAccess & EDKII_IOMMU_ACCESS_WRITE) != 0);
+}
+
+/**
+  Create context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create context entry.
+**/
+EFI_STATUS
+CreateContextEntry (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN                  Index;
+  VOID                   *Buffer;
+  UINTN                  RootPages;
+  UINTN                  ContextPages;
+  VTD_ROOT_ENTRY         *RootEntry;
+  VTD_CONTEXT_ENTRY      *ContextEntryTable;
+  VTD_CONTEXT_ENTRY      *ContextEntry;
+  VTD_SOURCE_ID          *PciSourceId;
+  VTD_SOURCE_ID          SourceId;
+  UINTN                  MaxBusNumber;
+  UINTN                  EntryTablePages;
+
+  MaxBusNumber = 0;
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+    if (PciSourceId->Bits.Bus > MaxBusNumber) {
+      MaxBusNumber = PciSourceId->Bits.Bus;
+    }
+  }
+  DEBUG ((DEBUG_INFO,"  MaxBusNumber - 0x%x\n", MaxBusNumber));
+
+  RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);
+  ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);
+  EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);
+  Buffer = AllocateZeroPages (EntryTablePages);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  mVtdUnitInformation[VtdIndex].RootEntryTable = (VTD_ROOT_ENTRY *)Buffer;
+  Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+
+    SourceId.Bits.Bus = PciSourceId->Bits.Bus;
+    SourceId.Bits.Device = PciSourceId->Bits.Device;
+    SourceId.Bits.Function = PciSourceId->Bits.Function;
+
+    RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
+    if (RootEntry->Bits.Present == 0) {
+      RootEntry->Bits.ContextTablePointerLo  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12);
+      RootEntry->Bits.ContextTablePointerHi  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);
+      RootEntry->Bits.Present = 1;
+      Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);
+    }
+
+    ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
+    ContextEntry = &ContextEntryTable[SourceId.Index.ContextIndex];
+    ContextEntry->Bits.TranslationType = 0;
+    ContextEntry->Bits.FaultProcessingDisable = 0;
+    ContextEntry->Bits.Present = 0;
+
+    DEBUG ((DEBUG_INFO,"Source: S%04x B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {
+    case BIT1:
+      ContextEntry->Bits.AddressWidth = 0x1;
+      break;
+    case BIT2:
+      ContextEntry->Bits.AddressWidth = 0x2;
+      break;
+    }
+  }
+
+  FlushPageTableMemory (VtdIndex, (UINTN)mVtdUnitInformation[VtdIndex].RootEntryTable, EFI_PAGES_TO_SIZE(EntryTablePages));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create second level paging entry table.
+
+  @param[in]  VtdIndex                    The index of the VTd engine.
+  @param[in]  SecondLevelPagingEntry      The second level paging entry.
+  @param[in]  MemoryBase                  The base of the memory.
+  @param[in]  MemoryLimit                 The limit of the memory.
+  @param[in]  IoMmuAccess                 The IOMMU access.
+
+  @return The second level paging entry.
+**/
+VTD_SECOND_LEVEL_PAGING_ENTRY *
+CreateSecondLevelPagingEntryTable (
+  IN UINTN                         VtdIndex,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        MemoryBase,
+  IN UINT64                        MemoryLimit,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  UINTN                          Index4;
+  UINTN                          Index3;
+  UINTN                          Index2;
+  UINTN                          Lvl4Start;
+  UINTN                          Lvl4End;
+  UINTN                          Lvl3Start;
+  UINTN                          Lvl3End;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl4PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl3PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl2PtEntry;
+  UINT64                         BaseAddress;
+  UINT64                         EndAddress;
+
+  if (MemoryLimit == 0) {
+    return EFI_SUCCESS;
+  }
+
+  BaseAddress = ALIGN_VALUE_LOW(MemoryBase, SIZE_2MB);
+  EndAddress = ALIGN_VALUE_UP(MemoryLimit, SIZE_2MB);
+  DEBUG ((DEBUG_INFO,"CreateSecondLevelPagingEntryTable: BaseAddress - 0x%016lx, EndAddress - 0x%016lx\n", BaseAddress, EndAddress));
+
+  if (SecondLevelPagingEntry == NULL) {
+    SecondLevelPagingEntry = AllocateZeroPages (1);
+    if (SecondLevelPagingEntry == NULL) {
+      DEBUG ((DEBUG_ERROR,"Could not Alloc LVL4 PT. \n"));
+      return NULL;
+    }
+    FlushPageTableMemory (VtdIndex, (UINTN)SecondLevelPagingEntry, EFI_PAGES_TO_SIZE(1));
+  }
+
+  //
+  // If no access is needed, just create not present entry.
+  //
+  if (IoMmuAccess == 0) {
+    return SecondLevelPagingEntry;
+  }
+
+  Lvl4Start = RShiftU64 (BaseAddress, 39) & 0x1FF;
+  Lvl4End = RShiftU64 (EndAddress - 1, 39) & 0x1FF;
+
+  DEBUG ((DEBUG_INFO,"  Lvl4Start - 0x%x, Lvl4End - 0x%x\n", Lvl4Start, Lvl4End));
+
+  Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;
+  for (Index4 = Lvl4Start; Index4 <= Lvl4End; Index4++) {
+    if (Lvl4PtEntry[Index4].Uint64 == 0) {
+      Lvl4PtEntry[Index4].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);
+      if (Lvl4PtEntry[Index4].Uint64 == 0) {
+        DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));
+        ASSERT(FALSE);
+        return NULL;
+      }
+      FlushPageTableMemory (VtdIndex, (UINTN)Lvl4PtEntry[Index4].Uint64, SIZE_4KB);
+      SetSecondLevelPagingEntryAttribute (&Lvl4PtEntry[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+    }
+
+    Lvl3Start = RShiftU64 (BaseAddress, 30) & 0x1FF;
+    if (ALIGN_VALUE_LOW(BaseAddress + SIZE_1GB, SIZE_1GB) <= EndAddress) {
+      Lvl3End = SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY) - 1;
+    } else {
+      Lvl3End = RShiftU64 (EndAddress - 1, 30) & 0x1FF;
+    }
+    DEBUG ((DEBUG_INFO,"  Lvl4(0x%x): Lvl3Start - 0x%x, Lvl3End - 0x%x\n", Index4, Lvl3Start, Lvl3End));
+
+    Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);
+    for (Index3 = Lvl3Start; Index3 <= Lvl3End; Index3++) {
+      if (Lvl3PtEntry[Index3].Uint64 == 0) {
+        Lvl3PtEntry[Index3].Uint64 = (UINT64)(UINTN)AllocateZeroPages (1);
+        if (Lvl3PtEntry[Index3].Uint64 == 0) {
+          DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));
+          ASSERT(FALSE);
+          return NULL;
+        }
+        FlushPageTableMemory (VtdIndex, (UINTN)Lvl3PtEntry[Index3].Uint64, SIZE_4KB);
+        SetSecondLevelPagingEntryAttribute (&Lvl3PtEntry[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      }
+
+      Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);
+      for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {
+        Lvl2PtEntry[Index2].Uint64 = BaseAddress;
+        SetSecondLevelPagingEntryAttribute (&Lvl2PtEntry[Index2], IoMmuAccess);
+        Lvl2PtEntry[Index2].Bits.PageSize = 1;
+        BaseAddress += SIZE_2MB;
+        if (BaseAddress >= MemoryLimit) {
+          break;
+        }
+      }
+      FlushPageTableMemory (VtdIndex, (UINTN)Lvl2PtEntry, SIZE_4KB);
+      if (BaseAddress >= MemoryLimit) {
+        break;
+      }
+    }
+    FlushPageTableMemory (VtdIndex, (UINTN)&Lvl3PtEntry[Lvl3Start], (UINTN)&Lvl3PtEntry[Lvl3End + 1] - (UINTN)&Lvl3PtEntry[Lvl3Start]);
+    if (BaseAddress >= MemoryLimit) {
+      break;
+    }
+  }
+  FlushPageTableMemory (VtdIndex, (UINTN)&Lvl4PtEntry[Lvl4Start], (UINTN)&Lvl4PtEntry[Lvl4End + 1] - (UINTN)&Lvl4PtEntry[Lvl4Start]);
+
+  return SecondLevelPagingEntry;
+}
+
+/**
+  Create second level paging entry.
+
+  @param[in]  VtdIndex                    The index of the VTd engine.
+  @param[in]  IoMmuAccess                 The IOMMU access.
+
+  @return The second level paging entry.
+**/
+VTD_SECOND_LEVEL_PAGING_ENTRY *
+CreateSecondLevelPagingEntry (
+  IN UINTN   VtdIndex,
+  IN UINT64  IoMmuAccess
+  )
+{
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+
+  SecondLevelPagingEntry = NULL;
+  SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, 0, mBelow4GMemoryLimit, IoMmuAccess);
+  if (SecondLevelPagingEntry == NULL) {
+    return NULL;
+  }
+
+  if (mAbove4GMemoryLimit != 0) {
+    ASSERT (mAbove4GMemoryLimit > BASE_4GB);
+    SecondLevelPagingEntry = CreateSecondLevelPagingEntryTable (VtdIndex, SecondLevelPagingEntry, SIZE_4GB, mAbove4GMemoryLimit, IoMmuAccess);
+    if (SecondLevelPagingEntry == NULL) {
+      return NULL;
+    }
+  }
+
+  return SecondLevelPagingEntry;
+}
+
+/**
+  Setup VTd translation table.
+
+  @retval EFI_SUCCESS           Setup translation table successfully.
+  @retval EFI_OUT_OF_RESOURCE   Setup translation table fail.
+**/
+EFI_STATUS
+SetupTranslationTable (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  UINTN           Index;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, "CreateContextEntry - %d\n", Index));
+    if (mVtdUnitInformation[Index].ECapReg.Bits.ECS) {
+      Status = CreateExtContextEntry (Index);
+    } else {
+      Status = CreateContextEntry (Index);
+    }
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump DMAR context entry table.
+
+  @param[in]  RootEntry DMAR root entry.
+**/
+VOID
+DumpDmarContextEntryTable (
+  IN VTD_ROOT_ENTRY *RootEntry
+  )
+{
+  UINTN                 Index;
+  UINTN                 Index2;
+  VTD_CONTEXT_ENTRY     *ContextEntry;
+
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+  DEBUG ((DEBUG_INFO,"DMAR Context Entry Table:\n"));
+
+  DEBUG ((DEBUG_INFO,"RootEntry Address - 0x%x\n", RootEntry));
+
+  for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {
+    if ((RootEntry[Index].Uint128.Uint64Lo != 0) || (RootEntry[Index].Uint128.Uint64Hi != 0)) {
+      DEBUG ((DEBUG_INFO,"  RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
+        Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].Uint128.Uint64Lo));
+    }
+    if (RootEntry[Index].Bits.Present == 0) {
+      continue;
+    }
+    ContextEntry = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry[Index].Bits.ContextTablePointerLo, RootEntry[Index].Bits.ContextTablePointerHi);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) {
+      if ((ContextEntry[Index2].Uint128.Uint64Lo != 0) || (ContextEntry[Index2].Uint128.Uint64Hi != 0)) {
+        DEBUG ((DEBUG_INFO,"    ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n",
+          Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo));
+      }
+      if (ContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+      DumpSecondLevelPagingEntry ((VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi));
+    }
+  }
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+}
+
+/**
+  Dump DMAR second level paging entry.
+
+  @param[in]  SecondLevelPagingEntry The second level paging entry.
+**/
+VOID
+DumpSecondLevelPagingEntry (
+  IN VOID *SecondLevelPagingEntry
+  )
+{
+  UINTN                          Index4;
+  UINTN                          Index3;
+  UINTN                          Index2;
+  UINTN                          Index1;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl4PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl3PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl2PtEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *Lvl1PtEntry;
+
+  DEBUG ((DEBUG_VERBOSE,"================\n"));
+  DEBUG ((DEBUG_VERBOSE,"DMAR Second Level Page Table:\n"));
+
+  DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));
+  Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry;
+  for (Index4 = 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index4++) {
+    if (Lvl4PtEntry[Index4].Uint64 != 0) {
+      DEBUG ((DEBUG_VERBOSE,"  Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4, Lvl4PtEntry[Index4].Uint64));
+    }
+    if (Lvl4PtEntry[Index4].Uint64 == 0) {
+      continue;
+    }
+    Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi);
+    for (Index3 = 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index3++) {
+      if (Lvl3PtEntry[Index3].Uint64 != 0) {
+        DEBUG ((DEBUG_VERBOSE,"    Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3, Lvl3PtEntry[Index3].Uint64));
+      }
+      if (Lvl3PtEntry[Index3].Uint64 == 0) {
+        continue;
+      }
+
+      Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi);
+      for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) {
+        if (Lvl2PtEntry[Index2].Uint64 != 0) {
+          DEBUG ((DEBUG_VERBOSE,"      Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2, Lvl2PtEntry[Index2].Uint64));
+        }
+        if (Lvl2PtEntry[Index2].Uint64 == 0) {
+          continue;
+        }
+        if (Lvl2PtEntry[Index2].Bits.PageSize == 0) {
+          Lvl1PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.AddressHi);
+          for (Index1 = 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index1++) {
+            if (Lvl1PtEntry[Index1].Uint64 != 0) {
+              DEBUG ((DEBUG_VERBOSE,"        Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64));
+            }
+          }
+        }
+      }
+    }
+  }
+  DEBUG ((DEBUG_VERBOSE,"================\n"));
+}
+
+/**
+  Invalid page entry.
+
+  @param VtdIndex  The VTd engine index.
+**/
+VOID
+InvalidatePageEntry (
+  IN UINTN                 VtdIndex
+  )
+{
+  if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {
+    InvalidateVtdIOTLBGlobal (VtdIndex);
+  }
+  mVtdUnitInformation[VtdIndex].HasDirtyContext = FALSE;
+  mVtdUnitInformation[VtdIndex].HasDirtyPages = FALSE;
+}
+
+#define VTD_PG_R                   BIT0
+#define VTD_PG_W                   BIT1
+#define VTD_PG_X                   BIT2
+#define VTD_PG_EMT                 (BIT3 | BIT4 | BIT5)
+#define VTD_PG_TM                  (BIT62)
+
+#define VTD_PG_PS                  BIT7
+
+#define PAGE_PROGATE_BITS          (VTD_PG_TM | VTD_PG_EMT | VTD_PG_W | VTD_PG_R)
+
+#define PAGING_4K_MASK  0xFFF
+#define PAGING_2M_MASK  0x1FFFFF
+#define PAGING_1G_MASK  0x3FFFFFFF
+
+#define PAGING_VTD_INDEX_MASK     0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
+
+typedef enum {
+  PageNone,
+  Page4K,
+  Page2M,
+  Page1G,
+} PAGE_ATTRIBUTE;
+
+typedef struct {
+  PAGE_ATTRIBUTE   Attribute;
+  UINT64           Length;
+  UINT64           AddressMask;
+} PAGE_ATTRIBUTE_TABLE;
+
+PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
+  {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
+  {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
+  {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
+};
+
+/**
+  Return length according to page attributes.
+
+  @param[in]  PageAttributes   The page attribute of the page entry.
+
+  @return The length of page entry.
+**/
+UINTN
+PageAttributeToLength (
+  IN PAGE_ATTRIBUTE  PageAttribute
+  )
+{
+  UINTN  Index;
+  for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
+    if (PageAttribute == mPageAttributeTable[Index].Attribute) {
+      return (UINTN)mPageAttributeTable[Index].Length;
+    }
+  }
+  return 0;
+}
+
+/**
+  Return page table entry to match the address.
+
+  @param[in]   VtdIndex                 The index used to identify a VTd engine.
+  @param[in]   SecondLevelPagingEntry   The second level paging entry in VTd table for the device.
+  @param[in]   Address                  The address to be checked.
+  @param[out]  PageAttributes           The page attribute of the page entry.
+
+  @return The page entry.
+**/
+VOID *
+GetSecondLevelPageTableEntry (
+  IN  UINTN                         VtdIndex,
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN  PHYSICAL_ADDRESS              Address,
+  OUT PAGE_ATTRIBUTE                *PageAttribute
+  )
+{
+  UINTN                 Index1;
+  UINTN                 Index2;
+  UINTN                 Index3;
+  UINTN                 Index4;
+  UINT64                *L1PageTable;
+  UINT64                *L2PageTable;
+  UINT64                *L3PageTable;
+  UINT64                *L4PageTable;
+
+  Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_VTD_INDEX_MASK;
+  Index3 = ((UINTN)Address >> 30) & PAGING_VTD_INDEX_MASK;
+  Index2 = ((UINTN)Address >> 21) & PAGING_VTD_INDEX_MASK;
+  Index1 = ((UINTN)Address >> 12) & PAGING_VTD_INDEX_MASK;
+
+  L4PageTable = (UINT64 *)SecondLevelPagingEntry;
+  if (L4PageTable[Index4] == 0) {
+    L4PageTable[Index4] = (UINT64)(UINTN)AllocateZeroPages (1);
+    if (L4PageTable[Index4] == 0) {
+      DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL4 PAGE FAIL (0x%x)!!!!!!\n", Index4));
+      ASSERT(FALSE);
+      *PageAttribute = PageNone;
+      return NULL;
+    }
+    FlushPageTableMemory (VtdIndex, (UINTN)L4PageTable[Index4], SIZE_4KB);
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L4PageTable[Index4], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+    FlushPageTableMemory (VtdIndex, (UINTN)&L4PageTable[Index4], sizeof(L4PageTable[Index4]));
+  }
+
+  L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
+  if (L3PageTable[Index3] == 0) {
+    L3PageTable[Index3] = (UINT64)(UINTN)AllocateZeroPages (1);
+    if (L3PageTable[Index3] == 0) {
+      DEBUG ((DEBUG_ERROR,"!!!!!! ALLOCATE LVL3 PAGE FAIL (0x%x, 0x%x)!!!!!!\n", Index4, Index3));
+      ASSERT(FALSE);
+      *PageAttribute = PageNone;
+      return NULL;
+    }
+    FlushPageTableMemory (VtdIndex, (UINTN)L3PageTable[Index3], SIZE_4KB);
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L3PageTable[Index3], EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+    FlushPageTableMemory (VtdIndex, (UINTN)&L3PageTable[Index3], sizeof(L3PageTable[Index3]));
+  }
+  if ((L3PageTable[Index3] & VTD_PG_PS) != 0) {
+    // 1G
+    *PageAttribute = Page1G;
+    return &L3PageTable[Index3];
+  }
+
+  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
+  if (L2PageTable[Index2] == 0) {
+    L2PageTable[Index2] = Address & PAGING_2M_ADDRESS_MASK_64;
+    SetSecondLevelPagingEntryAttribute ((VTD_SECOND_LEVEL_PAGING_ENTRY *)&L2PageTable[Index2], 0);
+    L2PageTable[Index2] |= VTD_PG_PS;
+    FlushPageTableMemory (VtdIndex, (UINTN)&L2PageTable[Index2], sizeof(L2PageTable[Index2]));
+  }
+  if ((L2PageTable[Index2] & VTD_PG_PS) != 0) {
+    // 2M
+    *PageAttribute = Page2M;
+    return &L2PageTable[Index2];
+  }
+
+  // 4k
+  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
+  if ((L1PageTable[Index1] == 0) && (Address != 0)) {
+    *PageAttribute = PageNone;
+    return NULL;
+  }
+  *PageAttribute = Page4K;
+  return &L1PageTable[Index1];
+}
+
+/**
+  Modify memory attributes of page entry.
+
+  @param[in]   VtdIndex         The index used to identify a VTd engine.
+  @param[in]   PageEntry        The page entry.
+  @param[in]   IoMmuAccess      The IOMMU access.
+  @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.
+**/
+VOID
+ConvertSecondLevelPageEntryAttribute (
+  IN  UINTN                             VtdIndex,
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,
+  IN  UINT64                            IoMmuAccess,
+  OUT BOOLEAN                           *IsModified
+  )
+{
+  UINT64  CurrentPageEntry;
+  UINT64  NewPageEntry;
+
+  CurrentPageEntry = PageEntry->Uint64;
+  SetSecondLevelPagingEntryAttribute (PageEntry, IoMmuAccess);
+  FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));
+  NewPageEntry = PageEntry->Uint64;
+  if (CurrentPageEntry != NewPageEntry) {
+    *IsModified = TRUE;
+    DEBUG ((DEBUG_VERBOSE, "ConvertSecondLevelPageEntryAttribute 0x%lx", CurrentPageEntry));
+    DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
+  } else {
+    *IsModified = FALSE;
+  }
+}
+
+/**
+  This function returns if there is need to split page entry.
+
+  @param[in]  BaseAddress      The base address to be checked.
+  @param[in]  Length           The length to be checked.
+  @param[in]  PageAttribute    The page attribute of the page entry.
+
+  @retval SplitAttributes on if there is need to split page entry.
+**/
+PAGE_ATTRIBUTE
+NeedSplitPage (
+  IN  PHYSICAL_ADDRESS                  BaseAddress,
+  IN  UINT64                            Length,
+  IN  PAGE_ATTRIBUTE                    PageAttribute
+  )
+{
+  UINT64                PageEntryLength;
+
+  PageEntryLength = PageAttributeToLength (PageAttribute);
+
+  if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
+    return PageNone;
+  }
+
+  if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
+    return Page4K;
+  }
+
+  return Page2M;
+}
+
+/**
+  This function splits one page entry to small page entries.
+
+  @param[in]  VtdIndex         The index used to identify a VTd engine.
+  @param[in]  PageEntry        The page entry to be splitted.
+  @param[in]  PageAttribute    The page attribute of the page entry.
+  @param[in]  SplitAttribute   How to split the page entry.
+
+  @retval RETURN_SUCCESS            The page entry is splitted.
+  @retval RETURN_UNSUPPORTED        The page entry does not support to be splitted.
+  @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.
+**/
+RETURN_STATUS
+SplitSecondLevelPage (
+  IN  UINTN                             VtdIndex,
+  IN  VTD_SECOND_LEVEL_PAGING_ENTRY     *PageEntry,
+  IN  PAGE_ATTRIBUTE                    PageAttribute,
+  IN  PAGE_ATTRIBUTE                    SplitAttribute
+  )
+{
+  UINT64   BaseAddress;
+  UINT64   *NewPageEntry;
+  UINTN    Index;
+
+  ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
+
+  if (PageAttribute == Page2M) {
+    //
+    // Split 2M to 4K
+    //
+    ASSERT (SplitAttribute == Page4K);
+    if (SplitAttribute == Page4K) {
+      NewPageEntry = AllocateZeroPages (1);
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
+      if (NewPageEntry == NULL) {
+        return RETURN_OUT_OF_RESOURCES;
+      }
+      BaseAddress = PageEntry->Uint64 & PAGING_2M_ADDRESS_MASK_64;
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
+        NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) | (PageEntry->Uint64 & PAGE_PROGATE_BITS);
+      }
+      FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);
+
+      PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;
+      SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));
+      return RETURN_SUCCESS;
+    } else {
+      return RETURN_UNSUPPORTED;
+    }
+  } else if (PageAttribute == Page1G) {
+    //
+    // Split 1G to 2M
+    // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
+    //
+    ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
+    if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
+      NewPageEntry = AllocateZeroPages (1);
+      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
+      if (NewPageEntry == NULL) {
+        return RETURN_OUT_OF_RESOURCES;
+      }
+      BaseAddress = PageEntry->Uint64 & PAGING_1G_ADDRESS_MASK_64;
+      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
+        NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) | VTD_PG_PS | (PageEntry->Uint64 & PAGE_PROGATE_BITS);
+      }
+      FlushPageTableMemory (VtdIndex, (UINTN)NewPageEntry, SIZE_4KB);
+
+      PageEntry->Uint64 = (UINT64)(UINTN)NewPageEntry;
+      SetSecondLevelPagingEntryAttribute (PageEntry, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+      FlushPageTableMemory (VtdIndex, (UINTN)PageEntry, sizeof(*PageEntry));
+      return RETURN_SUCCESS;
+    } else {
+      return RETURN_UNSUPPORTED;
+    }
+  } else {
+    return RETURN_UNSUPPORTED;
+  }
+}
+
+/**
+  Set VTd attribute for a system memory on second level page entry
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  DomainIdentifier        The domain ID of the source.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetSecondLevelPagingAttribute (
+  IN UINTN                         VtdIndex,
+  IN UINT16                        DomainIdentifier,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  VTD_SECOND_LEVEL_PAGING_ENTRY  *PageEntry;
+  PAGE_ATTRIBUTE                 PageAttribute;
+  UINTN                          PageEntryLength;
+  PAGE_ATTRIBUTE                 SplitAttribute;
+  EFI_STATUS                     Status;
+  BOOLEAN                        IsEntryModified;
+
+  DEBUG ((DEBUG_VERBOSE,"SetSecondLevelPagingAttribute (%d) (0x%016lx - 0x%016lx : %x) \n", VtdIndex, BaseAddress, Length, IoMmuAccess));
+  DEBUG ((DEBUG_VERBOSE,"  SecondLevelPagingEntry Base - 0x%x\n", SecondLevelPagingEntry));
+
+  if (BaseAddress != ALIGN_VALUE(BaseAddress, SIZE_4KB)) {
+    DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
+    return EFI_UNSUPPORTED;
+  }
+  if (Length != ALIGN_VALUE(Length, SIZE_4KB)) {
+    DEBUG ((DEBUG_ERROR, "SetSecondLevelPagingAttribute - Invalid Alignment\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  while (Length != 0) {
+    PageEntry = GetSecondLevelPageTableEntry (VtdIndex, SecondLevelPagingEntry, BaseAddress, &PageAttribute);
+    if (PageEntry == NULL) {
+      DEBUG ((DEBUG_ERROR, "PageEntry - NULL\n"));
+      return RETURN_UNSUPPORTED;
+    }
+    PageEntryLength = PageAttributeToLength (PageAttribute);
+    SplitAttribute = NeedSplitPage (BaseAddress, Length, PageAttribute);
+    if (SplitAttribute == PageNone) {
+      ConvertSecondLevelPageEntryAttribute (VtdIndex, PageEntry, IoMmuAccess, &IsEntryModified);
+      if (IsEntryModified) {
+        mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;
+      }
+      //
+      // Convert success, move to next
+      //
+      BaseAddress += PageEntryLength;
+      Length -= PageEntryLength;
+    } else {
+      Status = SplitSecondLevelPage (VtdIndex, PageEntry, PageAttribute, SplitAttribute);
+      if (RETURN_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "SplitSecondLevelPage - %r\n", Status));
+        return RETURN_UNSUPPORTED;
+      }
+      mVtdUnitInformation[VtdIndex].HasDirtyPages = TRUE;
+      //
+      // Just split current page
+      // Convert success in next around
+      //
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  DomainIdentifier        The domain ID of the source.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetPageAttribute (
+  IN UINTN                         VtdIndex,
+  IN UINT16                        DomainIdentifier,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  )
+{
+  EFI_STATUS Status;
+  Status = EFI_NOT_FOUND;
+  if (SecondLevelPagingEntry != NULL) {
+    Status = SetSecondLevelPagingAttribute (VtdIndex, DomainIdentifier, SecondLevelPagingEntry, BaseAddress, Length, IoMmuAccess);
+  }
+  return Status;
+}
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetAccessAttribute (
+  IN UINT16                Segment,
+  IN VTD_SOURCE_ID         SourceId,
+  IN UINT64                BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  )
+{
+  UINTN                         VtdIndex;
+  EFI_STATUS                    Status;
+  VTD_EXT_CONTEXT_ENTRY         *ExtContextEntry;
+  VTD_CONTEXT_ENTRY             *ContextEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+  UINT64                        Pt;
+  UINTN                         PciDataIndex;
+  UINT16                        DomainIdentifier;
+
+  SecondLevelPagingEntry = NULL;
+
+  DEBUG ((DEBUG_VERBOSE,"SetAccessAttribute (S%04x B%02x D%02x F%02x) (0x%016lx - 0x%08x, %x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, BaseAddress, (UINTN)Length, IoMmuAccess));
+
+  VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);
+  if (VtdIndex == (UINTN)-1) {
+    DEBUG ((DEBUG_ERROR,"SetAccessAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    return EFI_DEVICE_ERROR;
+  }
+
+  PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
+  mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciDataIndex].AccessCount++;
+  //
+  // DomainId should not be 0.
+  //
+  DomainIdentifier = (UINT16)(PciDataIndex + 1);
+
+  if (ExtContextEntry != NULL) {
+    if (ExtContextEntry->Bits.Present == 0) {
+      SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+
+      ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;
+      ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);
+      ExtContextEntry->Bits.DomainIdentifier = DomainIdentifier;
+      ExtContextEntry->Bits.Present = 1;
+      FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));
+      DumpDmarExtContextEntryTable (mVtdUnitInformation[VtdIndex].ExtRootEntryTable);
+      mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;
+    } else {
+      SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    }
+  } else if (ContextEntry != NULL) {
+    if (ContextEntry->Bits.Present == 0) {
+      SecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, 0);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x) New\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+
+      ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;
+      ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);
+      ContextEntry->Bits.DomainIdentifier = DomainIdentifier;
+      ContextEntry->Bits.Present = 1;
+      FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));
+      DumpDmarContextEntryTable (mVtdUnitInformation[VtdIndex].RootEntryTable);
+      mVtdUnitInformation[VtdIndex].HasDirtyContext = TRUE;
+    } else {
+      SecondLevelPagingEntry = (VOID *)(UINTN)VTD_64BITS_ADDRESS(ContextEntry->Bits.SecondLevelPageTranslationPointerLo, ContextEntry->Bits.SecondLevelPageTranslationPointerHi);
+      DEBUG ((DEBUG_VERBOSE,"SecondLevelPagingEntry - 0x%x (S%04x B%02x D%02x F%02x)\n", SecondLevelPagingEntry, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    }
+  }
+
+  //
+  // Do not update FixedSecondLevelPagingEntry
+  //
+  if (SecondLevelPagingEntry != mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry) {
+    Status = SetPageAttribute (
+               VtdIndex,
+               DomainIdentifier,
+               SecondLevelPagingEntry,
+               BaseAddress,
+               Length,
+               IoMmuAccess
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR,"SetPageAttribute - %r\n", Status));
+      return Status;
+    }
+  }
+
+  InvalidatePageEntry (VtdIndex);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Always enable the VTd page attribute for the device.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+AlwaysEnablePageAttribute (
+  IN UINT16                  Segment,
+  IN VTD_SOURCE_ID           SourceId
+  )
+{
+  UINTN                         VtdIndex;
+  VTD_EXT_CONTEXT_ENTRY         *ExtContextEntry;
+  VTD_CONTEXT_ENTRY             *ContextEntry;
+  VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry;
+  UINT64                        Pt;
+
+  DEBUG ((DEBUG_INFO,"AlwaysEnablePageAttribute (S%04x B%02x D%02x F%02x)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+  VtdIndex = FindVtdIndexByPciDevice (Segment, SourceId, &ExtContextEntry, &ContextEntry);
+  if (VtdIndex == (UINTN)-1) {
+    DEBUG ((DEBUG_ERROR,"AlwaysEnablePageAttribute - Pci device (S%04x B%02x D%02x F%02x) not found!\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry == 0) {
+    DEBUG((DEBUG_INFO, "CreateSecondLevelPagingEntry - %d\n", VtdIndex));
+    mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry = CreateSecondLevelPagingEntry (VtdIndex, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE);
+  }
+
+  SecondLevelPagingEntry = mVtdUnitInformation[VtdIndex].FixedSecondLevelPagingEntry;
+  Pt = (UINT64)RShiftU64 ((UINT64)(UINTN)SecondLevelPagingEntry, 12);
+  if (ExtContextEntry != NULL) {
+    ExtContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;
+    ExtContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);
+    ExtContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);
+    ExtContextEntry->Bits.Present = 1;
+    FlushPageTableMemory (VtdIndex, (UINTN)ExtContextEntry, sizeof(*ExtContextEntry));
+  } else if (ContextEntry != NULL) {
+    ContextEntry->Bits.SecondLevelPageTranslationPointerLo = (UINT32) Pt;
+    ContextEntry->Bits.SecondLevelPageTranslationPointerHi = (UINT32) RShiftU64(Pt, 20);
+    ContextEntry->Bits.DomainIdentifier = ((1 << (UINT8)((UINTN)mVtdUnitInformation[VtdIndex].CapReg.Bits.ND * 2 + 4)) - 1);
+    ContextEntry->Bits.Present = 1;
+    FlushPageTableMemory (VtdIndex, (UINTN)ContextEntry, sizeof(*ContextEntry));
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTableEx.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTableEx.c
new file mode 100644
index 0000000000..ee8c9e3ad2
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/TranslationTableEx.c
@@ -0,0 +1,152 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+/**
+  Create extended context entry.
+
+  @param[in]  VtdIndex  The index of the VTd engine.
+
+  @retval EFI_SUCCESS          The extended context entry is created.
+  @retval EFI_OUT_OF_RESOURCE  No enough resource to create extended context entry.
+**/
+EFI_STATUS
+CreateExtContextEntry (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN                  Index;
+  VOID                   *Buffer;
+  UINTN                  RootPages;
+  UINTN                  ContextPages;
+  VTD_EXT_ROOT_ENTRY     *ExtRootEntry;
+  VTD_EXT_CONTEXT_ENTRY  *ExtContextEntryTable;
+  VTD_EXT_CONTEXT_ENTRY  *ExtContextEntry;
+  VTD_SOURCE_ID          *PciSourceId;
+  VTD_SOURCE_ID          SourceId;
+  UINTN                  MaxBusNumber;
+  UINTN                  EntryTablePages;
+
+  MaxBusNumber = 0;
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+    if (PciSourceId->Bits.Bus > MaxBusNumber) {
+      MaxBusNumber = PciSourceId->Bits.Bus;
+    }
+  }
+  DEBUG ((DEBUG_INFO,"  MaxBusNumber - 0x%x\n", MaxBusNumber));
+
+  RootPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_ROOT_ENTRY) * VTD_ROOT_ENTRY_NUMBER);
+  ContextPages = EFI_SIZE_TO_PAGES (sizeof (VTD_EXT_CONTEXT_ENTRY) * VTD_CONTEXT_ENTRY_NUMBER);
+  EntryTablePages = RootPages + ContextPages * (MaxBusNumber + 1);
+  Buffer = AllocateZeroPages (EntryTablePages);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_INFO,"Could not Alloc Root Entry Table.. \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+  mVtdUnitInformation[VtdIndex].ExtRootEntryTable = (VTD_EXT_ROOT_ENTRY *)Buffer;
+  Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (RootPages);
+
+  for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
+    PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
+
+    SourceId.Bits.Bus = PciSourceId->Bits.Bus;
+    SourceId.Bits.Device = PciSourceId->Bits.Device;
+    SourceId.Bits.Function = PciSourceId->Bits.Function;
+
+    ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
+    if (ExtRootEntry->Bits.LowerPresent == 0) {
+      ExtRootEntry->Bits.LowerContextTablePointerLo  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12);
+      ExtRootEntry->Bits.LowerContextTablePointerHi  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 32);
+      ExtRootEntry->Bits.LowerPresent = 1;
+      ExtRootEntry->Bits.UpperContextTablePointerLo  = (UINT32) RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1;
+      ExtRootEntry->Bits.UpperContextTablePointerHi  = (UINT32) RShiftU64 (RShiftU64 ((UINT64)(UINTN)Buffer, 12) + 1, 20);
+      ExtRootEntry->Bits.UpperPresent = 1;
+      Buffer = (UINT8 *)Buffer + EFI_PAGES_TO_SIZE (ContextPages);
+    }
+
+    ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
+    ExtContextEntry = &ExtContextEntryTable[SourceId.Index.ContextIndex];
+    ExtContextEntry->Bits.TranslationType = 0;
+    ExtContextEntry->Bits.FaultProcessingDisable = 0;
+    ExtContextEntry->Bits.Present = 0;
+
+    DEBUG ((DEBUG_INFO,"DOMAIN: S%04x, B%02x D%02x F%02x\n", mVtdUnitInformation[VtdIndex].Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+
+    switch (mVtdUnitInformation[VtdIndex].CapReg.Bits.SAGAW) {
+    case BIT1:
+      ExtContextEntry->Bits.AddressWidth = 0x1;
+      break;
+    case BIT2:
+      ExtContextEntry->Bits.AddressWidth = 0x2;
+      break;
+    }
+  }
+
+  FlushPageTableMemory (VtdIndex, (UINTN)mVtdUnitInformation[VtdIndex].ExtRootEntryTable, EFI_PAGES_TO_SIZE(EntryTablePages));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump DMAR extended context entry table.
+
+  @param[in]  ExtRootEntry DMAR extended root entry.
+**/
+VOID
+DumpDmarExtContextEntryTable (
+  IN VTD_EXT_ROOT_ENTRY *ExtRootEntry
+  )
+{
+  UINTN                 Index;
+  UINTN                 Index2;
+  VTD_EXT_CONTEXT_ENTRY *ExtContextEntry;
+
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+  DEBUG ((DEBUG_INFO,"DMAR ExtContext Entry Table:\n"));
+
+  DEBUG ((DEBUG_INFO,"ExtRootEntry Address - 0x%x\n", ExtRootEntry));
+
+  for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) {
+    if ((ExtRootEntry[Index].Uint128.Uint64Lo != 0) || (ExtRootEntry[Index].Uint128.Uint64Hi != 0)) {
+      DEBUG ((DEBUG_INFO,"  ExtRootEntry(0x%02x) B%02x - 0x%016lx %016lx\n",
+        Index, Index, ExtRootEntry[Index].Uint128.Uint64Hi, ExtRootEntry[Index].Uint128.Uint64Lo));
+    }
+    if (ExtRootEntry[Index].Bits.LowerPresent == 0) {
+      continue;
+    }
+    ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry[Index].Bits.LowerContextTablePointerLo, ExtRootEntry[Index].Bits.LowerContextTablePointerHi);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {
+      if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||
+          (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {
+        DEBUG ((DEBUG_INFO,"    ExtContextEntryLower(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",
+          Index2, Index2 >> 3, Index2 & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));
+      }
+      if (ExtContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+      DumpSecondLevelPagingEntry ((VOID *)(UINTN)VTD_64BITS_ADDRESS(ExtContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi));
+    }
+
+    if (ExtRootEntry[Index].Bits.UpperPresent == 0) {
+      continue;
+    }
+    ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry[Index].Bits.UpperContextTablePointerLo, ExtRootEntry[Index].Bits.UpperContextTablePointerHi);
+    for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) {
+      if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) ||
+          (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) {
+        DEBUG ((DEBUG_INFO,"    ExtContextEntryUpper(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n",
+          Index2, (Index2 + 128) >> 3, (Index2 + 128) & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1));
+      }
+      if (ExtContextEntry[Index2].Bits.Present == 0) {
+        continue;
+      }
+    }
+  }
+  DEBUG ((DEBUG_INFO,"=========================\n"));
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
new file mode 100644
index 0000000000..22bf821d2b
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/VtdReg.c
@@ -0,0 +1,561 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DmaProtection.h"
+
+UINTN                            mVtdUnitNumber;
+VTD_UNIT_INFORMATION             *mVtdUnitInformation;
+
+BOOLEAN  mVtdEnabled;
+
+/**
+  Flush VTD page table and context table memory.
+
+  This action is to make sure the IOMMU engine can get final data in memory.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Base              The base address of memory to be flushed.
+  @param[in]  Size              The size of memory in bytes to be flushed.
+**/
+VOID
+FlushPageTableMemory (
+  IN UINTN  VtdIndex,
+  IN UINTN  Base,
+  IN UINTN  Size
+  )
+{
+  if (mVtdUnitInformation[VtdIndex].ECapReg.Bits.C == 0) {
+    WriteBackDataCacheRange ((VOID *)Base, Size);
+  }
+}
+
+/**
+  Flush VTd engine write buffer.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+VOID
+FlushWriteBuffer (
+  IN UINTN  VtdIndex
+  )
+{
+  UINT32  Reg32;
+
+  if (mVtdUnitInformation[VtdIndex].CapReg.Bits.RWBF != 0) {
+    Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+    MmioWrite32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_WBF) != 0);
+  }
+}
+
+/**
+  Invalidate VTd context cache.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+  IN UINTN  VtdIndex
+  )
+{
+  UINT64  Reg64;
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%d)\n",VtdIndex));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalidate VTd IOTLB.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+  IN UINTN  VtdIndex
+  )
+{
+  UINT64  Reg64;
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%d)\n", VtdIndex));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+  Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+  MmioWrite64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalid VTd global IOTLB.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+
+  @retval EFI_SUCCESS           VTd global IOTLB is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd global IOTLB is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBGlobal (
+  IN UINTN  VtdIndex
+  )
+{
+  if (!mVtdEnabled) {
+    return EFI_SUCCESS;
+  }
+
+  DEBUG((DEBUG_VERBOSE, "InvalidateVtdIOTLBGlobal(%d)\n", VtdIndex));
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdIndex);
+
+  //
+  // Invalidate the context cache
+  //
+  if (mVtdUnitInformation[VtdIndex].HasDirtyContext) {
+    InvalidateContextCache (VtdIndex);
+  }
+
+  //
+  // Invalidate the IOTLB cache
+  //
+  if (mVtdUnitInformation[VtdIndex].HasDirtyContext || mVtdUnitInformation[VtdIndex].HasDirtyPages) {
+    InvalidateIOTLB (VtdIndex);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Prepare VTD configuration.
+**/
+VOID
+PrepareVtdConfig (
+  VOID
+  )
+{
+  UINTN         Index;
+  UINTN         DomainNumber;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG ((DEBUG_INFO, "Dump VTd Capability (%d)\n", Index));
+    mVtdUnitInformation[Index].CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
+    DumpVtdCapRegs (&mVtdUnitInformation[Index].CapReg);
+    mVtdUnitInformation[Index].ECapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_ECAP_REG);
+    DumpVtdECapRegs (&mVtdUnitInformation[Index].ECapReg);
+
+    if ((mVtdUnitInformation[Index].CapReg.Bits.SLLPS & BIT0) == 0) {
+      DEBUG((DEBUG_WARN, "!!!! 2MB super page is not supported on VTD %d !!!!\n", Index));
+    }
+    if ((mVtdUnitInformation[Index].CapReg.Bits.SAGAW & BIT2) == 0) {
+      DEBUG((DEBUG_ERROR, "!!!! 4-level page-table is not supported on VTD %d !!!!\n", Index));
+      return ;
+    }
+
+    DomainNumber = (UINTN)1 << (UINT8)((UINTN)mVtdUnitInformation[Index].CapReg.Bits.ND * 2 + 4);
+    if (mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber >= DomainNumber) {
+      DEBUG((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber, DomainNumber));
+      return ;
+    }
+  }
+  return ;
+}
+
+/**
+  Disable PMR in all VTd engine.
+**/
+VOID
+DisablePmr (
+  VOID
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+  UINTN         Index;
+
+  DEBUG ((DEBUG_INFO,"DisablePmr\n"));
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_CAP_REG);
+    if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+      continue ;
+    }
+
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+    if ((Reg32 & BIT0) != 0) {
+      MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
+      do {
+        Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+      } while((Reg32 & BIT0) != 0);
+      DEBUG ((DEBUG_INFO,"Pmr(%d) disabled\n", Index));
+    } else {
+      DEBUG ((DEBUG_INFO,"Pmr(%d) not enabled\n", Index));
+    }
+  }
+  return ;
+}
+
+/**
+  Enable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  VOID
+  )
+{
+  UINTN     Index;
+  UINT32    Reg32;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%d] \n", Index));
+
+    if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
+      DEBUG((DEBUG_INFO, "ExtRootEntryTable 0x%x \n", mVtdUnitInformation[Index].ExtRootEntryTable));
+      MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].ExtRootEntryTable | BIT11);
+    } else {
+      DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", mVtdUnitInformation[Index].RootEntryTable));
+      MmioWrite64 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)mVtdUnitInformation[Index].RootEntryTable);
+    }
+
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+
+    DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+    //
+    // Init DMAr Fault Event and Data registers
+    //
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_FEDATA_REG);
+
+    //
+    // Write Buffer Flush before invalidation
+    //
+    FlushWriteBuffer (Index);
+
+    //
+    // Invalidate the context cache
+    //
+    InvalidateContextCache (Index);
+
+    //
+    // Invalidate the IOTLB cache
+    //
+    InvalidateIOTLB (Index);
+
+    //
+    // Enable VTd
+    //
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+    DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+    DEBUG ((DEBUG_INFO,"VTD (%d) enabled!<<<<<<\n",Index));
+  }
+
+  //
+  // Need disable PMR, since we already setup translation table.
+  //
+  DisablePmr ();
+
+  mVtdEnabled = TRUE;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  VOID
+  )
+{
+  UINTN     Index;
+  UINTN     SubIndex;
+  UINT32    Reg32;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%d] \n", Index));
+
+    //
+    // Write Buffer Flush before invalidation
+    //
+    FlushWriteBuffer (Index);
+
+    //
+    // Disable VTd
+    //
+    MmioWrite32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+    do {
+      Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+    Reg32 = MmioRead32 (mVtdUnitInformation[Index].VtdUnitBaseAddress + R_GSTS_REG);
+    DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
+
+    DEBUG ((DEBUG_INFO,"VTD (%d) Disabled!<<<<<<\n",Index));
+  }
+
+  mVtdEnabled = FALSE;
+
+  for (Index = 0; Index < mVtdUnitNumber; Index++) {
+    DEBUG((DEBUG_INFO, "engine [%d] access\n", Index));
+    for (SubIndex = 0; SubIndex < mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceDataNumber; SubIndex++) {
+      DEBUG ((DEBUG_INFO, "  PCI S%04X B%02x D%02x F%02x - %d\n",
+        mVtdUnitInformation[Index].Segment,
+        mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
+        mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
+        mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function,
+        mVtdUnitInformation[Index].PciDeviceInfo.PciDeviceData[Index].AccessCount
+        ));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump VTd capability registers.
+
+  @param[in]  CapReg              The capability register.
+**/
+VOID
+DumpVtdCapRegs (
+  IN VTD_CAP_REG *CapReg
+  )
+{
+  DEBUG((DEBUG_INFO, "  CapReg:\n", CapReg->Uint64));
+  DEBUG((DEBUG_INFO, "    ND     - 0x%x\n", CapReg->Bits.ND));
+  DEBUG((DEBUG_INFO, "    AFL    - 0x%x\n", CapReg->Bits.AFL));
+  DEBUG((DEBUG_INFO, "    RWBF   - 0x%x\n", CapReg->Bits.RWBF));
+  DEBUG((DEBUG_INFO, "    PLMR   - 0x%x\n", CapReg->Bits.PLMR));
+  DEBUG((DEBUG_INFO, "    PHMR   - 0x%x\n", CapReg->Bits.PHMR));
+  DEBUG((DEBUG_INFO, "    CM     - 0x%x\n", CapReg->Bits.CM));
+  DEBUG((DEBUG_INFO, "    SAGAW  - 0x%x\n", CapReg->Bits.SAGAW));
+  DEBUG((DEBUG_INFO, "    MGAW   - 0x%x\n", CapReg->Bits.MGAW));
+  DEBUG((DEBUG_INFO, "    ZLR    - 0x%x\n", CapReg->Bits.ZLR));
+  DEBUG((DEBUG_INFO, "    FRO    - 0x%x\n", CapReg->Bits.FRO));
+  DEBUG((DEBUG_INFO, "    SLLPS  - 0x%x\n", CapReg->Bits.SLLPS));
+  DEBUG((DEBUG_INFO, "    PSI    - 0x%x\n", CapReg->Bits.PSI));
+  DEBUG((DEBUG_INFO, "    NFR    - 0x%x\n", CapReg->Bits.NFR));
+  DEBUG((DEBUG_INFO, "    MAMV   - 0x%x\n", CapReg->Bits.MAMV));
+  DEBUG((DEBUG_INFO, "    DWD    - 0x%x\n", CapReg->Bits.DWD));
+  DEBUG((DEBUG_INFO, "    DRD    - 0x%x\n", CapReg->Bits.DRD));
+  DEBUG((DEBUG_INFO, "    FL1GP  - 0x%x\n", CapReg->Bits.FL1GP));
+  DEBUG((DEBUG_INFO, "    PI     - 0x%x\n", CapReg->Bits.PI));
+}
+
+/**
+  Dump VTd extended capability registers.
+
+  @param[in]  ECapReg              The extended capability register.
+**/
+VOID
+DumpVtdECapRegs (
+  IN VTD_ECAP_REG *ECapReg
+  )
+{
+  DEBUG((DEBUG_INFO, "  ECapReg:\n", ECapReg->Uint64));
+  DEBUG((DEBUG_INFO, "    C      - 0x%x\n", ECapReg->Bits.C));
+  DEBUG((DEBUG_INFO, "    QI     - 0x%x\n", ECapReg->Bits.QI));
+  DEBUG((DEBUG_INFO, "    DT     - 0x%x\n", ECapReg->Bits.DT));
+  DEBUG((DEBUG_INFO, "    IR     - 0x%x\n", ECapReg->Bits.IR));
+  DEBUG((DEBUG_INFO, "    EIM    - 0x%x\n", ECapReg->Bits.EIM));
+  DEBUG((DEBUG_INFO, "    PT     - 0x%x\n", ECapReg->Bits.PT));
+  DEBUG((DEBUG_INFO, "    SC     - 0x%x\n", ECapReg->Bits.SC));
+  DEBUG((DEBUG_INFO, "    IRO    - 0x%x\n", ECapReg->Bits.IRO));
+  DEBUG((DEBUG_INFO, "    MHMV   - 0x%x\n", ECapReg->Bits.MHMV));
+  DEBUG((DEBUG_INFO, "    ECS    - 0x%x\n", ECapReg->Bits.ECS));
+  DEBUG((DEBUG_INFO, "    MTS    - 0x%x\n", ECapReg->Bits.MTS));
+  DEBUG((DEBUG_INFO, "    NEST   - 0x%x\n", ECapReg->Bits.NEST));
+  DEBUG((DEBUG_INFO, "    DIS    - 0x%x\n", ECapReg->Bits.DIS));
+  DEBUG((DEBUG_INFO, "    PASID  - 0x%x\n", ECapReg->Bits.PASID));
+  DEBUG((DEBUG_INFO, "    PRS    - 0x%x\n", ECapReg->Bits.PRS));
+  DEBUG((DEBUG_INFO, "    ERS    - 0x%x\n", ECapReg->Bits.ERS));
+  DEBUG((DEBUG_INFO, "    SRS    - 0x%x\n", ECapReg->Bits.SRS));
+  DEBUG((DEBUG_INFO, "    NWFS   - 0x%x\n", ECapReg->Bits.NWFS));
+  DEBUG((DEBUG_INFO, "    EAFS   - 0x%x\n", ECapReg->Bits.EAFS));
+  DEBUG((DEBUG_INFO, "    PSS    - 0x%x\n", ECapReg->Bits.PSS));
+}
+
+/**
+  Dump VTd registers.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpVtdRegs (
+  IN UINTN  VtdIndex
+  )
+{
+  UINTN         Index;
+  UINT64        Reg64;
+  VTD_FRCD_REG  FrcdReg;
+  VTD_CAP_REG   CapReg;
+  UINT32        Reg32;
+  VTD_SOURCE_ID SourceId;
+
+  DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) Begin ####\n", VtdIndex));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_VER_REG);
+  DEBUG((DEBUG_INFO, "  VER_REG     - 0x%08x\n", Reg32));
+
+  CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CAP_REG);
+  DEBUG((DEBUG_INFO, "  CAP_REG     - 0x%016lx\n", CapReg.Uint64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_ECAP_REG);
+  DEBUG((DEBUG_INFO, "  ECAP_REG    - 0x%016lx\n", Reg64));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_GSTS_REG);
+  DEBUG((DEBUG_INFO, "  GSTS_REG    - 0x%08x \n", Reg32));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_RTADDR_REG);
+  DEBUG((DEBUG_INFO, "  RTADDR_REG  - 0x%016lx\n", Reg64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_CCMD_REG);
+  DEBUG((DEBUG_INFO, "  CCMD_REG    - 0x%016lx\n", Reg64));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FSTS_REG);
+  DEBUG((DEBUG_INFO, "  FSTS_REG    - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FECTL_REG);
+  DEBUG((DEBUG_INFO, "  FECTL_REG   - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEDATA_REG);
+  DEBUG((DEBUG_INFO, "  FEDATA_REG  - 0x%08x\n", Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEADDR_REG);
+  DEBUG((DEBUG_INFO, "  FEADDR_REG  - 0x%08x\n",Reg32));
+
+  Reg32 = MmioRead32 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + R_FEUADDR_REG);
+  DEBUG((DEBUG_INFO, "  FEUADDR_REG - 0x%08x\n",Reg32));
+
+  for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
+    FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
+    FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
+    DEBUG((DEBUG_INFO, "  FRCD_REG[%d] - 0x%016lx %016lx\n", Index, FrcdReg.Uint64[1], FrcdReg.Uint64[0]));
+    if (FrcdReg.Uint64[1] != 0 || FrcdReg.Uint64[0] != 0) {
+      DEBUG((DEBUG_INFO, "    Fault Info - 0x%016lx\n", VTD_64BITS_ADDRESS(FrcdReg.Bits.FILo, FrcdReg.Bits.FIHi)));
+      SourceId.Uint16 = (UINT16)FrcdReg.Bits.SID;
+      DEBUG((DEBUG_INFO, "    Source - B%02x D%02x F%02x\n", SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
+      DEBUG((DEBUG_INFO, "    Type - %x (%a)\n", FrcdReg.Bits.T, FrcdReg.Bits.T ? "read" : "write"));
+      DEBUG((DEBUG_INFO, "    Reason - %x (Refer to VTd Spec, Appendix A)\n", FrcdReg.Bits.FR));
+    }
+  }
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IVA_REG);
+  DEBUG((DEBUG_INFO, "  IVA_REG     - 0x%016lx\n",Reg64));
+
+  Reg64 = MmioRead64 (mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress + (mVtdUnitInformation[VtdIndex].ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  DEBUG((DEBUG_INFO, "  IOTLB_REG   - 0x%016lx\n",Reg64));
+
+  DEBUG((DEBUG_INFO, "#### DumpVtdRegs(%d) End ####\n", VtdIndex));
+}
+
+/**
+  Dump VTd registers for all VTd engine.
+**/
+VOID
+DumpVtdRegsAll (
+  VOID
+  )
+{
+  UINTN       Num;
+
+  for (Num = 0; Num < mVtdUnitNumber; Num++) {
+    DumpVtdRegs (Num);
+  }
+}
+
+/**
+  Dump VTd registers if there is error.
+**/
+VOID
+DumpVtdIfError (
+  VOID
+  )
+{
+  UINTN         Num;
+  UINTN         Index;
+  VTD_FRCD_REG  FrcdReg;
+  VTD_CAP_REG   CapReg;
+  UINT32        Reg32;
+  BOOLEAN       HasError;
+
+  for (Num = 0; Num < mVtdUnitNumber; Num++) {
+    HasError = FALSE;
+    Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG);
+    if (Reg32 != 0) {
+      HasError = TRUE;
+    }
+    Reg32 = MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FECTL_REG);
+    if ((Reg32 & BIT30) != 0) {
+      HasError = TRUE;
+    }
+
+    CapReg.Uint64 = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_CAP_REG);
+    for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
+      FrcdReg.Uint64[0] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG));
+      FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
+      if (FrcdReg.Bits.F != 0) {
+        HasError = TRUE;
+      }
+    }
+
+    if (HasError) {
+      REPORT_STATUS_CODE (EFI_ERROR_CODE, PcdGet32 (PcdErrorCodeVTdError));
+      DEBUG((DEBUG_INFO, "\n#### ERROR ####\n"));
+      DumpVtdRegs (Num);
+      DEBUG((DEBUG_INFO, "#### ERROR ####\n\n"));
+      //
+      // Clear
+      //
+      for (Index = 0; Index < (UINTN)CapReg.Bits.NFR + 1; Index++) {
+        FrcdReg.Uint64[1] = MmioRead64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)));
+        if (FrcdReg.Bits.F != 0) {
+          //
+          // Software writes the value read from this field (F) to Clear it.
+          //
+          MmioWrite64 (mVtdUnitInformation[Num].VtdUnitBaseAddress + ((CapReg.Bits.FRO * 16) + (Index * 16) + R_FRCD_REG + sizeof(UINT64)), FrcdReg.Uint64[1]);
+        }
+      }
+      MmioWrite32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG, MmioRead32 (mVtdUnitInformation[Num].VtdUnitBaseAddress + R_FSTS_REG));
+    }
+  }
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
new file mode 100644
index 0000000000..d920d136f1
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/DmarTable.c
@@ -0,0 +1,578 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Dump DMAR DeviceScopeEntry.
+
+  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry
+**/
+VOID
+DumpDmarDeviceScopeEntry (
+  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry
+  )
+{
+  UINTN   PciPathNumber;
+  UINTN   PciPathIndex;
+  EFI_ACPI_DMAR_PCI_PATH  *PciPath;
+
+  if (DmarDeviceScopeEntry == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :
+    "    DMAR Device Scope Entry address ...................... 0x%08x\n",
+    DmarDeviceScopeEntry
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Device Scope Entry Type ............................ 0x%02x\n",
+    DmarDeviceScopeEntry->Type
+    ));
+  switch (DmarDeviceScopeEntry->Type) {
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Endpoint Device\n"
+      ));
+    break;
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+    DEBUG ((DEBUG_INFO,
+      "        PCI Sub-hierachy\n"
+      ));
+    break;
+  default:
+    break;
+  }
+  DEBUG ((DEBUG_INFO,
+    "      Length ............................................. 0x%02x\n",
+    DmarDeviceScopeEntry->Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Enumeration ID ..................................... 0x%02x\n",
+    DmarDeviceScopeEntry->EnumerationId
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      Starting Bus Number ................................ 0x%02x\n",
+    DmarDeviceScopeEntry->StartBusNumber
+    ));
+
+  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
+  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
+  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
+    DEBUG ((DEBUG_INFO,
+      "      Device ............................................. 0x%02x\n",
+      PciPath[PciPathIndex].Device
+      ));
+    DEBUG ((DEBUG_INFO,
+      "      Function ........................................... 0x%02x\n",
+      PciPath[PciPathIndex].Function
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "    *************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR RMRR table.
+
+  @param[in]  Rmrr  DMAR RMRR table
+**/
+VOID
+DumpDmarRmrr (
+  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    RmrrLen;
+
+  if (Rmrr == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       Reserved Memory Region Reporting Structure                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  RMRR address ........................................... 0x%016lx\n" :
+    "  RMRR address ........................................... 0x%08x\n",
+    Rmrr
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Rmrr->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Rmrr->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Rmrr->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Base Address .................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionBaseAddress
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",
+    Rmrr->ReservedMemoryRegionLimitAddress
+    ));
+
+  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
+  while (RmrrLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    RmrrLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR DRHD table.
+
+  @param[in]  Drhd  DMAR DRHD table
+**/
+VOID
+DumpDmarDrhd (
+  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;
+  INTN                                    DrhdLen;
+
+  if (Drhd == NULL) {
+    return;
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "  DRHD address ........................................... 0x%016lx\n" :
+    "  DRHD address ........................................... 0x%08x\n",
+    Drhd
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Type ................................................. 0x%04x\n",
+    Drhd->Header.Type
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Length ............................................... 0x%04x\n",
+    Drhd->Header.Length
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Drhd->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",
+    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Segment Number ....................................... 0x%04x\n",
+    Drhd->SegmentNumber
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Register Base Address ................................ 0x%016lx\n",
+    Drhd->RegisterBaseAddress
+    ));
+
+  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
+  while (DrhdLen > 0) {
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+    DrhdLen -= DmarDeviceScopeEntry->Length;
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "  ***************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+  INTN                  DmarLen;
+
+  if (Dmar == NULL) {
+    return;
+  }
+
+  //
+  // Dump Dmar table
+  //
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*         DMAR Table                                                        *\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n"
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    (sizeof(UINTN) == sizeof(UINT64)) ?
+    "DMAR address ............................................. 0x%016lx\n" :
+    "DMAR address ............................................. 0x%08x\n",
+    Dmar
+    ));
+
+  DEBUG ((DEBUG_INFO,
+    "  Table Contents:\n"
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Host Address Width ................................... 0x%02x\n",
+    Dmar->HostAddressWidth
+    ));
+  DEBUG ((DEBUG_INFO,
+    "    Flags ................................................ 0x%02x\n",
+    Dmar->Flags
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      INTR_REMAP ......................................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
+    ));
+  DEBUG ((DEBUG_INFO,
+    "      DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
+    ));
+
+  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
+  while (DmarLen > 0) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      break;
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarLen -= DmarHeader->Length;
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+
+  DEBUG ((DEBUG_INFO,
+    "*****************************************************************************\n\n"
+    ));
+
+  return;
+}
+
+/**
+  Get VTd engine number.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return the VTd engine number.
+**/
+UINTN
+GetVtdEngineNumber (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      VtdIndex++;
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return VtdIndex ;
+}
+
+/**
+  Process DMAR DHRD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  VtdIndex  The index of VTd engine.
+  @param[in]  DmarDrhd  The DRHD table.
+**/
+VOID
+ProcessDhrd (
+  IN VTD_INFO                   *VTdInfo,
+  IN UINTN                      VtdIndex,
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd
+  )
+{
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+  VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdUnitNumber;
+  UINTN                                             VtdIndex;
+  VTD_INFO                                          *VTdInfo;
+
+  VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
+  if (VtdUnitNumber == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
+  ASSERT(VTdInfo != NULL);
+  if (VTdInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the engine mask to all.
+  //
+  VTdInfo->AcpiDmarTable    = AcpiDmarTable;
+  VTdInfo->EngineMask       = LShiftU64 (1, VtdUnitNumber) - 1;
+  VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
+  VTdInfo->VTdEngineCount   = VtdUnitNumber;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      ASSERT (VtdIndex < VtdUnitNumber);
+      ProcessDhrd (VTdInfo, VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+      VtdIndex++;
+
+      break;
+
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  ASSERT (VtdIndex == VtdUnitNumber);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return the VTd engine index according to the Segment and DevScopeEntry.
+
+  @param AcpiDmarTable   DMAR ACPI table
+  @param Segment         The segment of the VTd engine
+  @param DevScopeEntry   The DevScopeEntry of the VTd engine
+
+  @return The VTd engine index according to the Segment and DevScopeEntry.
+  @retval -1  The VTd engine is not found.
+**/
+UINTN
+GetVTdEngineFromDevScopeEntry (
+  IN  EFI_ACPI_DMAR_HEADER                        *AcpiDmarTable,
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+  )
+{
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;
+  UINTN                                             VtdIndex;
+  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;
+
+  VtdIndex = 0;
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_DRHD:
+      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
+      if (DmarDrhd->SegmentNumber != Segment) {
+        // Mismatch
+        break;
+      }
+      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
+          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
+        // No DevScopeEntry
+        // Do not handle PCI_ALL
+        break;
+      }
+      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
+            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
+          return VtdIndex;
+        }
+        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
+      }
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+  return (UINTN)-1;
+}
+
+/**
+  Process DMAR RMRR table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+  @param[in]  DmarRmrr  The RMRR table.
+**/
+VOID
+ProcessRmrr (
+  IN VTD_INFO                   *VTdInfo,
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr
+  )
+{
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;
+  UINTN                                             VTdIndex;
+  UINT64                                            RmrrMask;
+  UINTN                                             LowBottom;
+  UINTN                                             LowTop;
+  UINTN                                             HighBottom;
+  UINT64                                            HighTop;
+  EFI_ACPI_DMAR_HEADER                              *AcpiDmarTable;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
+      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
+    return ;
+  }
+
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
+
+    VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
+    if (VTdIndex != (UINTN)-1) {
+      RmrrMask = LShiftU64 (1, VTdIndex);
+
+      LowBottom = 0;
+      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
+      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
+      HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
+
+      SetDmaProtectedRange (
+        VTdInfo,
+        RmrrMask,
+        0,
+        (UINT32)(LowTop - LowBottom),
+        HighBottom,
+        HighTop - HighBottom
+        );
+
+      //
+      // Remove the engine from the engine mask.
+      // The assumption is that any other PEI driver does not access
+      // the device covered by this engine.
+      //
+      VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
+    }
+
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+  }
+}
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  VTdInfo   The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  )
+{
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  EFI_ACPI_DMAR_STRUCTURE_HEADER          *DmarHeader;
+
+  AcpiDmarTable = VTdInfo->AcpiDmarTable;
+
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));
+  while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {
+    switch (DmarHeader->Type) {
+    case EFI_ACPI_DMAR_TYPE_RMRR:
+      ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+      break;
+    default:
+      break;
+    }
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+  }
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
new file mode 100644
index 0000000000..37283f0fab
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
@@ -0,0 +1,420 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Get protected low memory alignment.
+
+  @param HostAddressWidth   The host address width.
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @return protected low memory alignment.
+**/
+UINT32
+GetPlmrAlignment (
+  IN UINT8         HostAddressWidth,
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Data32;
+
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, 0xFFFFFFFF);
+  Data32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG);
+  Data32 = ~Data32 + 1;
+
+  return Data32;
+}
+
+/**
+  Get protected high memory alignment.
+
+  @param HostAddressWidth   The host address width.
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @return protected high memory alignment.
+**/
+UINT64
+GetPhmrAlignment (
+  IN UINT8         HostAddressWidth,
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT64        Data64;
+
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
+  Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
+  Data64 = ~Data64 + 1;
+  Data64 = Data64 & (LShiftU64 (1, HostAddressWidth) - 1);
+
+  return Data64;
+}
+
+/**
+  Get protected low memory alignment.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return protected low memory alignment.
+**/
+UINT32
+GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN         Index;
+  UINT32        Alignment;
+  UINT32        FinalAlignment;
+
+  FinalAlignment = 0;
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (FinalAlignment < Alignment) {
+      FinalAlignment = Alignment;
+    }
+  }
+  return FinalAlignment;
+}
+
+/**
+  Get protected high memory alignment.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return protected high memory alignment.
+**/
+UINT64
+GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN         Index;
+  UINT64        Alignment;
+  UINT64        FinalAlignment;
+
+  FinalAlignment = 0;
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (FinalAlignment < Alignment) {
+      FinalAlignment = Alignment;
+    }
+  }
+  return FinalAlignment;
+}
+
+/**
+  Enable PMR in the VTd engine.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval EFI_SUCCESS      The PMR is enabled.
+  @retval EFI_UNSUPPORTED  The PMR is not supported.
+**/
+EFI_STATUS
+EnablePmr (
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+
+  DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
+  if ((Reg32 & BIT0) == 0) {
+    MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);
+    do {
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+    } while((Reg32 & BIT0) == 0);
+  }
+
+  DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable PMR in the VTd engine.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval EFI_SUCCESS      The PMR is disabled.
+  @retval EFI_UNSUPPORTED  The PMR is not supported.
+**/
+EFI_STATUS
+DisablePmr (
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if (Reg32 == 0xFFFFFFFF) {
+    DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));
+    ASSERT(FALSE);
+  }
+
+  if ((Reg32 & BIT0) != 0) {
+    MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);
+    do {
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+    } while((Reg32 & BIT0) != 0);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set PMR region in the VTd engine.
+
+  @param HostAddressWidth   The host address width.
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+  @param LowMemoryBase      The protected low memory region base.
+  @param LowMemoryLength    The protected low memory region length.
+  @param HighMemoryBase     The protected high memory region base.
+  @param HighMemoryLength   The protected high memory region length.
+
+  @retval EFI_SUCCESS      The PMR is set to protected region.
+  @retval EFI_UNSUPPORTED  The PMR is not supported.
+**/
+EFI_STATUS
+SetPmrRegion (
+  IN UINT8         HostAddressWidth,
+  IN UINTN         VtdUnitBaseAddress,
+  IN UINT32        LowMemoryBase,
+  IN UINT32        LowMemoryLength,
+  IN UINT64        HighMemoryBase,
+  IN UINT64        HighMemoryLength
+  )
+{
+  VTD_CAP_REG   CapReg;
+  UINT32        PlmrAlignment;
+  UINT64        PhmrAlignment;
+
+  DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress));
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
+  DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));
+  PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);
+  DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));
+
+  if ((LowMemoryBase    != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||
+      (LowMemoryLength  != ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) ||
+      (HighMemoryBase   != ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) ||
+      (HighMemoryLength != ALIGN_VALUE(HighMemoryLength, PhmrAlignment))) {
+    DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  if (LowMemoryBase == 0 && LowMemoryLength == 0) {
+    LowMemoryBase = 0xFFFFFFFF;
+  }
+  if (HighMemoryBase == 0 && HighMemoryLength == 0) {
+    HighMemoryBase = 0xFFFFFFFFFFFFFFFF;
+  }
+
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG,    LowMemoryBase);
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG,  LowMemoryBase + LowMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PLMR set done\n"));
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG,   HighMemoryBase);
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);
+  DEBUG ((DEBUG_INFO, "PHMR set done\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set DMA protected region.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+  @param LowMemoryBase      The protected low memory region base.
+  @param LowMemoryLength    The protected low memory region length.
+  @param HighMemoryBase     The protected high memory region base.
+  @param HighMemoryLength   The protected high memory region length.
+
+  @retval EFI_SUCCESS      The DMA protection is set.
+  @retval EFI_UNSUPPORTED  The DMA protection is not set.
+**/
+EFI_STATUS
+SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask,
+  IN UINT32        LowMemoryBase,
+  IN UINT32        LowMemoryLength,
+  IN UINT64        HighMemoryBase,
+  IN UINT64        HighMemoryLength
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    Status = SetPmrRegion (
+               VTdInfo->HostAddressWidth,
+               (UINTN)VTdInfo->VTdEngineAddress[Index],
+               LowMemoryBase,
+               LowMemoryLength,
+               HighMemoryBase,
+               HighMemoryLength
+               );
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+    Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Diable DMA protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @retval EFI_SUCCESS DMA protection is disabled.
+**/
+EFI_STATUS
+DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));
+
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Return if the PMR is enabled.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval TRUE  PMR is enabled.
+  @retval FALSE PMR is disabled or unsupported.
+**/
+BOOLEAN
+IsPmrEnabled (
+  IN UINTN         VtdUnitBaseAddress
+  )
+{
+  UINT32        Reg32;
+  VTD_CAP_REG   CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {
+    return FALSE;
+  }
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);
+  if ((Reg32 & BIT0) == 0) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Return the mask of the VTd engine which is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return the mask of the VTd engine which is enabled.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  BOOLEAN     Result;
+  UINT64      EnabledEngineMask;
+
+  DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));
+
+  EnabledEngineMask = 0;
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+    if (Result) {
+      EnabledEngineMask |= LShiftU64(1, Index);
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));
+  return EnabledEngineMask;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
new file mode 100644
index 0000000000..ca099ed71d
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
@@ -0,0 +1,810 @@
+/** @file
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/HobLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/VtdInfo.h>
+#include <Ppi/MemoryDiscovered.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include "IntelVTdPmrPei.h"
+
+EFI_GUID mVTdInfoGuid = {
+  0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }
+};
+
+EFI_GUID mDmaBufferInfoGuid = {
+  0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }
+};
+
+typedef struct {
+  UINTN                             DmaBufferBase;
+  UINTN                             DmaBufferSize;
+  UINTN                             DmaBufferCurrentTop;
+  UINTN                             DmaBufferCurrentBottom;
+} DMA_BUFFER_INFO;
+
+#define MAP_INFO_SIGNATURE  SIGNATURE_32 ('D', 'M', 'A', 'P')
+typedef struct {
+  UINT32                                    Signature;
+  EDKII_IOMMU_OPERATION                     Operation;
+  UINTN                                     NumberOfBytes;
+  EFI_PHYSICAL_ADDRESS                      HostAddress;
+  EFI_PHYSICAL_ADDRESS                      DeviceAddress;
+} MAP_INFO;
+
+/**
+
+  PEI Memory Layout:
+
+              +------------------+ <=============== PHMR.Limit (+ alignment) (1 << (HostAddressWidth + 1))
+              |   Mem Resource   |
+              |                  |
+
+              +------------------+ <------- EfiMemoryTop
+              |   PEI allocated  |
+  =========== +==================+ <=============== PHMR.Base
+       ^      |    Commom Buf    |
+       |      |  --------------  |
+  DMA Buffer  |   * DMA FREE *   |
+       |      |  --------------  |
+       V      |  Read/Write Buf  |
+  =========== +==================+ <=============== PLMR.Limit (+ alignment)
+              |   PEI allocated  |
+              |  --------------  | <------- EfiFreeMemoryTop
+              |   * PEI FREE *   |
+              |  --------------  | <------- EfiFreeMemoryBottom
+              |       hob        |
+              |  --------------  |
+              |      Stack       |
+              +------------------+ <------- EfiMemoryBottom / Stack Bottom
+
+              +------------------+
+              |   Mem Alloc Hob  |
+              +------------------+
+
+              |                  |
+              |   Mem Resource   |
+              +------------------+ <=============== PLMR.Base (0)
+**/
+
+/**
+  Set IOMMU attribute for a system memory.
+
+  If the IOMMU PPI exists, the system memory cannot be used
+  for DMA by default.
+
+  When a device requests a DMA access for a system memory,
+  the device driver need use SetAttribute() to update the IOMMU
+  attribute to request DMA access (read and/or write).
+
+  @param[in]  This              The PPI instance pointer.
+  @param[in]  Mapping           The mapping value returned from Map().
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.
+  @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by Map().
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by Mapping.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+  @retval EFI_NOT_AVAILABLE_YET  DMA protection has been enabled, but DMA buffer are
+                                 not available to be allocated yet.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiIoMmuSetAttribute (
+  IN EDKII_IOMMU_PPI       *This,
+  IN VOID                  *Mapping,
+  IN UINT64                IoMmuAccess
+  )
+{
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Provides the controller-specific addresses required to access system memory from a
+  DMA bus master.
+
+  @param  This                  The PPI instance pointer.
+  @param  Operation             Indicates if the bus master is going to read or write to system memory.
+  @param  HostAddress           The system memory address to map to the PCI controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
+                                that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
+                                access the hosts HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
+  @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+                                not available to be allocated yet.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiIoMmuMap (
+  IN     EDKII_IOMMU_PPI                            *This,
+  IN     EDKII_IOMMU_OPERATION                      Operation,
+  IN     VOID                                       *HostAddress,
+  IN OUT UINTN                                      *NumberOfBytes,
+  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
+  OUT    VOID                                       **Mapping
+  )
+{
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
+
+  if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||
+      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {
+    *DeviceAddress = (UINTN)HostAddress;
+    *Mapping = NULL;
+    return EFI_SUCCESS;
+  }
+
+  Length = *NumberOfBytes + sizeof(MAP_INFO);
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
+    DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;
+  DmaBufferInfo->DmaBufferCurrentBottom += Length;
+
+  MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);
+  MapInfo->Signature     = MAP_INFO_SIGNATURE;
+  MapInfo->Operation     = Operation;
+  MapInfo->NumberOfBytes = *NumberOfBytes;
+  MapInfo->HostAddress   = (UINTN)HostAddress;
+  MapInfo->DeviceAddress = *DeviceAddress;
+  *Mapping = MapInfo;
+  DEBUG ((DEBUG_VERBOSE, "  Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));
+
+  //
+  // If this is a read operation from the Bus Master's point of view,
+  // then copy the contents of the real buffer into the mapped buffer
+  // so the Bus Master can read the contents of the real buffer.
+  //
+  if (Operation == EdkiiIoMmuOperationBusMasterRead ||
+      Operation == EdkiiIoMmuOperationBusMasterRead64) {
+    CopyMem (
+      (VOID *) (UINTN) MapInfo->DeviceAddress,
+      (VOID *) (UINTN) MapInfo->HostAddress,
+      MapInfo->NumberOfBytes
+      );
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  The PPI instance pointer.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+  @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+  @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.
+  @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+                                not available to be allocated yet.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiIoMmuUnmap (
+  IN  EDKII_IOMMU_PPI                          *This,
+  IN  VOID                                     *Mapping
+  )
+{
+  MAP_INFO                    *MapInfo;
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
+
+  if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  if (Mapping == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  MapInfo = Mapping;
+  ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);
+  DEBUG ((DEBUG_VERBOSE, "  Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));
+
+  //
+  // If this is a write operation from the Bus Master's point of view,
+  // then copy the contents of the mapped buffer into the real buffer
+  // so the processor can read the contents of the real buffer.
+  //
+  if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
+      MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
+    CopyMem (
+      (VOID *) (UINTN) MapInfo->HostAddress,
+      (VOID *) (UINTN) MapInfo->DeviceAddress,
+      MapInfo->NumberOfBytes
+      );
+  }
+
+  Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);
+  if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {
+    DmaBufferInfo->DmaBufferCurrentBottom -= Length;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+  OperationBusMasterCommonBuffer64 mapping.
+
+  @param  This                  The PPI instance pointer.
+  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
+                                EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory address of the
+                                allocated range.
+  @param  Attributes            The requested bit mask of attributes for the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
+                                MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+  @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+                                not available to be allocated yet.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiIoMmuAllocateBuffer (
+  IN     EDKII_IOMMU_PPI                          *This,
+  IN     EFI_MEMORY_TYPE                          MemoryType,
+  IN     UINTN                                    Pages,
+  IN OUT VOID                                     **HostAddress,
+  IN     UINT64                                   Attributes
+  )
+{
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
+
+  if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  Length = EFI_PAGES_TO_SIZE(Pages);
+  if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {
+    DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);
+  DmaBufferInfo->DmaBufferCurrentTop -= Length;
+
+  DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));
+  return EFI_SUCCESS;
+}
+
+/**
+  Frees memory that was allocated with AllocateBuffer().
+
+  @param  This                  The PPI instance pointer.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+                                was not allocated with AllocateBuffer().
+  @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are
+                                not available to be allocated yet.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiIoMmuFreeBuffer (
+  IN  EDKII_IOMMU_PPI                          *This,
+  IN  UINTN                                    Pages,
+  IN  VOID                                     *HostAddress
+  )
+{
+  UINTN                       Length;
+  VOID                        *Hob;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));
+  DEBUG ((DEBUG_VERBOSE, "  DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));
+
+  if (DmaBufferInfo->DmaBufferCurrentTop == 0) {
+    return EFI_NOT_AVAILABLE_YET;
+  }
+
+  Length = EFI_PAGES_TO_SIZE(Pages);
+  if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {
+    DmaBufferInfo->DmaBufferCurrentTop += Length;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EDKII_IOMMU_PPI mIoMmuPpi = {
+  EDKII_IOMMU_PPI_REVISION,
+  PeiIoMmuSetAttribute,
+  PeiIoMmuMap,
+  PeiIoMmuUnmap,
+  PeiIoMmuAllocateBuffer,
+  PeiIoMmuFreeBuffer,
+};
+
+CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {
+  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+  &gEdkiiIoMmuPpiGuid,
+  (VOID *) &mIoMmuPpi
+};
+
+/**
+  Initialize DMA protection.
+
+  @param VTdInfo        The VTd engine context information.
+
+  @retval EFI_SUCCESS           the DMA protection is initialized.
+  @retval EFI_OUT_OF_RESOURCES  no enough resource to initialize DMA protection.
+**/
+EFI_STATUS
+InitDmaProtection (
+  IN   VTD_INFO                    *VTdInfo
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      LowMemoryAlignment;
+  UINT64                      HighMemoryAlignment;
+  UINTN                       MemoryAlignment;
+  UINTN                       LowBottom;
+  UINTN                       LowTop;
+  UINTN                       HighBottom;
+  UINT64                      HighTop;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+  VOID                        *Hob;
+  EFI_PEI_PPI_DESCRIPTOR      *OldDescriptor;
+  EDKII_IOMMU_PPI             *OldIoMmuPpi;
+
+  Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);
+  DmaBufferInfo = GET_GUID_HOB_DATA(Hob);
+
+  DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));
+
+  LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
+  HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);
+  if (LowMemoryAlignment < HighMemoryAlignment) {
+    MemoryAlignment = (UINTN)HighMemoryAlignment;
+  } else {
+    MemoryAlignment = LowMemoryAlignment;
+  }
+  ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));
+  DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);
+  ASSERT (DmaBufferInfo->DmaBufferBase != 0);
+  if (DmaBufferInfo->DmaBufferBase == 0) {
+    DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));
+
+  DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
+  DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;
+
+  //
+  // (Re)Install PPI.
+  //
+  Status = PeiServicesLocatePpi (
+             &gEdkiiIoMmuPpiGuid,
+             0,
+             &OldDescriptor,
+             (VOID **) &OldIoMmuPpi
+             );
+  if (!EFI_ERROR (Status)) {
+    Status = PeiServicesReInstallPpi (OldDescriptor, &mIoMmuPpiList);
+  } else {
+    Status = PeiServicesInstallPpi (&mIoMmuPpiList);
+  }
+  ASSERT_EFI_ERROR (Status);
+
+  LowBottom = 0;
+  LowTop = DmaBufferInfo->DmaBufferBase;
+  HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;
+  HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
+
+  Status = SetDmaProtectedRange (
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
+
+  if (EFI_ERROR(Status)) {
+    FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));
+  }
+
+  return Status;
+}
+
+/**
+  Initializes the Intel VTd Info.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
+
+**/
+EFI_STATUS
+InitVTdInfo (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_ACPI_DMAR_HEADER        *AcpiDmarTable;
+  VOID                        *Hob;
+
+  Status = PeiServicesLocatePpi (
+             &gEdkiiVTdInfoPpiGuid,
+             0,
+             NULL,
+             (VOID **)&AcpiDmarTable
+             );
+  ASSERT_EFI_ERROR(Status);
+
+  DumpAcpiDMAR (AcpiDmarTable);
+
+  //
+  // Clear old VTdInfo Hob.
+  //
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  if (Hob != NULL) {
+    ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));
+  }
+
+  //
+  // Get DMAR information to local VTdInfo
+  //
+  Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.
+  //
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initializes the Intel VTd PMR for all memory.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
+
+**/
+EFI_STATUS
+InitVTdPmrForAll (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINTN                       LowBottom;
+  UINTN                       LowTop;
+  UINTN                       HighBottom;
+  UINT64                      HighTop;
+
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+  LowBottom = 0;
+  LowTop = 0;
+  HighBottom = 0;
+  HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);
+
+  Status = SetDmaProtectedRange (
+             VTdInfo,
+             VTdInfo->EngineMask,
+             (UINT32)LowBottom,
+             (UINT32)(LowTop - LowBottom),
+             HighBottom,
+             HighTop - HighBottom
+             );
+
+  return Status;
+}
+
+/**
+  Initializes the Intel VTd PMR for DMA buffer.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
+
+**/
+EFI_STATUS
+InitVTdPmrForDma (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+
+  Hob = GetFirstGuidHob (&mVTdInfoGuid);
+  VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+  //
+  // If there is RMRR memory, parse it here.
+  //
+  ParseDmarAcpiTableRmrr (VTdInfo);
+
+  //
+  // Allocate a range in PEI memory as DMA buffer
+  // Mark others to be DMA protected.
+  //
+  Status = InitDmaProtection (VTdInfo);
+
+  return Status;
+}
+
+/**
+  This function handles S3 resume task at the end of PEI
+
+  @param[in] PeiServices    Pointer to PEI Services Table.
+  @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
+                            caused this function to execute.
+  @param[in] Ppi            Pointer to the PPI data associated with this function.
+
+  @retval EFI_STATUS        Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+S3EndOfPeiNotify(
+  IN EFI_PEI_SERVICES          **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+  IN VOID                      *Ppi
+  )
+{
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  UINT64                      EngineMask;
+
+  DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));
+
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    if (Hob == NULL) {
+      return EFI_SUCCESS;
+    }
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+    EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;
+    DisableDmaProtection (VTdInfo, EngineMask);
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiEndOfPeiSignalPpiGuid,
+  S3EndOfPeiNotify
+};
+
+/**
+  This function handles VTd engine setup
+
+  @param[in] PeiServices    Pointer to PEI Services Table.
+  @param[in] NotifyDesc     Pointer to the descriptor for the Notification event that
+                            caused this function to execute.
+  @param[in] Ppi            Pointer to the PPI data associated with this function.
+
+  @retval EFI_STATUS        Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+VTdInfoNotify (
+  IN EFI_PEI_SERVICES          **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+  IN VOID                      *Ppi
+  )
+{
+  EFI_STATUS                  Status;
+  VOID                        *MemoryDiscovered;
+  UINT64                      EnabledEngineMask;
+  VOID                        *Hob;
+  VTD_INFO                    *VTdInfo;
+  BOOLEAN                     MemoryInitialized;
+
+  DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));
+
+  //
+  // Check if memory is initialized.
+  //
+  MemoryInitialized = FALSE;
+  Status = PeiServicesLocatePpi (
+             &gEfiPeiMemoryDiscoveredPpiGuid,
+             0,
+             NULL,
+             &MemoryDiscovered
+             );
+  if (!EFI_ERROR(Status)) {
+    MemoryInitialized = TRUE;
+  }
+
+  DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));
+
+  if (!MemoryInitialized) {
+    //
+    // If the memory is not initialized,
+    // Protect all system memory
+    //
+    InitVTdInfo ();
+    InitVTdPmrForAll ();
+
+    //
+    // Install PPI.
+    //
+    Status = PeiServicesInstallPpi (&mIoMmuPpiList);
+    ASSERT_EFI_ERROR(Status);
+  } else {
+    //
+    // If the memory is initialized,
+    // Allocate DMA buffer and protect rest system memory
+    //
+
+    //
+    // NOTE: We need reinit VTdInfo because previous information might be overriden.
+    //
+    InitVTdInfo ();
+
+    Hob = GetFirstGuidHob (&mVTdInfoGuid);
+    VTdInfo = GET_GUID_HOB_DATA(Hob);
+
+    //
+    // NOTE: We need check if PMR is enabled or not.
+    //
+    EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);
+    if (EnabledEngineMask != 0) {
+      EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+      DisableDmaProtection (VTdInfo, EnabledEngineMask);
+    }
+    InitVTdPmrForDma ();
+    if (EnabledEngineMask != 0) {
+      DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);
+    }
+
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiVTdInfoPpiGuid,
+  VTdInfoNotify
+};
+
+/**
+  Initializes the Intel VTd PMR PEIM.
+
+  @param  FileHandle  Handle of the file being invoked.
+  @param  PeiServices Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
+  @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IntelVTdPmrInitialize (
+  IN EFI_PEI_FILE_HANDLE       FileHandle,
+  IN CONST EFI_PEI_SERVICES    **PeiServices
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_BOOT_MODE               BootMode;
+  DMA_BUFFER_INFO             *DmaBufferInfo;
+
+  DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));
+
+  if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));
+  ASSERT(DmaBufferInfo != NULL);
+  if (DmaBufferInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));
+
+  PeiServicesGetBootMode (&BootMode);
+
+  if (BootMode == BOOT_ON_S3_RESUME) {
+    DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSizeS3);
+  } else {
+    DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSize);
+  }
+
+  Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Register EndOfPei Notify for S3
+  //
+  if (BootMode == BOOT_ON_S3_RESUME) {
+    Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
new file mode 100644
index 0000000000..4774a2ae5b
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/VtdReg.c
@@ -0,0 +1,287 @@
+/** @file
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <IndustryStandard/Vtd.h>
+#include <Ppi/VtdInfo.h>
+
+#include "IntelVTdPmrPei.h"
+
+/**
+  Flush VTD page table and context table memory.
+
+  This action is to make sure the IOMMU engine can get final data in memory.
+
+  @param[in]  Base              The base address of memory to be flushed.
+  @param[in]  Size              The size of memory in bytes to be flushed.
+**/
+VOID
+FlushPageTableMemory (
+  IN UINTN  Base,
+  IN UINTN  Size
+  )
+{
+  WriteBackDataCacheRange ((VOID *)Base, Size);
+}
+
+/**
+  Flush VTd engine write buffer.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+VOID
+FlushWriteBuffer (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32      Reg32;
+  VTD_CAP_REG CapReg;
+
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
+
+  if (CapReg.Bits.RWBF != 0) {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
+    do {
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+    } while ((Reg32 & B_GSTS_REG_WBF) != 0);
+  }
+}
+
+/**
+  Invalidate VTd context cache.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64  Reg64;
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  if ((Reg64 & B_CCMD_REG_ICC) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
+  Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
+  } while ((Reg64 & B_CCMD_REG_ICC) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Invalidate VTd IOTLB.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT64       Reg64;
+  VTD_ECAP_REG ECapReg;
+
+  ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
+
+  Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
+    DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
+  Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
+  MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
+
+  do {
+    Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
+  } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+  @param RootEntryTable     The address of the VTd RootEntryTable.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  IN UINTN  VtdUnitBaseAddress,
+  IN UINTN  RootEntryTable
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);
+
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+
+  DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  //
+  // Init DMAr Fault Event and Data registers
+  //
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the context cache
+  //
+  InvalidateContextCache (VtdUnitBaseAddress);
+
+  //
+  // Invalidate the IOTLB cache
+  //
+  InvalidateIOTLB (VtdUnitBaseAddress);
+
+  //
+  // Enable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
+  DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while ((Reg32 & B_GSTS_REG_TE) == 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Disable DMAR translation.
+
+  @param VtdUnitBaseAddress The base address of the VTd engine.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  IN UINTN  VtdUnitBaseAddress
+  )
+{
+  UINT32    Reg32;
+
+  DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
+
+  //
+  // Write Buffer Flush before invalidation
+  //
+  FlushWriteBuffer (VtdUnitBaseAddress);
+
+  //
+  // Disable VTd
+  //
+  MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
+  do {
+    Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  } while((Reg32 & B_GSTS_REG_RTPS) == 0);
+
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
+  DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
+
+  MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
+
+  DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+  VOID        *RootEntryTable;
+
+  DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  RootEntryTable = AllocatePages (1);
+  ASSERT (RootEntryTable != NULL);
+  if (RootEntryTable == NULL) {
+    DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));
+    return ;
+  }
+
+  ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));
+  FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);
+  }
+
+  return ;
+}
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  )
+{
+  UINTN       Index;
+
+  DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
+
+  for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {
+      continue;
+    }
+    DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);
+  }
+
+  return ;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.c
new file mode 100644
index 0000000000..3698c3d3f1
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.c
@@ -0,0 +1,361 @@
+/** @file
+  Platform VTd Info Sample PEI driver.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Ppi/VtdInfo.h>
+
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PciLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define R_SA_MCHBAR               (0x48)
+#define R_SA_GGC                  (0x50)
+#define N_SKL_SA_GGC_GGMS_OFFSET  (0x6)
+#define B_SKL_SA_GGC_GGMS_MASK    (0xc0)
+#define N_SKL_SA_GGC_GMS_OFFSET   (0x8)
+#define B_SKL_SA_GGC_GMS_MASK     (0xff00)
+#define V_SKL_SA_GGC_GGMS_8MB     3
+#define R_SA_TOLUD                (0xbc)
+
+#define R_SA_MCHBAR_VTD1_OFFSET  0x5400  ///< HW UNIT for IGD
+#define R_SA_MCHBAR_VTD2_OFFSET  0x5410  ///< HW UNIT for all other - PEG, USB, SATA etc
+
+EFI_GUID gEdkiiSiliconInitializedPpiGuid = {0x82a72dc8, 0x61ec, 0x403e, {0xb1, 0x5a, 0x8d, 0x7a, 0x3a, 0x71, 0x84, 0x98}};
+
+typedef struct {
+  EFI_ACPI_DMAR_HEADER                         DmarHeader;
+  //
+  // VTd engine 1 - integrated graphic
+  //
+  EFI_ACPI_DMAR_DRHD_HEADER                    Drhd1;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER  Drhd11;
+  EFI_ACPI_DMAR_PCI_PATH                       Drhd111;
+  //
+  // VTd engine 2 - all rest
+  //
+  EFI_ACPI_DMAR_DRHD_HEADER                    Drhd2;
+  //
+  // RMRR 1 - integrated graphic
+  //
+  EFI_ACPI_DMAR_RMRR_HEADER                    Rmrr1;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER  Rmrr11;
+  EFI_ACPI_DMAR_PCI_PATH                       Rmrr111;
+} MY_VTD_INFO_PPI;
+
+MY_VTD_INFO_PPI  mPlatformVTdSample = {
+  { // DmarHeader
+    { // Header
+      EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE,
+      sizeof(MY_VTD_INFO_PPI),
+      EFI_ACPI_DMAR_REVISION,
+    },
+    0x26, // HostAddressWidth
+  },
+
+  { // Drhd1
+    { // Header
+      EFI_ACPI_DMAR_TYPE_DRHD,
+      sizeof(EFI_ACPI_DMAR_DRHD_HEADER) +
+        sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
+        sizeof(EFI_ACPI_DMAR_PCI_PATH)
+    },
+    0, // Flags
+    0, // Reserved
+    0, // SegmentNumber
+    0xFED90000 // RegisterBaseAddress -- TO BE PATCHED
+  },
+  { // Drhd11
+    EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT,
+    sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
+      sizeof(EFI_ACPI_DMAR_PCI_PATH),
+    0, // Reserved2
+    0, // EnumerationId
+    0  // StartBusNumber
+  },
+  { // Drhd111
+    2,  // Device
+    0   // Function
+  },
+
+  { // Drhd2
+    { // Header
+      EFI_ACPI_DMAR_TYPE_DRHD,
+      sizeof(EFI_ACPI_DMAR_DRHD_HEADER)
+    },
+    EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL, // Flags
+    0, // Reserved
+    0, // SegmentNumber
+    0xFED91000 // RegisterBaseAddress -- TO BE PATCHED
+  },
+
+  { // Rmrr1
+    { // Header
+      EFI_ACPI_DMAR_TYPE_RMRR,
+      sizeof(EFI_ACPI_DMAR_RMRR_HEADER) +
+        sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
+        sizeof(EFI_ACPI_DMAR_PCI_PATH)
+    },
+    {0}, // Reserved
+    0, // SegmentNumber
+    0x0, // ReservedMemoryRegionBaseAddress -- TO BE PATCHED
+    0x0 // ReservedMemoryRegionLimitAddress -- TO BE PATCHED
+  },
+  { // Rmrr11
+    EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT,
+    sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
+      sizeof(EFI_ACPI_DMAR_PCI_PATH),
+    0, // Reserved2
+    0, // EnumerationId
+    0  // StartBusNumber
+  },
+  { // Rmrr111
+    2,  // Device
+    0   // Function
+  },
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPlatformVTdInfoSampleDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiVTdInfoPpiGuid,
+  &mPlatformVTdSample
+};
+
+typedef struct {
+  EFI_ACPI_DMAR_HEADER                         DmarHeader;
+  //
+  // VTd engine 2 - all rest
+  //
+  EFI_ACPI_DMAR_DRHD_HEADER                    Drhd2;
+} MY_VTD_INFO_NO_IGD_PPI;
+
+MY_VTD_INFO_NO_IGD_PPI  mPlatformVTdNoIgdSample = {
+  { // DmarHeader
+    { // Header
+      EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE,
+      sizeof(MY_VTD_INFO_NO_IGD_PPI),
+      EFI_ACPI_DMAR_REVISION,
+    },
+    0x26, // HostAddressWidth
+  },
+
+  { // Drhd2
+    { // Header
+      EFI_ACPI_DMAR_TYPE_DRHD,
+      sizeof(EFI_ACPI_DMAR_DRHD_HEADER)
+    },
+    EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL, // Flags
+    0, // Reserved
+    0, // SegmentNumber
+    0xFED91000 // RegisterBaseAddress -- TO BE PATCHED
+  },
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPlatformVTdNoIgdInfoSampleDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiVTdInfoPpiGuid,
+  &mPlatformVTdNoIgdSample
+};
+
+/**
+  Initialize VTd register.
+**/
+VOID
+InitDmar (
+  VOID
+  )
+{
+  UINT32              MchBar;
+
+  DEBUG ((DEBUG_INFO, "InitDmar\n"));
+
+  MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
+  PciWrite32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR), 0xFED10000 | BIT0);
+  DEBUG ((DEBUG_INFO, "MchBar - %x\n", MchBar));
+
+  MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)mPlatformVTdSample.Drhd2.RegisterBaseAddress | 1);
+  DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
+}
+
+/**
+  Patch Graphic UMA address in RMRR and base address.
+**/
+EFI_PEI_PPI_DESCRIPTOR *
+PatchDmar (
+  VOID
+  )
+{
+  UINT32                  MchBar;
+  UINT16                  IgdMode;
+  UINT16                  GttMode;
+  UINT32                  IgdMemSize;
+  UINT32                  GttMemSize;
+  MY_VTD_INFO_PPI         *PlatformVTdSample;
+  EFI_PEI_PPI_DESCRIPTOR  *PlatformVTdInfoSampleDesc;
+  MY_VTD_INFO_NO_IGD_PPI  *PlatformVTdNoIgdSample;
+  EFI_PEI_PPI_DESCRIPTOR  *PlatformVTdNoIgdInfoSampleDesc;
+
+  DEBUG ((DEBUG_INFO, "PatchDmar\n"));
+
+  if (PciRead16 (PCI_LIB_ADDRESS(0, 2, 0, 0)) != 0xFFFF) {
+    PlatformVTdSample = AllocateCopyPool (sizeof(MY_VTD_INFO_PPI), &mPlatformVTdSample);
+    ASSERT(PlatformVTdSample != NULL);
+    PlatformVTdInfoSampleDesc = AllocateCopyPool (sizeof(EFI_PEI_PPI_DESCRIPTOR), &mPlatformVTdInfoSampleDesc);
+    ASSERT(PlatformVTdInfoSampleDesc != NULL);
+    PlatformVTdInfoSampleDesc->Ppi = PlatformVTdSample;
+
+    ///
+    /// Calculate IGD memsize
+    ///
+    IgdMode = ((PciRead16 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_GGC)) & B_SKL_SA_GGC_GMS_MASK) >> N_SKL_SA_GGC_GMS_OFFSET) & 0xFF;
+    if (IgdMode < 0xF0) {
+      IgdMemSize = IgdMode * 32 * (1024) * (1024);
+    } else {
+      IgdMemSize = 4 * (IgdMode - 0xF0 + 1) * (1024) * (1024);
+    }
+
+    ///
+    /// Calculate GTT mem size
+    ///
+    GttMemSize = 0;
+    GttMode = (PciRead16 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_GGC)) & B_SKL_SA_GGC_GGMS_MASK) >> N_SKL_SA_GGC_GGMS_OFFSET;
+    if (GttMode <= V_SKL_SA_GGC_GGMS_8MB) {
+      GttMemSize = (1 << GttMode) * (1024) * (1024);
+    }
+
+    PlatformVTdSample->Rmrr1.ReservedMemoryRegionBaseAddress  = (PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_TOLUD)) & ~(0x01)) - IgdMemSize - GttMemSize;
+    PlatformVTdSample->Rmrr1.ReservedMemoryRegionLimitAddress = PlatformVTdSample->Rmrr1.ReservedMemoryRegionBaseAddress + IgdMemSize + GttMemSize - 1;
+
+    ///
+    /// Update DRHD structures of DmarTable
+    ///
+    MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
+
+    if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET) &~1) != 0) {
+      PlatformVTdSample->Drhd1.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET) &~1);
+    } else {
+      MmioWrite32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET, (UINT32)PlatformVTdSample->Drhd1.RegisterBaseAddress | 1);
+    }
+    DEBUG ((DEBUG_INFO, "VTd1 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET))));
+
+    if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1) != 0) {
+      PlatformVTdSample->Drhd2.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1);
+    } else {
+      MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)PlatformVTdSample->Drhd2.RegisterBaseAddress | 1);
+    }
+    DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
+
+    return PlatformVTdInfoSampleDesc;
+  } else {
+    PlatformVTdNoIgdSample = AllocateCopyPool (sizeof(MY_VTD_INFO_NO_IGD_PPI), &mPlatformVTdNoIgdSample);
+    ASSERT(PlatformVTdNoIgdSample != NULL);
+    PlatformVTdNoIgdInfoSampleDesc = AllocateCopyPool (sizeof(EFI_PEI_PPI_DESCRIPTOR), &mPlatformVTdNoIgdInfoSampleDesc);
+    ASSERT(PlatformVTdNoIgdInfoSampleDesc != NULL);
+    PlatformVTdNoIgdInfoSampleDesc->Ppi = PlatformVTdNoIgdSample;
+
+    ///
+    /// Update DRHD structures of DmarTable
+    ///
+    MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
+
+    if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1) != 0) {
+      PlatformVTdNoIgdSample->Drhd2.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1);
+    } else {
+      MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)PlatformVTdNoIgdSample->Drhd2.RegisterBaseAddress | 1);
+    }
+    DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
+
+    return PlatformVTdNoIgdInfoSampleDesc;
+  }
+}
+
+/**
+  The callback function for SiliconInitializedPpi.
+  It reinstalls VTD_INFO_PPI.
+
+  @param[in]  PeiServices       General purpose services available to every PEIM.
+  @param[in]  NotifyDescriptor  Notify that this module published.
+  @param[in]  Ppi               PPI that was installed.
+
+  @retval     EFI_SUCCESS       The function completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+SiliconInitializedPpiNotifyCallback (
+  IN CONST EFI_PEI_SERVICES     **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
+  IN VOID                       *Ppi
+  )
+{
+  EFI_STATUS               Status;
+  EFI_PEI_PPI_DESCRIPTOR   *PpiDesc;
+
+  PpiDesc = PatchDmar ();
+
+  Status = PeiServicesReInstallPpi (&mPlatformVTdNoIgdInfoSampleDesc, PpiDesc);
+  ASSERT_EFI_ERROR (Status);
+  return EFI_SUCCESS;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mSiliconInitializedNotifyList = {
+  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEdkiiSiliconInitializedPpiGuid,
+  (EFI_PEIM_NOTIFY_ENTRY_POINT) SiliconInitializedPpiNotifyCallback
+};
+
+/**
+  Platform VTd Info sample driver.
+
+  @param[in] FileHandle  Handle of the file being invoked.
+  @param[in] PeiServices Describes the list of possible PEI Services.
+
+  @retval EFI_SUCCESS if it completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdInfoSampleInitialize (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS               Status;
+  BOOLEAN                  SiliconInitialized;
+  VOID                     *SiliconInitializedPpi;
+  EFI_PEI_PPI_DESCRIPTOR   *PpiDesc;
+
+  SiliconInitialized = FALSE;
+  //
+  // Check if silicon is initialized.
+  //
+  Status = PeiServicesLocatePpi (
+             &gEdkiiSiliconInitializedPpiGuid,
+             0,
+             NULL,
+             &SiliconInitializedPpi
+             );
+  if (!EFI_ERROR(Status)) {
+    SiliconInitialized = TRUE;
+  }
+  DEBUG ((DEBUG_INFO, "SiliconInitialized - %x\n", SiliconInitialized));
+  if (!SiliconInitialized) {
+    Status = PeiServicesNotifyPpi (&mSiliconInitializedNotifyList);
+    InitDmar ();
+
+    Status = PeiServicesInstallPpi (&mPlatformVTdNoIgdInfoSampleDesc);
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    PpiDesc = PatchDmar ();
+
+    Status = PeiServicesInstallPpi (PpiDesc);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return Status;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
new file mode 100644
index 0000000000..fb77e6aa3f
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.c
@@ -0,0 +1,407 @@
+/** @file
+  Platform VTd Sample driver.
+
+  Note: This module should only be used for dev/debug purposes.
+        It MUST never be used for production builds.
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Vtd.h>
+#include <Protocol/PlatformVtdPolicy.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+
+typedef struct {
+  ACPI_EXTENDED_HID_DEVICE_PATH      I2cController;
+  UINT8                              HidStr[8];
+  UINT8                              UidStr[1];
+  UINT8                              CidStr[8];
+} PLATFORM_I2C_CONTROLLER_DEVICE_PATH;
+
+typedef struct {
+  ACPI_EXTENDED_HID_DEVICE_PATH      I2cDevice;
+  UINT8                              HidStr[13];
+  UINT8                              UidStr[1];
+  UINT8                              CidStr[13];
+} PLATFORM_I2C_DEVICE_DEVICE_PATH;
+
+typedef struct {
+  PLATFORM_I2C_CONTROLLER_DEVICE_PATH      I2cController;
+  PLATFORM_I2C_DEVICE_DEVICE_PATH          I2cDevice;
+  EFI_DEVICE_PATH_PROTOCOL                 End;
+} PLATFORM_I2C_DEVICE_PATH;
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  PCI_DEVICE_PATH           PciDevice;
+  EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
+} PLATFORM_PCI_DEVICE_PATH;
+
+typedef struct {
+  ACPI_HID_DEVICE_PATH      PciRootBridge;
+  PCI_DEVICE_PATH           PciBridge;
+  PCI_DEVICE_PATH           PciDevice;
+  EFI_DEVICE_PATH_PROTOCOL  EndDevicePath;
+} PLATFORM_PCI_BRIDGE_DEVICE_PATH;
+
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINT16                    Segment;
+  VTD_SOURCE_ID             SourceId;
+} PLATFORM_ACPI_DEVICE_MAPPING;
+
+#define PLATFORM_PCI_ROOT_BRIDGE \
+  { \
+    { \
+      ACPI_DEVICE_PATH, \
+      ACPI_DP, \
+      { \
+        (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+        (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+      }, \
+    }, \
+    EISA_PNP_ID (0x0A03), \
+    0 \
+  }
+
+#define PLATFORM_END_ENTIRE \
+  { \
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } \
+  }
+
+#define PLATFORM_PCI(Device, Function) \
+  { \
+    { \
+      HARDWARE_DEVICE_PATH, \
+      HW_PCI_DP, \
+      { \
+        (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+        (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+      } \
+    }, \
+    (Function), \
+    (Device) \
+  }
+
+#define PLATFORM_I2C(Hid, Uid, Cid, HidStr, UidStr, CidStr) \
+  { \
+    { \
+      { \
+        ACPI_DEVICE_PATH, \
+        ACPI_EXTENDED_DP, \
+        {sizeof(ACPI_EXTENDED_HID_DEVICE_PATH) + sizeof(HidStr) + sizeof(UidStr) + sizeof(CidStr), 0} \
+      }, \
+      Hid, \
+      Uid, \
+      Cid \
+    }, \
+    HidStr, \
+    UidStr, \
+    CidStr \
+  }
+
+PLATFORM_I2C_DEVICE_PATH mPlatformI2CDevicePath = {
+  PLATFORM_I2C(0, 2, 0, "INT33C3", "", "INT33C3"),
+  PLATFORM_I2C(0, 1, 0, "I2C01\\TPANEL", "", "I2C01\\TPANEL"),
+  PLATFORM_END_ENTIRE
+};
+
+PLATFORM_ACPI_DEVICE_MAPPING  mAcpiDeviceMapping[] = {
+  {
+    (EFI_DEVICE_PATH_PROTOCOL *)&mPlatformI2CDevicePath,
+    0x0,                 // Segment
+    {{0x01, 0x15, 0x00}} // Function, Device, Bus
+  }
+};
+
+PLATFORM_PCI_BRIDGE_DEVICE_PATH mPlatformPciBridgeDevicePath = {
+  PLATFORM_PCI_ROOT_BRIDGE,
+  PLATFORM_PCI(0x1C, 1),
+  PLATFORM_PCI(0, 0),
+  PLATFORM_END_ENTIRE
+};
+
+#pragma pack(1)
+
+typedef struct {
+  EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO     ExceptionDeviceInfo;
+  EDKII_PLATFORM_VTD_DEVICE_SCOPE              DeviceScope;
+  EFI_ACPI_DMAR_PCI_PATH                       PciBridge;
+  EFI_ACPI_DMAR_PCI_PATH                       PciDevice;
+} PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT;
+
+typedef struct {
+  EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO     ExceptionDeviceInfo;
+  EDKII_PLATFORM_VTD_PCI_DEVICE_ID             PciDeviceId;
+} PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT;
+
+#pragma pack()
+
+PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT  mExceptionDeviceScopeList[] = {
+  {
+    {
+      EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE,
+      sizeof(PLATFORM_EXCEPTION_DEVICE_SCOPE_STRUCT)
+    },  // ExceptionDeviceInfo
+    {
+      0,                                                    // SegmentNumber
+      {
+        EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT,      // Type
+        sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
+          2 * sizeof(EFI_ACPI_DMAR_PCI_PATH),               // Length
+        0,                                                  // Reserved2
+        0,                                                  // EnumerationId
+        0,                                                  // StartBusNumber
+      },
+    },                                                      // DeviceScope
+    { 0x1C, 1 },                                            // PciBridge
+    { 0x0,  0 },                                            // PciDevice
+  },
+};
+
+PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT  mExceptionPciDeviceIdList[] = {
+  {
+    {
+      EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID,
+      sizeof(PLATFORM_EXCEPTION_PCI_DEVICE_ID_STRUCT)
+    },  // ExceptionDeviceInfo
+    {
+      0x8086,                                               // VendorId
+      0x9D2F,                                               // DeviceId
+      0x21,                                                 // RevisionId
+      0x8086,                                               // SubsystemVendorId
+      0x7270,                                               // SubsystemDeviceId
+    },
+  },
+};
+
+/**
+  Compares 2 device path.
+
+  @param[in] DevicePath1  A device path with EndDevicePath node.
+  @param[in] DevicePath2  A device path with EndDevicePath node.
+
+  @retval TRUE   2 device path are identical.
+  @retval FALSE  2 device path are not identical.
+**/
+BOOLEAN
+CompareDevicePath (
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath1,
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath2
+  )
+{
+  UINTN  Size1;
+  UINTN  Size2;
+
+  Size1 = GetDevicePathSize (DevicePath1);
+  Size2 = GetDevicePathSize (DevicePath2);
+  if (Size1 != Size2) {
+    return FALSE;
+  }
+  if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Get the VTD SourceId from the device handler.
+  This function is required for non PCI device handler.
+
+  Pseudo-algo in Intel VTd driver:
+    Status = PlatformGetVTdDeviceId ();
+    if (EFI_ERROR(Status)) {
+      if (DeviceHandle is PCI) {
+        Get SourceId from Bus/Device/Function
+      } else {
+        return EFI_UNSUPPORTED
+      }
+    }
+    Get VTd engine by Segment/Bus/Device/Function.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[in]  DeviceHandle          Device Identifier in UEFI.
+  @param[out] DeviceInfo            DeviceInfo for indentify the VTd engine in ACPI Table
+                                    and the VTd page entry.
+
+  @retval EFI_SUCCESS           The VtdIndex and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
+  @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
+  @retval EFI_NOT_FOUND         The Segment or SourceId information is NOT found.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdGetDeviceId (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  IN  EFI_HANDLE                               DeviceHandle,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           *DeviceInfo
+  )
+{
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  UINTN                     Seg;
+  UINTN                     Bus;
+  UINTN                     Dev;
+  UINTN                     Func;
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  UINTN                     Index;
+
+  DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetDeviceId\n"));
+
+  if (DeviceInfo == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (DeviceHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Handle PCI device
+  //
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, (VOID **)&PciIo);
+  if (!EFI_ERROR(Status)) {
+    Status = PciIo->GetLocation (PciIo, &Seg, &Bus, &Dev, &Func);
+    if (EFI_ERROR(Status)) {
+      return EFI_UNSUPPORTED;
+    }
+    DeviceInfo->Segment = (UINT16)Seg;
+    DeviceInfo->SourceId.Bits.Bus = (UINT8)Bus;
+    DeviceInfo->SourceId.Bits.Device = (UINT8)Dev;
+    DeviceInfo->SourceId.Bits.Function = (UINT8)Func;
+
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Handle ACPI device
+  //
+  Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
+  if (!EFI_ERROR(Status)) {
+    for (Index = 0; Index < ARRAY_SIZE(mAcpiDeviceMapping); Index++) {
+      if (CompareDevicePath (mAcpiDeviceMapping[Index].DevicePath, DevicePath)) {
+        DeviceInfo->Segment = mAcpiDeviceMapping[Index].Segment;
+        DeviceInfo->SourceId = mAcpiDeviceMapping[Index].SourceId;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get a list of the exception devices.
+
+  The VTd driver should always set ALLOW for the device in this list.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[out] DeviceInfoCount       The count of the list of DeviceInfo.
+  @param[out] DeviceInfo            A callee allocated buffer to hold a list of DeviceInfo.
+                                    Each DeviceInfo pointer points to EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO.
+
+  @retval EFI_SUCCESS           The DeviceInfoCount and DeviceInfo are returned.
+  @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdGetExceptionDeviceList (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  OUT UINTN                                    *DeviceInfoCount,
+  OUT VOID                                     **DeviceInfo
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "PlatformVTdGetExceptionDeviceList\n"));
+
+  if (DeviceInfoCount == NULL || DeviceInfo == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Sample codes for device scope based exception list.
+  // Uncomment to take affect and comment the sample codes for PCI vendor id
+  // based exception list.
+  //
+  /*
+  *DeviceInfo = AllocateZeroPool (sizeof(mExceptionDeviceScopeList));
+  if (*DeviceInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (*DeviceInfo, mExceptionDeviceScopeList, sizeof(mExceptionDeviceScopeList));
+
+  *DeviceInfoCount = ARRAY_SIZE(mExceptionDeviceScopeList);
+  */
+
+  //
+  // Sample codes for PCI vendor id based exception list.
+  // Uncomment to take affect and comment the sample codes for device scope
+  // based exception list.
+  //
+  /*
+  *DeviceInfo = AllocateZeroPool (sizeof(mExceptionPciDeviceIdList));
+  if (*DeviceInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (*DeviceInfo, mExceptionPciDeviceIdList, sizeof(mExceptionPciDeviceIdList));
+
+  *DeviceInfoCount = ARRAY_SIZE(mExceptionPciDeviceIdList);
+  */
+  return EFI_UNSUPPORTED;
+}
+
+EDKII_PLATFORM_VTD_POLICY_PROTOCOL  mPlatformVTdSample = {
+  EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION,
+  PlatformVTdGetDeviceId,
+  PlatformVTdGetExceptionDeviceList,
+};
+
+/**
+  Platform VTd sample driver.
+
+  @param[in]  ImageHandle  ImageHandle of the loaded driver
+  @param[in]  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           The Protocol is installed.
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVTdSampleInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEdkiiPlatformVTdPolicyProtocolGuid, &mPlatformVTdSample,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.c b/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.c
new file mode 100644
index 0000000000..bcb77eb122
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.c
@@ -0,0 +1,81 @@
+/** @file
+  Library to add SMBIOS data records from HOB to SMBIOS table.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Specification Reference:
+  System Management BIOS (SMBIOS) Reference Specification v3.0.0
+  dated 2015-Feb-12 (DSP0134)
+  http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
+
+**/
+#include <IndustryStandard/SmBios.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Smbios.h>
+
+
+/**
+  Adds SMBIOS records to tables
+
+  @param[in] ImageHandle          Image handle of this driver.
+  @param[in] SystemTable          Global system service table.
+
+  @retval EFI_UNSUPPORTED      -  Could not locate SMBIOS protocol
+  @retval EFI_OUT_OF_RESOURCES -  Failed to allocate memory for SMBIOS HOB type.
+  @retval EFI_SUCCESS          -  Successfully added SMBIOS records based on HOB.
+**/
+EFI_STATUS
+EFIAPI
+DxeSmbiosDataHobLibConstructor (
+  IN EFI_HANDLE                ImageHandle,
+  IN EFI_SYSTEM_TABLE          *SystemTable
+  )
+{
+  EFI_PEI_HOB_POINTERS         Hob;
+  EFI_SMBIOS_HANDLE            SmbiosHandle;
+  EFI_SMBIOS_PROTOCOL          *Smbios;
+  EFI_STATUS                   Status;
+  UINT8                        *RecordPtr;
+  UINT16                       RecordCount;
+
+  RecordCount = 0;
+
+  DEBUG ((DEBUG_INFO, "Adding SMBIOS records from HOB..\n"));
+
+  Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
+  if (Smbios == NULL) {
+    DEBUG ((DEBUG_WARN, "Can't locate SMBIOS protocol\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  ///
+  /// Get SMBIOS HOB data (each hob contains one SMBIOS record)
+  ///
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+    if ((GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_GUID_EXTENSION) && (CompareGuid (&Hob.Guid->Name, &gIntelSmbiosDataHobGuid))) {
+      RecordPtr = GET_GUID_HOB_DATA (Hob.Raw);
+
+      ///
+      /// Add generic SMBIOS HOB to SMBIOS table
+      ///
+      DEBUG ((DEBUG_VERBOSE, "Add SMBIOS record type: %x\n", ((EFI_SMBIOS_TABLE_HEADER *) RecordPtr)->Type));
+      SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+      Status = Smbios->Add (Smbios, NULL, &SmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *) RecordPtr);
+      if (!EFI_ERROR (Status)) {
+        RecordCount++;
+      }
+    }
+  }
+  DEBUG ((DEBUG_INFO, "Found %d Records and added to SMBIOS table.\n", RecordCount));
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
new file mode 100644
index 0000000000..5ade90fe31
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+#  Microcode flash device access library.
+#
+#  Microcode flash device access library NULL instance.
+#
+#  Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MicrocodeFlashAccessLibNull
+  MODULE_UNI_FILE                = MicrocodeFlashAccessLibNull.uni
+  FILE_GUID                      = 6F871ADD-9D86-4676-8BAD-68E2E451FC5B
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MicrocodeFlashAccessLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  MicrocodeFlashAccessLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni
new file mode 100644
index 0000000000..79918daf2b
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.uni
@@ -0,0 +1,16 @@
+// /** @file
+//  Microcode flash device access library.
+//
+//  Microcode flash device access library NULL instance.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Microcode flash device access library."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Microcode flash device access library NULL instance."
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc
new file mode 100644
index 0000000000..b4cf1d2638
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc
@@ -0,0 +1,27 @@
+## @file
+# MicrocodeCapsulePdb
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  PLATFORM_NAME                  = <PlatformPkg>
+  PLATFORM_GUID                  = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF
+  PLATFORM_VERSION               = 0.1
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  FLASH_DEFINITION               = <PlatformPkg>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  OUTPUT_DIRECTORY               = Build/<PlatformPkg>
+  SUPPORTED_ARCHITECTURES        = IA32|X64
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
new file mode 100644
index 0000000000..bba1a2b583
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
@@ -0,0 +1,26 @@
+## @file
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[FmpPayload.FmpPayloadMicrocode1]
+IMAGE_HEADER_INIT_VERSION = 0x02
+IMAGE_TYPE_ID             = 96d4fdcd-1502-424d-9d4c-9b12d2dcae5c # Microcode GUID (do not change it)
+IMAGE_INDEX               = 0x1
+HARDWARE_INSTANCE         = 0x0
+
+#
+# Uncomment the following line and update with path to Microcode PDB file
+#
+#FILE DATA = $(WORKSPACE)/<PlatformPkg>/Microcode/Microcode.pdb
+
+[Capsule.MicrocodeCapsule]
+CAPSULE_GUID                = 6dcbd5ed-e82d-4c44-bda1-7194199ad92a # FMP special Guid (do not change it)
+CAPSULE_FLAGS               = PersistAcrossReset,InitiateReset
+CAPSULE_HEADER_SIZE         = 0x20
+CAPSULE_HEADER_INIT_VERSION = 0x1
+
+FMP_PAYLOAD = FmpPayloadMicrocode1
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md
new file mode 100644
index 0000000000..9f81373fda
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsulePdb/Readme.md
@@ -0,0 +1,20 @@
+# How to generate Microcode FMP from Microcode PDB file
+
+1) Copy directory `UefiCpuPkg/Feature/Capsule/MicrocodeUpdatePdb` to `<Your Platform Package>/MicrocodeUpdatePdb`.
+
+2) Uncomment and update `FILE DATA` statement in `<Your Platform Package>/MicrocodeUpdatePdb/MicrocodeCapsulePdb.fdf` with path to a Microcode PDB file.  The PDB file can placed in `<Your Platform Package>/MicrocodeUpdatePdb` or any other path.
+
+`FILE DATA = <your Microcode PDB file path>`
+
+Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `<Your Platform Package>/MicrocodeUpdatePdb/MicrocodeCapsulePdb.dsc` with <Your Platform Package>.
+
+    PLATFORM_NAME                  = <Your Platform Package>
+    FLASH_DEFINITION               = <Your Platform Package>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.fdf
+    OUTPUT_DIRECTORY               = Build/<Your Platform Package>
+
+3) Use EDK II build tools to generate the Microcode FMP Capsule
+
+`build -p <Your Platform Package>/MicrocodeCapsulePdb/MicrocodeCapsulePdb.dsc`
+
+4) The Microcode FMP Capsule is generated at `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/MicrocodeCapsule.Cap`
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf
new file mode 100644
index 0000000000..7a4f2491ff
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Microcode/Microcode.inf
@@ -0,0 +1,21 @@
+## @file
+# Microcode text file to binary
+#
+# Convert text format microcode to binary format.
+#
+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+BASE_NAME            = Microcode
+FILE_GUID            = ABC36AAC-2031-4422-896E-0A3B899AD0B4
+COMPONENT_TYPE       = Microcode
+FFS_EXT              = .ffs
+
+[Sources]
+#
+# Uncomment the following line and update with name of Microcode TXT file
+#
+#Microcode.txt
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc
new file mode 100644
index 0000000000..0dffe20f4e
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc
@@ -0,0 +1,33 @@
+## @file
+# MicrocodeCapsuleTxt
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  PLATFORM_NAME                  = <PlatformPkg>
+  PLATFORM_GUID                  = 6875FD33-602E-4EF9-9DF2-8BA7D8B7A7AF
+  PLATFORM_VERSION               = 0.1
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  FLASH_DEFINITION               = <PlatformPkg>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
+#
+# Uncomment the following line and update with your platform pkg name
+#
+#  OUTPUT_DIRECTORY               = Build/<PlatformPkg>
+  SUPPORTED_ARCHITECTURES        = IA32|X64
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+
+[Components]
+#
+# Uncomment the following line and update with path to Microcode INF file
+#
+#  <PlatformPkg>/MicrocodeCapsuleTxt/Microcode/Microcode.inf
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
new file mode 100644
index 0000000000..8366405501
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
@@ -0,0 +1,26 @@
+## @file
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[FmpPayload.FmpPayloadMicrocode1]
+IMAGE_HEADER_INIT_VERSION = 0x02
+IMAGE_TYPE_ID             = 96d4fdcd-1502-424d-9d4c-9b12d2dcae5c # Microcode GUID (do not change it)
+IMAGE_INDEX               = 0x1
+HARDWARE_INSTANCE         = 0x0
+
+#
+# Uncomment the following line and update with path to Microcode MCB file
+#
+#FILE DATA = $(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/IA32/PlatformPkg/MicrocodeCapsuleTxt/Microcode/Microcode/OUTPUT/Microcode.mcb
+
+[Capsule.MicrocodeCapsule]
+CAPSULE_GUID                = 6dcbd5ed-e82d-4c44-bda1-7194199ad92a # FMP special Guid (do not change it)
+CAPSULE_FLAGS               = PersistAcrossReset,InitiateReset
+CAPSULE_HEADER_SIZE         = 0x20
+CAPSULE_HEADER_INIT_VERSION = 0x1
+
+FMP_PAYLOAD = FmpPayloadMicrocode1
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md
new file mode 100644
index 0000000000..f7d7040fcb
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeCapsuleTxt/Readme.md
@@ -0,0 +1,33 @@
+# How to generate Microcode FMP from Microcode TXT file
+
+1) Copy directory `UefiCpuPkg/Feature/Capsule/MicrocodeUpdateTxt` to `<Your Platform Package>/MicrocodeUpdateTxt`
+
+2) Copy microcode TXT file to`<Your Platform Package>/MicrocodeUpdateTxt/Microcode`
+
+3) Uncomment and update statement in `[Sources]` section of `<Your Platform Package>/MicrocodeUpdateTxt/Microcode/Microcode.inf` with name of Microcode TXT file copied in previous step.
+
+    [Sources]
+    <Your Microcode TXT file>
+
+Uncomment and update `FILE DATA` statement in `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.fdf` with path to a Microcode MCB file.  The MCB file is placed in `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/IA32/<Your Platform Package>/MicrocodeUpdateTxt/Microcode/Microcode/OUTPUT/`.
+
+`FILE DATA = <your Microcode MCB file path>`
+
+Uncomment and update `PLATFORM_NAME`, `FLASH_DEFINITION`, `OUTPUT_DIRECTORY` section in `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with <Your Platform Package>.
+
+    PLATFORM_NAME                  = <Your Platform Package>
+    FLASH_DEFINITION               = <Your Platform Package>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.fdf
+    OUTPUT_DIRECTORY               = Build/<Your Platform Package>
+
+Uncomment and update statement in `Components` section of `<Your Platform Package>/MicrocodeUpdateTxt/MicrocodeCapsuleTxt.dsc` with path to a Microcode INF file.
+
+    [Components]
+    <Your Microcode INF file>
+
+4) Use EDK II build tools to generate the Microcode FMP Capsule
+
+`build -p <Your Platform Package>/MicrocodeCapsuleTxt/MicrocodeCapsuleTxt.dsc`
+
+5) The generated Microcode FMP Capsule is found at `$(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/MicrocodeCapsule.Cap`
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
new file mode 100644
index 0000000000..ecbe8b4994
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
@@ -0,0 +1,499 @@
+/** @file
+  Microcode update header file.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MICROCODE_FMP_H_
+#define _MICROCODE_FMP_H_
+
+#include <PiDxe.h>
+
+#include <Guid/SystemResourceTable.h>
+#include <Guid/MicrocodeFmp.h>
+
+#include <IndustryStandard/FirmwareInterfaceTable.h>
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/MpService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HobLib.h>
+#include <Library/MicrocodeFlashAccessLib.h>
+
+#include <Register/Cpuid.h>
+#include <Register/Msr.h>
+#include <Register/Microcode.h>
+
+#define MICROCODE_FMP_PRIVATE_DATA_SIGNATURE  SIGNATURE_32('M', 'C', 'U', 'F')
+
+//
+// Microcode FMP private data structure.
+//
+
+typedef struct {
+  UINT32 LastAttemptVersion;
+  UINT32 LastAttemptStatus;
+} MICROCODE_FMP_LAST_ATTEMPT_VARIABLE;
+
+typedef struct {
+  CPU_MICROCODE_HEADER   *MicrocodeEntryPoint;
+  UINTN                  TotalSize;
+  BOOLEAN                InUse;
+} MICROCODE_INFO;
+
+typedef struct {
+  CPU_MICROCODE_HEADER   *MicrocodeEntryPoint;
+  UINTN                  TotalSize;
+  BOOLEAN                InUse;
+  BOOLEAN                Empty;
+} FIT_MICROCODE_INFO;
+
+typedef struct {
+  UINTN                  CpuIndex;
+  UINT32                 ProcessorSignature;
+  UINT8                  PlatformId;
+  UINT32                 MicrocodeRevision;
+  UINTN                  MicrocodeIndex;
+} PROCESSOR_INFO;
+
+typedef struct {
+  UINT64                 Address;
+  UINT32                 Revision;
+} MICROCODE_LOAD_BUFFER;
+
+struct _MICROCODE_FMP_PRIVATE_DATA {
+  UINT32                               Signature;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL     Fmp;
+  EFI_HANDLE                           Handle;
+  VOID                                 *MicrocodePatchAddress;
+  UINTN                                MicrocodePatchRegionSize;
+  UINT8                                DescriptorCount;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR        *ImageDescriptor;
+  MICROCODE_INFO                       *MicrocodeInfo;
+  UINT32                               PackageVersion;
+  CHAR16                               *PackageVersionName;
+  MICROCODE_FMP_LAST_ATTEMPT_VARIABLE  LastAttempt;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  UINTN                                BspIndex;
+  UINTN                                ProcessorCount;
+  PROCESSOR_INFO                       *ProcessorInfo;
+  UINT32                               FitMicrocodeEntryCount;
+  FIT_MICROCODE_INFO                   *FitMicrocodeInfo;
+};
+
+typedef struct _MICROCODE_FMP_PRIVATE_DATA  MICROCODE_FMP_PRIVATE_DATA;
+
+#define MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME  L"MicrocodeLastAttemptVar"
+
+/**
+  Returns a pointer to the MICROCODE_FMP_PRIVATE_DATA structure from the input a as Fmp.
+
+  If the signatures matches, then a pointer to the data structure that contains
+  a specified field of that data structure is returned.
+
+  @param  a              Pointer to the field specified by ServiceBinding within
+                         a data structure of type MICROCODE_FMP_PRIVATE_DATA.
+
+**/
+#define MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(a) \
+  CR ( \
+  (a), \
+  MICROCODE_FMP_PRIVATE_DATA, \
+  Fmp, \
+  MICROCODE_FMP_PRIVATE_DATA_SIGNATURE \
+  )
+
+/**
+  Get Microcode Region.
+
+  @param[out] MicrocodePatchAddress      The address of Microcode
+  @param[out] MicrocodePatchRegionSize   The region size of Microcode
+
+  @retval TRUE   The Microcode region is returned.
+  @retval FALSE  No Microcode region.
+**/
+BOOLEAN
+GetMicrocodeRegion (
+  OUT VOID     **MicrocodePatchAddress,
+  OUT UINTN    *MicrocodePatchRegionSize
+  );
+
+/**
+  Collect processor information.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+  IN OUT VOID  *Buffer
+  );
+
+/**
+  Get current Microcode information.
+
+  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+  in MicrocodeFmpPrivate must be initialized.
+
+  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+  in MicrocodeFmpPrivate may not be avaiable in this function.
+
+  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
+  @param[out]  ImageDescriptor            Microcode ImageDescriptor
+  @param[out]  MicrocodeInfo              Microcode information
+
+  @return Microcode count
+**/
+UINTN
+GetMicrocodeInfo (
+  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
+  IN  UINTN                          DescriptorCount,  OPTIONAL
+  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
+  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
+  );
+
+/**
+  Verify Microcode.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  Image                      The Microcode image buffer.
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.
+  @param[in]  TryLoad                    Try to load Microcode or not.
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out] AbortReason                A pointer to a pointer to a null-terminated string providing more
+                                         details for the aborted operation. The buffer is allocated by this function
+                                         with AllocatePool(), and it is the caller's responsibility to free it with a
+                                         call to FreePool().
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
+
+  @retval EFI_SUCCESS               The Microcode image passes verification.
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
+  @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
+**/
+EFI_STATUS
+VerifyMicrocode (
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  VOID                        *Image,
+  IN  UINTN                       ImageSize,
+  IN  BOOLEAN                     TryLoad,
+  OUT UINT32                      *LastAttemptStatus,
+  OUT CHAR16                      **AbortReason,   OPTIONAL
+  IN OUT UINTN                    *TargetCpuIndex  OPTIONAL
+  );
+
+/**
+  Write Microcode.
+
+  @param[in]   MicrocodeFmpPrivate The Microcode driver private data
+  @param[in]   Image               The Microcode image buffer.
+  @param[in]   ImageSize           The size of Microcode image buffer in bytes.
+  @param[out]  LastAttemptVersion  The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]  LastAttemptStatus   The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]  AbortReason         A pointer to a pointer to a null-terminated string providing more
+                                   details for the aborted operation. The buffer is allocated by this function
+                                   with AllocatePool(), and it is the caller's responsibility to free it with a
+                                   call to FreePool().
+
+  @retval EFI_SUCCESS               The Microcode image is written.
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.
+  @retval EFI_WRITE_PROTECTED       The flash device is read only.
+**/
+EFI_STATUS
+MicrocodeWrite (
+  IN MICROCODE_FMP_PRIVATE_DATA    *MicrocodeFmpPrivate,
+  IN VOID                          *Image,
+  IN UINTN                         ImageSize,
+  OUT UINT32                       *LastAttemptVersion,
+  OUT UINT32                       *LastAttemptStatus,
+  OUT CHAR16                       **AbortReason
+  );
+
+/**
+  Dump private information.
+
+  @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  );
+
+/**
+  Returns information about the current firmware image(s) of the device.
+
+  This function allows a copy of the current firmware image to be created and saved.
+  The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+  @param[in]      This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in, out] ImageInfoSize      A pointer to the size, in bytes, of the ImageInfo buffer.
+                                     On input, this is the size of the buffer allocated by the caller.
+                                     On output, it is the size of the buffer returned by the firmware
+                                     if the buffer was large enough, or the size of the buffer needed
+                                     to contain the image(s) information if the buffer was too small.
+  @param[in, out] ImageInfo          A pointer to the buffer in which firmware places the current image(s)
+                                     information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+  @param[out]     DescriptorVersion  A pointer to the location in which firmware returns the version number
+                                     associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]     DescriptorCount    A pointer to the location in which firmware returns the number of
+                                     descriptors or firmware images within this device.
+  @param[out]     DescriptorSize     A pointer to the location in which firmware returns the size, in bytes,
+                                     of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[out]     PackageVersion     A version number that represents all the firmware images in the device.
+                                     The format is vendor specific and new version must have a greater value
+                                     than the old version. If PackageVersion is not supported, the value is
+                                     0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
+                                     is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
+                                     that package version update is in progress.
+  @param[out]     PackageVersionName A pointer to a pointer to a null-terminated string representing the
+                                     package version name. The buffer is allocated by this function with
+                                     AllocatePool(), and it is the caller's responsibility to free it with a call
+                                     to FreePool().
+
+  @retval EFI_SUCCESS                The device was successfully updated with the new image.
+  @retval EFI_BUFFER_TOO_SMALL       The ImageInfo buffer was too small. The current buffer size
+                                     needed to hold the image(s) information is returned in ImageInfoSize.
+  @retval EFI_INVALID_PARAMETER      ImageInfoSize is NULL.
+  @retval EFI_DEVICE_ERROR           Valid information could not be returned. Possible corrupted image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImageInfo (
+  IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL       *This,
+  IN OUT    UINTN                           *ImageInfoSize,
+  IN OUT    EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,
+  OUT       UINT32                          *DescriptorVersion,
+  OUT       UINT8                           *DescriptorCount,
+  OUT       UINTN                           *DescriptorSize,
+  OUT       UINT32                          *PackageVersion,
+  OUT       CHAR16                          **PackageVersionName
+  );
+
+/**
+  Retrieves a copy of the current firmware image of the device.
+
+  This function allows a copy of the current firmware image to be created and saved.
+  The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+  @param[in]     This            A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]     ImageIndex      A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in,out] Image           Points to the buffer where the current image is copied to.
+  @param[in,out] ImageSize       On entry, points to the size of the buffer pointed to by Image, in bytes.
+                                 On return, points to the length of the image, in bytes.
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new image.
+  @retval EFI_BUFFER_TOO_SMALL   The buffer specified by ImageSize is too small to hold the
+                                 image. The current buffer size needed to hold the image is returned
+                                 in ImageSize.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_NOT_FOUND          The current image is not copied to the buffer.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
+  IN  UINT8                             ImageIndex,
+  IN  OUT  VOID                         *Image,
+  IN  OUT  UINTN                        *ImageSize
+  );
+
+/**
+  Updates the firmware image of the device.
+
+  This function updates the hardware with the new firmware image.
+  This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
+  If the firmware image is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+  - Validate the image authentication if image has attribute
+    IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
+    EFI_SECURITY_VIOLATION if the validation fails.
+  - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
+    the image is unsupported. The function can optionally provide more detailed information on
+    why the image is not a supported image.
+  - Validate the data from VendorCode if not null. Image validation must be performed before
+    VendorCode data validation. VendorCode data is ignored or considered invalid if image
+    validation failed. The function returns EFI_ABORTED if the data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
+  the caller did not specify the policy or use the default policy. As an example, vendor can implement
+  a policy to allow an option to force a firmware image update when the abort reason is due to the new
+  firmware image version is older than the current firmware image version or bad image checksum.
+  Sensitive operations such as those wiping the entire firmware image and render the device to be
+  non-functional should be encoded in the image itself rather than passed with the VendorCode.
+  AbortReason enables vendor to have the option to provide a more detailed description of the abort
+  reason to the caller.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in]  Image              Points to the new image.
+  @param[in]  ImageSize          Size of the new image in bytes.
+  @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware image update policy.
+                                 Null indicates the caller did not specify the policy or use the default policy.
+  @param[in]  Progress           A function used by the driver to report the progress of the firmware update.
+  @param[out] AbortReason        A pointer to a pointer to a null-terminated string providing more
+                                 details for the aborted operation. The buffer is allocated by this function
+                                 with AllocatePool(), and it is the caller's responsibility to free it with a
+                                 call to FreePool().
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new image.
+  @retval EFI_ABORTED            The operation is aborted.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL                 *This,
+  IN  UINT8                                            ImageIndex,
+  IN  CONST VOID                                       *Image,
+  IN  UINTN                                            ImageSize,
+  IN  CONST VOID                                       *VendorCode,
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS    Progress,
+  OUT CHAR16                                           **AbortReason
+  );
+
+/**
+  Checks if the firmware image is valid for the device.
+
+  This function allows firmware update application to validate the firmware image without
+  invoking the SetImage() first.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.
+                                 The number is between 1 and DescriptorCount.
+  @param[in]  Image              Points to the new image.
+  @param[in]  ImageSize          Size of the new image in bytes.
+  @param[out] ImageUpdatable     Indicates if the new image is valid for update. It also provides,
+                                 if available, additional information if the image is invalid.
+
+  @retval EFI_SUCCESS            The image was successfully checked.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpCheckImage (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *This,
+  IN  UINT8                             ImageIndex,
+  IN  CONST VOID                        *Image,
+  IN  UINTN                             ImageSize,
+  OUT UINT32                            *ImageUpdatable
+  );
+
+/**
+  Returns information about the firmware package.
+
+  This function returns package information.
+
+  @param[in]  This                     A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[out] PackageVersion           A version number that represents all the firmware images in the device.
+                                       The format is vendor specific and new version must have a greater value
+                                       than the old version. If PackageVersion is not supported, the value is
+                                       0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
+                                       comparison is to be performed using PackageVersionName. A value of
+                                       0xFFFFFFFD indicates that package version update is in progress.
+  @param[out] PackageVersionName       A pointer to a pointer to a null-terminated string representing
+                                       the package version name. The buffer is allocated by this function with
+                                       AllocatePool(), and it is the caller's responsibility to free it with a
+                                       call to FreePool().
+  @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
+                                       package version name. A value of 0 indicates the device does not support
+                                       update of package version name. Length is the number of Unicode characters,
+                                       including the terminating null character.
+  @param[out] AttributesSupported      Package attributes that are supported by this device. See 'Package Attribute
+                                       Definitions' for possible returned values of this parameter. A value of 1
+                                       indicates the attribute is supported and the current setting value is
+                                       indicated in AttributesSetting. A value of 0 indicates the attribute is not
+                                       supported and the current setting value in AttributesSetting is meaningless.
+  @param[out] AttributesSetting        Package attributes. See 'Package Attribute Definitions' for possible returned
+                                       values of this parameter
+
+  @retval EFI_SUCCESS                  The package information was successfully returned.
+  @retval EFI_UNSUPPORTED              The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpGetPackageInfo (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+  OUT UINT32                           *PackageVersion,
+  OUT CHAR16                           **PackageVersionName,
+  OUT UINT32                           *PackageVersionNameMaxLen,
+  OUT UINT64                           *AttributesSupported,
+  OUT UINT64                           *AttributesSetting
+  );
+
+/**
+  Updates information about the firmware package.
+
+  This function updates package information.
+  This function returns EFI_UNSUPPORTED if the package information is not updatable.
+  VendorCode enables vendor to implement vendor-specific package information update policy.
+  Null if the caller did not specify this policy or use the default policy.
+
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+  @param[in]  Image              Points to the authentication image.
+                                 Null if authentication is not required.
+  @param[in]  ImageSize          Size of the authentication image in bytes.
+                                 0 if authentication is not required.
+  @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware
+                                 image update policy.
+                                 Null indicates the caller did not specify this policy or use
+                                 the default policy.
+  @param[in]  PackageVersion     The new package version.
+  @param[in]  PackageVersionName A pointer to the new null-terminated Unicode string representing
+                                 the package version name.
+                                 The string length is equal to or less than the value returned in
+                                 PackageVersionNameMaxLen.
+
+  @retval EFI_SUCCESS            The device was successfully updated with the new package
+                                 information.
+  @retval EFI_INVALID_PARAMETER  The PackageVersionName length is longer than the value
+                                 returned in PackageVersionNameMaxLen.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpSetPackageInfo (
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL   *This,
+  IN  CONST VOID                         *Image,
+  IN  UINTN                              ImageSize,
+  IN  CONST VOID                         *VendorCode,
+  IN  UINT32                             PackageVersion,
+  IN  CONST CHAR16                       *PackageVersionName
+  );
+
+#endif
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
new file mode 100644
index 0000000000..8e9fa440f0
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
@@ -0,0 +1,67 @@
+## @file
+# Microcode FMP update driver.
+#
+# Produce FMP instance to update Microcode.
+#
+#  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MicrocodeUpdateDxe
+  MODULE_UNI_FILE                = MicrocodeUpdateDxe.uni
+  FILE_GUID                      = 0565365C-2FE1-4F88-B3BE-624C04623A20
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MicrocodeFmpMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources]
+  MicrocodeUpdate.h
+  MicrocodeFmp.c
+  MicrocodeUpdate.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  UefiLib
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  HobLib
+  UefiRuntimeServicesTableLib
+  UefiDriverEntryPoint
+  MicrocodeFlashAccessLib
+
+[Guids]
+  gMicrocodeFmpImageTypeIdGuid                  ## CONSUMES   ## GUID
+
+[Protocols]
+  gEfiFirmwareManagementProtocolGuid            ## PRODUCES
+  gEfiMpServiceProtocolGuid                     ## CONSUMES
+
+[Pcd]
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress            ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
+
+[Depex]
+  gEfiVariableArchProtocolGuid AND
+  gEfiVariableWriteArchProtocolGuid AND
+  gEfiMpServiceProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  MicrocodeUpdateDxeExtra.uni
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni
new file mode 100644
index 0000000000..a793631c10
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Microcode FMP update driver.
+//
+// Produce FMP instance to update Microcode.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Microcode FMP update driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Produce FMP instance to update Microcode."
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni
new file mode 100644
index 0000000000..cf9853d02c
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// MicrocodeUpdateDxe Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"MicrocodeUpdate DXE Driver"
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
new file mode 100644
index 0000000000..a3331db8f7
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.h
@@ -0,0 +1,632 @@
+/** @file
+
+  Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DMAR_PROTECTION_H_
+#define _DMAR_PROTECTION_H_
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/Acpi.h>
+
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciEnumerationComplete.h>
+#include <Protocol/PlatformVtdPolicy.h>
+#include <Protocol/IoMmu.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+#include <IndustryStandard/Vtd.h>
+
+#define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32))
+
+#define ALIGN_VALUE_UP(Value, Alignment)  (((Value) + (Alignment) - 1) & (~((Alignment) - 1)))
+#define ALIGN_VALUE_LOW(Value, Alignment) ((Value) & (~((Alignment) - 1)))
+
+#define VTD_TPL_LEVEL TPL_NOTIFY
+
+//
+// This is the initial max PCI DATA number.
+// The number may be enlarged later.
+//
+#define MAX_VTD_PCI_DATA_NUMBER             0x100
+
+typedef struct {
+  UINT8                            DeviceType;
+  VTD_SOURCE_ID                    PciSourceId;
+  EDKII_PLATFORM_VTD_PCI_DEVICE_ID PciDeviceId;
+  // for statistic analysis
+  UINTN                            AccessCount;
+} PCI_DEVICE_DATA;
+
+typedef struct {
+  BOOLEAN                          IncludeAllFlag;
+  UINTN                            PciDeviceDataNumber;
+  UINTN                            PciDeviceDataMaxNumber;
+  PCI_DEVICE_DATA                  *PciDeviceData;
+} PCI_DEVICE_INFORMATION;
+
+typedef struct {
+  UINTN                            VtdUnitBaseAddress;
+  UINT16                           Segment;
+  VTD_CAP_REG                      CapReg;
+  VTD_ECAP_REG                     ECapReg;
+  VTD_ROOT_ENTRY                   *RootEntryTable;
+  VTD_EXT_ROOT_ENTRY               *ExtRootEntryTable;
+  VTD_SECOND_LEVEL_PAGING_ENTRY    *FixedSecondLevelPagingEntry;
+  BOOLEAN                          HasDirtyContext;
+  BOOLEAN                          HasDirtyPages;
+  PCI_DEVICE_INFORMATION           PciDeviceInfo;
+} VTD_UNIT_INFORMATION;
+
+//
+// This is the initial max ACCESS request.
+// The number may be enlarged later.
+//
+#define MAX_VTD_ACCESS_REQUEST      0x100
+
+typedef struct {
+  UINT16                Segment;
+  VTD_SOURCE_ID         SourceId;
+  UINT64                BaseAddress;
+  UINT64                Length;
+  UINT64                IoMmuAccess;
+} VTD_ACCESS_REQUEST;
+
+
+/**
+  The scan bus callback function.
+
+  It is called in PCI bus scan for each PCI device under the bus.
+
+  @param[in]  Context               The context of the callback.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Device                The device of the source.
+  @param[in]  Function              The function of the source.
+
+  @retval EFI_SUCCESS           The specific PCI device is processed in the callback.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SCAN_BUS_FUNC_CALLBACK_FUNC) (
+  IN VOID           *Context,
+  IN UINT16         Segment,
+  IN UINT8          Bus,
+  IN UINT8          Device,
+  IN UINT8          Function
+  );
+
+extern EFI_ACPI_DMAR_HEADER  *mAcpiDmarTable;
+
+extern UINTN                            mVtdUnitNumber;
+extern VTD_UNIT_INFORMATION             *mVtdUnitInformation;
+
+extern UINT64                           mBelow4GMemoryLimit;
+extern UINT64                           mAbove4GMemoryLimit;
+
+extern EDKII_PLATFORM_VTD_POLICY_PROTOCOL   *mPlatformVTdPolicy;
+
+/**
+  Prepare VTD configuration.
+**/
+VOID
+PrepareVtdConfig (
+  VOID
+  );
+
+/**
+  Setup VTd translation table.
+
+  @retval EFI_SUCCESS           Setup translation table successfully.
+  @retval EFI_OUT_OF_RESOURCE   Setup translation table fail.
+**/
+EFI_STATUS
+SetupTranslationTable (
+  VOID
+  );
+
+/**
+  Enable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is enabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
+**/
+EFI_STATUS
+EnableDmar (
+  VOID
+  );
+
+/**
+  Disable DMAR translation.
+
+  @retval EFI_SUCCESS           DMAR translation is disabled.
+  @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
+**/
+EFI_STATUS
+DisableDmar (
+  VOID
+  );
+
+/**
+  Flush VTd engine write buffer.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+VOID
+FlushWriteBuffer (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Invalidate VTd context cache.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateContextCache (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Invalidate VTd IOTLB.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+**/
+EFI_STATUS
+InvalidateIOTLB (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Invalid VTd global IOTLB.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+
+  @retval EFI_SUCCESS           VTd global IOTLB is invalidated.
+  @retval EFI_DEVICE_ERROR      VTd global IOTLB is not invalidated.
+**/
+EFI_STATUS
+InvalidateVtdIOTLBGlobal (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Dump VTd registers.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpVtdRegs (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Dump VTd registers for all VTd engine.
+**/
+VOID
+DumpVtdRegsAll (
+  VOID
+  );
+
+/**
+  Dump VTd capability registers.
+
+  @param[in]  CapReg              The capability register.
+**/
+VOID
+DumpVtdCapRegs (
+  IN VTD_CAP_REG *CapReg
+  );
+
+/**
+  Dump VTd extended capability registers.
+
+  @param[in]  ECapReg              The extended capability register.
+**/
+VOID
+DumpVtdECapRegs (
+  IN VTD_ECAP_REG *ECapReg
+  );
+
+/**
+  Register PCI device to VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[in]  DeviceType            The DMAR device scope type.
+  @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
+                                    FALSE: SUCCESS will be returned if the PCI device is registered.
+
+  @retval EFI_SUCCESS           The PCI device is registered.
+  @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
+  @retval EFI_ALREADY_STARTED   The device is already registered.
+**/
+EFI_STATUS
+RegisterPciDevice (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId,
+  IN UINT8          DeviceType,
+  IN BOOLEAN        CheckExist
+  );
+
+/**
+  The scan bus callback function to always enable page attribute.
+
+  @param[in]  Context               The context of the callback.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Device                The device of the source.
+  @param[in]  Function              The function of the source.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+EFIAPI
+ScanBusCallbackRegisterPciDevice (
+  IN VOID           *Context,
+  IN UINT16         Segment,
+  IN UINT8          Bus,
+  IN UINT8          Device,
+  IN UINT8          Function
+  );
+
+/**
+  Scan PCI bus and invoke callback function for each PCI devices under the bus.
+
+  @param[in]  Context               The context of the callback function.
+  @param[in]  Segment               The segment of the source.
+  @param[in]  Bus                   The bus of the source.
+  @param[in]  Callback              The callback function in PCI scan.
+
+  @retval EFI_SUCCESS           The PCI devices under the bus are scaned.
+**/
+EFI_STATUS
+ScanPciBus (
+  IN VOID                         *Context,
+  IN UINT16                       Segment,
+  IN UINT8                        Bus,
+  IN SCAN_BUS_FUNC_CALLBACK_FUNC  Callback
+  );
+
+/**
+  Dump the PCI device information managed by this VTd engine.
+
+  @param[in]  VtdIndex              The index of VTd engine.
+**/
+VOID
+DumpPciDeviceInfo (
+  IN UINTN  VtdIndex
+  );
+
+/**
+  Find the VTd index by the Segment and SourceId.
+
+  @param[in]  Segment               The segment of the source.
+  @param[in]  SourceId              The SourceId of the source.
+  @param[out] ExtContextEntry       The ExtContextEntry of the source.
+  @param[out] ContextEntry          The ContextEntry of the source.
+
+  @return The index of the VTd engine.
+  @retval (UINTN)-1  The VTd engine is not found.
+**/
+UINTN
+FindVtdIndexByPciDevice (
+  IN  UINT16                  Segment,
+  IN  VTD_SOURCE_ID           SourceId,
+  OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
+  OUT VTD_CONTEXT_ENTRY       **ContextEntry
+  );
+
+/**
+  Get the DMAR ACPI table.
+
+  @retval EFI_SUCCESS           The DMAR ACPI table is got.
+  @retval EFI_ALREADY_STARTED   The DMAR ACPI table has been got previously.
+  @retval EFI_NOT_FOUND         The DMAR ACPI table is not found.
+**/
+EFI_STATUS
+GetDmarAcpiTable (
+  VOID
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  VOID
+  );
+
+/**
+  Parse DMAR RMRR table.
+
+  @return EFI_SUCCESS  The DMAR RMRR table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableRmrr (
+  VOID
+  );
+
+/**
+  Dump DMAR context entry table.
+
+  @param[in]  RootEntry DMAR root entry.
+**/
+VOID
+DumpDmarContextEntryTable (
+  IN VTD_ROOT_ENTRY *RootEntry
+  );
+
+/**
+  Dump DMAR extended context entry table.
+
+  @param[in]  ExtRootEntry DMAR extended root entry.
+**/
+VOID
+DumpDmarExtContextEntryTable (
+  IN VTD_EXT_ROOT_ENTRY *ExtRootEntry
+  );
+
+/**
+  Dump DMAR second level paging entry.
+
+  @param[in]  SecondLevelPagingEntry The second level paging entry.
+**/
+VOID
+DumpSecondLevelPagingEntry (
+  IN VOID *SecondLevelPagingEntry
+  );
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  VtdIndex                The index used to identify a VTd engine.
+  @param[in]  DomainIdentifier        The domain ID of the source.
+  @param[in]  SecondLevelPagingEntry  The second level paging entry in VTd table for the device.
+  @param[in]  BaseAddress             The base of device memory address to be used as the DMA memory.
+  @param[in]  Length                  The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess             The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetPageAttribute (
+  IN UINTN                         VtdIndex,
+  IN UINT16                        DomainIdentifier,
+  IN VTD_SECOND_LEVEL_PAGING_ENTRY *SecondLevelPagingEntry,
+  IN UINT64                        BaseAddress,
+  IN UINT64                        Length,
+  IN UINT64                        IoMmuAccess
+  );
+
+/**
+  Set VTd attribute for a system memory.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER  BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER  Length is 0.
+  @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while attempting the operation.
+**/
+EFI_STATUS
+SetAccessAttribute (
+  IN UINT16                Segment,
+  IN VTD_SOURCE_ID         SourceId,
+  IN UINT64                BaseAddress,
+  IN UINT64                Length,
+  IN UINT64                IoMmuAccess
+  );
+
+/**
+  Return the index of PCI data.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @return The index of the PCI data.
+  @retval (UINTN)-1  The PCI data is not found.
+**/
+UINTN
+GetPciDataIndex (
+  IN UINTN          VtdIndex,
+  IN UINT16         Segment,
+  IN VTD_SOURCE_ID  SourceId
+  );
+
+/**
+  Dump VTd registers if there is error.
+**/
+VOID
+DumpVtdIfError (
+  VOID
+  );
+
+/**
+  Initialize platform VTd policy.
+**/
+VOID
+InitializePlatformVTdPolicy (
+  VOID
+  );
+
+/**
+  Always enable the VTd page attribute for the device.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS           The VTd entry is updated to always enable all DMA access for the specific device.
+**/
+EFI_STATUS
+AlwaysEnablePageAttribute (
+  IN UINT16                  Segment,
+  IN VTD_SOURCE_ID           SourceId
+  );
+
+/**
+  Convert the DeviceHandle to SourceId and Segment.
+
+  @param[in]  DeviceHandle      The device who initiates the DMA access request.
+  @param[out] Segment           The Segment used to identify a VTd engine.
+  @param[out] SourceId          The SourceId used to identify a VTd engine and table entry.
+
+  @retval EFI_SUCCESS            The Segment and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
+  @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
+**/
+EFI_STATUS
+DeviceHandleToSourceId (
+  IN EFI_HANDLE            DeviceHandle,
+  OUT UINT16               *Segment,
+  OUT VTD_SOURCE_ID        *SourceId
+  );
+
+/**
+  Get device information from mapping.
+
+  @param[in]  Mapping        The mapping.
+  @param[out] DeviceAddress  The device address of the mapping.
+  @param[out] NumberOfPages  The number of pages of the mapping.
+
+  @retval EFI_SUCCESS            The device information is returned.
+  @retval EFI_INVALID_PARAMETER  The mapping is invalid.
+**/
+EFI_STATUS
+GetDeviceInfoFromMapping (
+  IN  VOID                                     *Mapping,
+  OUT EFI_PHYSICAL_ADDRESS                     *DeviceAddress,
+  OUT UINTN                                    *NumberOfPages
+  );
+
+/**
+  Initialize DMA protection.
+**/
+VOID
+InitializeDmaProtection (
+  VOID
+  );
+
+/**
+  Allocate zero pages.
+
+  @param[in]  Pages the number of pages.
+
+  @return the page address.
+  @retval NULL No resource to allocate pages.
+**/
+VOID *
+EFIAPI
+AllocateZeroPages (
+  IN UINTN  Pages
+  );
+
+/**
+  Flush VTD page table and context table memory.
+
+  This action is to make sure the IOMMU engine can get final data in memory.
+
+  @param[in]  VtdIndex          The index used to identify a VTd engine.
+  @param[in]  Base              The base address of memory to be flushed.
+  @param[in]  Size              The size of memory in bytes to be flushed.
+**/
+VOID
+FlushPageTableMemory (
+  IN UINTN  VtdIndex,
+  IN UINTN  Base,
+  IN UINTN  Size
+  );
+
+/**
+  Get PCI device information from DMAR DevScopeEntry.
+
+  @param[in]  Segment               The segment number.
+  @param[in]  DmarDevScopeEntry     DMAR DevScopeEntry
+  @param[out] Bus                   The bus number.
+  @param[out] Device                The device number.
+  @param[out] Function              The function number.
+
+  @retval EFI_SUCCESS  The PCI device information is returned.
+**/
+EFI_STATUS
+GetPciBusDeviceFunction (
+  IN  UINT16                                      Segment,
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry,
+  OUT UINT8                                       *Bus,
+  OUT UINT8                                       *Device,
+  OUT UINT8                                       *Function
+  );
+
+/**
+  Append VTd Access Request to global.
+
+  @param[in]  Segment           The Segment used to identify a VTd engine.
+  @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
+  @param[in]  BaseAddress       The base of device memory address to be used as the DMA memory.
+  @param[in]  Length            The length of device memory address to be used as the DMA memory.
+  @param[in]  IoMmuAccess       The IOMMU access.
+
+  @retval EFI_SUCCESS           The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
+  @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
+  @retval EFI_INVALID_PARAMETER Length is 0.
+  @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
+  @retval EFI_UNSUPPORTED       The bit mask of IoMmuAccess is not supported by the IOMMU.
+  @retval EFI_UNSUPPORTED       The IOMMU does not support the memory range specified by BaseAddress and Length.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to modify the IOMMU access.
+  @retval EFI_DEVICE_ERROR      The IOMMU device reported an error while attempting the operation.
+
+**/
+EFI_STATUS
+RequestAccessAttribute (
+  IN UINT16                 Segment,
+  IN VTD_SOURCE_ID          SourceId,
+  IN UINT64                 BaseAddress,
+  IN UINT64                 Length,
+  IN UINT64                 IoMmuAccess
+  );
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf
new file mode 100644
index 0000000000..220636adab
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf
@@ -0,0 +1,83 @@
+## @file
+# Intel VTd DXE Driver.
+#
+# This driver initializes VTd engine based upon DMAR ACPI tables
+# and provide DMA protection to PCI or ACPI device.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IntelVTdDxe
+  MODULE_UNI_FILE                = IntelVTdDxe.uni
+  FILE_GUID                      = 987555D6-595D-4CFA-B895-59B89368BD4D
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = IntelVTdInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#
+
+[Sources]
+  IntelVTdDxe.c
+  BmDma.c
+  DmaProtection.c
+  DmaProtection.h
+  DmarAcpiTable.c
+  PciInfo.c
+  TranslationTable.c
+  TranslationTableEx.c
+  VtdReg.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  IoLib
+  PciSegmentLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+  CacheMaintenanceLib
+  PerformanceLib
+  PrintLib
+  ReportStatusCodeLib
+
+[Guids]
+  gEfiEventExitBootServicesGuid   ## CONSUMES ## Event
+  ## CONSUMES ## SystemTable
+  ## CONSUMES ## Event
+  gEfiAcpi20TableGuid
+  ## CONSUMES ## SystemTable
+  ## CONSUMES ## Event
+  gEfiAcpi10TableGuid
+
+[Protocols]
+  gEdkiiIoMmuProtocolGuid                     ## PRODUCES
+  gEfiPciIoProtocolGuid                       ## CONSUMES
+  gEfiPciEnumerationCompleteProtocolGuid      ## CONSUMES
+  gEdkiiPlatformVTdPolicyProtocolGuid         ## SOMETIMES_CONSUMES
+
+[Pcd]
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask   ## CONSUMES
+  gIntelSiliconPkgTokenSpaceGuid.PcdErrorCodeVTdError       ## CONSUMES
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  IntelVTdDxeExtra.uni
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.uni
new file mode 100644
index 0000000000..e41fcff0e9
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IntelVTdDxe Module Localized Abstract and Description Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Intel VTd DXE Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver initializes VTd engine based upon DMAR ACPI tables and provide DMA protection to PCI or ACPI device."
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxeExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxeExtra.uni
new file mode 100644
index 0000000000..cd08ff3eda
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IntelVTdDxe Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Intel VTd DXE Driver"
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
new file mode 100644
index 0000000000..58e6afad08
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
@@ -0,0 +1,159 @@
+/** @file
+  The definition for DMA access Library.
+
+  Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DMA_ACCESS_LIB_H__
+#define __DMA_ACCESS_LIB_H__
+
+typedef struct {
+  EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable;
+  UINT64                                  EngineMask;
+  UINT8                                   HostAddressWidth;
+  UINTN                                   VTdEngineCount;
+  UINT64                                  VTdEngineAddress[1];
+} VTD_INFO;
+
+/**
+  Set DMA protected region.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+  @param LowMemoryBase      The protected low memory region base.
+  @param LowMemoryLength    The protected low memory region length.
+  @param HighMemoryBase     The protected high memory region base.
+  @param HighMemoryLength   The protected high memory region length.
+
+  @retval EFI_SUCCESS      The DMA protection is set.
+  @retval EFI_UNSUPPORTED  The DMA protection is not set.
+**/
+EFI_STATUS
+SetDmaProtectedRange (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask,
+  IN UINT32        LowMemoryBase,
+  IN UINT32        LowMemoryLength,
+  IN UINT64        HighMemoryBase,
+  IN UINT64        HighMemoryLength
+  );
+
+/**
+  Diable DMA protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @retval DMA protection is disabled.
+**/
+EFI_STATUS
+DisableDmaProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Return if the DMA protection is enabled.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @retval TRUE  DMA protection is enabled in at least one VTd engine.
+  @retval FALSE DMA protection is disabled in all VTd engines.
+**/
+UINT64
+GetDmaProtectionEnabledEngineMask (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Get protected low memory alignment.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return protected low memory alignment.
+**/
+UINT32
+GetLowMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Get protected high memory alignment.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+
+  @return protected high memory alignment.
+**/
+UINT64
+GetHighMemoryAlignment (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Enable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+EnableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Disable VTd translation table protection.
+
+  @param VTdInfo            The VTd engine context information.
+  @param EngineMask         The mask of the VTd engine to be accessed.
+**/
+VOID
+DisableVTdTranslationProtection (
+  IN VTD_INFO      *VTdInfo,
+  IN UINT64        EngineMask
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @param[in]  AcpiDmarTable  DMAR ACPI table
+
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+  IN EFI_ACPI_DMAR_HEADER                    *AcpiDmarTable
+  );
+
+/**
+  Parse DMAR DRHD table.
+
+  @param VTdInfo            The VTd engine context information.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+  IN VTD_INFO                    *VTdInfo
+  );
+
+/**
+  Dump DMAR ACPI table.
+
+  @param[in]  Dmar  DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+  IN EFI_ACPI_DMAR_HEADER  *Dmar
+  );
+
+extern EFI_GUID mVTdInfoGuid;
+
+#endif
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
new file mode 100644
index 0000000000..39b914cd00
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
@@ -0,0 +1,60 @@
+## @file
+# Component INF file for the Intel VTd PMR PEIM.
+#
+# This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI
+# and provide DMA protection in PEI.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION     = 0x00010017
+  BASE_NAME       = IntelVTdPmrPei
+  MODULE_UNI_FILE = IntelVTdPmrPei.uni
+  FILE_GUID       = F906769F-4AED-4A0D-8C7C-FF21B9D1051A
+  MODULE_TYPE     = PEIM
+  VERSION_STRING  = 1.0
+  ENTRY_POINT     = IntelVTdPmrInitialize
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[Sources]
+  IntelVTdPmrPei.c
+  IntelVTdPmrPei.h
+  IntelVTdPmr.c
+  DmarTable.c
+  VtdReg.c
+
+[LibraryClasses]
+  DebugLib
+  BaseMemoryLib
+  BaseLib
+  PeimEntryPoint
+  PeiServicesLib
+  HobLib
+  IoLib
+  CacheMaintenanceLib
+
+[Ppis]
+  gEdkiiIoMmuPpiGuid                  ## PRODUCES
+  gEdkiiVTdInfoPpiGuid                ## CONSUMES
+  gEfiPeiMemoryDiscoveredPpiGuid      ## CONSUMES
+  gEfiEndOfPeiSignalPpiGuid           ## CONSUMES
+
+[Pcd]
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask   ## CONSUMES
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSize     ## CONSUMES
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSizeS3   ## CONSUMES
+
+[Depex]
+  gEfiPeiMasterBootModePpiGuid AND
+  gEdkiiVTdInfoPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  IntelVTdPmrPeiExtra.uni
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.uni
new file mode 100644
index 0000000000..1aecacdc4f
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IntelVTdPmrPei Module Localized Abstract and Description Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Intel VTd PMR PEI Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver initializes VTd engine based upon EDKII_VTD_INFO_PPI and provide DMA protection to device in PEI."
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni
new file mode 100644
index 0000000000..080842f4c3
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// IntelVTdPmrPei Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Intel VTd PMR PEI Driver"
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf
new file mode 100644
index 0000000000..dacfdf5e10
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf
@@ -0,0 +1,48 @@
+## @file
+# Platform VTd Info Sample PEI driver.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformVTdInfoSamplePei
+  MODULE_UNI_FILE                = PlatformVTdInfoSamplePei.uni
+  FILE_GUID                      = 839EB770-5C64-4EED-A6D5-EC515B2B2B23
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformVTdInfoSampleInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#
+
+[Sources]
+  PlatformVTdInfoSamplePei.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  PeimEntryPoint
+  PeiServicesLib
+  DebugLib
+  PciLib
+  IoLib
+
+[Ppis]
+  gEdkiiVTdInfoPpiGuid         ## PRODUCES
+
+[Depex]
+  gEfiPeiMasterBootModePpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PlatformVTdInfoSamplePeiExtra.uni
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.uni
new file mode 100644
index 0000000000..3662fe5bfb
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PlatformVTdInfoSamplePei Module Localized Abstract and Description Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Platform VTd Info PEI Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides sample on how to produce Platform VTd Info PPI."
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePeiExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePeiExtra.uni
new file mode 100644
index 0000000000..ddfa629169
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PlatformVTdInfoSamplePei Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform VTd Info Sample PEI Driver"
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
new file mode 100644
index 0000000000..be18284ed4
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# Platform VTd Sample driver.
+#
+# Note: This module should only be used for dev/debug purposes.
+#       It MUST never be used for production builds.
+#
+# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformVTdSampleDxe
+  MODULE_UNI_FILE                = PlatformVTdSampleDxe.uni
+  FILE_GUID                      = 5DFAE03E-9C19-4996-85BF-65297BD4137F
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformVTdSampleInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+#
+
+[Sources]
+  PlatformVTdSampleDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  IoLib
+  PciSegmentLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  DevicePathLib
+
+[Protocols]
+  gEdkiiPlatformVTdPolicyProtocolGuid         ## PRODUCES
+  gEfiPciIoProtocolGuid                       ## CONSUMES
+
+[Depex]
+  gEfiPciRootBridgeIoProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  PlatformVTdSampleDxeExtra.uni
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
new file mode 100644
index 0000000000..7e9963d696
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PlatformVTdSampleDxe Module Localized Abstract and Description Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Platform VTd Sample DXE Driver."
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides sample on how to produce Platform VTd policy protocol."
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni
new file mode 100644
index 0000000000..e2726f4a68
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PlatformVTdSampleDxe Localized Strings and Content
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Platform VTd Sample DXE Driver"
+
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Guid/MicrocodeFmp.h b/Silicon/Intel/IntelSiliconPkg/Include/Guid/MicrocodeFmp.h
new file mode 100644
index 0000000000..b6ee34d65d
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/Guid/MicrocodeFmp.h
@@ -0,0 +1,15 @@
+/** @file
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MICROCODE_FMP_GUID_H__
+#define __MICROCODE_FMP_GUID_H__
+
+#define MICROCODE_FMP_IMAGE_TYPE_ID_GUID { 0x96d4fdcd, 0x1502, 0x424d, { 0x9d, 0x4c, 0x9b, 0x12, 0xd2, 0xdc, 0xae, 0x5c } }
+
+extern EFI_GUID gMicrocodeFmpImageTypeIdGuid;
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareInterfaceTable.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareInterfaceTable.h
new file mode 100644
index 0000000000..3a8dd24dea
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareInterfaceTable.h
@@ -0,0 +1,69 @@
+/** @file
+  FirmwareInterfaceTable (FIT) related definitions.
+
+  @todo update document/spec reference
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FIRMWARE_INTERFACE_TABLE_H__
+#define __FIRMWARE_INTERFACE_TABLE_H__
+
+//
+// FIT Entry type definitions
+//
+#define FIT_TYPE_00_HEADER                  0x00
+#define FIT_TYPE_01_MICROCODE               0x01
+#define FIT_TYPE_02_STARTUP_ACM             0x02
+#define FIT_TYPE_07_BIOS_STARTUP_MODULE     0x07
+#define FIT_TYPE_08_TPM_POLICY              0x08
+#define FIT_TYPE_09_BIOS_POLICY             0x09
+#define FIT_TYPE_0A_TXT_POLICY              0x0A
+#define FIT_TYPE_0B_KEY_MANIFEST            0x0B
+#define FIT_TYPE_0C_BOOT_POLICY_MANIFEST    0x0C
+#define FIT_TYPE_10_CSE_SECURE_BOOT         0x10
+#define FIT_TYPE_2D_TXTSX_POLICY            0x2D
+#define FIT_TYPE_2F_JMP_DEBUG_POLICY        0x2F
+#define FIT_TYPE_7F_SKIP                    0x7F
+
+#define FIT_POINTER_ADDRESS                 0xFFFFFFC0 ///< Fixed address at 4G - 40h
+
+#define FIT_TYPE_VERSION                    0x0100
+
+#define FIT_TYPE_00_SIGNATURE  SIGNATURE_64 ('_', 'F', 'I', 'T', '_', ' ', ' ', ' ')
+
+#pragma pack(1)
+
+typedef struct {
+  /**
+    Address is the base address of the firmware component
+    must be aligned on 16 byte boundary
+  **/
+  UINT64 Address;
+  UINT8  Size[3];   ///< Size is the span of the component in multiple of 16 bytes
+  UINT8  Reserved;  ///< Reserved must be set to 0
+  /**
+    Component's version number in binary coded decimal (BCD) format.
+    For the FIT header entry, the value in this field will indicate the revision
+    number of the FIT data structure. The upper byte of the revision field
+    indicates the major revision and the lower byte indicates the minor revision.
+  **/
+  UINT16 Version;
+  UINT8  Type : 7;  ///< FIT types 0x00 to 0x7F
+  ///
+  /// Checksum Valid indicates whether component has valid checksum.
+  ///
+  UINT8  C_V  : 1;
+  /**
+    Component's checksum. The modulo sum of all the bytes in the component and
+    the value in this field (Chksum) must add up to zero. This field is only
+    valid if the C_V flag is non-zero.
+  **/
+  UINT8  Chksum;
+} FIRMWARE_INTERFACE_TABLE_ENTRY;
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareVersionInfo.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareVersionInfo.h
new file mode 100644
index 0000000000..b30bc3f9e7
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/FirmwareVersionInfo.h
@@ -0,0 +1,54 @@
+/** @file
+  Intel Firmware Version Info (FVI) related definitions.
+
+  @todo update document/spec reference
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ at par Specification Reference:
+  System Management BIOS (SMBIOS) Reference Specification v3.0.0 dated 2015-Feb-12
+  http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
+
+**/
+
+#ifndef __FIRMWARE_VERSION_INFO_H__
+#define __FIRMWARE_VERSION_INFO_H__
+
+#include <IndustryStandard/SmBios.h>
+
+#define INTEL_FIRMWARE_VERSION_INFO_GROUP_NAME    "Firmware Version Info"
+
+#pragma pack(1)
+
+///
+/// Firmware Version Structure
+///
+typedef struct {
+  UINT8                       MajorVersion;
+  UINT8                       MinorVersion;
+  UINT8                       Revision;
+  UINT16                      BuildNumber;
+} INTEL_FIRMWARE_VERSION;
+
+///
+/// Firmware Version Info (FVI) Structure
+///
+typedef struct {
+  SMBIOS_TABLE_STRING         ComponentName;  ///< String Index of Component Name
+  SMBIOS_TABLE_STRING         VersionString;  ///< String Index of Version String
+  INTEL_FIRMWARE_VERSION      Version;        ///< Firmware version
+} INTEL_FIRMWARE_VERSION_INFO;
+
+///
+/// SMBIOS OEM Type Intel Firmware Version Info (FVI) Structure
+///
+typedef struct {
+  SMBIOS_STRUCTURE            Header;         ///< SMBIOS structure header
+  UINT8                       Count;          ///< Number of FVI entries in this structure
+  INTEL_FIRMWARE_VERSION_INFO Fvi[1];         ///< FVI structure(s)
+} SMBIOS_TABLE_TYPE_OEM_INTEL_FVI;
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/IgdOpRegion.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/IgdOpRegion.h
new file mode 100644
index 0000000000..f512535803
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/IgdOpRegion.h
@@ -0,0 +1,149 @@
+/** @file
+  IGD OpRegion definition from Intel Integrated Graphics Device OpRegion
+  Specification.
+
+  https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf
+
+  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _IGD_OPREGION_H_
+#define _IGD_OPREGION_H_
+
+#define IGD_OPREGION_HEADER_SIGN "IntelGraphicsMem"
+#define IGD_OPREGION_HEADER_MBOX1 BIT0
+#define IGD_OPREGION_HEADER_MBOX2 BIT1
+#define IGD_OPREGION_HEADER_MBOX3 BIT2
+#define IGD_OPREGION_HEADER_MBOX4 BIT3
+#define IGD_OPREGION_HEADER_MBOX5 BIT4
+
+/**
+  OpRegion structures:
+  Sub-structures define the different parts of the OpRegion followed by the
+  main structure representing the entire OpRegion.
+
+  @note These structures are packed to 1 byte offsets because the exact
+  data location is required by the supporting design specification due to
+  the fact that the data is used by ASL and Graphics driver code compiled
+  separately.
+**/
+#pragma pack(1)
+///
+/// OpRegion Mailbox 0 Header structure. The OpRegion Header is used to
+/// identify a block of memory as the graphics driver OpRegion.
+/// Offset 0x0, Size 0x100
+///
+typedef struct {
+  CHAR8  SIGN[0x10];    ///< Offset 0x00 OpRegion Signature
+  UINT32 SIZE;          ///< Offset 0x10 OpRegion Size
+  UINT32 OVER;          ///< Offset 0x14 OpRegion Structure Version
+  UINT8  SVER[0x20];    ///< Offset 0x18 System BIOS Build Version
+  UINT8  VVER[0x10];    ///< Offset 0x38 Video BIOS Build Version
+  UINT8  GVER[0x10];    ///< Offset 0x48 Graphic Driver Build Version
+  UINT32 MBOX;          ///< Offset 0x58 Supported Mailboxes
+  UINT32 DMOD;          ///< Offset 0x5C Driver Model
+  UINT32 PCON;          ///< Offset 0x60 Platform Configuration
+  CHAR16 DVER[0x10];    ///< Offset 0x64 GOP Version
+  UINT8  RM01[0x7C];    ///< Offset 0x84 Reserved Must be zero
+} IGD_OPREGION_HEADER;
+
+///
+/// OpRegion Mailbox 1 - Public ACPI Methods
+/// Offset 0x100, Size 0x100
+///
+typedef struct {
+  UINT32 DRDY;          ///< Offset 0x100 Driver Readiness
+  UINT32 CSTS;          ///< Offset 0x104 Status
+  UINT32 CEVT;          ///< Offset 0x108 Current Event
+  UINT8  RM11[0x14];    ///< Offset 0x10C Reserved Must be Zero
+  UINT32 DIDL[8];       ///< Offset 0x120 Supported Display Devices ID List
+  UINT32 CPDL[8];       ///< Offset 0x140 Currently Attached Display Devices List
+  UINT32 CADL[8];       ///< Offset 0x160 Currently Active Display Devices List
+  UINT32 NADL[8];       ///< Offset 0x180 Next Active Devices List
+  UINT32 ASLP;          ///< Offset 0x1A0 ASL Sleep Time Out
+  UINT32 TIDX;          ///< Offset 0x1A4 Toggle Table Index
+  UINT32 CHPD;          ///< Offset 0x1A8 Current Hotplug Enable Indicator
+  UINT32 CLID;          ///< Offset 0x1AC Current Lid State Indicator
+  UINT32 CDCK;          ///< Offset 0x1B0 Current Docking State Indicator
+  UINT32 SXSW;          ///< Offset 0x1B4 Display Switch Notification on Sx State Resume
+  UINT32 EVTS;          ///< Offset 0x1B8 Events supported by ASL
+  UINT32 CNOT;          ///< Offset 0x1BC Current OS Notification
+  UINT32 NRDY;          ///< Offset 0x1C0 Driver Status
+  UINT8  DID2[0x1C];    ///< Offset 0x1C4 Extended Supported Devices ID List (DOD)
+  UINT8  CPD2[0x1C];    ///< Offset 0x1E0 Extended Attached Display Devices List
+  UINT8  RM12[4];       ///< Offset 0x1FC - 0x1FF Reserved Must be zero
+} IGD_OPREGION_MBOX1;
+
+///
+/// OpRegion Mailbox 2 - Software SCI Interface
+/// Offset 0x200, Size 0x100
+///
+typedef struct {
+  UINT32 SCIC;          ///< Offset 0x200 Software SCI Command / Status / Data
+  UINT32 PARM;          ///< Offset 0x204 Software SCI Parameters
+  UINT32 DSLP;          ///< Offset 0x208 Driver Sleep Time Out
+  UINT8  RM21[0xF4];    ///< Offset 0x20C - 0x2FF Reserved Must be zero
+} IGD_OPREGION_MBOX2;
+
+///
+/// OpRegion Mailbox 3 - BIOS/Driver Notification - ASLE Support
+/// Offset 0x300, Size 0x100
+///
+typedef struct {
+  UINT32 ARDY;          ///< Offset 0x300 Driver Readiness
+  UINT32 ASLC;          ///< Offset 0x304 ASLE Interrupt Command / Status
+  UINT32 TCHE;          ///< Offset 0x308 Technology Enabled Indicator
+  UINT32 ALSI;          ///< Offset 0x30C Current ALS Luminance Reading
+  UINT32 BCLP;          ///< Offset 0x310 Requested Backlight Brightness
+  UINT32 PFIT;          ///< Offset 0x314 Panel Fitting State or Request
+  UINT32 CBLV;          ///< Offset 0x318 Current Brightness Level
+  UINT16 BCLM[0x14];    ///< Offset 0x31C Backlight Brightness Levels Duty Cycle Mapping Table
+  UINT32 CPFM;          ///< Offset 0x344 Current Panel Fitting Mode
+  UINT32 EPFM;          ///< Offset 0x348 Enabled Panel Fitting Modes
+  UINT8  PLUT[0x4A];    ///< Offset 0x34C Panel Look Up Table & Identifier
+  UINT32 PFMB;          ///< Offset 0x396 PWM Frequency and Minimum Brightness
+  UINT32 CCDV;          ///< Offset 0x39A Color Correction Default Values
+  UINT32 PCFT;          ///< Offset 0x39E Power Conservation Features
+  UINT32 SROT;          ///< Offset 0x3A2 Supported Rotation Angles
+  UINT32 IUER;          ///< Offset 0x3A6 Intel Ultrabook(TM) Event Register
+  UINT64 FDSS;          ///< Offset 0x3AA DSS Buffer address allocated for IFFS feature
+  UINT32 FDSP;          ///< Offset 0x3B2 Size of DSS buffer
+  UINT32 STAT;          ///< Offset 0x3B6 State Indicator
+  UINT64 RVDA;          ///< Offset 0x3BA Physical address of Raw VBT data. Added from Spec Version 0.90 to support VBT greater than 6KB.
+  UINT32 RVDS;          ///< Offset 0x3C2 Size of Raw VBT data. Added from Spec Version 0.90 to support VBT greater than 6KB.
+  UINT8  RM32[0x3A];    ///< Offset 0x3C6 - 0x3FF  Reserved Must be zero.
+} IGD_OPREGION_MBOX3;
+
+///
+/// OpRegion Mailbox 4 - VBT Video BIOS Table
+/// Offset 0x400, Size 0x1800
+///
+typedef struct {
+  UINT8  RVBT[0x1800];  ///< Offset 0x400 - 0x1BFF Raw VBT Data
+} IGD_OPREGION_MBOX4;
+
+///
+/// OpRegion Mailbox 5 - BIOS/Driver Notification - Data storage BIOS to Driver data sync
+/// Offset 0x1C00, Size 0x400
+///
+typedef struct {
+  UINT32 PHED;          ///< Offset 0x1C00 Panel Header
+  UINT8  BDDC[0x100];   ///< Offset 0x1C04 Panel EDID (DDC data)
+  UINT8  RM51[0x2FC];   ///< Offset 0x1D04 - 0x1FFF Reserved Must be zero
+} IGD_OPREGION_MBOX5;
+
+///
+/// IGD OpRegion Structure
+///
+typedef struct {
+  IGD_OPREGION_HEADER Header; ///< OpRegion header (Offset 0x0, Size 0x100)
+  IGD_OPREGION_MBOX1  MBox1;  ///< Mailbox 1: Public ACPI Methods (Offset 0x100, Size 0x100)
+  IGD_OPREGION_MBOX2  MBox2;  ///< Mailbox 2: Software SCI Interface (Offset 0x200, Size 0x100)
+  IGD_OPREGION_MBOX3  MBox3;  ///< Mailbox 3: BIOS to Driver Notification (Offset 0x300, Size 0x100)
+  IGD_OPREGION_MBOX4  MBox4;  ///< Mailbox 4: Video BIOS Table (VBT) (Offset 0x400, Size 0x1800)
+  IGD_OPREGION_MBOX5  MBox5;  ///< Mailbox 5: BIOS to Driver Notification Extension (Offset 0x1C00, Size 0x400)
+} IGD_OPREGION_STRUCTURE;
+#pragma pack()
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
new file mode 100644
index 0000000000..b2f745bd47
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/IndustryStandard/Vtd.h
@@ -0,0 +1,355 @@
+/** @file
+  The definition for VTD register.
+  It is defined in "Intel VT for Direct IO Architecture Specification".
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VTD_REG_H__
+#define __VTD_REG_H__
+
+#pragma pack(1)
+
+//
+// Translation Structure Formats
+//
+#define VTD_ROOT_ENTRY_NUMBER       256
+#define VTD_CONTEXT_ENTRY_NUMBER    256
+
+typedef union {
+  struct {
+    UINT32  Present:1;
+    UINT32  Reserved_1:11;
+    UINT32  ContextTablePointerLo:20;
+    UINT32  ContextTablePointerHi:32;
+
+    UINT64  Reserved_64;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_ROOT_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  LowerPresent:1;
+    UINT32  Reserved_1:11;
+    UINT32  LowerContextTablePointerLo:20;
+    UINT32  LowerContextTablePointerHi:32;
+
+    UINT32  UpperPresent:1;
+    UINT32  Reserved_65:11;
+    UINT32  UpperContextTablePointerLo:20;
+    UINT32  UpperContextTablePointerHi:32;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_EXT_ROOT_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Present:1;
+    UINT32  FaultProcessingDisable:1;
+    UINT32  TranslationType:2;
+    UINT32  Reserved_4:8;
+    UINT32  SecondLevelPageTranslationPointerLo:20;
+    UINT32  SecondLevelPageTranslationPointerHi:32;
+
+    UINT32  AddressWidth:3;
+    UINT32  Ignored_67:4;
+    UINT32  Reserved_71:1;
+    UINT32  DomainIdentifier:16;
+    UINT32  Reserved_88:8;
+    UINT32  Reserved_96:32;
+  } Bits;
+  struct {
+    UINT64  Uint64Lo;
+    UINT64  Uint64Hi;
+  } Uint128;
+} VTD_CONTEXT_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Present:1;
+    UINT32  FaultProcessingDisable:1;
+    UINT32  TranslationType:3;
+    UINT32  ExtendedMemoryType:3;
+    UINT32  DeferredInvalidateEnable:1;
+    UINT32  PageRequestEnable:1;
+    UINT32  NestedTranslationEnable:1;
+    UINT32  PASIDEnable:1;
+    UINT32  SecondLevelPageTranslationPointerLo:20;
+    UINT32  SecondLevelPageTranslationPointerHi:32;
+
+    UINT32  AddressWidth:3;
+    UINT32  PageGlobalEnable:1;
+    UINT32  NoExecuteEnable:1;
+    UINT32  WriteProtectEnable:1;
+    UINT32  CacheDisable:1;
+    UINT32  ExtendedMemoryTypeEnable:1;
+    UINT32  DomainIdentifier:16;
+    UINT32  SupervisorModeExecuteProtection:1;
+    UINT32  ExtendedAccessedFlagEnable:1;
+    UINT32  ExecuteRequestsEnable:1;
+    UINT32  SecondLevelExecuteEnable:1;
+    UINT32  Reserved_92:4;
+    UINT32  PageAttributeTable0:3;
+    UINT32  Reserved_Pat0:1;
+    UINT32  PageAttributeTable1:3;
+    UINT32  Reserved_Pat1:1;
+    UINT32  PageAttributeTable2:3;
+    UINT32  Reserved_Pat2:1;
+    UINT32  PageAttributeTable3:3;
+    UINT32  Reserved_Pat3:1;
+    UINT32  PageAttributeTable4:3;
+    UINT32  Reserved_Pat4:1;
+    UINT32  PageAttributeTable5:3;
+    UINT32  Reserved_Pat5:1;
+    UINT32  PageAttributeTable6:3;
+    UINT32  Reserved_Pat6:1;
+    UINT32  PageAttributeTable7:3;
+    UINT32  Reserved_Pat7:1;
+
+    UINT32  PASIDTableSize:4;
+    UINT32  Reserved_132:8;
+    UINT32  PASIDTablePointerLo:20;
+    UINT32  PASIDTablePointerHi:32;
+
+    UINT32  Reserved_192:12;
+    UINT32  PASIDStateTablePointerLo:20;
+    UINT32  PASIDStateTablePointerHi:32;
+  } Bits;
+  struct {
+    UINT64  Uint64_1;
+    UINT64  Uint64_2;
+    UINT64  Uint64_3;
+    UINT64  Uint64_4;
+  } Uint256;
+} VTD_EXT_CONTEXT_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Present:1;
+    UINT32  Reserved_1:2;
+    UINT32  PageLevelCacheDisable:1;
+    UINT32  PageLevelWriteThrough:1;
+    UINT32  Reserved_5:6;
+    UINT32  SupervisorRequestsEnable:1;
+    UINT32  FirstLevelPageTranslationPointerLo:20;
+    UINT32  FirstLevelPageTranslationPointerHi:32;
+  } Bits;
+  UINT64    Uint64;
+} VTD_PASID_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Reserved_0:32;
+    UINT32  ActiveReferenceCount:16;
+    UINT32  Reserved_48:15;
+    UINT32  DeferredInvalidate:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_PASID_STATE_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Present:1;
+    UINT32  ReadWrite:1;
+    UINT32  UserSupervisor:1;
+    UINT32  PageLevelWriteThrough:1;
+    UINT32  PageLevelCacheDisable:1;
+    UINT32  Accessed:1;
+    UINT32  Dirty:1;
+    UINT32  PageSize:1; // It is PageAttribute:1 for 4K page entry
+    UINT32  Global:1;
+    UINT32  Ignored_9:1;
+    UINT32  ExtendedAccessed:1;
+    UINT32  Ignored_11:1;
+    // NOTE: There is PageAttribute:1 as bit12 for 1G page entry and 2M page entry
+    UINT32  AddressLo:20;
+    UINT32  AddressHi:20;
+    UINT32  Ignored_52:11;
+    UINT32  ExecuteDisable:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_FIRST_LEVEL_PAGING_ENTRY;
+
+typedef union {
+  struct {
+    UINT32  Read:1;
+    UINT32  Write:1;
+    UINT32  Execute:1;
+    UINT32  ExtendedMemoryType:3;
+    UINT32  IgnorePAT:1;
+    UINT32  PageSize:1;
+    UINT32  Ignored_8:3;
+    UINT32  Snoop:1;
+    UINT32  AddressLo:20;
+    UINT32  AddressHi:20;
+    UINT32  Ignored_52:10;
+    UINT32  TransientMapping:1;
+    UINT32  Ignored_63:1;
+  } Bits;
+  UINT64    Uint64;
+} VTD_SECOND_LEVEL_PAGING_ENTRY;
+
+//
+// Register Descriptions
+//
+#define R_VER_REG        0x00
+#define R_CAP_REG        0x08
+#define   B_CAP_REG_RWBF       BIT4
+#define R_ECAP_REG       0x10
+#define R_GCMD_REG       0x18
+#define   B_GMCD_REG_WBF       BIT27
+#define   B_GMCD_REG_SRTP      BIT30
+#define   B_GMCD_REG_TE        BIT31
+#define R_GSTS_REG       0x1C
+#define   B_GSTS_REG_WBF       BIT27
+#define   B_GSTS_REG_RTPS      BIT30
+#define   B_GSTS_REG_TE        BIT31
+#define R_RTADDR_REG     0x20
+#define R_CCMD_REG       0x28
+#define   B_CCMD_REG_CIRG_MASK    (BIT62|BIT61)
+#define   V_CCMD_REG_CIRG_GLOBAL  BIT61
+#define   V_CCMD_REG_CIRG_DOMAIN  BIT62
+#define   V_CCMD_REG_CIRG_DEVICE  (BIT62|BIT61)
+#define   B_CCMD_REG_ICC          BIT63
+#define R_FSTS_REG       0x34
+#define R_FECTL_REG      0x38
+#define R_FEDATA_REG     0x3C
+#define R_FEADDR_REG     0x40
+#define R_FEUADDR_REG    0x44
+#define R_AFLOG_REG      0x58
+
+#define R_IVA_REG        0x00 // + IRO
+#define   B_IVA_REG_AM_MASK       (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5)
+#define   B_IVA_REG_AM_4K         0 // 1 page
+#define   B_IVA_REG_AM_2M         9 // 2M page
+#define   B_IVA_REG_IH            BIT6
+#define R_IOTLB_REG      0x08 // + IRO
+#define   B_IOTLB_REG_IIRG_MASK   (BIT61|BIT60)
+#define   V_IOTLB_REG_IIRG_GLOBAL BIT60
+#define   V_IOTLB_REG_IIRG_DOMAIN BIT61
+#define   V_IOTLB_REG_IIRG_PAGE   (BIT61|BIT60)
+#define   B_IOTLB_REG_IVT         BIT63
+
+#define R_FRCD_REG       0x00 // + FRO
+
+#define R_PMEN_ENABLE_REG         0x64
+#define R_PMEN_LOW_BASE_REG       0x68
+#define R_PMEN_LOW_LIMITE_REG     0x6C
+#define R_PMEN_HIGH_BASE_REG      0x70
+#define R_PMEN_HIGH_LIMITE_REG    0x78
+
+typedef union {
+  struct {
+    UINT8         ND:3; // Number of domains supported
+    UINT8         AFL:1; // Advanced Fault Logging
+    UINT8         RWBF:1; // Required Write-Buffer Flushing
+    UINT8         PLMR:1; // Protected Low-Memory Region
+    UINT8         PHMR:1; // Protected High-Memory Region
+    UINT8         CM:1; // Caching Mode
+
+    UINT8         SAGAW:5; // Supported Adjusted Guest Address Widths
+    UINT8         Rsvd_13:3;
+
+    UINT8         MGAW:6; // Maximum Guest Address Width
+    UINT8         ZLR:1; // Zero Length Read
+    UINT8         Rsvd_23:1;
+
+    UINT16        FRO:10; // Fault-recording Register offset
+    UINT16        SLLPS:4; // Second Level Large Page Support
+    UINT16        Rsvd_38:1;
+    UINT16        PSI:1; // Page Selective Invalidation
+
+    UINT8         NFR:8; // Number of Fault-recording Registers
+
+    UINT8         MAMV:6; // Maximum Address Mask Value
+    UINT8         DWD:1; // Write Draining
+    UINT8         DRD:1; // Read Draining
+
+    UINT8         FL1GP:1; // First Level 1-GByte Page Support
+    UINT8         Rsvd_57:2;
+    UINT8         PI:1; // Posted Interrupts Support
+    UINT8         Rsvd_60:4;
+  } Bits;
+  UINT64     Uint64;
+} VTD_CAP_REG;
+
+typedef union {
+  struct {
+    UINT8         C:1; // Page-walk Coherency
+    UINT8         QI:1; // Queued Invalidation support
+    UINT8         DT:1; // Device-TLB support
+    UINT8         IR:1; // Interrupt Remapping support
+    UINT8         EIM:1; // Extended Interrupt Mode
+    UINT8         Rsvd_5:1;
+    UINT8         PT:1; // Pass Through
+    UINT8         SC:1; // Snoop Control
+
+    UINT16        IRO:10; // IOTLB Register Offset
+    UINT16        Rsvd_18:2;
+    UINT16        MHMV:4; // Maximum Handle Mask Value
+
+    UINT8         ECS:1; // Extended Context Support
+    UINT8         MTS:1; // Memory Type Support
+    UINT8         NEST:1; // Nested Translation Support
+    UINT8         DIS:1; // Deferred Invalidate Support
+    UINT8         PASID:1; // Process Address Space ID Support
+    UINT8         PRS:1; // Page Request Support
+    UINT8         ERS:1; // Execute Request Support
+    UINT8         SRS:1; // Supervisor Request Support
+
+    UINT32        Rsvd_32:1;
+    UINT32        NWFS:1; // No Write Flag Support
+    UINT32        EAFS:1; // Extended Accessed Flag Support
+    UINT32        PSS:5; // PASID Size Supported
+    UINT32        Rsvd_40:24;
+  } Bits;
+  UINT64     Uint64;
+} VTD_ECAP_REG;
+
+typedef union {
+  struct {
+    UINT32   Rsvd_0:12;
+    UINT32   FILo:20;      // FaultInfo
+    UINT32   FIHi:32;      // FaultInfo
+
+    UINT32   SID:16;       // Source Identifier
+    UINT32   Rsvd_80:13;
+    UINT32   PRIV:1;       // Privilege Mode Requested
+    UINT32   EXE:1;        // Execute Permission Requested
+    UINT32   PP:1;         // PASID Present
+
+    UINT32   FR:8;         // Fault Reason
+    UINT32   PV:20;        // PASID Value
+    UINT32   AT:2;         // Address Type
+    UINT32   T:1;          // Type (0: Write, 1: Read)
+    UINT32   F:1;          // Fault
+  } Bits;
+  UINT64     Uint64[2];
+} VTD_FRCD_REG;
+
+typedef union {
+  struct {
+    UINT8    Function:3;
+    UINT8    Device:5;
+    UINT8    Bus;
+  } Bits;
+  struct {
+    UINT8    ContextIndex;
+    UINT8    RootIndex;
+  } Index;
+  UINT16     Uint16;
+} VTD_SOURCE_ID;
+
+#pragma pack()
+
+#endif
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Library/MicrocodeFlashAccessLib.h b/Silicon/Intel/IntelSiliconPkg/Include/Library/MicrocodeFlashAccessLib.h
new file mode 100644
index 0000000000..f991945c23
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/Library/MicrocodeFlashAccessLib.h
@@ -0,0 +1,33 @@
+/** @file
+  Microcode flash device access library.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef __MICROCODE_FLASH_ACCESS_LIB_H__
+#define __MICROCODE_FLASH_ACCESS_LIB_H__
+
+/**
+  Perform microcode write opreation.
+
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFlashWrite (
+  IN EFI_PHYSICAL_ADDRESS         FlashAddress,
+  IN VOID                         *Buffer,
+  IN UINTN                        Length
+  );
+
+#endif
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Ppi/VtdInfo.h b/Silicon/Intel/IntelSiliconPkg/Include/Ppi/VtdInfo.h
new file mode 100644
index 0000000000..f91dbc0381
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/Ppi/VtdInfo.h
@@ -0,0 +1,37 @@
+/** @file
+  The definition for VTD information PPI.
+
+  This is a lightweight VTd information report in PEI phase.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VTD_INFO_PPI_H__
+#define __VTD_INFO_PPI_H__
+
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+
+#define EDKII_VTD_INFO_PPI_GUID \
+    { \
+      0x8a59fcb3, 0xf191, 0x400c, { 0x97, 0x67, 0x67, 0xaf, 0x2b, 0x25, 0x68, 0x4a } \
+    }
+
+//
+// VTD info PPI just use same data structure as DMAR table.
+//
+// The reported information must include what is needed in PEI phase, e.g.
+//   the VTd engine (such as DRHD)
+//   the reserved DMA address in PEI for eary graphic (such as RMRR for graphic UMA)
+//
+// The reported information can be and might be a subset of full DMAR table, e.g.
+//   if some data is not avaiable (such as ANDD),
+//   if some data is not needed (such as RMRR for legacy USB).
+//
+typedef EFI_ACPI_DMAR_HEADER EDKII_VTD_INFO_PPI;
+
+extern EFI_GUID gEdkiiVTdInfoPpiGuid;
+
+#endif
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h b/Silicon/Intel/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
new file mode 100644
index 0000000000..acab432ede
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Include/Protocol/PlatformVtdPolicy.h
@@ -0,0 +1,143 @@
+/** @file
+  The definition for platform VTD policy.
+
+  Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_VTD_POLICY_PROTOCOL_H__
+#define __PLATFORM_VTD_POLICY_PROTOCOL_H__
+
+#include <IndustryStandard/Vtd.h>
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_GUID \
+    { \
+      0x3d17e448, 0x466, 0x4e20, { 0x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 } \
+    }
+
+typedef struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL  EDKII_PLATFORM_VTD_POLICY_PROTOCOL;
+
+#define EDKII_PLATFORM_VTD_POLICY_PROTOCOL_REVISION 0x00010000
+
+typedef struct {
+  UINT16                                   Segment;
+  VTD_SOURCE_ID                            SourceId;
+} EDKII_PLATFORM_VTD_DEVICE_INFO;
+
+/**
+  Get the VTD SourceId from the device handler.
+  This function is required for non PCI device handler.
+
+  Pseudo-algo in Intel VTd driver:
+    Status = PlatformGetVTdDeviceId ();
+    if (EFI_ERROR(Status)) {
+      if (DeviceHandle is PCI) {
+        Get SourceId from Bus/Device/Function
+      } else {
+        return EFI_UNSUPPORTED
+      }
+    }
+    Get VTd engine by Segment/Bus/Device/Function.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[in]  DeviceHandle          Device Identifier in UEFI.
+  @param[out] DeviceInfo            DeviceInfo for indentify the VTd engine in ACPI Table
+                                    and the VTd page entry.
+
+  @retval EFI_SUCCESS           The VtdIndex and SourceId are returned.
+  @retval EFI_INVALID_PARAMETER DeviceHandle is not a valid handler.
+  @retval EFI_INVALID_PARAMETER DeviceInfo is NULL.
+  @retval EFI_NOT_FOUND         The Segment or SourceId information is NOT found.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  IN  EFI_HANDLE                               DeviceHandle,
+  OUT EDKII_PLATFORM_VTD_DEVICE_INFO           *DeviceInfo
+  );
+
+#pragma pack(1)
+
+typedef struct {
+  //
+  // The segment number of the device
+  //
+  UINT16                                          SegmentNumber;
+  //
+  // Device scope definition in DMAR table
+  //
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     DeviceScope;
+  //
+  // Pci path definition in DMAR table
+  //
+//EFI_ACPI_DMAR_PCI_PATH                          PciPath[];
+} EDKII_PLATFORM_VTD_DEVICE_SCOPE;
+
+typedef struct {
+  UINT16                                   VendorId;
+  UINT16                                   DeviceId;
+  UINT8                                    RevisionId;
+  UINT16                                   SubsystemVendorId;
+  UINT16                                   SubsystemDeviceId;
+} EDKII_PLATFORM_VTD_PCI_DEVICE_ID;
+
+#define EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END           0
+#define EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE  1
+#define EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID 2
+
+typedef struct {
+  //
+  // EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_xxx defined above.
+  //
+  UINT8             Type;
+  //
+  // The length of the full data structure including EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO and Data.
+  //
+  UINT8             Length;
+  //
+  // Data can be EDKII_PLATFORM_VTD_DEVICE_SCOPE or EDKII_PLATFORM_VTD_PCI_DEVICE_ID
+  //
+//UINT8             Data[Length - sizeof(EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO)];
+} EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO;
+
+#pragma pack()
+
+
+/**
+  Get a list of the exception devices.
+
+  The VTd driver should always set ALLOW for the device in this list.
+
+  @param[in]  This                  The protocol instance pointer.
+  @param[out] DeviceInfoCount       The count of the list of DeviceInfo.
+  @param[out] DeviceInfo            A callee allocated buffer to hold a list of DeviceInfo.
+                                    Each DeviceInfo pointer points to EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO.
+
+  @retval EFI_SUCCESS           The DeviceInfoCount and DeviceInfo are returned.
+  @retval EFI_INVALID_PARAMETER DeviceInfoCount is NULL, or DeviceInfo is NULL.
+  @retval EFI_UNSUPPORTED       This function is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST) (
+  IN  EDKII_PLATFORM_VTD_POLICY_PROTOCOL       *This,
+  OUT UINTN                                    *DeviceInfoCount,
+  OUT VOID                                     **DeviceInfo
+  );
+
+struct _EDKII_PLATFORM_VTD_POLICY_PROTOCOL {
+  UINT64                                               Revision;
+  EDKII_PLATFORM_VTD_POLICY_GET_DEVICE_ID              GetDeviceId;
+  EDKII_PLATFORM_VTD_POLICY_GET_EXCEPTION_DEVICE_LIST  GetExceptionDeviceList;
+};
+
+extern EFI_GUID gEdkiiPlatformVTdPolicyProtocolGuid;
+
+#endif
+
diff --git a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec
new file mode 100644
index 0000000000..fe5bfa0dc6
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec
@@ -0,0 +1,80 @@
+## @file
+# IntelSilicon Package
+#
+# This package provides common open source Intel silicon modules.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = IntelSiliconPkg
+  PACKAGE_GUID                   = F7A58914-FA0E-4F71-BD6A-220FDF824A49
+  PACKAGE_VERSION                = 0.1
+
+[Includes]
+  Include
+
+[LibraryClasses.IA32, LibraryClasses.X64]
+  ## @libraryclass  Provides services to access Microcode region on flash device.
+  #
+  MicrocodeFlashAccessLib|Include/Library/MicrocodeFlashAccessLib.h
+
+[Guids]
+  ## GUID for Package token space
+  # {A9F8D54E-1107-4F0A-ADD0-4587E7A4A735}
+  gIntelSiliconPkgTokenSpaceGuid  = { 0xa9f8d54e, 0x1107, 0x4f0a, { 0xad, 0xd0, 0x45, 0x87, 0xe7, 0xa4, 0xa7, 0x35 } }
+
+  ## HOB GUID to publish SMBIOS data records from PEI phase
+  # HOB data format is same as SMBIOS records defined in SMBIOS spec or OEM defined types
+  # Generic DXE Library / Driver can locate HOB(s) and add SMBIOS records into SMBIOS table
+  gIntelSmbiosDataHobGuid         = { 0x798e722e, 0x15b2, 0x4e13, { 0x8a, 0xe9, 0x6b, 0xa3, 0x0f, 0xf7, 0xf1, 0x67 }}
+
+  ## Include/Guid/MicrocodeFmp.h
+  gMicrocodeFmpImageTypeIdGuid      = { 0x96d4fdcd, 0x1502, 0x424d, { 0x9d, 0x4c, 0x9b, 0x12, 0xd2, 0xdc, 0xae, 0x5c } }
+
+[Ppis]
+  gEdkiiVTdInfoPpiGuid = { 0x8a59fcb3, 0xf191, 0x400c, { 0x97, 0x67, 0x67, 0xaf, 0x2b, 0x25, 0x68, 0x4a } }
+
+[Protocols]
+  gEdkiiPlatformVTdPolicyProtocolGuid = { 0x3d17e448, 0x466, 0x4e20, { 0x99, 0x9f, 0xb2, 0xe1, 0x34, 0x88, 0xee, 0x22 }}
+
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+  ## Error code for VTd error.<BR><BR>
+  #  EDKII_ERROR_CODE_VTD_ERROR = (EFI_IO_BUS_UNSPECIFIED | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x02008000<BR>
+  # @Prompt Error code for VTd error.
+  gIntelSiliconPkgTokenSpaceGuid.PcdErrorCodeVTdError|0x02008000|UINT32|0x00000005
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+  ## This is the GUID of the FFS which contains the Graphics Video BIOS Table (VBT)
+  # The VBT content is stored as a RAW section which is consumed by GOP PEI/UEFI driver.
+  # The default GUID can be updated by patching or runtime if platform support multiple VBT configurations.
+  # @Prompt GUID of the FFS which contains the Graphics Video BIOS Table (VBT)
+  # { 0x56752da9, 0xde6b, 0x4895, 0x88, 0x19, 0x19, 0x45, 0xb6, 0xb7, 0x6c, 0x22 }
+  gIntelSiliconPkgTokenSpaceGuid.PcdIntelGraphicsVbtFileGuid|{ 0xa9, 0x2d, 0x75, 0x56, 0x6b, 0xde, 0x95, 0x48, 0x88, 0x19, 0x19, 0x45, 0xb6, 0xb7, 0x6c, 0x22 }|VOID*|0x00000001
+
+  ## The mask is used to control VTd behavior.<BR><BR>
+  #  BIT0: Enable IOMMU during boot (If DMAR table is installed in DXE. If VTD_INFO_PPI is installed in PEI.)
+  #  BIT1: Enable IOMMU when transfer control to OS (ExitBootService in normal boot. EndOfPEI in S3)
+  #  BIT2: Force no IOMMU access attribute request recording before DMAR table is installed.
+  # @Prompt The policy for VTd driver behavior.
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask|1|UINT8|0x00000002
+
+  ## Declares VTd PEI DMA buffer size.<BR><BR>
+  #  When this PCD value is referred by platform to calculate the required
+  #  memory size for PEI (InstallPeiMemory), the PMR alignment requirement
+  #  needs be considered to be added with this PCD value for alignment
+  #  adjustment need by AllocateAlignedPages.
+  # @Prompt The VTd PEI DMA buffer size.
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSize|0x00400000|UINT32|0x00000003
+
+  ## Declares VTd PEI DMA buffer size for S3.<BR><BR>
+  #  When this PCD value is referred by platform to calculate the required
+  #  memory size for PEI S3 (InstallPeiMemory), the PMR alignment requirement
+  #  needs be considered to be added with this PCD value for alignment
+  #  adjustment need by AllocateAlignedPages.
+  # @Prompt The VTd PEI DMA buffer size for S3.
+  gIntelSiliconPkgTokenSpaceGuid.PcdVTdPeiDmaBufferSizeS3|0x00200000|UINT32|0x00000004
+
diff --git a/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc
new file mode 100644
index 0000000000..58b5b656ef
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dsc
@@ -0,0 +1,86 @@
+## @file
+# This package provides common open source Intel silicon modules.
+#
+# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  PLATFORM_NAME                  = IntelSiliconPkg
+  PLATFORM_GUID                  = 9B96228E-1155-4967-8E16-D0ED8E1B4297
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x00010005
+  OUTPUT_DIRECTORY               = Build/IntelSiliconPkg
+  SUPPORTED_ARCHITECTURES        = IA32|X64
+  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
+  SKUID_IDENTIFIER               = DEFAULT
+
+[LibraryClasses]
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+  ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+  PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
+  PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
+  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+  UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
+  PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+  SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+  CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+  MicrocodeFlashAccessLib|IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
+
+[LibraryClasses.common.PEIM]
+  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+  PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+
+  MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+
+  HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+#                      tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+#       into firmware volume images. This section is just a list of modules to compile from
+#       source into UEFI-compliant binaries.
+#       It is the FDF file that contains information on combining binary files into firmware
+#       volume images, whose concept is beyond UEFI and is described in PI specification.
+#       Binary modules do not need to be listed in this section, as they should be
+#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+#       Logo (Logo.bmp), and etc.
+#       There may also be modules listed in this section that are not required in the FDF file,
+#       When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+#       generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components]
+  IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf
+  IntelSiliconPkg/Feature/VTd/IntelVTdDxe/IntelVTdDxe.inf
+  IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.inf
+  IntelSiliconPkg/Feature/VTd/PlatformVTdSampleDxe/PlatformVTdSampleDxe.inf
+  IntelSiliconPkg/Feature/VTd/PlatformVTdInfoSamplePei/PlatformVTdInfoSamplePei.inf
+  IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
+  IntelSiliconPkg/Feature/Capsule/Library/MicrocodeFlashAccessLibNull/MicrocodeFlashAccessLibNull.inf
+
+[BuildOptions]
+  *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
diff --git a/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf b/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf
new file mode 100644
index 0000000000..df3c751f37
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Library/DxeSmbiosDataHobLib/DxeSmbiosDataHobLib.inf
@@ -0,0 +1,38 @@
+## @file
+# Component INF file for the DxeSmbiosDataHob library.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+INF_VERSION   = 0x00010017
+BASE_NAME     = DxeSmbiosDataHobLib
+FILE_GUID     = AF55A9B6-2AE6-4B08-8CF7-750B7CBF49D7
+MODULE_TYPE   = DXE_DRIVER
+LIBRARY_CLASS = NULL|DXE_DRIVER
+CONSTRUCTOR   = DxeSmbiosDataHobLibConstructor
+
+[Packages]
+MdePkg/MdePkg.dec
+IntelSiliconPkg/IntelSiliconPkg.dec
+
+[Sources]
+DxeSmbiosDataHobLib.c
+
+[LibraryClasses]
+DebugLib
+BaseMemoryLib
+MemoryAllocationLib
+BaseLib
+HobLib
+UefiLib
+
+[Guids]
+gIntelSmbiosDataHobGuid ## CONSUMES   ## GUID
+
+[Depex]
+gEfiSmbiosProtocolGuid
+
-- 
2.13.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#42116): https://edk2.groups.io/g/devel/message/42116
Mute This Topic: https://groups.io/mt/32005625/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list