On Tue, Mar 02, 2021 at 03:48:36PM -0500, Tobin Feldman-Fitzthum wrote: > From: Dov Murik <dovmu...@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 <to...@linux.ibm.com> > Signed-off-by: Dov Murik <dovmu...@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 > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#72394): https://edk2.groups.io/g/devel/message/72394 Mute This Topic: https://groups.io/mt/81036386/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-