public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ashish Kalra" <ashish.kalra@amd.com>
To: Tobin Feldman-Fitzthum <tobin@linux.ibm.com>
Cc: devel@edk2.groups.io, Dov Murik <dovmurik@linux.vnet.ibm.com>,
	Tobin Feldman-Fitzthum <tobin@ibm.com>,
	James Bottomley <jejb@linux.ibm.com>,
	Hubertus Franke <frankeh@us.ibm.com>,
	Brijesh Singh <brijesh.singh@amd.com>,
	Jon Grimm <jon.grimm@amd.com>,
	Tom Lendacky <thomas.lendacky@amd.com>
Subject: Re: [RFC PATCH 11/14] OvmfPkg/AmdSev: Build page table for migration handler
Date: Wed, 3 Mar 2021 16:32:02 +0000	[thread overview]
Message-ID: <20210303163202.GA31638@ashkalra_ubuntu_server> (raw)
In-Reply-To: <20210302204839.82042-12-tobin@linux.ibm.com>

On Tue, Mar 02, 2021 at 03:48:36PM -0500, Tobin Feldman-Fitzthum wrote:
> From: Dov Murik <dovmurik@linux.ibm.com>
> 
> The migration handler builds its own page tables and switches
> to them. The MH pagetables are reserved as runtime memory.
> 
> When the hypervisor asks the MH to import/export a page, the HV
> writes the guest physical address of the page in question to the
> mailbox. The MH uses an identity mapping so that it can read/write
> whatever GPA is requested by the HV. The hypervisor only asks the
> MH to import/export encrypted pages. Thus, the C-Bit can be set
> for every page in the identity map.
> 
> The MH also needs to read shared pages, such as the mailbox.
> These are mapped at an offset. The offset must be added to
> the physical address before it can be resolved.
> 
> Signed-off-by: Tobin Feldman-Fitzthum <tobin@linux.ibm.com>
> Signed-off-by: Dov Murik <dovmurik@linux.vnet.ibm.com>
> ---
>  .../ConfidentialMigrationDxe.inf              |   1 +
>  .../ConfidentialMigration/VirtualMemory.h     | 177 ++++++++++++++++++
>  .../ConfidentialMigrationDxe.c                |  88 ++++++++-
>  3 files changed, 265 insertions(+), 1 deletion(-)
>  create mode 100644 OvmfPkg/AmdSev/ConfidentialMigration/VirtualMemory.h
> 
> diff --git a/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.inf b/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.inf
> index 49457d5d17..8dadfd1d13 100644
> --- a/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.inf
> +++ b/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.inf
> @@ -15,6 +15,7 @@
>  
>  [Sources]
>    ConfidentialMigrationDxe.c
> +  VirtualMemory.h
>  
>  [Packages]
>    MdePkg/MdePkg.dec
> diff --git a/OvmfPkg/AmdSev/ConfidentialMigration/VirtualMemory.h b/OvmfPkg/AmdSev/ConfidentialMigration/VirtualMemory.h
> new file mode 100644
> index 0000000000..c50cb64c63
> --- /dev/null
> +++ b/OvmfPkg/AmdSev/ConfidentialMigration/VirtualMemory.h
> @@ -0,0 +1,177 @@
> +/** @file
> +  Virtual Memory Management Services to set or clear the memory encryption bit
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +  Code is derived from OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
> +
> +**/
> +
> +#ifndef __VIRTUAL_MEMORY__
> +#define __VIRTUAL_MEMORY__
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Uefi.h>
> +
> +#define SYS_CODE64_SEL 0x38
> +
> +#pragma pack(1)
> +
> +//
> +// Page-Map Level-4 Offset (PML4) and
> +// Page-Directory-Pointer Offset (PDPE) entries 4K & 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  Reserved:1;               // Reserved
> +    UINT64  MustBeZero:2;             // Must Be Zero
> +    UINT64  Available:3;              // Available for use by system software
> +    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
> +    UINT64  AvabilableHigh:11;        // Available for use by system software
> +    UINT64  Nx:1;                     // No Execute bit
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_MAP_AND_DIRECTORY_POINTER;
> +
> +//
> +// 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  AvabilableHigh: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  AvabilableHigh:11;        // Available for use by system software
> +    UINT64  Nx:1;                     // 0 = Execute Code,
> +                                      //   1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_ENTRY;
> +
> +//
> +// Page Table Entry 1GB
> +//
> +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:17;            // Must be zero;
> +    UINT64  PageTableBaseAddress:22;  // Page Table Base Address
> +    UINT64  AvabilableHigh:11;        // Available for use by system software
> +    UINT64  Nx:1;                     // 0 = Execute Code,
> +                                      //   1 = No Code Execution
> +  } Bits;
> +  UINT64    Uint64;
> +} PAGE_TABLE_1G_ENTRY;
> +
> +#pragma pack()
> +
> +#define IA32_PG_P                   BIT0
> +#define IA32_PG_RW                  BIT1
> +#define IA32_PG_PS                  BIT7
> +
> +#define PAGING_PAE_INDEX_MASK       0x1FF
> +
> +#define PAGING_4K_ADDRESS_MASK_64   0x000FFFFFFFFFF000ull
> +#define PAGING_2M_ADDRESS_MASK_64   0x000FFFFFFFE00000ull
> +#define PAGING_1G_ADDRESS_MASK_64   0x000FFFFFC0000000ull
> +
> +#define PAGING_L1_ADDRESS_SHIFT     12
> +#define PAGING_L2_ADDRESS_SHIFT     21
> +#define PAGING_L3_ADDRESS_SHIFT     30
> +#define PAGING_L4_ADDRESS_SHIFT     39
> +
> +#define PAGING_PML4E_NUMBER         4
> +
> +#define PAGETABLE_ENTRY_MASK        ((1UL << 9) - 1)
> +#define PML4_OFFSET(x)              ( (x >> 39) & PAGETABLE_ENTRY_MASK)
> +#define PDP_OFFSET(x)               ( (x >> 30) & PAGETABLE_ENTRY_MASK)
> +#define PDE_OFFSET(x)               ( (x >> 21) & PAGETABLE_ENTRY_MASK)
> +#define PTE_OFFSET(x)               ( (x >> 12) & PAGETABLE_ENTRY_MASK)
> +#define PAGING_1G_ADDRESS_MASK_64   0x000FFFFFC0000000ull
> +
> +#define PAGE_TABLE_POOL_ALIGNMENT   BASE_2MB
> +#define PAGE_TABLE_POOL_UNIT_SIZE   SIZE_2MB
> +#define PAGE_TABLE_POOL_UNIT_PAGES  \
> +  EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
> +#define PAGE_TABLE_POOL_ALIGN_MASK  \
> +  (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
> +
> +typedef struct {
> +  VOID            *NextPool;
> +  UINTN           Offset;
> +  UINTN           FreePages;
> +} PAGE_TABLE_POOL;
> +
> +#endif
> diff --git a/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.c b/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.c
> index 8402fcc4fa..3df3b09732 100644
> --- a/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.c
> +++ b/OvmfPkg/AmdSev/ConfidentialMigration/ConfidentialMigrationDxe.c
> @@ -11,6 +11,7 @@
>  #include <Protocol/MpService.h>
>  #include <Library/BaseMemoryLib.h>
>  
> +#include "VirtualMemory.h"
>  //
>  // Functions implemented by the migration handler
>  //
> @@ -43,6 +44,83 @@ typedef volatile struct {
>    UINT32       done;
>  } MH_COMMAND_PARAMETERS;
>  
> +//
> +// Addresses for MH page table.
> +//
> +STATIC PAGE_TABLE_POOL   *mPageTablePool = NULL;
> +STATIC PHYSICAL_ADDRESS  mMigrationHelperPageTables = 0;
> +
> +//
> +// Offset for non-cbit mapping.
> +//
> +#define UNENC_VIRT_ADDR_BASE    0xffffff8000000000ULL
> +
> +
> +/**
> +  Allocates and fills in custom page tables for Migration Handler.
> +  The MH must be able to write to any encrypted page. Thus, it
> +  uses an identity map where the C-bit is set for every page. The
> +  HV should never ask the MH to import/export a shared page. The
> +  MH must also be able to read some shared pages. The first 1GB
> +  of memory is mapped at offset UNENC_VIRT_ADDR_BASE.
> +
> +**/
> +VOID
> +PrepareMigrationHandlerPageTables (
> +  VOID
> +  )
> +{
> +  UINTN                            PoolPages;
> +  VOID                             *Buffer;
> +  VOID                             *Start;
> +  PAGE_MAP_AND_DIRECTORY_POINTER   *PageMapLevel4Entry;
> +  PAGE_TABLE_1G_ENTRY              *PageDirectory1GEntry;
> +  PAGE_TABLE_1G_ENTRY              *Unenc1GEntry;
> +  UINT64                           AddressEncMask;
> +
> +  PoolPages = 1 + 10;
> +  Buffer = AllocateAlignedRuntimePages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
> +  mPageTablePool = Buffer;
> +  mPageTablePool->NextPool = mPageTablePool;
> +  mPageTablePool->FreePages  = PoolPages - 1;
> +  mPageTablePool->Offset = EFI_PAGES_TO_SIZE (1);
> +
> +  Start = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
> +  ZeroMem(Start, mPageTablePool->FreePages * EFI_PAGE_SIZE);
> +
> +  AddressEncMask = 1ULL << 47;
> +

Preferably getting the encryption bit location from SEV CPUID
information.

> +  PageMapLevel4Entry = Start;
> +  PageDirectory1GEntry = (PAGE_TABLE_1G_ENTRY*)((UINT8*)Start + EFI_PAGE_SIZE);
> +  Unenc1GEntry = (PAGE_TABLE_1G_ENTRY*)((UINT8*)Start + 2 * EFI_PAGE_SIZE);
> +
> +  PageMapLevel4Entry = Start;
> +  PageMapLevel4Entry += PML4_OFFSET(0x0ULL);
> +  PageMapLevel4Entry->Uint64 = (UINT64)PageDirectory1GEntry | AddressEncMask | 0x23;
> +
> +  PageMapLevel4Entry = Start;
> +  PageMapLevel4Entry += PML4_OFFSET(UNENC_VIRT_ADDR_BASE); // should be 511
> +  PageMapLevel4Entry->Uint64 = (UINT64)Unenc1GEntry | AddressEncMask | 0x23;
> +
> +  UINT64 PageAddr = 0;
> +  for (int i = 0; i < 512; i++, PageAddr += SIZE_1GB) {
> +    PAGE_TABLE_1G_ENTRY *e = PageDirectory1GEntry + i;
> +    e->Uint64 = PageAddr | AddressEncMask | 0xe3; // 1GB page
> +  }
> +

Changing encryption attributes of a page requires to flush it from
the caches, you may need to do a clflush here.

Thanks,
Ashish

> +  UINT64 UnencPageAddr = 0;
> +  Unenc1GEntry->Uint64 = UnencPageAddr | 0xe3; // 1GB page unencrypted
> +
> +  mMigrationHelperPageTables = (UINT64)Start | AddressEncMask;
> +}
> +
> +VOID
> +SwitchToMigrationHelperPageTables(VOID)
> +{
> +  AsmWriteCr3(mMigrationHelperPageTables);
> +}
> +
> +
>  
>  VOID
>  EFIAPI
> @@ -56,7 +134,12 @@ MigrationHandlerMain (
>  
>    DebugPrint (DEBUG_INFO,"MIGRATION Handler Started\n");
>  
> -  params_base = PcdGet32 (PcdConfidentialMigrationMailboxBase);
> +  SwitchToMigrationHelperPageTables();
> +
> +  //
> +  // Shared pages must be offset by UNENC_VIRT_ADDR_BASE.
> +  //
> +  params_base = PcdGet32 (PcdConfidentialMigrationMailboxBase) + UNENC_VIRT_ADDR_BASE;
>    params = (VOID *)params_base;
>    page_va = (VOID *)params_base + 0x1000;
>  
> @@ -134,6 +217,8 @@ LaunchMigrationHandler (
>  
>    MigrationHandlerCpuIndex = NumProc - 1;
>  
> +  PrepareMigrationHandlerPageTables();
> +
>    EFI_EVENT Event;
>    MpProto->GetProcessorInfo (MpProto, MigrationHandlerCpuIndex, &Tcb);
>    if (Tcb.StatusFlag != 7) {
> @@ -154,6 +239,7 @@ LaunchMigrationHandler (
>    if (PcdGetBool(PcdIsConfidentialMigrationTarget)) {
>      DebugPrint (DEBUG_INFO,"Waiting for incoming confidential migration.\n");
>      DisableInterrupts ();
> +    SwitchToMigrationHelperPageTables();
>      CpuDeadLoop ();
>    }
>  
> -- 
> 2.20.1
> 

  reply	other threads:[~2021-03-03 16:32 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-02 20:48 [RFC PATCH 00/14] Firmware Support for Fast Live Migration for AMD SEV Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 01/14] OvmfPkg/BaseMemEncryptLib: Support to issue unencrypted hypercall Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 02/14] OvmfPkg/PlatformPei: Mark SEC GHCB page in the page encrpytion bitmap Tobin Feldman-Fitzthum
2021-03-03  0:16   ` Ashish Kalra
2021-03-03 14:56     ` [edk2-devel] " Tobin Feldman-Fitzthum
2021-03-03 15:01       ` Ashish Kalra
2021-03-02 20:48 ` [RFC PATCH 03/14] OvmfPkg/PlatformDxe: Add support for SEV live migration Tobin Feldman-Fitzthum
2021-03-03 16:41   ` Ashish Kalra
2021-03-03 16:47     ` Tobin Feldman-Fitzthum
2021-03-03 16:57       ` Ashish Kalra
2021-03-02 20:48 ` [RFC PATCH 04/14] OvmfPkg/AmdSev: Base for Confidential Migration Handler Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 05/14] OvmfPkg/PlatfomPei: Set Confidential Migration PCD Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 06/14] OvmfPkg/AmdSev: Setup Migration Handler Mailbox Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 07/14] OvmfPkg/AmdSev: MH support for mailbox protocol Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 08/14] UefiCpuPkg/MpInitLib: temp removal of MpLib cleanup Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 09/14] UefiCpuPkg/MpInitLib: Allocate MP buffer as runtime memory Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 10/14] UefiCpuPkg/CpuExceptionHandlerLib: Exception handling " Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 11/14] OvmfPkg/AmdSev: Build page table for migration handler Tobin Feldman-Fitzthum
2021-03-03 16:32   ` Ashish Kalra [this message]
2021-03-03 18:58     ` Dov Murik
2021-03-02 20:48 ` [RFC PATCH 12/14] OvmfPkg/AmdSev: Don't overwrite mailbox or pagetables Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 13/14] OvmfPkg/AmdSev: Don't overwrite MH stack Tobin Feldman-Fitzthum
2021-03-02 20:48 ` [RFC PATCH 14/14] OvmfPkg/AmdSev: MH page encryption POC Tobin Feldman-Fitzthum
2021-03-03 16:14 ` [edk2-devel] [RFC PATCH 00/14] Firmware Support for Fast Live Migration for AMD SEV Laszlo Ersek
2021-03-03 18:25   ` Tobin Feldman-Fitzthum
2021-03-04 17:35     ` Laszlo Ersek
2021-03-05 10:44     ` Ashish Kalra
2021-03-05 16:10       ` Ashish Kalra
2021-03-05 21:22         ` Tobin Feldman-Fitzthum
2021-03-04  1:49 ` Yao, Jiewen
2021-03-04  9:21 ` Paolo Bonzini
2021-03-04 20:45   ` Laszlo Ersek
2021-03-04 21:18     ` Laszlo Ersek
2021-03-05  8:59     ` Paolo Bonzini
     [not found] ` <166900903D364B89.9163@groups.io>
2021-03-13  2:32   ` Yao, Jiewen
2021-03-16 17:05     ` Singh, Brijesh
2021-03-16 17:47     ` Tobin Feldman-Fitzthum
2021-03-17 15:30       ` Yao, Jiewen

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20210303163202.GA31638@ashkalra_ubuntu_server \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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