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
>
next prev parent 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