[edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions

Leo Duran posted 1 patch 7 years, 7 months ago
Failed in applying to current master (apply log)
MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151 ++++++++++++++++++++++++++++
MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120 ++++++++++++++++++++++
MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c  | 115 +++++++++++++++++++++
MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129 ++++++++++++++++++++++++
6 files changed, 554 insertions(+)
create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
[edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
Posted by Leo Duran 7 years, 7 months ago
This patch intercepts MMIO configuration in the GCD module
to ensure those regions are unmasked.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Leo Duran <leo.duran@amd.com>
---
 MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
 MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151 ++++++++++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120 ++++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c  | 115 +++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129 ++++++++++++++++++++++++
 6 files changed, 554 insertions(+)
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c

diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 30d5984..183d1e7 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -4,6 +4,8 @@
 #  It provides an implementation of DXE Core that is compliant with DXE CIS.
 #  
 #  Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+#
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD License
 #  which accompanies this distribution.  The full text of the license may be found at
@@ -51,6 +53,8 @@
   Hand/Handle.h
   Gcd/Gcd.c
   Gcd/Gcd.h
+  Gcd/GcdHelperCommon.c
+  Gcd/GcdHelper.h
   Mem/Pool.c
   Mem/Page.c
   Mem/MemData.c
@@ -73,6 +77,12 @@
   DxeMain/DxeProtocolNotify.c
   DxeMain/DxeMain.c
 
+[Sources.Ia32]
+  Gcd/Ia32/GcdHelper.c
+
+[Sources.X64]
+  Gcd/X64/GcdHelper.c
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
@@ -192,6 +202,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable                   ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy                   ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy             ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask        ## CONSUMES
 
 # [Hob]
 # RESOURCE_DESCRIPTOR   ## CONSUMES
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
index a06f8bb..6f85c21 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -4,6 +4,8 @@
   are accessible to the CPU that is executing the DXE core.
 
 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
 which accompanies this distribution.  The full text of the license may be found at
@@ -16,6 +18,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include "DxeMain.h"
 #include "Gcd.h"
+#include "GcdHelper.h"
 
 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
 
@@ -723,6 +726,7 @@ CoreConvertSpace (
   LIST_ENTRY         *StartLink;
   LIST_ENTRY         *EndLink;
   UINT64             CpuArchAttributes;
+  UINT64             AddressEncMask;
 
   if (Length == 0) {
     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
@@ -741,6 +745,11 @@ CoreConvertSpace (
   }
 
   //
+  // Make sure AddressEncMask is contained to smallest supported address field.
+  //
+  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+
+  //
   // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
   //
   Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
@@ -893,6 +902,11 @@ CoreConvertSpace (
       Entry->GcdMemoryType = GcdMemoryType;
       if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, CLEAR_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not CLEAR EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
       } else {
         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
       }
@@ -904,6 +918,13 @@ CoreConvertSpace (
     // Free operations
     //
     case GCD_FREE_MEMORY_OPERATION:
+      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, SET_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
+      }
     case GCD_FREE_IO_OPERATION:
       Entry->ImageHandle  = NULL;
       Entry->DeviceHandle = NULL;
@@ -912,6 +933,13 @@ CoreConvertSpace (
     // Remove operations
     //
     case GCD_REMOVE_MEMORY_OPERATION:
+      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, SET_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
+      }
       Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
       Entry->Capabilities  = 0;
       break;
diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
new file mode 100644
index 0000000..d6ec339
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
@@ -0,0 +1,151 @@
+/** @file
+  Definitions for helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _GCD_HELPER_H_
+#define _GCD_HELPER_H_
+
+
+#pragma pack(1)
+//
+// Page Table Entry 4KB
+//
+typedef union {
+  struct {
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64  PAT:1;                    //
+    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64  Available:3;              // Available for use by system software
+    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
+    UINT64  AvailableHigh:11;         // Available for use by system software
+    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+  struct {
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64  MustBe1:1;                // Must be 1 
+    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64  Available:3;              // Available for use by system software
+    UINT64  PAT:1;                    //
+    UINT64  MustBeZero:8;             // Must be zero;
+    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
+    UINT64  AvailableHigh:11;         // Available for use by system software
+    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_2M_ENTRY;
+#pragma pack()
+
+
+typedef enum {
+  CLEAR_ADDR_ENC_OPERATION,
+  SET_ADDR_ENC_OPERATION,
+  INVALID_ENC_OPERATION
+} ADDR_ENC_OPERATION;
+
+
+#define IA32_PG_P                  BIT0
+#define IA32_PG_RW                 BIT1
+#define IA32_PG_PS                 BIT7
+
+#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
+
+
+/**
+  Convert Encryption on address range
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the segment
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified segment.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  );
+
+/**
+  Convert Encryption on page table entry.
+
+  @param  PageTableEntry         Start address of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+**/
+VOID
+ConvertEncryptionOnPageTableEntry (
+  IN UINT64              *PageTableEntry,
+  IN ADDR_ENC_OPERATION  Operation,
+  IN UINT64              AddressEncMask
+  );
+
+/**
+  Split 1G page to 2M on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the encryted range.
+  @param[in]      AddressEncMask        Address Encryption Mask.
+  @param[in, out] PageEntry1G           Pointer to 1G page entry.
+
+**/
+VOID
+Split1GPageTo2MPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry1G
+  );
+
+/**
+  Split 2M page to 4K on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the range.
+  @param[in]      AddressEncmask        Encryption Mask.
+  @param[in, out] PageEntry2M           Pointer to 2M page entry.
+
+**/
+VOID
+Split2MPageTo4KPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry2M
+  );
+
+#endif // _GCD_HELPER_H_
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
new file mode 100644
index 0000000..1660732
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
@@ -0,0 +1,120 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Split 2M page to 4K on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the range.
+  @param[in]      AddressEncmask        Encryption Mask.
+  @param[in, out] PageEntry2M           Pointer to 2M page entry.
+
+**/
+VOID
+Split2MPageTo4KPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry2M
+  )
+{
+  EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
+  UINTN                                 IndexOfPageTableEntries;
+  PAGE_TABLE_4K_ENTRY                   *PageTableEntry;
+
+  PageTableEntry = (PAGE_TABLE_4K_ENTRY *)AllocatePages (1);
+  ASSERT (PageTableEntry != NULL);
+
+  //
+  // Fill in 2M page entry.
+  //
+  *PageEntry2M = (UINT64)(UINTN) PageTableEntry | AddressEncMask | IA32_PG_P | IA32_PG_RW;
+
+  PhysicalAddress4K = PhysicalAddress;
+  for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) {
+    //
+    // Fill in the Page Table entries
+    //
+    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+    PageTableEntry->Bits.ReadWrite = 1;
+    PageTableEntry->Bits.Present = 1;
+  }
+}
+
+
+/**
+  Split 1G page to 2M on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the encryted range.
+  @param[in]      AddressEncMask        Address Encryption Mask.
+  @param[in, out] PageEntry1G           Pointer to 1G page entry.
+
+**/
+VOID
+Split1GPageTo2MPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry1G
+  )
+{
+  EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
+  UINTN                                 IndexOfPageDirectoryEntries;
+  PAGE_TABLE_2M_ENTRY                   *PageDirectoryEntry;
+
+  PageDirectoryEntry = (PAGE_TABLE_2M_ENTRY *)AllocatePages (1);
+  ASSERT (PageDirectoryEntry != NULL);
+
+  //
+  // Fill in 1G page entry.
+  //
+  *PageEntry1G = (UINT64)(UINTN) PageDirectoryEntry | AddressEncMask | IA32_PG_P | IA32_PG_RW;
+
+  PhysicalAddress2M = PhysicalAddress;
+  for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
+    //
+    // Fill in the Page Directory entries
+    //
+    PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | AddressEncMask;
+    PageDirectoryEntry->Bits.ReadWrite = 1;
+    PageDirectoryEntry->Bits.Present = 1;
+    PageDirectoryEntry->Bits.MustBe1 = 1;
+  }
+}
+
+
+/**
+  Convert Encryption on page table entry.
+
+  @param  PageTableEntry         Start address of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+**/
+VOID
+ConvertEncryptionOnPageTableEntry (
+  IN UINT64              *PageTableEntry,
+  IN ADDR_ENC_OPERATION  Operation,
+  IN UINT64              AddressEncMask
+  )
+{
+  if (Operation == CLEAR_ADDR_ENC_OPERATION) {
+    *PageTableEntry &= ~AddressEncMask;
+  } else if (Operation == SET_ADDR_ENC_OPERATION) {
+    *PageTableEntry |= AddressEncMask;
+  }
+}
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
new file mode 100644
index 0000000..4781900
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
@@ -0,0 +1,115 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Convert Encryption on address range.
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified range.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  )
+{
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+  UINT64                *PageTable;
+  UINTN                 PTIndex;
+  UINT64                Cr3;
+
+  // Do we have actual work to do?
+  if (Length == 0 || AddressEncMask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // PAE *must* be enabled on 32-bit page tables
+  // (else we can't configure AddressEncMask)
+  if ((AsmReadCr4 () & BIT5) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // Make sure we're PAGE_SIZE aligned
+  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate Operation
+  if (Operation >= INVALID_ENC_OPERATION) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Cr3 = AsmReadCr3 ();
+  PhysicalAddress = BaseAddress;
+
+  do {
+    // PDPE Present?
+    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 30, 31);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // PDE Present?
+    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // Is it a 2MB page entry?
+    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+      if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
+        // Consume 2MB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_2MB;
+        Length -= SIZE_2MB;
+      } else {
+        // Split 2MB page entry to consume 4K chunks
+        Split2MPageTo4KPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+      }
+    } else {
+      // PTE Present?
+      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+      PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
+      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+        return EFI_NO_MAPPING;
+      }
+
+      // Consume 4KB from the range
+      ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+      PhysicalAddress += SIZE_4KB;
+      Length -= SIZE_4KB;
+    }
+  } while (Length);
+
+  // Flush TLB
+  AsmWriteCr3 (Cr3);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
new file mode 100644
index 0000000..5943f7a
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
@@ -0,0 +1,129 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Convert Encryption on address range.
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified range.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  )
+{
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+  UINT64                *PageTable;
+  UINTN                 PTIndex;
+  UINT64                Cr3;
+
+  // Do we have actual work to do?
+  if (Length == 0 || AddressEncMask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // Make sure we're PAGE_SIZE aligned
+  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate Operation
+  if (Operation >= INVALID_ENC_OPERATION) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Cr3 = AsmReadCr3 ();
+  PhysicalAddress = BaseAddress;
+
+  do {
+    // PML4E Present?
+    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 39, 47);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // PDPE Present?
+    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 30, 38);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // Is it a 1GB page entry?
+    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+      if ((PhysicalAddress & (SIZE_1GB - 1)) == 0 && Length >= SIZE_1GB) {
+        // Consume 1GB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_1GB;
+        Length -= SIZE_1GB;
+      } else {
+        // Split 1G page entry to attempt consuming 2MB chunks
+        Split1GPageTo2MPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+      }
+    } else {
+      // PDE Present?
+      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+      PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
+      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+        return EFI_NO_MAPPING;
+      }
+
+      // Is it a 2MB page entry?
+      if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+        if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
+          // Consume 2MB from the range
+          ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+          PhysicalAddress += SIZE_2MB;
+          Length -= SIZE_2MB;
+        } else {
+          // Split 2MB page entry to consume 4K chunks
+          Split2MPageTo4KPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+        }
+      } else {
+        // PTE Present?
+        PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+        PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
+        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+          return EFI_NO_MAPPING;
+        }
+
+        // Consume 4KB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_4KB;
+        Length -= SIZE_4KB;
+      }
+    }
+  } while (Length);
+
+  // Flush TLB
+  AsmWriteCr3 (Cr3);
+
+  return EFI_SUCCESS;
+}
+
-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
Posted by Zeng, Star 7 years, 7 months ago
I have comments below.

1. Why need to call ConvertEncryptionOnAddressRange() at GCD_FREE_MEMORY_OPERATION case? GCD_FREE_MEMORY_OPERATION does not change the Entry->GcdMemoryType.
2. I think it is better to use if (Entry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) instead of if (Entry->Capabilities & EFI_MEMORY_PORT_IO) for GCD_REMOVE_MEMORY_OPERATION case.
3. Why need to use PAGING_4K_ADDRESS_MASK_64 in GcdHelper.c? Why need to define PAGING_2M_ADDRESS_MASK_64?
4. Why need to unmask Cr3 like below in GcdHelper.c? The PageTables is not masked at DxeIpl before written to CR3. Only the table entry needs to be unmask in GcdHelper.c, right?
  GcdHelper.c: Cr3 & ~AddressEncMask
  DxeIpl: AsmWriteCr3 (PageTables); 
5. Do you need to add dummy GcdHelper.c for other archs? Do you need to put GcdHelperCommon.c and GcdHelper.h under the arch IA32 and X64 as other archs do not need them?


Thanks,
Star
-----Original Message-----
From: Leo Duran [mailto:leo.duran@amd.com] 
Sent: Friday, March 24, 2017 10:51 AM
To: edk2-devel@ml01.01.org
Cc: Leo Duran <leo.duran@amd.com>; Tian, Feng <feng.tian@intel.com>; Zeng, Star <star.zeng@intel.com>; Brijesh Singh <brijesh.singh@amd.com>
Subject: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions

This patch intercepts MMIO configuration in the GCD module to ensure those regions are unmasked.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Leo Duran <leo.duran@amd.com>
---
 MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
 MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151 ++++++++++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120 ++++++++++++++++++++++  MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c  | 115 +++++++++++++++++++++
 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129 ++++++++++++++++++++++++
 6 files changed, 554 insertions(+)
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
 create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c

diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 30d5984..183d1e7 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -4,6 +4,8 @@
 #  It provides an implementation of DXE Core that is compliant with DXE CIS.
 #
 #  Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> #
 #  This program and the accompanying materials  #  are licensed and made available under the terms and conditions of the BSD License  #  which accompanies this distribution.  The full text of the license may be found at @@ -51,6 +53,8 @@
   Hand/Handle.h
   Gcd/Gcd.c
   Gcd/Gcd.h
+  Gcd/GcdHelperCommon.c
+  Gcd/GcdHelper.h
   Mem/Pool.c
   Mem/Page.c
   Mem/MemData.c
@@ -73,6 +77,12 @@
   DxeMain/DxeProtocolNotify.c
   DxeMain/DxeMain.c
 
+[Sources.Ia32]
+  Gcd/Ia32/GcdHelper.c
+
+[Sources.X64]
+  Gcd/X64/GcdHelper.c
+
 [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
@@ -192,6 +202,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable                   ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy                   ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy             ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask        ## CONSUMES
 
 # [Hob]
 # RESOURCE_DESCRIPTOR   ## CONSUMES
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index a06f8bb..6f85c21 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -4,6 +4,8 @@
   are accessible to the CPU that is executing the DXE core.
 
 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
 This program and the accompanying materials  are licensed and made available under the terms and conditions of the BSD License  which accompanies this distribution.  The full text of the license may be found at @@ -16,6 +18,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include "DxeMain.h"
 #include "Gcd.h"
+#include "GcdHelper.h"
 
 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
 
@@ -723,6 +726,7 @@ CoreConvertSpace (
   LIST_ENTRY         *StartLink;
   LIST_ENTRY         *EndLink;
   UINT64             CpuArchAttributes;
+  UINT64             AddressEncMask;
 
   if (Length == 0) {
     DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER)); @@ -741,6 +745,11 @@ CoreConvertSpace (
   }
 
   //
+  // Make sure AddressEncMask is contained to smallest supported address field.
+  //
+  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & 
+ PAGING_1G_ADDRESS_MASK_64;
+
+  //
   // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
   //
   Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map); @@ -893,6 +902,11 @@ CoreConvertSpace (
       Entry->GcdMemoryType = GcdMemoryType;
       if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, CLEAR_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not CLEAR EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
       } else {
         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
       }
@@ -904,6 +918,13 @@ CoreConvertSpace (
     // Free operations
     //
     case GCD_FREE_MEMORY_OPERATION:
+      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, SET_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
+      }
     case GCD_FREE_IO_OPERATION:
       Entry->ImageHandle  = NULL;
       Entry->DeviceHandle = NULL;
@@ -912,6 +933,13 @@ CoreConvertSpace (
     // Remove operations
     //
     case GCD_REMOVE_MEMORY_OPERATION:
+      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
+        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length, SET_ADDR_ENC_OPERATION, AddressEncMask);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range: BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
+            BaseAddress, Length, Status));
+        }
+      }
       Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
       Entry->Capabilities  = 0;
       break;
diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
new file mode 100644
index 0000000..d6ec339
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
@@ -0,0 +1,151 @@
+/** @file
+  Definitions for helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made 
+available under the terms and conditions of the BSD License which 
+accompanies this distribution.  The full text of the license may be 
+found at http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _GCD_HELPER_H_
+#define _GCD_HELPER_H_
+
+
+#pragma pack(1)
+//
+// Page Table Entry 4KB
+//
+typedef union {
+  struct {
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64  PAT:1;                    //
+    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64  Available:3;              // Available for use by system software
+    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
+    UINT64  AvailableHigh:11;         // Available for use by system software
+    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+  struct {
+    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
+    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
+    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
+    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
+    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
+    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
+    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
+    UINT64  MustBe1:1;                // Must be 1 
+    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+    UINT64  Available:3;              // Available for use by system software
+    UINT64  PAT:1;                    //
+    UINT64  MustBeZero:8;             // Must be zero;
+    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
+    UINT64  AvailableHigh:11;         // Available for use by system software
+    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_2M_ENTRY;
+#pragma pack()
+
+
+typedef enum {
+  CLEAR_ADDR_ENC_OPERATION,
+  SET_ADDR_ENC_OPERATION,
+  INVALID_ENC_OPERATION
+} ADDR_ENC_OPERATION;
+
+
+#define IA32_PG_P                  BIT0
+#define IA32_PG_RW                 BIT1
+#define IA32_PG_PS                 BIT7
+
+#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull #define 
+PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull #define 
+PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
+
+
+/**
+  Convert Encryption on address range
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the segment
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified segment.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  );
+
+/**
+  Convert Encryption on page table entry.
+
+  @param  PageTableEntry         Start address of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+**/
+VOID
+ConvertEncryptionOnPageTableEntry (
+  IN UINT64              *PageTableEntry,
+  IN ADDR_ENC_OPERATION  Operation,
+  IN UINT64              AddressEncMask
+  );
+
+/**
+  Split 1G page to 2M on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the encryted range.
+  @param[in]      AddressEncMask        Address Encryption Mask.
+  @param[in, out] PageEntry1G           Pointer to 1G page entry.
+
+**/
+VOID
+Split1GPageTo2MPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry1G
+  );
+
+/**
+  Split 2M page to 4K on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the range.
+  @param[in]      AddressEncmask        Encryption Mask.
+  @param[in, out] PageEntry2M           Pointer to 2M page entry.
+
+**/
+VOID
+Split2MPageTo4KPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry2M
+  );
+
+#endif // _GCD_HELPER_H_
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
new file mode 100644
index 0000000..1660732
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
@@ -0,0 +1,120 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made 
+available under the terms and conditions of the BSD License which 
+accompanies this distribution.  The full text of the license may be 
+found at http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Split 2M page to 4K on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the range.
+  @param[in]      AddressEncmask        Encryption Mask.
+  @param[in, out] PageEntry2M           Pointer to 2M page entry.
+
+**/
+VOID
+Split2MPageTo4KPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry2M
+  )
+{
+  EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
+  UINTN                                 IndexOfPageTableEntries;
+  PAGE_TABLE_4K_ENTRY                   *PageTableEntry;
+
+  PageTableEntry = (PAGE_TABLE_4K_ENTRY *)AllocatePages (1);  ASSERT 
+ (PageTableEntry != NULL);
+
+  //
+  // Fill in 2M page entry.
+  //
+  *PageEntry2M = (UINT64)(UINTN) PageTableEntry | AddressEncMask | 
+ IA32_PG_P | IA32_PG_RW;
+
+  PhysicalAddress4K = PhysicalAddress;
+  for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) {
+    //
+    // Fill in the Page Table entries
+    //
+    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
+    PageTableEntry->Bits.ReadWrite = 1;
+    PageTableEntry->Bits.Present = 1;
+  }
+}
+
+
+/**
+  Split 1G page to 2M on Encrypted address range.
+
+  @param[in]      PhysicalAddress       Address of the encryted range.
+  @param[in]      AddressEncMask        Address Encryption Mask.
+  @param[in, out] PageEntry1G           Pointer to 1G page entry.
+
+**/
+VOID
+Split1GPageTo2MPageOnEncRange (
+  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
+  IN UINT64                             AddressEncMask,
+  IN OUT UINT64                         *PageEntry1G
+  )
+{
+  EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
+  UINTN                                 IndexOfPageDirectoryEntries;
+  PAGE_TABLE_2M_ENTRY                   *PageDirectoryEntry;
+
+  PageDirectoryEntry = (PAGE_TABLE_2M_ENTRY *)AllocatePages (1);  
+ ASSERT (PageDirectoryEntry != NULL);
+
+  //
+  // Fill in 1G page entry.
+  //
+  *PageEntry1G = (UINT64)(UINTN) PageDirectoryEntry | AddressEncMask | 
+ IA32_PG_P | IA32_PG_RW;
+
+  PhysicalAddress2M = PhysicalAddress;
+  for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
+    //
+    // Fill in the Page Directory entries
+    //
+    PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | AddressEncMask;
+    PageDirectoryEntry->Bits.ReadWrite = 1;
+    PageDirectoryEntry->Bits.Present = 1;
+    PageDirectoryEntry->Bits.MustBe1 = 1;
+  }
+}
+
+
+/**
+  Convert Encryption on page table entry.
+
+  @param  PageTableEntry         Start address of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+**/
+VOID
+ConvertEncryptionOnPageTableEntry (
+  IN UINT64              *PageTableEntry,
+  IN ADDR_ENC_OPERATION  Operation,
+  IN UINT64              AddressEncMask
+  )
+{
+  if (Operation == CLEAR_ADDR_ENC_OPERATION) {
+    *PageTableEntry &= ~AddressEncMask;
+  } else if (Operation == SET_ADDR_ENC_OPERATION) {
+    *PageTableEntry |= AddressEncMask;
+  }
+}
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
new file mode 100644
index 0000000..4781900
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
@@ -0,0 +1,115 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made 
+available under the terms and conditions of the BSD License which 
+accompanies this distribution.  The full text of the license may be 
+found at http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Convert Encryption on address range.
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified range.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  )
+{
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+  UINT64                *PageTable;
+  UINTN                 PTIndex;
+  UINT64                Cr3;
+
+  // Do we have actual work to do?
+  if (Length == 0 || AddressEncMask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // PAE *must* be enabled on 32-bit page tables  // (else we can't 
+ configure AddressEncMask)  if ((AsmReadCr4 () & BIT5) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // Make sure we're PAGE_SIZE aligned
+  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate Operation
+  if (Operation >= INVALID_ENC_OPERATION) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Cr3 = AsmReadCr3 ();
+  PhysicalAddress = BaseAddress;
+
+  do {
+    // PDPE Present?
+    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 30, 31);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // PDE Present?
+    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // Is it a 2MB page entry?
+    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+      if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
+        // Consume 2MB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_2MB;
+        Length -= SIZE_2MB;
+      } else {
+        // Split 2MB page entry to consume 4K chunks
+        Split2MPageTo4KPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+      }
+    } else {
+      // PTE Present?
+      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+      PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
+      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+        return EFI_NO_MAPPING;
+      }
+
+      // Consume 4KB from the range
+      ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+      PhysicalAddress += SIZE_4KB;
+      Length -= SIZE_4KB;
+    }
+  } while (Length);
+
+  // Flush TLB
+  AsmWriteCr3 (Cr3);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
new file mode 100644
index 0000000..5943f7a
--- /dev/null
+++ b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
@@ -0,0 +1,129 @@
+/** @file
+  The file contains helper functions used by GCD.
+
+Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+This program and the accompanying materials are licensed and made 
+available under the terms and conditions of the BSD License which 
+accompanies this distribution.  The full text of the license may be 
+found at http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeMain.h"
+#include "GcdHelper.h"
+
+
+/**
+  Convert Encryption on address range.
+
+  @param  BaseAddress            Start address of the range
+  @param  Length                 Length of the range
+  @param  Operation              Convertion operation (set or clear)
+  @param  AddressEncMask         Address Encryption Mask
+
+  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on EFI_PAGE_SIZE boundary.
+  @retval EFI_NO_MAPPING         Missing page table mappings for the specified range.
+  @retval EFI_SUCCESS            Action successfully done.
+**/
+EFI_STATUS
+ConvertEncryptionOnAddressRange (
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
+  IN UINT64                Length,
+  IN ADDR_ENC_OPERATION    Operation,
+  IN UINT64                AddressEncMask
+  )
+{
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+  UINT64                *PageTable;
+  UINTN                 PTIndex;
+  UINT64                Cr3;
+
+  // Do we have actual work to do?
+  if (Length == 0 || AddressEncMask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // Make sure we're PAGE_SIZE aligned
+  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate Operation
+  if (Operation >= INVALID_ENC_OPERATION) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Cr3 = AsmReadCr3 ();
+  PhysicalAddress = BaseAddress;
+
+  do {
+    // PML4E Present?
+    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 39, 47);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // PDPE Present?
+    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+    PTIndex = BitFieldRead64(PhysicalAddress, 30, 38);
+    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+      return EFI_NO_MAPPING;
+    }
+
+    // Is it a 1GB page entry?
+    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+      if ((PhysicalAddress & (SIZE_1GB - 1)) == 0 && Length >= SIZE_1GB) {
+        // Consume 1GB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_1GB;
+        Length -= SIZE_1GB;
+      } else {
+        // Split 1G page entry to attempt consuming 2MB chunks
+        Split1GPageTo2MPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+      }
+    } else {
+      // PDE Present?
+      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+      PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
+      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+        return EFI_NO_MAPPING;
+      }
+
+      // Is it a 2MB page entry?
+      if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
+        if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
+          // Consume 2MB from the range
+          ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+          PhysicalAddress += SIZE_2MB;
+          Length -= SIZE_2MB;
+        } else {
+          // Split 2MB page entry to consume 4K chunks
+          Split2MPageTo4KPageOnEncRange (PhysicalAddress, AddressEncMask, &PageTable[PTIndex]); 
+        }
+      } else {
+        // PTE Present?
+        PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+        PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
+        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+          return EFI_NO_MAPPING;
+        }
+
+        // Consume 4KB from the range
+        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation, AddressEncMask);
+        PhysicalAddress += SIZE_4KB;
+        Length -= SIZE_4KB;
+      }
+    }
+  } while (Length);
+
+  // Flush TLB
+  AsmWriteCr3 (Cr3);
+
+  return EFI_SUCCESS;
+}
+
--
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
Posted by Yao, Jiewen 7 years, 7 months ago
Hi Duran
I have a little concern about this patch, because we do not introduce any CPU specific thing in DxeCore so far.

I think the basic requirement for SEV is to encrypt system memory, but not MMIO. (Please correct me if I am wrong.)

If that is the case, I would like to propose another solution for your consideration.

1) In PEI phage, a platform should report PI resource description hob to describe system resource, including system memory, and MMIO.

2) The DxeIpl can be updated to parse the PI resource description hob to get all system memory (DRAM) and MMIO. The DxeIpl can setup page table based upon the SEV policy on DRAM/MMIO. I think we should set SEV mask for DRAM (no matter it is tested or untested), but always clear SEV mask for MMIO and all rest.

3) When DxeCore gets control, the page table only has DRAM as encrypted, all rest MMIO as decrypted.

4) In DXE phase, if a platform module wants to add new DRAM resource, the entity which submit ADD request needs to update page table. (NOTE: If a platform just want to convert an UNTESTED DRAM to a TESTED DRAM, this entity does not update page table, because it is already encrypted in DxeIpl.) If a platform module wants to add new MMIO resource, this entity does not update table, because it is already decrypted in DxeIpl.)

Can above flow meet the AMD SEV requirement?

Thank you
Yao Jiewen



> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Zeng,
> Star
> Sent: Friday, March 24, 2017 3:20 PM
> To: Leo Duran <leo.duran@amd.com>; edk2-devel@ml01.01.org
> Cc: Tian, Feng <feng.tian@intel.com>; Brijesh Singh <brijesh.singh@amd.com>;
> Zeng, Star <star.zeng@intel.com>
> Subject: Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on
> MMIO regions
> 
> I have comments below.
> 
> 1. Why need to call ConvertEncryptionOnAddressRange() at
> GCD_FREE_MEMORY_OPERATION case? GCD_FREE_MEMORY_OPERATION does
> not change the Entry->GcdMemoryType.
> 2. I think it is better to use if (Entry->GcdMemoryType ==
> EfiGcdMemoryTypeMemoryMappedIo) instead of if (Entry->Capabilities &
> EFI_MEMORY_PORT_IO) for GCD_REMOVE_MEMORY_OPERATION case.
> 3. Why need to use PAGING_4K_ADDRESS_MASK_64 in GcdHelper.c? Why need
> to define PAGING_2M_ADDRESS_MASK_64?
> 4. Why need to unmask Cr3 like below in GcdHelper.c? The PageTables is not
> masked at DxeIpl before written to CR3. Only the table entry needs to be
> unmask in GcdHelper.c, right?
>   GcdHelper.c: Cr3 & ~AddressEncMask
>   DxeIpl: AsmWriteCr3 (PageTables);
> 5. Do you need to add dummy GcdHelper.c for other archs? Do you need to put
> GcdHelperCommon.c and GcdHelper.h under the arch IA32 and X64 as other
> archs do not need them?
> 
> 
> Thanks,
> Star
> -----Original Message-----
> From: Leo Duran [mailto:leo.duran@amd.com]
> Sent: Friday, March 24, 2017 10:51 AM
> To: edk2-devel@ml01.01.org
> Cc: Leo Duran <leo.duran@amd.com>; Tian, Feng <feng.tian@intel.com>; Zeng,
> Star <star.zeng@intel.com>; Brijesh Singh <brijesh.singh@amd.com>
> Subject: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
> 
> This patch intercepts MMIO configuration in the GCD module to ensure those
> regions are unmasked.
> 
> Cc: Feng Tian <feng.tian@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Leo Duran <leo.duran@amd.com>
> ---
>  MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
>  MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
>  MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151
> ++++++++++++++++++++++++++++
>  MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120
> ++++++++++++++++++++++  MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> | 115 +++++++++++++++++++++
>  MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129
> ++++++++++++++++++++++++
>  6 files changed, 554 insertions(+)
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> 
> diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf
> b/MdeModulePkg/Core/Dxe/DxeMain.inf
> index 30d5984..183d1e7 100644
> --- a/MdeModulePkg/Core/Dxe/DxeMain.inf
> +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
> @@ -4,6 +4,8 @@
>  #  It provides an implementation of DXE Core that is compliant with DXE CIS.
>  #
>  #  Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> #
>  #  This program and the accompanying materials  #  are licensed and made
> available under the terms and conditions of the BSD License  #  which
> accompanies this distribution.  The full text of the license may be found at @@
> -51,6 +53,8 @@
>    Hand/Handle.h
>    Gcd/Gcd.c
>    Gcd/Gcd.h
> +  Gcd/GcdHelperCommon.c
> +  Gcd/GcdHelper.h
>    Mem/Pool.c
>    Mem/Page.c
>    Mem/MemData.c
> @@ -73,6 +77,12 @@
>    DxeMain/DxeProtocolNotify.c
>    DxeMain/DxeMain.c
> 
> +[Sources.Ia32]
> +  Gcd/Ia32/GcdHelper.c
> +
> +[Sources.X64]
> +  Gcd/X64/GcdHelper.c
> +
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> @@ -192,6 +202,7 @@
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
> ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy
> ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy
> ## CONSUMES
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
> ## CONSUMES
> 
>  # [Hob]
>  # RESOURCE_DESCRIPTOR   ## CONSUMES
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index a06f8bb..6f85c21 100644
> --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> @@ -4,6 +4,8 @@
>    are accessible to the CPU that is executing the DXE core.
> 
>  Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
>  This program and the accompanying materials  are licensed and made available
> under the terms and conditions of the BSD License  which accompanies this
> distribution.  The full text of the license may be found at @@ -16,6 +18,7 @@
> WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
> IMPLIED.
> 
>  #include "DxeMain.h"
>  #include "Gcd.h"
> +#include "GcdHelper.h"
> 
>  #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
> 
> @@ -723,6 +726,7 @@ CoreConvertSpace (
>    LIST_ENTRY         *StartLink;
>    LIST_ENTRY         *EndLink;
>    UINT64             CpuArchAttributes;
> +  UINT64             AddressEncMask;
> 
>    if (Length == 0) {
>      DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER)); @@
> -741,6 +745,11 @@ CoreConvertSpace (
>    }
> 
>    //
> +  // Make sure AddressEncMask is contained to smallest supported address
> field.
> +  //
> +  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
> + PAGING_1G_ADDRESS_MASK_64;
> +
> +  //
>    // Search for the list of descriptors that cover the range BaseAddress to
> BaseAddress+Length
>    //
>    Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink,
> &EndLink, Map); @@ -893,6 +902,11 @@ CoreConvertSpace (
>        Entry->GcdMemoryType = GcdMemoryType;
>        if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
>          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME |
> EFI_MEMORY_PORT_IO;
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length,
> CLEAR_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not CLEAR EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
>        } else {
>          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
>        }
> @@ -904,6 +918,13 @@ CoreConvertSpace (
>      // Free operations
>      //
>      case GCD_FREE_MEMORY_OPERATION:
> +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length,
> SET_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
> +      }
>      case GCD_FREE_IO_OPERATION:
>        Entry->ImageHandle  = NULL;
>        Entry->DeviceHandle = NULL;
> @@ -912,6 +933,13 @@ CoreConvertSpace (
>      // Remove operations
>      //
>      case GCD_REMOVE_MEMORY_OPERATION:
> +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, Length,
> SET_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
> +      }
>        Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
>        Entry->Capabilities  = 0;
>        break;
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> new file mode 100644
> index 0000000..d6ec339
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> @@ -0,0 +1,151 @@
> +/** @file
> +  Definitions for helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made
> +available under the terms and conditions of the BSD License which
> +accompanies this distribution.  The full text of the license may be
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _GCD_HELPER_H_
> +#define _GCD_HELPER_H_
> +
> +
> +#pragma pack(1)
> +//
> +// Page Table Entry 4KB
> +//
> +typedef union {
> +  struct {
> +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> Present in memory
> +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> 1=Write-Through caching
> +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> (set by CPU)
> +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> processor on access to page
> +    UINT64  PAT:1;                    //
> +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> page TLB not cleared on CR3 write
> +    UINT64  Available:3;              // Available for use by system
> software
> +    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
> +    UINT64  AvailableHigh:11;         // Available for use by system
> software
> +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_4K_ENTRY;
> +
> +//
> +// Page Table Entry 2MB
> +//
> +typedef union {
> +  struct {
> +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> Present in memory
> +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> 1=Write-Through caching
> +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> (set by CPU)
> +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> processor on access to page
> +    UINT64  MustBe1:1;                // Must be 1
> +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> page TLB not cleared on CR3 write
> +    UINT64  Available:3;              // Available for use by system
> software
> +    UINT64  PAT:1;                    //
> +    UINT64  MustBeZero:8;             // Must be zero;
> +    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
> +    UINT64  AvailableHigh:11;         // Available for use by system
> software
> +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_2M_ENTRY;
> +#pragma pack()
> +
> +
> +typedef enum {
> +  CLEAR_ADDR_ENC_OPERATION,
> +  SET_ADDR_ENC_OPERATION,
> +  INVALID_ENC_OPERATION
> +} ADDR_ENC_OPERATION;
> +
> +
> +#define IA32_PG_P                  BIT0
> +#define IA32_PG_RW                 BIT1
> +#define IA32_PG_PS                 BIT7
> +
> +#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull #define
> +PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull #define
> +PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
> +
> +
> +/**
> +  Convert Encryption on address range
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the segment
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified segment.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  );
> +
> +/**
> +  Convert Encryption on page table entry.
> +
> +  @param  PageTableEntry         Start address of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +**/
> +VOID
> +ConvertEncryptionOnPageTableEntry (
> +  IN UINT64              *PageTableEntry,
> +  IN ADDR_ENC_OPERATION  Operation,
> +  IN UINT64              AddressEncMask
> +  );
> +
> +/**
> +  Split 1G page to 2M on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the encryted range.
> +  @param[in]      AddressEncMask        Address Encryption Mask.
> +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> +
> +**/
> +VOID
> +Split1GPageTo2MPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry1G
> +  );
> +
> +/**
> +  Split 2M page to 4K on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the range.
> +  @param[in]      AddressEncmask        Encryption Mask.
> +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> +
> +**/
> +VOID
> +Split2MPageTo4KPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry2M
> +  );
> +
> +#endif // _GCD_HELPER_H_
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> new file mode 100644
> index 0000000..1660732
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> @@ -0,0 +1,120 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made
> +available under the terms and conditions of the BSD License which
> +accompanies this distribution.  The full text of the license may be
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Split 2M page to 4K on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the range.
> +  @param[in]      AddressEncmask        Encryption Mask.
> +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> +
> +**/
> +VOID
> +Split2MPageTo4KPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry2M
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
> +  UINTN                                 IndexOfPageTableEntries;
> +  PAGE_TABLE_4K_ENTRY                   *PageTableEntry;
> +
> +  PageTableEntry = (PAGE_TABLE_4K_ENTRY *)AllocatePages (1);  ASSERT
> + (PageTableEntry != NULL);
> +
> +  //
> +  // Fill in 2M page entry.
> +  //
> +  *PageEntry2M = (UINT64)(UINTN) PageTableEntry | AddressEncMask |
> + IA32_PG_P | IA32_PG_RW;
> +
> +  PhysicalAddress4K = PhysicalAddress;
> +  for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512;
> IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB)
> {
> +    //
> +    // Fill in the Page Table entries
> +    //
> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> +    PageTableEntry->Bits.ReadWrite = 1;
> +    PageTableEntry->Bits.Present = 1;
> +  }
> +}
> +
> +
> +/**
> +  Split 1G page to 2M on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the encryted range.
> +  @param[in]      AddressEncMask        Address Encryption Mask.
> +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> +
> +**/
> +VOID
> +Split1GPageTo2MPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry1G
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
> +  UINTN                                 IndexOfPageDirectoryEntries;
> +  PAGE_TABLE_2M_ENTRY                   *PageDirectoryEntry;
> +
> +  PageDirectoryEntry = (PAGE_TABLE_2M_ENTRY *)AllocatePages (1);
> + ASSERT (PageDirectoryEntry != NULL);
> +
> +  //
> +  // Fill in 1G page entry.
> +  //
> +  *PageEntry1G = (UINT64)(UINTN) PageDirectoryEntry | AddressEncMask |
> + IA32_PG_P | IA32_PG_RW;
> +
> +  PhysicalAddress2M = PhysicalAddress;
> +  for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M +=
> SIZE_2MB) {
> +    //
> +    // Fill in the Page Directory entries
> +    //
> +    PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M |
> AddressEncMask;
> +    PageDirectoryEntry->Bits.ReadWrite = 1;
> +    PageDirectoryEntry->Bits.Present = 1;
> +    PageDirectoryEntry->Bits.MustBe1 = 1;
> +  }
> +}
> +
> +
> +/**
> +  Convert Encryption on page table entry.
> +
> +  @param  PageTableEntry         Start address of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +**/
> +VOID
> +ConvertEncryptionOnPageTableEntry (
> +  IN UINT64              *PageTableEntry,
> +  IN ADDR_ENC_OPERATION  Operation,
> +  IN UINT64              AddressEncMask
> +  )
> +{
> +  if (Operation == CLEAR_ADDR_ENC_OPERATION) {
> +    *PageTableEntry &= ~AddressEncMask;
> +  } else if (Operation == SET_ADDR_ENC_OPERATION) {
> +    *PageTableEntry |= AddressEncMask;
> +  }
> +}
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> new file mode 100644
> index 0000000..4781900
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> @@ -0,0 +1,115 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made
> +available under the terms and conditions of the BSD License which
> +accompanies this distribution.  The full text of the license may be
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Convert Encryption on address range.
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified range.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> +  UINT64                *PageTable;
> +  UINTN                 PTIndex;
> +  UINT64                Cr3;
> +
> +  // Do we have actual work to do?
> +  if (Length == 0 || AddressEncMask == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // PAE *must* be enabled on 32-bit page tables  // (else we can't
> + configure AddressEncMask)  if ((AsmReadCr4 () & BIT5) == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Make sure we're PAGE_SIZE aligned
> +  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Validate Operation
> +  if (Operation >= INVALID_ENC_OPERATION) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Cr3 = AsmReadCr3 ();
> +  PhysicalAddress = BaseAddress;
> +
> +  do {
> +    // PDPE Present?
> +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 31);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // PDE Present?
> +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask
> & PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // Is it a 2MB page entry?
> +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +      if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> +        // Consume 2MB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_2MB;
> +        Length -= SIZE_2MB;
> +      } else {
> +        // Split 2MB page entry to consume 4K chunks
> +        Split2MPageTo4KPageOnEncRange (PhysicalAddress, AddressEncMask,
> &PageTable[PTIndex]);
> +      }
> +    } else {
> +      // PTE Present?
> +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +      PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +        return EFI_NO_MAPPING;
> +      }
> +
> +      // Consume 4KB from the range
> +      ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], Operation,
> AddressEncMask);
> +      PhysicalAddress += SIZE_4KB;
> +      Length -= SIZE_4KB;
> +    }
> +  } while (Length);
> +
> +  // Flush TLB
> +  AsmWriteCr3 (Cr3);
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> new file mode 100644
> index 0000000..5943f7a
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> @@ -0,0 +1,129 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made
> +available under the terms and conditions of the BSD License which
> +accompanies this distribution.  The full text of the license may be
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Convert Encryption on address range.
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified range.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> +  UINT64                *PageTable;
> +  UINTN                 PTIndex;
> +  UINT64                Cr3;
> +
> +  // Do we have actual work to do?
> +  if (Length == 0 || AddressEncMask == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Make sure we're PAGE_SIZE aligned
> +  if ((BaseAddress & EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Validate Operation
> +  if (Operation >= INVALID_ENC_OPERATION) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Cr3 = AsmReadCr3 ();
> +  PhysicalAddress = BaseAddress;
> +
> +  do {
> +    // PML4E Present?
> +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 39, 47);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // PDPE Present?
> +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & ~AddressEncMask
> & PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 38);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // Is it a 1GB page entry?
> +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +      if ((PhysicalAddress & (SIZE_1GB - 1)) == 0 && Length >= SIZE_1GB) {
> +        // Consume 1GB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_1GB;
> +        Length -= SIZE_1GB;
> +      } else {
> +        // Split 1G page entry to attempt consuming 2MB chunks
> +        Split1GPageTo2MPageOnEncRange (PhysicalAddress, AddressEncMask,
> &PageTable[PTIndex]);
> +      }
> +    } else {
> +      // PDE Present?
> +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +      PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +        return EFI_NO_MAPPING;
> +      }
> +
> +      // Is it a 2MB page entry?
> +      if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +        if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> +          // Consume 2MB from the range
> +          ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +          PhysicalAddress += SIZE_2MB;
> +          Length -= SIZE_2MB;
> +        } else {
> +          // Split 2MB page entry to consume 4K chunks
> +          Split2MPageTo4KPageOnEncRange (PhysicalAddress,
> AddressEncMask, &PageTable[PTIndex]);
> +        }
> +      } else {
> +        // PTE Present?
> +        PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +        PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> +        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +          return EFI_NO_MAPPING;
> +        }
> +
> +        // Consume 4KB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_4KB;
> +        Length -= SIZE_4KB;
> +      }
> +    }
> +  } while (Length);
> +
> +  // Flush TLB
> +  AsmWriteCr3 (Cr3);
> +
> +  return EFI_SUCCESS;
> +}
> +
> --
> 2.7.4
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
Posted by Zeng, Star 7 years, 7 months ago
Jiewen,

I like the solution you proposed. :)

Thanks,
Star
-----Original Message-----
From: Yao, Jiewen 
Sent: Friday, March 24, 2017 3:49 PM
To: Zeng, Star <star.zeng@intel.com>; Leo Duran <leo.duran@amd.com>; edk2-devel@ml01.01.org
Cc: Tian, Feng <feng.tian@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Zeng, Star <star.zeng@intel.com>
Subject: RE: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions

Hi Duran
I have a little concern about this patch, because we do not introduce any CPU specific thing in DxeCore so far.

I think the basic requirement for SEV is to encrypt system memory, but not MMIO. (Please correct me if I am wrong.)

If that is the case, I would like to propose another solution for your consideration.

1) In PEI phage, a platform should report PI resource description hob to describe system resource, including system memory, and MMIO.

2) The DxeIpl can be updated to parse the PI resource description hob to get all system memory (DRAM) and MMIO. The DxeIpl can setup page table based upon the SEV policy on DRAM/MMIO. I think we should set SEV mask for DRAM (no matter it is tested or untested), but always clear SEV mask for MMIO and all rest.

3) When DxeCore gets control, the page table only has DRAM as encrypted, all rest MMIO as decrypted.

4) In DXE phase, if a platform module wants to add new DRAM resource, the entity which submit ADD request needs to update page table. (NOTE: If a platform just want to convert an UNTESTED DRAM to a TESTED DRAM, this entity does not update page table, because it is already encrypted in DxeIpl.) If a platform module wants to add new MMIO resource, this entity does not update table, because it is already decrypted in DxeIpl.)

Can above flow meet the AMD SEV requirement?

Thank you
Yao Jiewen



> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of 
> Zeng, Star
> Sent: Friday, March 24, 2017 3:20 PM
> To: Leo Duran <leo.duran@amd.com>; edk2-devel@ml01.01.org
> Cc: Tian, Feng <feng.tian@intel.com>; Brijesh Singh 
> <brijesh.singh@amd.com>; Zeng, Star <star.zeng@intel.com>
> Subject: Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on 
> MMIO regions
> 
> I have comments below.
> 
> 1. Why need to call ConvertEncryptionOnAddressRange() at 
> GCD_FREE_MEMORY_OPERATION case? GCD_FREE_MEMORY_OPERATION does not 
> change the Entry->GcdMemoryType.
> 2. I think it is better to use if (Entry->GcdMemoryType ==
> EfiGcdMemoryTypeMemoryMappedIo) instead of if (Entry->Capabilities &
> EFI_MEMORY_PORT_IO) for GCD_REMOVE_MEMORY_OPERATION case.
> 3. Why need to use PAGING_4K_ADDRESS_MASK_64 in GcdHelper.c? Why need 
> to define PAGING_2M_ADDRESS_MASK_64?
> 4. Why need to unmask Cr3 like below in GcdHelper.c? The PageTables is 
> not masked at DxeIpl before written to CR3. Only the table entry needs 
> to be unmask in GcdHelper.c, right?
>   GcdHelper.c: Cr3 & ~AddressEncMask
>   DxeIpl: AsmWriteCr3 (PageTables);
> 5. Do you need to add dummy GcdHelper.c for other archs? Do you need 
> to put GcdHelperCommon.c and GcdHelper.h under the arch IA32 and X64 
> as other archs do not need them?
> 
> 
> Thanks,
> Star
> -----Original Message-----
> From: Leo Duran [mailto:leo.duran@amd.com]
> Sent: Friday, March 24, 2017 10:51 AM
> To: edk2-devel@ml01.01.org
> Cc: Leo Duran <leo.duran@amd.com>; Tian, Feng <feng.tian@intel.com>; 
> Zeng, Star <star.zeng@intel.com>; Brijesh Singh 
> <brijesh.singh@amd.com>
> Subject: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
> 
> This patch intercepts MMIO configuration in the GCD module to ensure 
> those regions are unmasked.
> 
> Cc: Feng Tian <feng.tian@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Leo Duran <leo.duran@amd.com>
> ---
>  MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
>  MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
>  MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151
> ++++++++++++++++++++++++++++
>  MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120
> ++++++++++++++++++++++  MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> | 115 +++++++++++++++++++++
>  MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129
> ++++++++++++++++++++++++
>  6 files changed, 554 insertions(+)
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
>  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> 
> diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf
> b/MdeModulePkg/Core/Dxe/DxeMain.inf
> index 30d5984..183d1e7 100644
> --- a/MdeModulePkg/Core/Dxe/DxeMain.inf
> +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
> @@ -4,6 +4,8 @@
>  #  It provides an implementation of DXE Core that is compliant with DXE CIS.
>  #
>  #  Copyright (c) 2006 - 2017, Intel Corporation. All rights 
> reserved.<BR>
> +#  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> #
>  #  This program and the accompanying materials  #  are licensed and 
> made available under the terms and conditions of the BSD License  #  
> which accompanies this distribution.  The full text of the license may 
> be found at @@
> -51,6 +53,8 @@
>    Hand/Handle.h
>    Gcd/Gcd.c
>    Gcd/Gcd.h
> +  Gcd/GcdHelperCommon.c
> +  Gcd/GcdHelper.h
>    Mem/Pool.c
>    Mem/Page.c
>    Mem/MemData.c
> @@ -73,6 +77,12 @@
>    DxeMain/DxeProtocolNotify.c
>    DxeMain/DxeMain.c
> 
> +[Sources.Ia32]
> +  Gcd/Ia32/GcdHelper.c
> +
> +[Sources.X64]
> +  Gcd/X64/GcdHelper.c
> +
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> @@ -192,6 +202,7 @@
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
> ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy
> ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy
> ## CONSUMES
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
> ## CONSUMES
> 
>  # [Hob]
>  # RESOURCE_DESCRIPTOR   ## CONSUMES
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c 
> b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index a06f8bb..6f85c21 100644
> --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> @@ -4,6 +4,8 @@
>    are accessible to the CPU that is executing the DXE core.
> 
>  Copyright (c) 2006 - 2017, Intel Corporation. All rights 
> reserved.<BR>
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
>  This program and the accompanying materials  are licensed and made 
> available under the terms and conditions of the BSD License  which 
> accompanies this distribution.  The full text of the license may be 
> found at @@ -16,6 +18,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF 
> ANY KIND, EITHER EXPRESS OR IMPLIED.
> 
>  #include "DxeMain.h"
>  #include "Gcd.h"
> +#include "GcdHelper.h"
> 
>  #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
> 
> @@ -723,6 +726,7 @@ CoreConvertSpace (
>    LIST_ENTRY         *StartLink;
>    LIST_ENTRY         *EndLink;
>    UINT64             CpuArchAttributes;
> +  UINT64             AddressEncMask;
> 
>    if (Length == 0) {
>      DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER)); @@
> -741,6 +745,11 @@ CoreConvertSpace (
>    }
> 
>    //
> +  // Make sure AddressEncMask is contained to smallest supported 
> + address
> field.
> +  //
> +  AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & 
> + PAGING_1G_ADDRESS_MASK_64;
> +
> +  //
>    // Search for the list of descriptors that cover the range 
> BaseAddress to
> BaseAddress+Length
>    //
>    Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, 
> &EndLink, Map); @@ -893,6 +902,11 @@ CoreConvertSpace (
>        Entry->GcdMemoryType = GcdMemoryType;
>        if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
>          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | 
> EFI_MEMORY_PORT_IO;
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, 
> + Length,
> CLEAR_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not CLEAR EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
>        } else {
>          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
>        }
> @@ -904,6 +918,13 @@ CoreConvertSpace (
>      // Free operations
>      //
>      case GCD_FREE_MEMORY_OPERATION:
> +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, 
> + Length,
> SET_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
> +      }
>      case GCD_FREE_IO_OPERATION:
>        Entry->ImageHandle  = NULL;
>        Entry->DeviceHandle = NULL;
> @@ -912,6 +933,13 @@ CoreConvertSpace (
>      // Remove operations
>      //
>      case GCD_REMOVE_MEMORY_OPERATION:
> +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> +        Status = ConvertEncryptionOnAddressRange (BaseAddress, 
> + Length,
> SET_ADDR_ENC_OPERATION, AddressEncMask);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> +            BaseAddress, Length, Status));
> +        }
> +      }
>        Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
>        Entry->Capabilities  = 0;
>        break;
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> new file mode 100644
> index 0000000..d6ec339
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> @@ -0,0 +1,151 @@
> +/** @file
> +  Definitions for helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made 
> +available under the terms and conditions of the BSD License which 
> +accompanies this distribution.  The full text of the license may be 
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#ifndef _GCD_HELPER_H_
> +#define _GCD_HELPER_H_
> +
> +
> +#pragma pack(1)
> +//
> +// Page Table Entry 4KB
> +//
> +typedef union {
> +  struct {
> +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> Present in memory
> +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> 1=Write-Through caching
> +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> (set by CPU)
> +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> processor on access to page
> +    UINT64  PAT:1;                    //
> +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> page TLB not cleared on CR3 write
> +    UINT64  Available:3;              // Available for use by system
> software
> +    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
> +    UINT64  AvailableHigh:11;         // Available for use by system
> software
> +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_4K_ENTRY;
> +
> +//
> +// Page Table Entry 2MB
> +//
> +typedef union {
> +  struct {
> +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> Present in memory
> +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> 1=Write-Through caching
> +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> (set by CPU)
> +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> processor on access to page
> +    UINT64  MustBe1:1;                // Must be 1
> +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> page TLB not cleared on CR3 write
> +    UINT64  Available:3;              // Available for use by system
> software
> +    UINT64  PAT:1;                    //
> +    UINT64  MustBeZero:8;             // Must be zero;
> +    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
> +    UINT64  AvailableHigh:11;         // Available for use by system
> software
> +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_2M_ENTRY;
> +#pragma pack()
> +
> +
> +typedef enum {
> +  CLEAR_ADDR_ENC_OPERATION,
> +  SET_ADDR_ENC_OPERATION,
> +  INVALID_ENC_OPERATION
> +} ADDR_ENC_OPERATION;
> +
> +
> +#define IA32_PG_P                  BIT0
> +#define IA32_PG_RW                 BIT1
> +#define IA32_PG_PS                 BIT7
> +
> +#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull #define
> +PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull #define
> +PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
> +
> +
> +/**
> +  Convert Encryption on address range
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the segment
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified segment.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  );
> +
> +/**
> +  Convert Encryption on page table entry.
> +
> +  @param  PageTableEntry         Start address of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +**/
> +VOID
> +ConvertEncryptionOnPageTableEntry (
> +  IN UINT64              *PageTableEntry,
> +  IN ADDR_ENC_OPERATION  Operation,
> +  IN UINT64              AddressEncMask
> +  );
> +
> +/**
> +  Split 1G page to 2M on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the encryted range.
> +  @param[in]      AddressEncMask        Address Encryption Mask.
> +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> +
> +**/
> +VOID
> +Split1GPageTo2MPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry1G
> +  );
> +
> +/**
> +  Split 2M page to 4K on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the range.
> +  @param[in]      AddressEncmask        Encryption Mask.
> +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> +
> +**/
> +VOID
> +Split2MPageTo4KPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry2M
> +  );
> +
> +#endif // _GCD_HELPER_H_
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> new file mode 100644
> index 0000000..1660732
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> @@ -0,0 +1,120 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made 
> +available under the terms and conditions of the BSD License which 
> +accompanies this distribution.  The full text of the license may be 
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Split 2M page to 4K on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the range.
> +  @param[in]      AddressEncmask        Encryption Mask.
> +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> +
> +**/
> +VOID
> +Split2MPageTo4KPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry2M
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
> +  UINTN                                 IndexOfPageTableEntries;
> +  PAGE_TABLE_4K_ENTRY                   *PageTableEntry;
> +
> +  PageTableEntry = (PAGE_TABLE_4K_ENTRY *)AllocatePages (1);  ASSERT 
> + (PageTableEntry != NULL);
> +
> +  //
> +  // Fill in 2M page entry.
> +  //
> +  *PageEntry2M = (UINT64)(UINTN) PageTableEntry | AddressEncMask | 
> + IA32_PG_P | IA32_PG_RW;
> +
> +  PhysicalAddress4K = PhysicalAddress;  for (IndexOfPageTableEntries 
> + = 0; IndexOfPageTableEntries < 512;
> IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += 
> IndexOfPageTableEntries++SIZE_4KB)
> {
> +    //
> +    // Fill in the Page Table entries
> +    //
> +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
> +    PageTableEntry->Bits.ReadWrite = 1;
> +    PageTableEntry->Bits.Present = 1;
> +  }
> +}
> +
> +
> +/**
> +  Split 1G page to 2M on Encrypted address range.
> +
> +  @param[in]      PhysicalAddress       Address of the encryted range.
> +  @param[in]      AddressEncMask        Address Encryption Mask.
> +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> +
> +**/
> +VOID
> +Split1GPageTo2MPageOnEncRange (
> +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> +  IN UINT64                             AddressEncMask,
> +  IN OUT UINT64                         *PageEntry1G
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
> +  UINTN                                 IndexOfPageDirectoryEntries;
> +  PAGE_TABLE_2M_ENTRY                   *PageDirectoryEntry;
> +
> +  PageDirectoryEntry = (PAGE_TABLE_2M_ENTRY *)AllocatePages (1); 
> + ASSERT (PageDirectoryEntry != NULL);
> +
> +  //
> +  // Fill in 1G page entry.
> +  //
> +  *PageEntry1G = (UINT64)(UINTN) PageDirectoryEntry | AddressEncMask 
> + | IA32_PG_P | IA32_PG_RW;
> +
> +  PhysicalAddress2M = PhysicalAddress;  for 
> + (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M 
> IndexOfPageDirectoryEntries+++=
> SIZE_2MB) {
> +    //
> +    // Fill in the Page Directory entries
> +    //
> +    PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M |
> AddressEncMask;
> +    PageDirectoryEntry->Bits.ReadWrite = 1;
> +    PageDirectoryEntry->Bits.Present = 1;
> +    PageDirectoryEntry->Bits.MustBe1 = 1;
> +  }
> +}
> +
> +
> +/**
> +  Convert Encryption on page table entry.
> +
> +  @param  PageTableEntry         Start address of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +**/
> +VOID
> +ConvertEncryptionOnPageTableEntry (
> +  IN UINT64              *PageTableEntry,
> +  IN ADDR_ENC_OPERATION  Operation,
> +  IN UINT64              AddressEncMask
> +  )
> +{
> +  if (Operation == CLEAR_ADDR_ENC_OPERATION) {
> +    *PageTableEntry &= ~AddressEncMask;
> +  } else if (Operation == SET_ADDR_ENC_OPERATION) {
> +    *PageTableEntry |= AddressEncMask;
> +  }
> +}
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> new file mode 100644
> index 0000000..4781900
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> @@ -0,0 +1,115 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made 
> +available under the terms and conditions of the BSD License which 
> +accompanies this distribution.  The full text of the license may be 
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Convert Encryption on address range.
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified range.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> +  UINT64                *PageTable;
> +  UINTN                 PTIndex;
> +  UINT64                Cr3;
> +
> +  // Do we have actual work to do?
> +  if (Length == 0 || AddressEncMask == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // PAE *must* be enabled on 32-bit page tables  // (else we can't 
> + configure AddressEncMask)  if ((AsmReadCr4 () & BIT5) == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Make sure we're PAGE_SIZE aligned  if ((BaseAddress & 
> + EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Validate Operation
> +  if (Operation >= INVALID_ENC_OPERATION) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Cr3 = AsmReadCr3 ();
> +  PhysicalAddress = BaseAddress;
> +
> +  do {
> +    // PDPE Present?
> +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 31);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // PDE Present?
> +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & 
> + ~AddressEncMask
> & PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // Is it a 2MB page entry?
> +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +      if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> +        // Consume 2MB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_2MB;
> +        Length -= SIZE_2MB;
> +      } else {
> +        // Split 2MB page entry to consume 4K chunks
> +        Split2MPageTo4KPageOnEncRange (PhysicalAddress, 
> + AddressEncMask,
> &PageTable[PTIndex]);
> +      }
> +    } else {
> +      // PTE Present?
> +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +      PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +        return EFI_NO_MAPPING;
> +      }
> +
> +      // Consume 4KB from the range
> +      ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex], 
> + Operation,
> AddressEncMask);
> +      PhysicalAddress += SIZE_4KB;
> +      Length -= SIZE_4KB;
> +    }
> +  } while (Length);
> +
> +  // Flush TLB
> +  AsmWriteCr3 (Cr3);
> +
> +  return EFI_SUCCESS;
> +}
> +
> diff --git a/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> new file mode 100644
> index 0000000..5943f7a
> --- /dev/null
> +++ b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> @@ -0,0 +1,129 @@
> +/** @file
> +  The file contains helper functions used by GCD.
> +
> +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +This program and the accompanying materials are licensed and made 
> +available under the terms and conditions of the BSD License which 
> +accompanies this distribution.  The full text of the license may be 
> +found at http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS
> OR IMPLIED.
> +
> +**/
> +
> +#include "DxeMain.h"
> +#include "GcdHelper.h"
> +
> +
> +/**
> +  Convert Encryption on address range.
> +
> +  @param  BaseAddress            Start address of the range
> +  @param  Length                 Length of the range
> +  @param  Operation              Convertion operation (set or clear)
> +  @param  AddressEncMask         Address Encryption Mask
> +
> +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> EFI_PAGE_SIZE boundary.
> +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> specified range.
> +  @retval EFI_SUCCESS            Action successfully done.
> +**/
> +EFI_STATUS
> +ConvertEncryptionOnAddressRange (
> +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> +  IN UINT64                Length,
> +  IN ADDR_ENC_OPERATION    Operation,
> +  IN UINT64                AddressEncMask
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> +  UINT64                *PageTable;
> +  UINTN                 PTIndex;
> +  UINT64                Cr3;
> +
> +  // Do we have actual work to do?
> +  if (Length == 0 || AddressEncMask == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  // Make sure we're PAGE_SIZE aligned  if ((BaseAddress & 
> + EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Validate Operation
> +  if (Operation >= INVALID_ENC_OPERATION) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Cr3 = AsmReadCr3 ();
> +  PhysicalAddress = BaseAddress;
> +
> +  do {
> +    // PML4E Present?
> +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 39, 47);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // PDPE Present?
> +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] & 
> + ~AddressEncMask
> & PAGING_4K_ADDRESS_MASK_64);
> +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 38);
> +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +      return EFI_NO_MAPPING;
> +    }
> +
> +    // Is it a 1GB page entry?
> +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +      if ((PhysicalAddress & (SIZE_1GB - 1)) == 0 && Length >= SIZE_1GB) {
> +        // Consume 1GB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_1GB;
> +        Length -= SIZE_1GB;
> +      } else {
> +        // Split 1G page entry to attempt consuming 2MB chunks
> +        Split1GPageTo2MPageOnEncRange (PhysicalAddress, 
> + AddressEncMask,
> &PageTable[PTIndex]);
> +      }
> +    } else {
> +      // PDE Present?
> +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +      PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +        return EFI_NO_MAPPING;
> +      }
> +
> +      // Is it a 2MB page entry?
> +      if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> +        if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> +          // Consume 2MB from the range
> +          ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +          PhysicalAddress += SIZE_2MB;
> +          Length -= SIZE_2MB;
> +        } else {
> +          // Split 2MB page entry to consume 4K chunks
> +          Split2MPageTo4KPageOnEncRange (PhysicalAddress,
> AddressEncMask, &PageTable[PTIndex]);
> +        }
> +      } else {
> +        // PTE Present?
> +        PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +        PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> +        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> +          return EFI_NO_MAPPING;
> +        }
> +
> +        // Consume 4KB from the range
> +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> Operation, AddressEncMask);
> +        PhysicalAddress += SIZE_4KB;
> +        Length -= SIZE_4KB;
> +      }
> +    }
> +  } while (Length);
> +
> +  // Flush TLB
> +  AsmWriteCr3 (Cr3);
> +
> +  return EFI_SUCCESS;
> +}
> +
> --
> 2.7.4
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO regions
Posted by Duran, Leo 7 years, 7 months ago
Jiewen, Star,
Thanks for the prompt & detailed review. I'll certainly consider your feedback.
Leo.

> -----Original Message-----
> From: Zeng, Star [mailto:star.zeng@intel.com]
> Sent: Friday, March 24, 2017 2:57 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; Duran, Leo
> <leo.duran@amd.com>; edk2-devel@ml01.01.org
> Cc: Tian, Feng <feng.tian@intel.com>; Singh, Brijesh
> <brijesh.singh@amd.com>; Zeng, Star <star.zeng@intel.com>
> Subject: RE: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO
> regions
> 
> Jiewen,
> 
> I like the solution you proposed. :)
> 
> Thanks,
> Star
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Friday, March 24, 2017 3:49 PM
> To: Zeng, Star <star.zeng@intel.com>; Leo Duran <leo.duran@amd.com>;
> edk2-devel@ml01.01.org
> Cc: Tian, Feng <feng.tian@intel.com>; Brijesh Singh
> <brijesh.singh@amd.com>; Zeng, Star <star.zeng@intel.com>
> Subject: RE: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO
> regions
> 
> Hi Duran
> I have a little concern about this patch, because we do not introduce any CPU
> specific thing in DxeCore so far.
> 
> I think the basic requirement for SEV is to encrypt system memory, but not
> MMIO. (Please correct me if I am wrong.)
> 
> If that is the case, I would like to propose another solution for your
> consideration.
> 
> 1) In PEI phage, a platform should report PI resource description hob to
> describe system resource, including system memory, and MMIO.
> 
> 2) The DxeIpl can be updated to parse the PI resource description hob to get
> all system memory (DRAM) and MMIO. The DxeIpl can setup page table
> based upon the SEV policy on DRAM/MMIO. I think we should set SEV mask
> for DRAM (no matter it is tested or untested), but always clear SEV mask for
> MMIO and all rest.
> 
> 3) When DxeCore gets control, the page table only has DRAM as encrypted,
> all rest MMIO as decrypted.
> 
> 4) In DXE phase, if a platform module wants to add new DRAM resource, the
> entity which submit ADD request needs to update page table. (NOTE: If a
> platform just want to convert an UNTESTED DRAM to a TESTED DRAM, this
> entity does not update page table, because it is already encrypted in DxeIpl.)
> If a platform module wants to add new MMIO resource, this entity does not
> update table, because it is already decrypted in DxeIpl.)
> 
> Can above flow meet the AMD SEV requirement?
> 
> Thank you
> Yao Jiewen
> 
> 
> 
> > -----Original Message-----
> > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of
> > Zeng, Star
> > Sent: Friday, March 24, 2017 3:20 PM
> > To: Leo Duran <leo.duran@amd.com>; edk2-devel@ml01.01.org
> > Cc: Tian, Feng <feng.tian@intel.com>; Brijesh Singh
> > <brijesh.singh@amd.com>; Zeng, Star <star.zeng@intel.com>
> > Subject: Re: [edk2] [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on
> > MMIO regions
> >
> > I have comments below.
> >
> > 1. Why need to call ConvertEncryptionOnAddressRange() at
> > GCD_FREE_MEMORY_OPERATION case?
> GCD_FREE_MEMORY_OPERATION does not
> > change the Entry->GcdMemoryType.
> > 2. I think it is better to use if (Entry->GcdMemoryType ==
> > EfiGcdMemoryTypeMemoryMappedIo) instead of if (Entry->Capabilities &
> > EFI_MEMORY_PORT_IO) for GCD_REMOVE_MEMORY_OPERATION case.
> > 3. Why need to use PAGING_4K_ADDRESS_MASK_64 in GcdHelper.c? Why
> need
> > to define PAGING_2M_ADDRESS_MASK_64?
> > 4. Why need to unmask Cr3 like below in GcdHelper.c? The PageTables is
> > not masked at DxeIpl before written to CR3. Only the table entry needs
> > to be unmask in GcdHelper.c, right?
> >   GcdHelper.c: Cr3 & ~AddressEncMask
> >   DxeIpl: AsmWriteCr3 (PageTables);
> > 5. Do you need to add dummy GcdHelper.c for other archs? Do you need
> > to put GcdHelperCommon.c and GcdHelper.h under the arch IA32 and X64
> > as other archs do not need them?
> >
> >
> > Thanks,
> > Star
> > -----Original Message-----
> > From: Leo Duran [mailto:leo.duran@amd.com]
> > Sent: Friday, March 24, 2017 10:51 AM
> > To: edk2-devel@ml01.01.org
> > Cc: Leo Duran <leo.duran@amd.com>; Tian, Feng <feng.tian@intel.com>;
> > Zeng, Star <star.zeng@intel.com>; Brijesh Singh
> > <brijesh.singh@amd.com>
> > Subject: [PATCH] MdeModulePkg/Core/Dxe: Clear SEV mask on MMIO
> regions
> >
> > This patch intercepts MMIO configuration in the GCD module to ensure
> > those regions are unmasked.
> >
> > Cc: Feng Tian <feng.tian@intel.com>
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Brijesh Singh <brijesh.singh@amd.com>
> > Contributed-under: TianoCore Contribution Agreement 1.0
> > Signed-off-by: Leo Duran <leo.duran@amd.com>
> > ---
> >  MdeModulePkg/Core/Dxe/DxeMain.inf           |  11 ++
> >  MdeModulePkg/Core/Dxe/Gcd/Gcd.c             |  28 ++++++
> >  MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h       | 151
> > ++++++++++++++++++++++++++++
> >  MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c | 120
> > ++++++++++++++++++++++
> MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> > | 115 +++++++++++++++++++++
> >  MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c   | 129
> > ++++++++++++++++++++++++
> >  6 files changed, 554 insertions(+)
> >  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> >  create mode 100644
> MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> >  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> >  create mode 100644 MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> >
> > diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf
> > b/MdeModulePkg/Core/Dxe/DxeMain.inf
> > index 30d5984..183d1e7 100644
> > --- a/MdeModulePkg/Core/Dxe/DxeMain.inf
> > +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
> > @@ -4,6 +4,8 @@
> >  #  It provides an implementation of DXE Core that is compliant with DXE
> CIS.
> >  #
> >  #  Copyright (c) 2006 - 2017, Intel Corporation. All rights
> > reserved.<BR>
> > +#  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> #
> >  #  This program and the accompanying materials  #  are licensed and
> > made available under the terms and conditions of the BSD License  #
> > which accompanies this distribution.  The full text of the license may
> > be found at @@
> > -51,6 +53,8 @@
> >    Hand/Handle.h
> >    Gcd/Gcd.c
> >    Gcd/Gcd.h
> > +  Gcd/GcdHelperCommon.c
> > +  Gcd/GcdHelper.h
> >    Mem/Pool.c
> >    Mem/Page.c
> >    Mem/MemData.c
> > @@ -73,6 +77,12 @@
> >    DxeMain/DxeProtocolNotify.c
> >    DxeMain/DxeMain.c
> >
> > +[Sources.Ia32]
> > +  Gcd/Ia32/GcdHelper.c
> > +
> > +[Sources.X64]
> > +  Gcd/X64/GcdHelper.c
> > +
> >  [Packages]
> >    MdePkg/MdePkg.dec
> >    MdeModulePkg/MdeModulePkg.dec
> > @@ -192,6 +202,7 @@
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdPropertiesTableEnable
> > ## CONSUMES
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy
> > ## CONSUMES
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy
> > ## CONSUMES
> > +
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrM
> ask
> > ## CONSUMES
> >
> >  # [Hob]
> >  # RESOURCE_DESCRIPTOR   ## CONSUMES
> > diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> > b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index a06f8bb..6f85c21 100644
> > --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> > +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
> > @@ -4,6 +4,8 @@
> >    are accessible to the CPU that is executing the DXE core.
> >
> >  Copyright (c) 2006 - 2017, Intel Corporation. All rights
> > reserved.<BR>
> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> > +
> >  This program and the accompanying materials  are licensed and made
> > available under the terms and conditions of the BSD License  which
> > accompanies this distribution.  The full text of the license may be
> > found at @@ -16,6 +18,7 @@ WITHOUT WARRANTIES OR
> REPRESENTATIONS OF
> > ANY KIND, EITHER EXPRESS OR IMPLIED.
> >
> >  #include "DxeMain.h"
> >  #include "Gcd.h"
> > +#include "GcdHelper.h"
> >
> >  #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
> >
> > @@ -723,6 +726,7 @@ CoreConvertSpace (
> >    LIST_ENTRY         *StartLink;
> >    LIST_ENTRY         *EndLink;
> >    UINT64             CpuArchAttributes;
> > +  UINT64             AddressEncMask;
> >
> >    if (Length == 0) {
> >      DEBUG ((DEBUG_GCD, "  Status = %r\n", EFI_INVALID_PARAMETER));
> @@
> > -741,6 +745,11 @@ CoreConvertSpace (
> >    }
> >
> >    //
> > +  // Make sure AddressEncMask is contained to smallest supported
> > + address
> > field.
> > +  //
> > +  AddressEncMask = PcdGet64
> (PcdPteMemoryEncryptionAddressOrMask) &
> > + PAGING_1G_ADDRESS_MASK_64;
> > +
> > +  //
> >    // Search for the list of descriptors that cover the range
> > BaseAddress to
> > BaseAddress+Length
> >    //
> >    Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink,
> > &EndLink, Map); @@ -893,6 +902,11 @@ CoreConvertSpace (
> >        Entry->GcdMemoryType = GcdMemoryType;
> >        if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
> >          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME |
> > EFI_MEMORY_PORT_IO;
> > +        Status = ConvertEncryptionOnAddressRange (BaseAddress,
> > + Length,
> > CLEAR_ADDR_ENC_OPERATION, AddressEncMask);
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((EFI_D_ERROR, "Could not CLEAR EncMask on Range:
> > BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> > +            BaseAddress, Length, Status));
> > +        }
> >        } else {
> >          Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;
> >        }
> > @@ -904,6 +918,13 @@ CoreConvertSpace (
> >      // Free operations
> >      //
> >      case GCD_FREE_MEMORY_OPERATION:
> > +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> > +        Status = ConvertEncryptionOnAddressRange (BaseAddress,
> > + Length,
> > SET_ADDR_ENC_OPERATION, AddressEncMask);
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> > BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> > +            BaseAddress, Length, Status));
> > +        }
> > +      }
> >      case GCD_FREE_IO_OPERATION:
> >        Entry->ImageHandle  = NULL;
> >        Entry->DeviceHandle = NULL;
> > @@ -912,6 +933,13 @@ CoreConvertSpace (
> >      // Remove operations
> >      //
> >      case GCD_REMOVE_MEMORY_OPERATION:
> > +      if (Entry->Capabilities & EFI_MEMORY_PORT_IO) {
> > +        Status = ConvertEncryptionOnAddressRange (BaseAddress,
> > + Length,
> > SET_ADDR_ENC_OPERATION, AddressEncMask);
> > +        if (EFI_ERROR (Status)) {
> > +          DEBUG ((EFI_D_ERROR, "Could not SET EncMask on Range:
> > BaseAddress = 0xlX, Length = 0xlX, Status = %r\n",
> > +            BaseAddress, Length, Status));
> > +        }
> > +      }
> >        Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
> >        Entry->Capabilities  = 0;
> >        break;
> > diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> > b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> > new file mode 100644
> > index 0000000..d6ec339
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelper.h
> > @@ -0,0 +1,151 @@
> > +/** @file
> > +  Definitions for helper functions used by GCD.
> > +
> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> > +
> > +This program and the accompanying materials are licensed and made
> > +available under the terms and conditions of the BSD License which
> > +accompanies this distribution.  The full text of the license may be
> > +found at http://opensource.org/licenses/bsd-license.php
> > +
> > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS
> > OR IMPLIED.
> > +
> > +**/
> > +
> > +#ifndef _GCD_HELPER_H_
> > +#define _GCD_HELPER_H_
> > +
> > +
> > +#pragma pack(1)
> > +//
> > +// Page Table Entry 4KB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> > Present in memory
> > +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> > +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> > +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> > 1=Write-Through caching
> > +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> > +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> > (set by CPU)
> > +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> > processor on access to page
> > +    UINT64  PAT:1;                    //
> > +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> > page TLB not cleared on CR3 write
> > +    UINT64  Available:3;              // Available for use by system
> > software
> > +    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
> > +    UINT64  AvailableHigh:11;         // Available for use by system
> > software
> > +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> > Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_4K_ENTRY;
> > +
> > +//
> > +// Page Table Entry 2MB
> > +//
> > +typedef union {
> > +  struct {
> > +    UINT64  Present:1;                // 0 = Not present in memory, 1 =
> > Present in memory
> > +    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
> > +    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
> > +    UINT64  WriteThrough:1;           // 0 = Write-Back caching,
> > 1=Write-Through caching
> > +    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
> > +    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed
> > (set by CPU)
> > +    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by
> > processor on access to page
> > +    UINT64  MustBe1:1;                // Must be 1
> > +    UINT64  Global:1;                 // 0 = Not global page, 1 = global
> > page TLB not cleared on CR3 write
> > +    UINT64  Available:3;              // Available for use by system
> > software
> > +    UINT64  PAT:1;                    //
> > +    UINT64  MustBeZero:8;             // Must be zero;
> > +    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
> > +    UINT64  AvailableHigh:11;         // Available for use by system
> > software
> > +    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code
> > Execution
> > +  } Bits;
> > +  UINT64    Uint64;
> > +} PAGE_TABLE_2M_ENTRY;
> > +#pragma pack()
> > +
> > +
> > +typedef enum {
> > +  CLEAR_ADDR_ENC_OPERATION,
> > +  SET_ADDR_ENC_OPERATION,
> > +  INVALID_ENC_OPERATION
> > +} ADDR_ENC_OPERATION;
> > +
> > +
> > +#define IA32_PG_P                  BIT0
> > +#define IA32_PG_RW                 BIT1
> > +#define IA32_PG_PS                 BIT7
> > +
> > +#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull
> #define
> > +PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull #define
> > +PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
> > +
> > +
> > +/**
> > +  Convert Encryption on address range
> > +
> > +  @param  BaseAddress            Start address of the range
> > +  @param  Length                 Length of the segment
> > +  @param  Operation              Convertion operation (set or clear)
> > +  @param  AddressEncMask         Address Encryption Mask
> > +
> > +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> > EFI_PAGE_SIZE boundary.
> > +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> > specified segment.
> > +  @retval EFI_SUCCESS            Action successfully done.
> > +**/
> > +EFI_STATUS
> > +ConvertEncryptionOnAddressRange (
> > +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> > +  IN UINT64                Length,
> > +  IN ADDR_ENC_OPERATION    Operation,
> > +  IN UINT64                AddressEncMask
> > +  );
> > +
> > +/**
> > +  Convert Encryption on page table entry.
> > +
> > +  @param  PageTableEntry         Start address of the range
> > +  @param  Operation              Convertion operation (set or clear)
> > +  @param  AddressEncMask         Address Encryption Mask
> > +
> > +**/
> > +VOID
> > +ConvertEncryptionOnPageTableEntry (
> > +  IN UINT64              *PageTableEntry,
> > +  IN ADDR_ENC_OPERATION  Operation,
> > +  IN UINT64              AddressEncMask
> > +  );
> > +
> > +/**
> > +  Split 1G page to 2M on Encrypted address range.
> > +
> > +  @param[in]      PhysicalAddress       Address of the encryted range.
> > +  @param[in]      AddressEncMask        Address Encryption Mask.
> > +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> > +
> > +**/
> > +VOID
> > +Split1GPageTo2MPageOnEncRange (
> > +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> > +  IN UINT64                             AddressEncMask,
> > +  IN OUT UINT64                         *PageEntry1G
> > +  );
> > +
> > +/**
> > +  Split 2M page to 4K on Encrypted address range.
> > +
> > +  @param[in]      PhysicalAddress       Address of the range.
> > +  @param[in]      AddressEncmask        Encryption Mask.
> > +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> > +
> > +**/
> > +VOID
> > +Split2MPageTo4KPageOnEncRange (
> > +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> > +  IN UINT64                             AddressEncMask,
> > +  IN OUT UINT64                         *PageEntry2M
> > +  );
> > +
> > +#endif // _GCD_HELPER_H_
> > +
> > diff --git a/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> > b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> > new file mode 100644
> > index 0000000..1660732
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/Dxe/Gcd/GcdHelperCommon.c
> > @@ -0,0 +1,120 @@
> > +/** @file
> > +  The file contains helper functions used by GCD.
> > +
> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> > +
> > +This program and the accompanying materials are licensed and made
> > +available under the terms and conditions of the BSD License which
> > +accompanies this distribution.  The full text of the license may be
> > +found at http://opensource.org/licenses/bsd-license.php
> > +
> > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS
> > OR IMPLIED.
> > +
> > +**/
> > +
> > +#include "DxeMain.h"
> > +#include "GcdHelper.h"
> > +
> > +
> > +/**
> > +  Split 2M page to 4K on Encrypted address range.
> > +
> > +  @param[in]      PhysicalAddress       Address of the range.
> > +  @param[in]      AddressEncmask        Encryption Mask.
> > +  @param[in, out] PageEntry2M           Pointer to 2M page entry.
> > +
> > +**/
> > +VOID
> > +Split2MPageTo4KPageOnEncRange (
> > +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> > +  IN UINT64                             AddressEncMask,
> > +  IN OUT UINT64                         *PageEntry2M
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
> > +  UINTN                                 IndexOfPageTableEntries;
> > +  PAGE_TABLE_4K_ENTRY                   *PageTableEntry;
> > +
> > +  PageTableEntry = (PAGE_TABLE_4K_ENTRY *)AllocatePages (1);  ASSERT
> > + (PageTableEntry != NULL);
> > +
> > +  //
> > +  // Fill in 2M page entry.
> > +  //
> > +  *PageEntry2M = (UINT64)(UINTN) PageTableEntry | AddressEncMask |
> > + IA32_PG_P | IA32_PG_RW;
> > +
> > +  PhysicalAddress4K = PhysicalAddress;  for (IndexOfPageTableEntries
> > + = 0; IndexOfPageTableEntries < 512;
> > IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K +=
> > IndexOfPageTableEntries++SIZE_4KB)
> > {
> > +    //
> > +    // Fill in the Page Table entries
> > +    //
> > +    PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K |
> AddressEncMask;
> > +    PageTableEntry->Bits.ReadWrite = 1;
> > +    PageTableEntry->Bits.Present = 1;
> > +  }
> > +}
> > +
> > +
> > +/**
> > +  Split 1G page to 2M on Encrypted address range.
> > +
> > +  @param[in]      PhysicalAddress       Address of the encryted range.
> > +  @param[in]      AddressEncMask        Address Encryption Mask.
> > +  @param[in, out] PageEntry1G           Pointer to 1G page entry.
> > +
> > +**/
> > +VOID
> > +Split1GPageTo2MPageOnEncRange (
> > +  IN EFI_PHYSICAL_ADDRESS               PhysicalAddress,
> > +  IN UINT64                             AddressEncMask,
> > +  IN OUT UINT64                         *PageEntry1G
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
> > +  UINTN                                 IndexOfPageDirectoryEntries;
> > +  PAGE_TABLE_2M_ENTRY                   *PageDirectoryEntry;
> > +
> > +  PageDirectoryEntry = (PAGE_TABLE_2M_ENTRY *)AllocatePages (1);
> > + ASSERT (PageDirectoryEntry != NULL);
> > +
> > +  //
> > +  // Fill in 1G page entry.
> > +  //
> > +  *PageEntry1G = (UINT64)(UINTN) PageDirectoryEntry | AddressEncMask
> > + | IA32_PG_P | IA32_PG_RW;
> > +
> > +  PhysicalAddress2M = PhysicalAddress;  for
> > + (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512;
> > IndexOfPageDirectoryEntries++, PageDirectoryEntry++,
> PhysicalAddress2M
> > IndexOfPageDirectoryEntries+++=
> > SIZE_2MB) {
> > +    //
> > +    // Fill in the Page Directory entries
> > +    //
> > +    PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M |
> > AddressEncMask;
> > +    PageDirectoryEntry->Bits.ReadWrite = 1;
> > +    PageDirectoryEntry->Bits.Present = 1;
> > +    PageDirectoryEntry->Bits.MustBe1 = 1;
> > +  }
> > +}
> > +
> > +
> > +/**
> > +  Convert Encryption on page table entry.
> > +
> > +  @param  PageTableEntry         Start address of the range
> > +  @param  Operation              Convertion operation (set or clear)
> > +  @param  AddressEncMask         Address Encryption Mask
> > +
> > +**/
> > +VOID
> > +ConvertEncryptionOnPageTableEntry (
> > +  IN UINT64              *PageTableEntry,
> > +  IN ADDR_ENC_OPERATION  Operation,
> > +  IN UINT64              AddressEncMask
> > +  )
> > +{
> > +  if (Operation == CLEAR_ADDR_ENC_OPERATION) {
> > +    *PageTableEntry &= ~AddressEncMask;
> > +  } else if (Operation == SET_ADDR_ENC_OPERATION) {
> > +    *PageTableEntry |= AddressEncMask;
> > +  }
> > +}
> > +
> > diff --git a/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> > b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> > new file mode 100644
> > index 0000000..4781900
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/Dxe/Gcd/Ia32/GcdHelper.c
> > @@ -0,0 +1,115 @@
> > +/** @file
> > +  The file contains helper functions used by GCD.
> > +
> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> > +
> > +This program and the accompanying materials are licensed and made
> > +available under the terms and conditions of the BSD License which
> > +accompanies this distribution.  The full text of the license may be
> > +found at http://opensource.org/licenses/bsd-license.php
> > +
> > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS
> > OR IMPLIED.
> > +
> > +**/
> > +
> > +#include "DxeMain.h"
> > +#include "GcdHelper.h"
> > +
> > +
> > +/**
> > +  Convert Encryption on address range.
> > +
> > +  @param  BaseAddress            Start address of the range
> > +  @param  Length                 Length of the range
> > +  @param  Operation              Convertion operation (set or clear)
> > +  @param  AddressEncMask         Address Encryption Mask
> > +
> > +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> > EFI_PAGE_SIZE boundary.
> > +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> > specified range.
> > +  @retval EFI_SUCCESS            Action successfully done.
> > +**/
> > +EFI_STATUS
> > +ConvertEncryptionOnAddressRange (
> > +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> > +  IN UINT64                Length,
> > +  IN ADDR_ENC_OPERATION    Operation,
> > +  IN UINT64                AddressEncMask
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> > +  UINT64                *PageTable;
> > +  UINTN                 PTIndex;
> > +  UINT64                Cr3;
> > +
> > +  // Do we have actual work to do?
> > +  if (Length == 0 || AddressEncMask == 0) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  // PAE *must* be enabled on 32-bit page tables  // (else we can't
> > + configure AddressEncMask)  if ((AsmReadCr4 () & BIT5) == 0) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  // Make sure we're PAGE_SIZE aligned  if ((BaseAddress &
> > + EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  // Validate Operation
> > +  if (Operation >= INVALID_ENC_OPERATION) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  Cr3 = AsmReadCr3 ();
> > +  PhysicalAddress = BaseAddress;
> > +
> > +  do {
> > +    // PDPE Present?
> > +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> > PAGING_4K_ADDRESS_MASK_64);
> > +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 31);
> > +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +      return EFI_NO_MAPPING;
> > +    }
> > +
> > +    // PDE Present?
> > +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> > + ~AddressEncMask
> > & PAGING_4K_ADDRESS_MASK_64);
> > +    PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> > +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +      return EFI_NO_MAPPING;
> > +    }
> > +
> > +    // Is it a 2MB page entry?
> > +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> > +      if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> > +        // Consume 2MB from the range
> > +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> > Operation, AddressEncMask);
> > +        PhysicalAddress += SIZE_2MB;
> > +        Length -= SIZE_2MB;
> > +      } else {
> > +        // Split 2MB page entry to consume 4K chunks
> > +        Split2MPageTo4KPageOnEncRange (PhysicalAddress,
> > + AddressEncMask,
> > &PageTable[PTIndex]);
> > +      }
> > +    } else {
> > +      // PTE Present?
> > +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> > ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +      PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> > +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +        return EFI_NO_MAPPING;
> > +      }
> > +
> > +      // Consume 4KB from the range
> > +      ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> > + Operation,
> > AddressEncMask);
> > +      PhysicalAddress += SIZE_4KB;
> > +      Length -= SIZE_4KB;
> > +    }
> > +  } while (Length);
> > +
> > +  // Flush TLB
> > +  AsmWriteCr3 (Cr3);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > diff --git a/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> > b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> > new file mode 100644
> > index 0000000..5943f7a
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/Dxe/Gcd/X64/GcdHelper.c
> > @@ -0,0 +1,129 @@
> > +/** @file
> > +  The file contains helper functions used by GCD.
> > +
> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> > +
> > +This program and the accompanying materials are licensed and made
> > +available under the terms and conditions of the BSD License which
> > +accompanies this distribution.  The full text of the license may be
> > +found at http://opensource.org/licenses/bsd-license.php
> > +
> > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS
> > OR IMPLIED.
> > +
> > +**/
> > +
> > +#include "DxeMain.h"
> > +#include "GcdHelper.h"
> > +
> > +
> > +/**
> > +  Convert Encryption on address range.
> > +
> > +  @param  BaseAddress            Start address of the range
> > +  @param  Length                 Length of the range
> > +  @param  Operation              Convertion operation (set or clear)
> > +  @param  AddressEncMask         Address Encryption Mask
> > +
> > +  @retval EFI_INVALID_PARAMETER  Length or Address not aligned on
> > EFI_PAGE_SIZE boundary.
> > +  @retval EFI_NO_MAPPING         Missing page table mappings for the
> > specified range.
> > +  @retval EFI_SUCCESS            Action successfully done.
> > +**/
> > +EFI_STATUS
> > +ConvertEncryptionOnAddressRange (
> > +  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
> > +  IN UINT64                Length,
> > +  IN ADDR_ENC_OPERATION    Operation,
> > +  IN UINT64                AddressEncMask
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
> > +  UINT64                *PageTable;
> > +  UINTN                 PTIndex;
> > +  UINT64                Cr3;
> > +
> > +  // Do we have actual work to do?
> > +  if (Length == 0 || AddressEncMask == 0) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  // Make sure we're PAGE_SIZE aligned  if ((BaseAddress &
> > + EFI_PAGE_MASK) || (Length & EFI_PAGE_MASK)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  // Validate Operation
> > +  if (Operation >= INVALID_ENC_OPERATION) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  Cr3 = AsmReadCr3 ();
> > +  PhysicalAddress = BaseAddress;
> > +
> > +  do {
> > +    // PML4E Present?
> > +    PageTable = (UINT64 *)(UINTN) (Cr3 & ~AddressEncMask &
> > PAGING_4K_ADDRESS_MASK_64);
> > +    PTIndex = BitFieldRead64(PhysicalAddress, 39, 47);
> > +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +      return EFI_NO_MAPPING;
> > +    }
> > +
> > +    // PDPE Present?
> > +    PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> > + ~AddressEncMask
> > & PAGING_4K_ADDRESS_MASK_64);
> > +    PTIndex = BitFieldRead64(PhysicalAddress, 30, 38);
> > +    if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +      return EFI_NO_MAPPING;
> > +    }
> > +
> > +    // Is it a 1GB page entry?
> > +    if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> > +      if ((PhysicalAddress & (SIZE_1GB - 1)) == 0 && Length >= SIZE_1GB) {
> > +        // Consume 1GB from the range
> > +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> > Operation, AddressEncMask);
> > +        PhysicalAddress += SIZE_1GB;
> > +        Length -= SIZE_1GB;
> > +      } else {
> > +        // Split 1G page entry to attempt consuming 2MB chunks
> > +        Split1GPageTo2MPageOnEncRange (PhysicalAddress,
> > + AddressEncMask,
> > &PageTable[PTIndex]);
> > +      }
> > +    } else {
> > +      // PDE Present?
> > +      PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> > ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +      PTIndex = BitFieldRead64(PhysicalAddress, 21, 29);
> > +      if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +        return EFI_NO_MAPPING;
> > +      }
> > +
> > +      // Is it a 2MB page entry?
> > +      if ((PageTable[PTIndex] & IA32_PG_PS ) != 0) {
> > +        if ((PhysicalAddress & (SIZE_2MB - 1)) == 0 && Length >= SIZE_2MB) {
> > +          // Consume 2MB from the range
> > +          ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> > Operation, AddressEncMask);
> > +          PhysicalAddress += SIZE_2MB;
> > +          Length -= SIZE_2MB;
> > +        } else {
> > +          // Split 2MB page entry to consume 4K chunks
> > +          Split2MPageTo4KPageOnEncRange (PhysicalAddress,
> > AddressEncMask, &PageTable[PTIndex]);
> > +        }
> > +      } else {
> > +        // PTE Present?
> > +        PageTable = (UINT64 *)(UINTN) (PageTable[PTIndex] &
> > ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +        PTIndex = BitFieldRead64(PhysicalAddress, 12, 20);
> > +        if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
> > +          return EFI_NO_MAPPING;
> > +        }
> > +
> > +        // Consume 4KB from the range
> > +        ConvertEncryptionOnPageTableEntry (&PageTable[PTIndex],
> > Operation, AddressEncMask);
> > +        PhysicalAddress += SIZE_4KB;
> > +        Length -= SIZE_4KB;
> > +      }
> > +    }
> > +  } while (Length);
> > +
> > +  // Flush TLB
> > +  AsmWriteCr3 (Cr3);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > --
> > 2.7.4
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel