From dbb569a545abc6e843b9c8c26e1efcb6b9064e07 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Wed, 23 Oct 2024 18:02:30 +0800 Subject: [PATCH 1/2] Support live migration for Hygon CSV1/2/3 guests, fix nesting #VC The live migration of Hygon CSV1/2/3 guest depends on the KVM hypercall KVM_HC_MAP_GPA_RANGE, add code to sync page enc/dec status to KVM. The MMIO routine of VC handler will get memory encrypt status to validate MMIO address. MemEncryptSevGetEncryptionMask() will enable interrupt while interrupt must be disabled during VC. During DXE stage, VC routine as below: CcExitHandleVc -> MemEncryptSevGetAddressRangeState -> MemEncryptSevGetEncryptionMask->PcdGet64(PcdPteMemoryEncryptionAddressOrMask) Signed-off-by: hanliyang --- ...ncryptLib-Detect-SEV-live-migration-.patch | 330 ++++++++++++++++++ ...ncryptLib-Hypercall-API-for-page-enc.patch | 301 ++++++++++++++++ ...ncryptLib-Invoke-page-encryption-sta.patch | 84 +++++ ...ib-Encryption-state-change-hypercall.patch | 47 +++ ...Pei-Mark-SEC-GHCB-page-as-unencrypte.patch | 44 +++ ...e-Add-support-for-SEV-live-migration.patch | 196 +++++++++++ ...ryptSevLib-Correct-the-calculation-o.patch | 35 ++ ...ncryptLib-Return-SUCCESS-if-not-supp.patch | 36 ++ ...ncryptLib-Save-memory-encrypt-status.patch | 159 +++++++++ edk2.spec | 17 +- 10 files changed, 1248 insertions(+), 1 deletion(-) create mode 100644 0068-OvmfPkg-BaseMemEncryptLib-Detect-SEV-live-migration-.patch create mode 100644 0069-OvmfPkg-BaseMemEncryptLib-Hypercall-API-for-page-enc.patch create mode 100644 0070-OvmfPkg-BaseMemEncryptLib-Invoke-page-encryption-sta.patch create mode 100644 0071-OvmfPkg-VmgExitLib-Encryption-state-change-hypercall.patch create mode 100644 0072-OvmfPkg-PlatformPei-Mark-SEC-GHCB-page-as-unencrypte.patch create mode 100644 0073-OvmfPkg-AmdSevDxe-Add-support-for-SEV-live-migration.patch create mode 100644 0074-OvmfPkg-BaseMemcryptSevLib-Correct-the-calculation-o.patch create mode 100644 0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch create mode 100644 0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch diff --git a/0068-OvmfPkg-BaseMemEncryptLib-Detect-SEV-live-migration-.patch b/0068-OvmfPkg-BaseMemEncryptLib-Detect-SEV-live-migration-.patch new file mode 100644 index 0000000..351440e --- /dev/null +++ b/0068-OvmfPkg-BaseMemEncryptLib-Detect-SEV-live-migration-.patch @@ -0,0 +1,330 @@ +From ae4bf41d9c71137a21e7b8fc4aceca7212145b40 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:09:28 +0000 +Subject: [PATCH 1/9] OvmfPkg/BaseMemEncryptLib: Detect SEV live migration + feature. + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Add support to check if we are running inside KVM HVM and +KVM HVM supports SEV Live Migration feature. + +Cc: Jordan Justen +Cc: Ard Biesheuvel +Signed-off-by: Ashish Kalra +--- + OvmfPkg/Include/Library/MemEncryptSevLib.h | 12 ++++ + .../DxeMemEncryptSevLibInternal.c | 49 ++++++++++++++-- + .../PeiDxeMemEncryptSevLibInternal.c | 58 +++++++++++++++++++ + .../PeiDxeMemEncryptSevLibInternal.h | 31 ++++++++++ + .../PeiMemEncryptSevLibInternal.c | 42 ++++++++++++++ + .../SecMemEncryptSevLibInternal.c | 18 ++++++ + 6 files changed, 206 insertions(+), 4 deletions(-) + create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.h + +diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h +index 4fa9c0d7..babec60d 100644 +--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h ++++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h +@@ -83,6 +83,18 @@ MemEncryptSevIsEnabled ( + VOID + ); + ++/** ++ Returns a boolean to indicate whether SEV live migration is enabled. ++ ++ @retval TRUE SEV live migration is enabled ++ @retval FALSE SEV live migration is not enabled ++**/ ++BOOLEAN ++EFIAPI ++MemEncryptSevLiveMigrationIsEnabled ( ++ VOID ++ ); ++ + /** + This function clears memory encryption bit for the memory region specified by + BaseAddress and NumPages from the current page table context. +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c +index 4aba0075..d80ebe2f 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c +@@ -18,10 +18,14 @@ + #include + #include + +-STATIC UINT64 mCurrentAttr = 0; +-STATIC BOOLEAN mCurrentAttrRead = FALSE; +-STATIC UINT64 mSevEncryptionMask = 0; +-STATIC BOOLEAN mSevEncryptionMaskSaved = FALSE; ++#include "PeiDxeMemEncryptSevLibInternal.h" ++ ++STATIC UINT64 mCurrentAttr = 0; ++STATIC BOOLEAN mCurrentAttrRead = FALSE; ++STATIC UINT64 mSevEncryptionMask = 0; ++STATIC BOOLEAN mSevEncryptionMaskSaved = FALSE; ++STATIC BOOLEAN mSevLiveMigrationStatus = FALSE; ++STATIC BOOLEAN mSevLiveMigrationStatusChecked = FALSE; + + /** + The function check if the specified Attr is set. +@@ -111,6 +115,24 @@ MemEncryptSevSnpIsEnabled ( + return ConfidentialComputingGuestHas (CCAttrAmdSevSnp); + } + ++/** ++ Figures out if we are running inside KVM HVM and ++ KVM HVM supports SEV Live Migration feature. ++**/ ++STATIC ++VOID ++EFIAPI ++InternalDetectSevLiveMigrationFeature ( ++ VOID ++ ) ++{ ++ if (KvmDetectSevLiveMigrationFeature ()) { ++ mSevLiveMigrationStatus = TRUE; ++ } ++ ++ mSevLiveMigrationStatusChecked = TRUE; ++} ++ + /** + Returns a boolean to indicate whether SEV-ES is enabled. + +@@ -141,6 +163,25 @@ MemEncryptSevIsEnabled ( + return ConfidentialComputingGuestHas (CCAttrAmdSev); + } + ++/** ++ Returns a boolean to indicate whether SEV live migration is enabled. ++ ++ @retval TRUE SEV live migration is enabled ++ @retval FALSE SEV live migration is not enabled ++**/ ++BOOLEAN ++EFIAPI ++MemEncryptSevLiveMigrationIsEnabled ( ++ VOID ++ ) ++{ ++ if (!mSevLiveMigrationStatusChecked) { ++ InternalDetectSevLiveMigrationFeature (); ++ } ++ ++ return mSevLiveMigrationStatus; ++} ++ + /** + Returns the SEV encryption mask. + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.c +index 78ea16ae..868392f7 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.c +@@ -16,6 +16,8 @@ + #include + #include + ++#include "PeiDxeMemEncryptSevLibInternal.h" ++ + /** + Locate the page range that covers the initial (pre-SMBASE-relocation) SMRAM + Save State Map. +@@ -61,3 +63,59 @@ MemEncryptSevLocateInitialSmramSaveStateMapPages ( + + return RETURN_SUCCESS; + } ++ ++/** ++ Figures out if we are running inside KVM HVM and ++ KVM HVM supports SEV Live Migration feature. ++ ++ @retval TRUE SEV live migration is supported. ++ @retval FALSE SEV live migration is not supported. ++**/ ++BOOLEAN ++EFIAPI ++KvmDetectSevLiveMigrationFeature ( ++ VOID ++ ) ++{ ++ CHAR8 Signature[13]; ++ UINT32 mKvmLeaf; ++ UINT32 RegEax; ++ UINT32 RegEbx; ++ UINT32 RegEcx; ++ UINT32 RegEdx; ++ ++ Signature[12] = '\0'; ++ for (mKvmLeaf = 0x40000000; mKvmLeaf < 0x40010000; mKvmLeaf += 0x100) { ++ AsmCpuid ( ++ mKvmLeaf, ++ NULL, ++ (UINT32 *)&Signature[0], ++ (UINT32 *)&Signature[4], ++ (UINT32 *)&Signature[8] ++ ); ++ ++ if (AsciiStrCmp (Signature, "KVMKVMKVM") == 0) { ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: KVM Detected, signature = %a\n", ++ __FUNCTION__, ++ Signature ++ )); ++ ++ RegEax = mKvmLeaf + 1; ++ RegEcx = 0; ++ AsmCpuid (mKvmLeaf + 1, &RegEax, &RegEbx, &RegEcx, &RegEdx); ++ if ((RegEax & KVM_FEATURE_MIGRATION_CONTROL) != 0) { ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: SEV Live Migration feature supported\n", ++ __FUNCTION__ ++ )); ++ ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.h b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.h +new file mode 100644 +index 00000000..b0ef053c +--- /dev/null ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiDxeMemEncryptSevLibInternal.h +@@ -0,0 +1,31 @@ ++/** @file ++ ++ Secure Encrypted Virtualization (SEV) library helper function ++ ++ Copyright (c) 2021, AMD Incorporated. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef PEI_DXE_MEM_ENCRYPT_SEV_LIB_INTERNAL_H_ ++#define PEI_DXE_MEM_ENCRYPT_SEV_LIB_INTERNAL_H_ ++ ++#include ++ ++#define KVM_FEATURE_MIGRATION_CONTROL BIT17 ++ ++/** ++ Figures out if we are running inside KVM HVM and ++ KVM HVM supports SEV Live Migration feature. ++ ++ @retval TRUE SEV live migration is supported. ++ @retval FALSE SEV live migration is not supported. ++**/ ++BOOLEAN ++EFIAPI ++KvmDetectSevLiveMigrationFeature ( ++ VOID ++ ); ++ ++#endif // PEI_DXE_MEM_ENCRYPT_SEV_LIB_INTERNAL_H_ +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c +index 41d1246a..307087a1 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLibInternal.c +@@ -17,6 +17,11 @@ + #include + #include + ++#include "PeiDxeMemEncryptSevLibInternal.h" ++ ++STATIC BOOLEAN mSevLiveMigrationStatus = FALSE; ++STATIC BOOLEAN mSevLiveMigrationStatusChecked = FALSE; ++ + /** + Read the workarea to determine whether SEV is enabled. If enabled, + then return the SevEsWorkArea pointer. +@@ -83,6 +88,24 @@ MemEncryptSevSnpIsEnabled ( + return Msr.Bits.SevSnpBit ? TRUE : FALSE; + } + ++/** ++ Figures out if we are running inside KVM HVM and ++ KVM HVM supports SEV Live Migration feature. ++**/ ++STATIC ++VOID ++EFIAPI ++InternalDetectSevLiveMigrationFeature ( ++ VOID ++ ) ++{ ++ if (KvmDetectSevLiveMigrationFeature ()) { ++ mSevLiveMigrationStatus = TRUE; ++ } ++ ++ mSevLiveMigrationStatusChecked = TRUE; ++} ++ + /** + Returns a boolean to indicate whether SEV-ES is enabled. + +@@ -121,6 +144,25 @@ MemEncryptSevIsEnabled ( + return Msr.Bits.SevBit ? TRUE : FALSE; + } + ++/** ++ Returns a boolean to indicate whether SEV live migration is enabled. ++ ++ @retval TRUE SEV live migration is enabled ++ @retval FALSE SEV live migration is not enabled ++**/ ++BOOLEAN ++EFIAPI ++MemEncryptSevLiveMigrationIsEnabled ( ++ VOID ++ ) ++{ ++ if (!mSevLiveMigrationStatusChecked) { ++ InternalDetectSevLiveMigrationFeature (); ++ } ++ ++ return mSevLiveMigrationStatus; ++} ++ + /** + Returns the SEV encryption mask. + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c +index 27148c7e..9142ac40 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c +@@ -121,6 +121,24 @@ MemEncryptSevIsEnabled ( + return Msr.Bits.SevBit ? TRUE : FALSE; + } + ++/** ++ Returns a boolean to indicate whether SEV live migration is enabled. ++ ++ @retval TRUE SEV live migration is enabled ++ @retval FALSE SEV live migration is not enabled ++**/ ++BOOLEAN ++EFIAPI ++MemEncryptSevLiveMigrationIsEnabled ( ++ VOID ++ ) ++{ ++ // ++ // Not used in SEC phase. ++ // ++ return FALSE; ++} ++ + /** + Returns the SEV encryption mask. + +-- +2.25.1 + diff --git a/0069-OvmfPkg-BaseMemEncryptLib-Hypercall-API-for-page-enc.patch b/0069-OvmfPkg-BaseMemEncryptLib-Hypercall-API-for-page-enc.patch new file mode 100644 index 0000000..462dfc0 --- /dev/null +++ b/0069-OvmfPkg-BaseMemEncryptLib-Hypercall-API-for-page-enc.patch @@ -0,0 +1,301 @@ +From 2c000372cab80ab68a8672138c8d0f5cb1ae43d9 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:23:53 +0000 +Subject: [PATCH 2/9] OvmfPkg/BaseMemEncryptLib: Hypercall API for page + encryption state change + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Add API to issue hypercall on page encryption state change. + +By default all the SEV guest memory regions are considered encrypted, +if a guest changes the encryption attribute of the page (e.g mark a +page as decrypted) then notify hypervisor. Hypervisor will need to +track the unencrypted pages. The information will be used during +guest live migration, guest page migration and guest debugging. + +This hypercall is used to notify hypervisor when the page's +encryption state changes. + +Cc: Jordan Justen +Cc: Ard Biesheuvel +Signed-off-by: Brijesh Singh +Signed-off-by: Ashish Kalra +--- + OvmfPkg/Include/Library/MemEncryptSevLib.h | 52 +++++++++++++++ + .../DxeMemEncryptSevLib.inf | 1 + + .../Ia32/MemEncryptSevLib.c | 27 ++++++++ + .../PeiMemEncryptSevLib.inf | 1 + + .../SecMemEncryptSevLibInternal.c | 20 ++++++ + .../X64/AsmHelperStub.nasm | 33 ++++++++++ + .../X64/MemEncryptSevLib.c | 66 +++++++++++++++++++ + 7 files changed, 200 insertions(+) + create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/AsmHelperStub.nasm + +diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h +index babec60d..b60496c2 100644 +--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h ++++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h +@@ -240,4 +240,56 @@ MemEncryptSevSnpPreValidateSystemRam ( + IN UINTN NumPages + ); + ++/** ++ This hypercall is used to notify hypervisor when the page's encryption ++ state changes. ++ ++ @param[in] PhysicalAddress The physical address that is the start address ++ of a memory region. ++ @param[in] Pages Number of pages in memory region. ++ @param[in] IsEncrypted Encrypted or Decrypted. ++ ++ @retval RETURN_SUCCESS Hypercall returned success. ++ @retval RETURN_UNSUPPORTED Hypercall not supported. ++ @retval RETURN_NO_MAPPING Hypercall returned error. ++**/ ++RETURN_STATUS ++EFIAPI ++SetMemoryEncDecHypercall3 ( ++ IN UINTN PhysicalAddress, ++ IN UINTN Pages, ++ IN BOOLEAN IsEncrypted ++ ); ++ ++#define KVM_HC_MAP_GPA_RANGE 12 ++#define KVM_MAP_GPA_RANGE_PAGE_SZ_4K 0 ++#define KVM_MAP_GPA_RANGE_PAGE_SZ_2M BIT0 ++#define KVM_MAP_GPA_RANGE_PAGE_SZ_1G BIT1 ++#define KVM_MAP_GPA_RANGE_ENC_STATE(n) ((n) << 4) ++#define KVM_MAP_GPA_RANGE_ENCRYPTED KVM_MAP_GPA_RANGE_ENC_STATE(1) ++#define KVM_MAP_GPA_RANGE_DECRYPTED KVM_MAP_GPA_RANGE_ENC_STATE(0) ++ ++/** ++ Interface exposed by the ASM implementation of the core hypercall ++ ++ @param[in] HypercallNum KVM_HC_MAP_GPA_RANGE hypercall. ++ @param[in] PhysicalAddress The physical address that is the start address ++ of a memory region. ++ @param[in] Pages Number of pages in memory region. ++ @param[in] Attributes Bits 3:0 - preferred page size encoding, ++ 0 = 4kb, 1 = 2mb, 2 = 1gb, etc... ++ Bit 4 - plaintext = 0, encrypted = 1 ++ Bits 63:5 - reserved (must be zero) ++ ++ @retval Hypercall returned status. ++**/ ++UINTN ++EFIAPI ++SetMemoryEncDecHypercall3AsmStub ( ++ IN UINTN HypercallNum, ++ IN UINTN PhysicalAddress, ++ IN UINTN Pages, ++ IN UINTN Attributes ++ ); ++ + #endif // _MEM_ENCRYPT_SEV_LIB_H_ +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +index 3a1d3089..4d32fae6 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +@@ -40,6 +40,7 @@ + X64/SnpPageStateChangeInternal.c + X64/VirtualMemory.c + X64/VirtualMemory.h ++ X64/AsmHelperStub.nasm + + [Sources.IA32] + Ia32/MemEncryptSevLib.c +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c +index f92299fc..c1c10a61 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c +@@ -153,3 +153,30 @@ MemEncryptSevSnpPreValidateSystemRam ( + { + ASSERT (FALSE); + } ++ ++/** ++ This hyercall is used to notify hypervisor when the page's encryption ++ state changes. ++ ++ @param[in] PhysicalAddress The physical address that is the start address ++ of a memory region. ++ @param[in] Pages Number of Pages in the memory region. ++ @param[in] IsEncrypted Encrypted or Decrypted. ++ ++ @retval RETURN_SUCCESS Hypercall returned success. ++ @retval RETURN_UNSUPPORTED Hypercall not supported. ++ @retval RETURN_NO_MAPPING Hypercall returned error. ++**/ ++RETURN_STATUS ++EFIAPI ++SetMemoryEncDecHypercall3 ( ++ IN UINTN PhysicalAddress, ++ IN UINTN Pages, ++ IN BOOLEAN IsEncrypted ++ ) ++{ ++ // ++ // Memory encryption bit is not accessible in 32-bit mode ++ // ++ return RETURN_UNSUPPORTED; ++} +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf +index 8f56783d..3f11f06a 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf +@@ -40,6 +40,7 @@ + X64/SnpPageStateChangeInternal.c + X64/VirtualMemory.c + X64/VirtualMemory.h ++ X64/AsmHelperStub.nasm + + [Sources.IA32] + Ia32/MemEncryptSevLib.c +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c +index 9142ac40..ffb22a08 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c +@@ -139,6 +139,26 @@ MemEncryptSevLiveMigrationIsEnabled ( + return FALSE; + } + ++/** ++ Interface exposed by the ASM implementation of the core hypercall ++ ++ @retval Hypercall returned status. ++**/ ++UINTN ++EFIAPI ++SetMemoryEncDecHypercall3AsmStub ( ++ IN UINTN HypercallNum, ++ IN UINTN PhysicalAddress, ++ IN UINTN Pages, ++ IN UINTN Attributes ++ ) ++{ ++ // ++ // Not used in SEC phase. ++ // ++ return RETURN_UNSUPPORTED; ++} ++ + /** + Returns the SEV encryption mask. + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/AsmHelperStub.nasm b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/AsmHelperStub.nasm +new file mode 100644 +index 00000000..0ec35dd9 +--- /dev/null ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/AsmHelperStub.nasm +@@ -0,0 +1,33 @@ ++/** @file ++ ++ ASM helper stub to invoke hypercall ++ ++ Copyright (c) 2021, AMD Incorporated. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++DEFAULT REL ++SECTION .text ++ ++; UINTN ++; EFIAPI ++; SetMemoryEncDecHypercall3AsmStub ( ++; IN UINTN HypercallNum, ++; IN UINTN Arg1, ++; IN UINTN Arg2, ++; IN UINTN Arg3 ++; ); ++global ASM_PFX(SetMemoryEncDecHypercall3AsmStub) ++ASM_PFX(SetMemoryEncDecHypercall3AsmStub): ++ ; UEFI calling conventions require RBX to ++ ; be nonvolatile/callee-saved. ++ push rbx ++ mov rax, rcx ; Copy HypercallNumber to rax ++ mov rbx, rdx ; Copy Arg1 to the register expected by KVM ++ mov rcx, r8 ; Copy Arg2 to register expected by KVM ++ mov rdx, r9 ; Copy Arg3 to register expected by KVM ++ vmmcall ; Call VMMCALL ++ pop rbx ++ ret +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c +index e7c703bb..a64ff2a5 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c +@@ -142,3 +142,69 @@ MemEncryptSevClearMmioPageEncMask ( + EFI_PAGES_TO_SIZE (NumPages) + ); + } ++ ++/** ++ This hyercall is used to notify hypervisor when the page's encryption ++ state changes. ++ ++ @param[in] PhysicalAddress The physical address that is the start address ++ of a memory region. ++ @param[in] Pages Number of Pages in the memory region. ++ @param[in] IsEncrypted Encrypted or Decrypted. ++ ++ @retval RETURN_SUCCESS Hypercall returned success. ++ @retval RETURN_UNSUPPORTED Hypercall not supported. ++ @retval RETURN_NO_MAPPING Hypercall returned error. ++**/ ++RETURN_STATUS ++EFIAPI ++SetMemoryEncDecHypercall3 ( ++ IN UINTN PhysicalAddress, ++ IN UINTN Pages, ++ IN BOOLEAN IsEncrypted ++ ) ++{ ++ RETURN_STATUS Ret; ++ UINTN Error; ++ UINTN EncryptState; ++ ++ Ret = RETURN_UNSUPPORTED; ++ ++ if (MemEncryptSevLiveMigrationIsEnabled ()) { ++ Ret = RETURN_SUCCESS; ++ // ++ // The encryption bit is set/clear on the smallest page size, hence ++ // use the 4k page size in MAP_GPA_RANGE hypercall below. ++ // ++ // Also, when the GCD map is being walked and the c-bit being cleared ++ // from MMIO and NonExistent memory spaces, the physical address ++ // range being passed may not be page-aligned and adding an assert ++ // here prevents booting. Hence, rounding it down when calling ++ // SetMemoryEncDecHypercall3AsmStub below. ++ // ++ ++ EncryptState = IsEncrypted ? KVM_MAP_GPA_RANGE_ENCRYPTED : ++ KVM_MAP_GPA_RANGE_DECRYPTED; ++ ++ Error = SetMemoryEncDecHypercall3AsmStub ( ++ KVM_HC_MAP_GPA_RANGE, ++ PhysicalAddress & ~EFI_PAGE_MASK, ++ Pages, ++ KVM_MAP_GPA_RANGE_PAGE_SZ_4K | EncryptState ++ ); ++ ++ if (Error != 0) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "SetMemoryEncDecHypercall3 failed, Phys = %x, Pages = %d, Err = %Ld\n", ++ PhysicalAddress, ++ Pages, ++ (INT64)Error ++ )); ++ ++ Ret = RETURN_NO_MAPPING; ++ } ++ } ++ ++ return Ret; ++} +-- +2.25.1 + diff --git a/0070-OvmfPkg-BaseMemEncryptLib-Invoke-page-encryption-sta.patch b/0070-OvmfPkg-BaseMemEncryptLib-Invoke-page-encryption-sta.patch new file mode 100644 index 0000000..f2131b1 --- /dev/null +++ b/0070-OvmfPkg-BaseMemEncryptLib-Invoke-page-encryption-sta.patch @@ -0,0 +1,84 @@ +From 481f0a191fc03e79bbb52b08c1d4890b6331e68d Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:26:02 +0000 +Subject: [PATCH 3/9] OvmfPkg/BaseMemEncryptLib: Invoke page encryption state + change hypercall + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Invoke the hypercall API to notify hypervisor when the page's +encryption state changes. + +Cc: Jordan Justen +Cc: Ard Biesheuvel +Signed-off-by: Brijesh Singh +Signed-off-by: Ashish Kalra +--- + .../X64/PeiDxeVirtualMemory.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c +index a49cf125..42e3b03f 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c +@@ -727,6 +727,7 @@ SetMemoryEncDec ( + UINT64 PgTableMask; + UINT64 AddressEncMask; + BOOLEAN IsWpEnabled; ++ BOOLEAN CBitChanged; + UINTN OrigLength; + RETURN_STATUS Status; + PHYSICAL_ADDRESS PageAddress; +@@ -800,6 +801,7 @@ SetMemoryEncDec ( + // Save the specified length and physical address (we need it later). + // + OrigLength = Length; ++ CBitChanged = FALSE; + OrigPhysicalAddress = PhysicalAddress; + + while (Length != 0) { +@@ -860,6 +862,7 @@ SetMemoryEncDec ( + )); + PhysicalAddress += BIT30; + Length -= BIT30; ++ CBitChanged = TRUE; + } else { + // + // We must split the page +@@ -915,6 +918,7 @@ SetMemoryEncDec ( + SetOrClearCBit (&PageDirectory2MEntry->Uint64, Mode); + PhysicalAddress += BIT21; + Length -= BIT21; ++ CBitChanged = TRUE; + } else { + // + // We must split up this page into 4K pages +@@ -958,6 +962,7 @@ SetMemoryEncDec ( + SetOrClearCBit (&PageTableEntry->Uint64, Mode); + PhysicalAddress += EFI_PAGE_SIZE; + Length -= EFI_PAGE_SIZE; ++ CBitChanged = TRUE; + } + } + } +@@ -990,6 +995,17 @@ SetMemoryEncDec ( + ); + } + ++ // ++ // Notify Hypervisor on C-bit status ++ // ++ if (CBitChanged) { ++ Status = SetMemoryEncDecHypercall3 ( ++ OrigPhysicalAddress, ++ EFI_SIZE_TO_PAGES (OrigLength), ++ (Mode == SetCBit) ? TRUE : FALSE ++ ); ++ } ++ + Done: + // + // Restore page table write protection, if any. +-- +2.25.1 + diff --git a/0071-OvmfPkg-VmgExitLib-Encryption-state-change-hypercall.patch b/0071-OvmfPkg-VmgExitLib-Encryption-state-change-hypercall.patch new file mode 100644 index 0000000..c1d3f81 --- /dev/null +++ b/0071-OvmfPkg-VmgExitLib-Encryption-state-change-hypercall.patch @@ -0,0 +1,47 @@ +From 1058be0934a043804f2ae0b8ea1aa42454dc0eb8 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:27:26 +0000 +Subject: [PATCH 4/9] OvmfPkg/VmgExitLib: Encryption state change hypercall + support in VC handler + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Make the #VC handler aware of the page encryption state +change hypercall by adding support to check KVM_HC_MAP_GPA_RANGE +hypercall and add the additional register values used by +hypercall in the GHCB. + +Cc: Jordan Justen +Cc: Ard Biesheuvel +Signed-off-by: Ashish Kalra +--- + OvmfPkg/Library/CcExitLib/CcExitVcHandler.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c +index 0fc30f7b..5c9a9085 100644 +--- a/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c ++++ b/OvmfPkg/Library/CcExitLib/CcExitVcHandler.c +@@ -677,6 +677,19 @@ VmmCallExit ( + Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3); + CcExitVmgSetOffsetValid (Ghcb, GhcbCpl); + ++ if (Regs->Rax == KVM_HC_MAP_GPA_RANGE) { ++ // ++ // KVM_HC_MAP_GPA_RANGE hypercall requires these ++ // extra registers. ++ // ++ Ghcb->SaveArea.Rbx = Regs->Rbx; ++ CcExitVmgSetOffsetValid (Ghcb, GhcbRbx); ++ Ghcb->SaveArea.Rcx = Regs->Rcx; ++ CcExitVmgSetOffsetValid (Ghcb, GhcbRcx); ++ Ghcb->SaveArea.Rdx = Regs->Rdx; ++ CcExitVmgSetOffsetValid (Ghcb, GhcbRdx); ++ } ++ + Status = CcExitVmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0); + if (Status != 0) { + return Status; +-- +2.25.1 + diff --git a/0072-OvmfPkg-PlatformPei-Mark-SEC-GHCB-page-as-unencrypte.patch b/0072-OvmfPkg-PlatformPei-Mark-SEC-GHCB-page-as-unencrypte.patch new file mode 100644 index 0000000..8ced9ea --- /dev/null +++ b/0072-OvmfPkg-PlatformPei-Mark-SEC-GHCB-page-as-unencrypte.patch @@ -0,0 +1,44 @@ +From 16e7adce62f7c28cc1823229b40a27493737cae6 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:30:54 +0000 +Subject: [PATCH 5/9] OvmfPkg/PlatformPei: Mark SEC GHCB page as unencrypted + via hypercall + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Mark the SEC GHCB page (that is mapped as unencrypted in +ResetVector code) in the hypervisor's guest page encryption +state tracking. + +Cc: Jordan Justen +Cc: Ard Biesheuvel +Signed-off-by: Ashish Kalra +--- + OvmfPkg/PlatformPei/AmdSev.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c +index e6b602d7..553e841e 100644 +--- a/OvmfPkg/PlatformPei/AmdSev.c ++++ b/OvmfPkg/PlatformPei/AmdSev.c +@@ -229,6 +229,17 @@ AmdSevEsInitialize ( + Status = PcdSetBoolS (PcdSevEsIsEnabled, TRUE); + ASSERT_RETURN_ERROR (Status); + ++ // ++ // The SEC Ghcb setup during reset-vector needs to be marked as ++ // decrypted in the hypervisor's guest page encryption state ++ // tracking. ++ // ++ SetMemoryEncDecHypercall3 ( ++ FixedPcdGet32 (PcdOvmfSecGhcbBase), ++ EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdOvmfSecGhcbSize)), ++ FALSE ++ ); ++ + // + // Allocate GHCB and per-CPU variable pages. + // Since the pages must survive across the UEFI to OS transition +-- +2.25.1 + diff --git a/0073-OvmfPkg-AmdSevDxe-Add-support-for-SEV-live-migration.patch b/0073-OvmfPkg-AmdSevDxe-Add-support-for-SEV-live-migration.patch new file mode 100644 index 0000000..9c027ac --- /dev/null +++ b/0073-OvmfPkg-AmdSevDxe-Add-support-for-SEV-live-migration.patch @@ -0,0 +1,196 @@ +From 8d82fca148d9564b666b5f4185a0e78e1f77e230 Mon Sep 17 00:00:00 2001 +From: Ashish Kalra +Date: Tue, 5 Apr 2022 16:40:03 +0000 +Subject: [PATCH 6/9] OvmfPkg/AmdSevDxe: Add support for SEV live migration. + +cherry-picked from https://patchew.org/EDK2/cover.1629380011.git.ashish.kalra@amd.com . + +Check for SEV live migration feature support, if detected +setup a new UEFI enviroment variable to indicate OVMF +support for SEV live migration. + +This environment variable is created by UEFI but consumed +by the (guest) linux kernel. This is actually part of a +3-way negotiation of the live migration feature between +hypervisor, guest OVMF and guest kernel. Host indicates +support for live migration, which is detected by OVMF +and correspondingly OVMF sets this SetLiveMigrationEnabled +UEFI variable, which is read by the guest kernel and it +indicates to the guest kernel that both host and OVMF +support and have enabled the live migration feature. + +The new runtime UEFI environment variable is set via the +notification function registered for the +EFI_END_OF_DXE_EVENT_GROUP_GUID event in AmdSevDxe driver. + +AmdSevDxe module is an apriori driver so it gets loaded between PEI +and DXE phases and the SetVariable call will fail at the driver's +entry point as the Variable DXE module is still not loaded yet. +So we need to wait for an event notification which is signaled +after the Variable DXE module is loaded, hence, using the +EndOfDxe event notification to make this call. + +Signed-off-by: Ashish Kalra +--- + OvmfPkg/AmdSevDxe/AmdSevDxe.c | 67 ++++++++++++++++++++++ + OvmfPkg/AmdSevDxe/AmdSevDxe.inf | 4 ++ + OvmfPkg/Include/Guid/AmdSevMemEncryptLib.h | 20 +++++++ + OvmfPkg/OvmfPkg.dec | 1 + + 4 files changed, 92 insertions(+) + create mode 100644 OvmfPkg/Include/Guid/AmdSevMemEncryptLib.h + +diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.c b/OvmfPkg/AmdSevDxe/AmdSevDxe.c +index db3675ae..e3a8049d 100644 +--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.c ++++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.c +@@ -15,10 +15,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -191,6 +194,39 @@ STATIC EDKII_MEMORY_ACCEPT_PROTOCOL mMemoryAcceptProtocol = { + AmdSevMemoryAccept + }; + ++STATIC ++VOID ++EFIAPI ++AmdSevDxeOnEndOfDxe ( ++ IN EFI_EVENT Event, ++ IN VOID *EventToSignal ++ ) ++{ ++ EFI_STATUS Status; ++ BOOLEAN SevLiveMigrationEnabled; ++ ++ SevLiveMigrationEnabled = MemEncryptSevLiveMigrationIsEnabled (); ++ ++ if (SevLiveMigrationEnabled) { ++ Status = gRT->SetVariable ( ++ L"SevLiveMigrationEnabled", ++ &gAmdSevMemEncryptGuid, ++ EFI_VARIABLE_NON_VOLATILE | ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ EFI_VARIABLE_RUNTIME_ACCESS, ++ sizeof SevLiveMigrationEnabled, ++ &SevLiveMigrationEnabled ++ ); ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: Setting SevLiveMigrationEnabled variable, status = %lx\n", ++ __FUNCTION__, ++ Status ++ )); ++ } ++} ++ + EFI_STATUS + EFIAPI + AmdSevDxeEntryPoint ( +@@ -203,6 +239,7 @@ AmdSevDxeEntryPoint ( + UINTN NumEntries; + UINTN Index; + CONFIDENTIAL_COMPUTING_SNP_BLOB_LOCATION *SnpBootDxeTable; ++ EFI_EVENT Event; + + // + // Do nothing when SEV is not enabled +@@ -361,5 +398,35 @@ AmdSevDxeEntryPoint ( + ); + } + ++ // ++ // AmdSevDxe module is an apriori driver so it gets loaded between PEI ++ // and DXE phases and the SetVariable call will fail at the driver's ++ // entry point as the Variable DXE module is still not loaded yet. ++ // So we need to wait for an event notification which is signaled ++ // after the Variable DXE module is loaded, hence, using the ++ // EndOfDxe event notification to make this call. ++ // ++ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. ++ // The notification function sets the runtime variable indicating OVMF ++ // support for SEV live migration. ++ // ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_CALLBACK, ++ AmdSevDxeOnEndOfDxe, ++ NULL, ++ &gEfiEndOfDxeEventGroupGuid, ++ &Event ++ ); ++ ++ if (EFI_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "%a: CreateEventEx(): %r\n", ++ __FUNCTION__, ++ Status ++ )); ++ } ++ + return EFI_SUCCESS; + } +diff --git a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf +index e7c7d526..dd1da527 100644 +--- a/OvmfPkg/AmdSevDxe/AmdSevDxe.inf ++++ b/OvmfPkg/AmdSevDxe/AmdSevDxe.inf +@@ -57,3 +57,7 @@ + + [Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId ++ ++[Guids] ++ gAmdSevMemEncryptGuid ++ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event +diff --git a/OvmfPkg/Include/Guid/AmdSevMemEncryptLib.h b/OvmfPkg/Include/Guid/AmdSevMemEncryptLib.h +new file mode 100644 +index 00000000..62d22e79 +--- /dev/null ++++ b/OvmfPkg/Include/Guid/AmdSevMemEncryptLib.h +@@ -0,0 +1,20 @@ ++/** @file ++ ++ AMD Memory Encryption GUID, define a new GUID for defining ++ new UEFI environment variables assocaiated with SEV Memory Encryption. ++ ++ Copyright (c) 2021, AMD Inc. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef __AMD_SEV_MEMENCRYPT_LIB_H__ ++#define __AMD_SEV_MEMENCRYPT_LIB_H__ ++ ++#define AMD_SEV_MEMENCRYPT_GUID \ ++{0x0cf29b71, 0x9e51, 0x433a, {0xa3, 0xb7, 0x81, 0xf3, 0xab, 0x16, 0xb8, 0x75}} ++ ++extern EFI_GUID gAmdSevMemEncryptGuid; ++ ++#endif +diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec +index 34bca309..d50b1ae3 100644 +--- a/OvmfPkg/OvmfPkg.dec ++++ b/OvmfPkg/OvmfPkg.dec +@@ -170,6 +170,7 @@ + gUefiOvmfPkgTdxAcpiHobGuid = {0x6a0c5870, 0xd4ed, 0x44f4, {0xa1, 0x35, 0xdd, 0x23, 0x8b, 0x6f, 0x0c, 0x8d}} + gEfiNonCcFvGuid = {0xae047c6d, 0xbce9, 0x426c, {0xae, 0x03, 0xa6, 0x8e, 0x3b, 0x8a, 0x04, 0x88}} + gOvmfVariableGuid = {0x50bea1e5, 0xa2c5, 0x46e9, {0x9b, 0x3a, 0x59, 0x59, 0x65, 0x16, 0xb0, 0x0a}} ++ gAmdSevMemEncryptGuid = {0x0cf29b71, 0x9e51, 0x433a, {0xa3, 0xb7, 0x81, 0xf3, 0xab, 0x16, 0xb8, 0x75}} + + [Ppis] + # PPI whose presence in the PPI database signals that the TPM base address +-- +2.25.1 + diff --git a/0074-OvmfPkg-BaseMemcryptSevLib-Correct-the-calculation-o.patch b/0074-OvmfPkg-BaseMemcryptSevLib-Correct-the-calculation-o.patch new file mode 100644 index 0000000..94b9e3c --- /dev/null +++ b/0074-OvmfPkg-BaseMemcryptSevLib-Correct-the-calculation-o.patch @@ -0,0 +1,35 @@ +From fbdd6e4664e41eb299a797f1ab615d81b1bd958b Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Mon, 17 Jan 2022 01:19:21 -0500 +Subject: [PATCH 7/9] OvmfPkg/BaseMemcryptSevLib: Correct the calculation of + page range that notified to hypervisor + +Correct the calculation of page range that notified to hypervisor. + +Signed-off-by: hanliyang +--- + .../Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c +index 42e3b03f..69ada871 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c +@@ -999,9 +999,13 @@ SetMemoryEncDec ( + // Notify Hypervisor on C-bit status + // + if (CBitChanged) { ++ UINTN StartPfn = OrigPhysicalAddress >> EFI_PAGE_SHIFT; ++ UINTN EndPfn = (OrigPhysicalAddress + OrigLength + ++ ((1 << EFI_PAGE_SHIFT) - 1)) >> EFI_PAGE_SHIFT; ++ + Status = SetMemoryEncDecHypercall3 ( + OrigPhysicalAddress, +- EFI_SIZE_TO_PAGES (OrigLength), ++ (EndPfn - StartPfn), + (Mode == SetCBit) ? TRUE : FALSE + ); + } +-- +2.25.1 + diff --git a/0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch b/0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch new file mode 100644 index 0000000..fd3f25f --- /dev/null +++ b/0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch @@ -0,0 +1,36 @@ +From 6b7bb04614be39e9903c602dd65ba18426f6a6f2 Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Sun, 19 Jun 2022 18:12:35 +0800 +Subject: [PATCH 8/9] OvmfPkg/BaseMemEncryptLib: Return SUCCESS if not support + SEV live migration + +Add this change to avoid trigger 'ASSERT_EFI_ERROR (Status = Unsupported)' +when QEMU doesn't support SEV live migration. + +Signed-off-by: hanliyang +--- + OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c +index a64ff2a5..7b29582d 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c +@@ -168,10 +168,12 @@ SetMemoryEncDecHypercall3 ( + UINTN Error; + UINTN EncryptState; + +- Ret = RETURN_UNSUPPORTED; ++ // ++ // Return success if not support migration. ++ // ++ Ret = RETURN_SUCCESS; + + if (MemEncryptSevLiveMigrationIsEnabled ()) { +- Ret = RETURN_SUCCESS; + // + // The encryption bit is set/clear on the smallest page size, hence + // use the 4k page size in MAP_GPA_RANGE hypercall below. +-- +2.25.1 + diff --git a/0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch b/0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch new file mode 100644 index 0000000..3180390 --- /dev/null +++ b/0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch @@ -0,0 +1,159 @@ +From d9edefe3936aecbb9640a390cd990f1771e0dac2 Mon Sep 17 00:00:00 2001 +From: Xin Jiang +Date: Wed, 10 Jan 2024 17:34:57 +0800 +Subject: [PATCH 9/9] OvmfPkg/BaseMemEncryptLib: Save memory encrypt status in + reserved memory + +The MMIO routine of VC handler will get memory encrypt status to +validate MMIO address. MemEncryptSevGetEncryptionMask() will enable +interrupt while interrupt must be disabled during VC. + +During DXE stage, VC routine as below: +CcExitHandleVc->MemEncryptSevGetAddressRangeState-> +MemEncryptSevGetEncryptionMask->PcdGet64(PcdPteMemoryEncryptionAddressOrMask) + +Unfortunately, PcdGet64() will enable interrupt in VC context. + +Signed-off-by: Xin Jiang +--- + OvmfPkg/AmdSev/AmdSevX64.fdf | 5 ++++- + .../Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf | 4 ++++ + .../BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c | 9 ++------- + OvmfPkg/OvmfPkg.dec | 4 ++++ + OvmfPkg/OvmfPkgX64.fdf | 5 ++++- + OvmfPkg/PlatformPei/AmdSev.c | 2 ++ + OvmfPkg/PlatformPei/Csv.c | 6 ++++++ + OvmfPkg/PlatformPei/PlatformPei.inf | 2 ++ + 8 files changed, 28 insertions(+), 9 deletions(-) + +diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf +index 714ab004..b0d9033f 100644 +--- a/OvmfPkg/AmdSev/AmdSevX64.fdf ++++ b/OvmfPkg/AmdSev/AmdSevX64.fdf +@@ -80,7 +80,10 @@ gUefiOvmfPkgTokenSpaceGuid.PcdCsvDefaultSecureCallBase|gUefiOvmfPkgTokenSpaceGui + 0x012000|0x001000 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidSize + +-0x013000|0x00D000 ++0x013000|0x001000 ++gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusBase|gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusSize ++ ++0x014000|0x00C000 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize + + 0x020000|0x0E0000 +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +index 4d32fae6..6f2f69d0 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +@@ -61,3 +61,7 @@ + [Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask + gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr ++ ++[FixedPcd] ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusBase ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusSize +diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c +index d80ebe2f..a9d43237 100644 +--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c ++++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLibInternal.c +@@ -22,8 +22,6 @@ + + STATIC UINT64 mCurrentAttr = 0; + STATIC BOOLEAN mCurrentAttrRead = FALSE; +-STATIC UINT64 mSevEncryptionMask = 0; +-STATIC BOOLEAN mSevEncryptionMaskSaved = FALSE; + STATIC BOOLEAN mSevLiveMigrationStatus = FALSE; + STATIC BOOLEAN mSevLiveMigrationStatusChecked = FALSE; + +@@ -193,10 +191,7 @@ MemEncryptSevGetEncryptionMask ( + VOID + ) + { +- if (!mSevEncryptionMaskSaved) { +- mSevEncryptionMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask); +- mSevEncryptionMaskSaved = TRUE; +- } ++ UINT64 *MemEncryptStatus = (UINT64 *)(UINT64)FixedPcdGet32 (PcdMemEncrpytStatusBase); + +- return mSevEncryptionMask; ++ return *MemEncryptStatus; + } +diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec +index d50b1ae3..a6016d58 100644 +--- a/OvmfPkg/OvmfPkg.dec ++++ b/OvmfPkg/OvmfPkg.dec +@@ -443,6 +443,10 @@ + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidBase|0|UINT32|0x72 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidSize|0|UINT32|0x73 + ++ ## the base address of memory encryption status. ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusBase|0|UINT32|0x74 ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusSize|0|UINT32|0x75 ++ + [PcdsDynamic, PcdsDynamicEx] + gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10 +diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf +index b1cf0d99..a34b9f57 100644 +--- a/OvmfPkg/OvmfPkgX64.fdf ++++ b/OvmfPkg/OvmfPkgX64.fdf +@@ -100,7 +100,10 @@ gUefiOvmfPkgTokenSpaceGuid.PcdCsvDefaultSecureCallBase|gUefiOvmfPkgTokenSpaceGui + 0x011000|0x001000 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidSize + +-0x012000|0x00E000 ++0x012000|0x001000 ++gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusBase|gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusSize ++ ++0x013000|0x00D000 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize + + 0x020000|0x0E0000 +diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c +index 553e841e..7c4ef899 100644 +--- a/OvmfPkg/PlatformPei/AmdSev.c ++++ b/OvmfPkg/PlatformPei/AmdSev.c +@@ -379,6 +379,8 @@ AmdSevInitialize ( + PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask); + ASSERT_RETURN_ERROR (PcdStatus); + ++ *(UINT64 *)(UINT64)FixedPcdGet32 (PcdMemEncrpytStatusBase) = EncryptionMask; ++ + DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask)); + + // +diff --git a/OvmfPkg/PlatformPei/Csv.c b/OvmfPkg/PlatformPei/Csv.c +index a52112d5..fe8c059b 100644 +--- a/OvmfPkg/PlatformPei/Csv.c ++++ b/OvmfPkg/PlatformPei/Csv.c +@@ -33,6 +33,12 @@ CsvInitializeMemInfo ( + UINT64 LowerMemorySize; + UINT64 UpperMemorySize; + ++ BuildMemoryAllocationHob ( ++ (EFI_PHYSICAL_ADDRESS)(UINTN) FixedPcdGet32 (PcdMemEncrpytStatusBase), ++ (UINT64)(UINTN) FixedPcdGet32 (PcdMemEncrpytStatusSize), ++ EfiReservedMemoryType ++ ); ++ + if (!CsvIsEnabled ()) { + return ; + } +diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf +index 07de179f..c2d503fa 100644 +--- a/OvmfPkg/PlatformPei/PlatformPei.inf ++++ b/OvmfPkg/PlatformPei/PlatformPei.inf +@@ -137,6 +137,8 @@ + gUefiOvmfPkgTokenSpaceGuid.PcdCsvDefaultSecureCallSize + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCsvCpuidSize ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusBase ++ gUefiOvmfPkgTokenSpaceGuid.PcdMemEncrpytStatusSize + + [FeaturePcd] + gUefiOvmfPkgTokenSpaceGuid.PcdCsmEnable +-- +2.25.1 + diff --git a/edk2.spec b/edk2.spec index 637a950..b9d5b6f 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 14 +Release: 15 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -110,6 +110,18 @@ patch65: 0065-OvmfPkg-IoMmuDxe-Add-CsvIoMmu-protocol.patch patch66: 0066-OvmfPkg-Reserve-a-CPUID-table-page-for-CSV-guest.patch patch67: 0067-OvmfPkg-Use-classic-mmio-window-for-CSV-guest.patch +# Support live migrate Hygon CSV/CSV2/CSV3 guest +patch68: 0068-OvmfPkg-BaseMemEncryptLib-Detect-SEV-live-migration-.patch +patch69: 0069-OvmfPkg-BaseMemEncryptLib-Hypercall-API-for-page-enc.patch +patch70: 0070-OvmfPkg-BaseMemEncryptLib-Invoke-page-encryption-sta.patch +patch71: 0071-OvmfPkg-VmgExitLib-Encryption-state-change-hypercall.patch +patch72: 0072-OvmfPkg-PlatformPei-Mark-SEC-GHCB-page-as-unencrypte.patch +patch73: 0073-OvmfPkg-AmdSevDxe-Add-support-for-SEV-live-migration.patch +patch74: 0074-OvmfPkg-BaseMemcryptSevLib-Correct-the-calculation-o.patch +patch75: 0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch +# Fix nesting #VC in mmio check +patch76: 0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -379,6 +391,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Wed Oct 23 2024 hanliyang - 202308-15 +- Add support for live migration of Hygon CSV1/2/3 guests, fix nesting #VC + * Tue Nov 12 2024 hanliyang - 202308-14 - Add support for running in Hygon CSV3 guest -- Gitee From da93b0b1f2336e784b029f6590962a3623dd6673 Mon Sep 17 00:00:00 2001 From: Adttil <2429917001@qq.com> Date: Fri, 29 Nov 2024 10:41:19 +0800 Subject: [PATCH 2/2] vdpa: support vdpa blk/scsi device boot --- ...pport-of-MMIO-Bar-for-virtio-devices.patch | 218 +++++++++++++++ ...Virtio-wait-virtio-device-reset-done.patch | 123 +++++++++ ...large-IO-according-to-segment_size_m.patch | 250 ++++++++++++++++++ edk2.spec | 10 +- 4 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 0077-VirtioDxe-add-support-of-MMIO-Bar-for-virtio-devices.patch create mode 100644 0078-Virtio-wait-virtio-device-reset-done.patch create mode 100644 0079-VirtioBlk-split-large-IO-according-to-segment_size_m.patch diff --git a/0077-VirtioDxe-add-support-of-MMIO-Bar-for-virtio-devices.patch b/0077-VirtioDxe-add-support-of-MMIO-Bar-for-virtio-devices.patch new file mode 100644 index 0000000..ff96d20 --- /dev/null +++ b/0077-VirtioDxe-add-support-of-MMIO-Bar-for-virtio-devices.patch @@ -0,0 +1,218 @@ +From ceb82e7d081399dd91cc6e0e8eabd5b7260afac0 Mon Sep 17 00:00:00 2001 +From: Adttil <2429917001@qq.com> +Date: Fri, 29 Nov 2024 08:35:27 +0800 +Subject: [PATCH 1/3] VirtioDxe: add support of MMIO Bar for virtio devices + +As some virtio devices support MMIO BAR, add support for +it in Virtio10Dxe and VirtioPciDeviceDXE. + +Signed-off-by: jiangdongxu +--- + OvmfPkg/Include/Protocol/VirtioDevice.h | 12 +++ + .../VirtioMmioDeviceLib/VirtioMmioDevice.c | 1 + + OvmfPkg/Virtio10Dxe/Virtio10.c | 1 + + OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c | 89 +++++++++++++++---- + 4 files changed, 85 insertions(+), 18 deletions(-) + +diff --git a/OvmfPkg/Include/Protocol/VirtioDevice.h b/OvmfPkg/Include/Protocol/VirtioDevice.h +index ad37f4e3..802b8970 100644 +--- a/OvmfPkg/Include/Protocol/VirtioDevice.h ++++ b/OvmfPkg/Include/Protocol/VirtioDevice.h +@@ -466,6 +466,16 @@ EFI_STATUS + IN VOID *Mapping + ); + ++/** ++ * Note: Zero virtio devices has BAR0 of type MMIO but not PIO which do not ++ * flow the virtio 0.95 spec due to hw limiation. We extend edk2 to support ++ * such variant. ++ */ ++typedef enum { ++ VirtioCfgSpaceAcessIo = 0, ++ VirtioCfgSpaceAcessMem ++} VIRTIO_CFG_SPACE_ACCESS_MODE; ++ + /// + /// This protocol provides an abstraction over the VirtIo transport layer + /// +@@ -482,6 +492,8 @@ struct _VIRTIO_DEVICE_PROTOCOL { + // + INT32 SubSystemDeviceId; + ++ VIRTIO_CFG_SPACE_ACCESS_MODE CfgAccessMode; ++ + VIRTIO_GET_DEVICE_FEATURES GetDeviceFeatures; + VIRTIO_SET_GUEST_FEATURES SetGuestFeatures; + +diff --git a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c +index fac32422..a340711d 100644 +--- a/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c ++++ b/OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDevice.c +@@ -17,6 +17,7 @@ + STATIC CONST VIRTIO_DEVICE_PROTOCOL mMmioDeviceProtocolTemplate = { + 0, // Revision + 0, // SubSystemDeviceId ++ 0, // CfgAccessMode + VirtioMmioGetDeviceFeatures, // GetDeviceFeatures + VirtioMmioSetGuestFeatures, // SetGuestFeatures + VirtioMmioSetQueueAddress, // SetQueueAddress +diff --git a/OvmfPkg/Virtio10Dxe/Virtio10.c b/OvmfPkg/Virtio10Dxe/Virtio10.c +index 970524f6..b968b016 100644 +--- a/OvmfPkg/Virtio10Dxe/Virtio10.c ++++ b/OvmfPkg/Virtio10Dxe/Virtio10.c +@@ -954,6 +954,7 @@ Virtio10UnmapSharedBuffer ( + STATIC CONST VIRTIO_DEVICE_PROTOCOL mVirtIoTemplate = { + VIRTIO_SPEC_REVISION (1, 0, 0), + 0, // SubSystemDeviceId, filled in dynamically ++ 0, // CfgAccessMode + Virtio10GetDeviceFeatures, + Virtio10SetGuestFeatures, + Virtio10SetQueueAddress, +diff --git a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c +index b4ac195b..61ff376d 100644 +--- a/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c ++++ b/OvmfPkg/VirtioPciDeviceDxe/VirtioPciDevice.c +@@ -23,6 +23,7 @@ + STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = { + 0, // Revision + 0, // SubSystemDeviceId ++ 0, // CfgAccessMode + VirtioPciGetDeviceFeatures, // GetDeviceFeatures + VirtioPciSetGuestFeatures, // SetGuestFeatures + VirtioPciSetQueueAddress, // SetQueueAddress +@@ -117,14 +118,25 @@ VirtioPciIoRead ( + return EFI_INVALID_PARAMETER; + } + +- return PciIo->Io.Read ( +- PciIo, +- Width, +- PCI_BAR_IDX0, +- FieldOffset, +- Count, +- Buffer +- ); ++ if (Dev->VirtioDevice.CfgAccessMode == VirtioCfgSpaceAcessIo) { ++ return PciIo->Io.Read ( ++ PciIo, ++ Width, ++ PCI_BAR_IDX0, ++ FieldOffset, ++ Count, ++ Buffer ++ ); ++ } else { ++ return PciIo->Mem.Read ( ++ PciIo, ++ Width, ++ PCI_BAR_IDX0, ++ FieldOffset, ++ Count, ++ Buffer ++ ); ++ } + } + + /** +@@ -197,14 +209,25 @@ VirtioPciIoWrite ( + return EFI_INVALID_PARAMETER; + } + +- return PciIo->Io.Write ( +- PciIo, +- Width, +- PCI_BAR_IDX0, +- FieldOffset, +- Count, +- &Value +- ); ++ if (Dev->VirtioDevice.CfgAccessMode == VirtioCfgSpaceAcessIo) { ++ return PciIo->Io.Write ( ++ PciIo, ++ Width, ++ PCI_BAR_IDX0, ++ FieldOffset, ++ Count, ++ &Value ++ ); ++ } else { ++ return PciIo->Mem.Write ( ++ PciIo, ++ Width, ++ PCI_BAR_IDX0, ++ FieldOffset, ++ Count, ++ &Value ++ ); ++ } + } + + /** +@@ -332,6 +355,7 @@ VirtioPciInit ( + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; ++ VOID *Resources; + + ASSERT (Device != NULL); + PciIo = Device->PciIo; +@@ -373,6 +397,27 @@ VirtioPciInit ( + Device->DeviceSpecificConfigurationOffset = + VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI; + ++ Status = PciIo->GetBarAttributes(PciIo, PCI_BAR_IDX0, NULL, &Resources); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ if (*(UINT8 *)Resources == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) { ++ EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *Descriptor; ++ ++ Descriptor = Resources; ++ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { ++ Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessMem; ++ DEBUG ((DEBUG_INFO, "%a: Legacy Virtio MMIO BAR used.\n", __FUNCTION__)); ++ } else { ++ Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessIo; ++ DEBUG ((DEBUG_INFO, "%a: Legacy Virtio IO BAR used.\n", __FUNCTION__)); ++ } ++ } else { ++ DEBUG ((DEBUG_WARN, "%a: Cannot determine BAR0 type, assume IO.\n", __FUNCTION__)); ++ Device->VirtioDevice.CfgAccessMode = VirtioCfgSpaceAcessIo; ++ } ++ + return EFI_SUCCESS; + } + +@@ -434,6 +479,7 @@ VirtioPciDeviceBindingStart ( + { + VIRTIO_PCI_DEVICE *Device; + EFI_STATUS Status; ++ UINT64 Attributes; + + Device = (VIRTIO_PCI_DEVICE *)AllocateZeroPool (sizeof *Device); + if (Device == NULL) { +@@ -473,11 +519,18 @@ VirtioPciDeviceBindingStart ( + goto ClosePciIo; + } + ++ Status = Device->PciIo->Attributes (Device->PciIo, ++ EfiPciIoAttributeOperationSupported, ++ 0, &Attributes); ++ if (EFI_ERROR (Status)) { ++ goto ClosePciIo; ++ } ++ ++ Attributes &= (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_IO); + Status = Device->PciIo->Attributes ( + Device->PciIo, + EfiPciIoAttributeOperationEnable, +- (EFI_PCI_IO_ATTRIBUTE_IO | +- EFI_PCI_IO_ATTRIBUTE_BUS_MASTER), ++ Attributes | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, + NULL + ); + if (EFI_ERROR (Status)) { +-- +2.43.0 + diff --git a/0078-Virtio-wait-virtio-device-reset-done.patch b/0078-Virtio-wait-virtio-device-reset-done.patch new file mode 100644 index 0000000..d60a9fe --- /dev/null +++ b/0078-Virtio-wait-virtio-device-reset-done.patch @@ -0,0 +1,123 @@ +From 05de598734e741c596394bfbe42b1ab7af8316e1 Mon Sep 17 00:00:00 2001 +From: Adttil <2429917001@qq.com> +Date: Fri, 29 Nov 2024 08:46:00 +0800 +Subject: [PATCH 2/3] Virtio: wait virtio device reset done. + +The Virtio 1.0 driver performs subsequent negotiation operations +only after the device reset operation is complete. + +Implement this in the VirtioScsiDxe and VirtioBlkDxe. + +Signed-off-by: jiangdongxu +--- + OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 21 +++++++++++++++++++++ + OvmfPkg/VirtioScsiDxe/VirtioScsi.c | 21 +++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +index 74ed52f9..eed56994 100644 +--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c ++++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +@@ -28,6 +28,9 @@ + + #include "VirtioBlk.h" + ++#define MAX_RETRY_TIMES 1000 ++#define DEVICE_WAIT_INTVL 1000 ++ + /** + + Convenience macros to read and write region 0 IO space elements of the +@@ -721,6 +724,10 @@ VirtioBlkInit ( + UINT32 OptIoSize; + UINT16 QueueSize; + UINT64 RingBaseShift; ++ UINT8 DevStat; ++ UINT16 RetryTimes; ++ ++ RetryTimes = MAX_RETRY_TIMES; + + PhysicalBlockExp = 0; + AlignmentOffset = 0; +@@ -735,12 +742,26 @@ VirtioBlkInit ( + goto Failed; + } + ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ while (DevStat != NextDevStat && RetryTimes) { ++ gBS->Stall(DEVICE_WAIT_INTVL); ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ RetryTimes--; ++ } ++ + NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); + if (EFI_ERROR (Status)) { + goto Failed; + } + ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ while (DevStat != NextDevStat && RetryTimes) { ++ gBS->Stall(DEVICE_WAIT_INTVL); ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ RetryTimes--; ++ } ++ + NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); + if (EFI_ERROR (Status)) { +diff --git a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c +index 3705f5fc..580fe731 100644 +--- a/OvmfPkg/VirtioScsiDxe/VirtioScsi.c ++++ b/OvmfPkg/VirtioScsiDxe/VirtioScsi.c +@@ -43,6 +43,9 @@ + + #include "VirtioScsi.h" + ++#define MAX_RETRY_TIMES 1000 ++#define DEVICE_WAIT_INTVL 1000 ++ + /** + + Convenience macros to read and write configuration elements of the +@@ -932,6 +935,10 @@ VirtioScsiInit ( + UINT16 MaxChannel; // for validation only + UINT32 NumQueues; // for validation only + UINT16 QueueSize; ++ UINT8 DevStat; ++ UINT16 RetryTimes; ++ ++ RetryTimes = MAX_RETRY_TIMES; + + // + // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. +@@ -942,12 +949,26 @@ VirtioScsiInit ( + goto Failed; + } + ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ while (DevStat != NextDevStat && RetryTimes) { ++ gBS->Stall(DEVICE_WAIT_INTVL); ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ RetryTimes--; ++ } ++ + NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); + if (EFI_ERROR (Status)) { + goto Failed; + } + ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ while (DevStat != NextDevStat && RetryTimes) { ++ gBS->Stall(DEVICE_WAIT_INTVL); ++ Status = Dev->VirtIo->GetDeviceStatus (Dev->VirtIo, &DevStat); ++ RetryTimes--; ++ } ++ + NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); + if (EFI_ERROR (Status)) { +-- +2.43.0 + diff --git a/0079-VirtioBlk-split-large-IO-according-to-segment_size_m.patch b/0079-VirtioBlk-split-large-IO-according-to-segment_size_m.patch new file mode 100644 index 0000000..4977b5a --- /dev/null +++ b/0079-VirtioBlk-split-large-IO-according-to-segment_size_m.patch @@ -0,0 +1,250 @@ +From 734457162d02f6b4d66b8eb82da0717765fceebe Mon Sep 17 00:00:00 2001 +From: Adttil <2429917001@qq.com> +Date: Fri, 29 Nov 2024 09:04:13 +0800 +Subject: [PATCH 3/3] VirtioBlk: split large IO according to segment_size_max + +When the VirtioBlk device is initialized, the value of SegmentSizeMax +is obtained based on the feature capability. Then delivere the requests + based on the value of SegmentSizeMax. + +Signed-off-by: jiangdongxu +--- + MdePkg/Include/Protocol/BlockIo.h | 10 ++ + OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 148 +++++++++++++++++++++--------- + 2 files changed, 117 insertions(+), 41 deletions(-) + +diff --git a/MdePkg/Include/Protocol/BlockIo.h b/MdePkg/Include/Protocol/BlockIo.h +index ac9adf7a..ac5e1c2a 100644 +--- a/MdePkg/Include/Protocol/BlockIo.h ++++ b/MdePkg/Include/Protocol/BlockIo.h +@@ -197,6 +197,16 @@ typedef struct { + /// granularity as a number of logical blocks. + /// + UINT32 OptimalTransferLengthGranularity; ++ ++ /// ++ /// Maximum size of any single segment ++ /// ++ UINT32 MaxSegmentSize; ++ ++ /// ++ /// Maximum number of segments in a request ++ /// ++ UINT32 MaxSegments; + } EFI_BLOCK_IO_MEDIA; + + #define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 +diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +index eed56994..6d7c7aef 100644 +--- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c ++++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +@@ -31,6 +31,8 @@ + #define MAX_RETRY_TIMES 1000 + #define DEVICE_WAIT_INTVL 1000 + ++#define DEFAULT_MAX_SEGMENTS 32 ++ + /** + + Convenience macros to read and write region 0 IO space elements of the +@@ -460,6 +462,68 @@ FreeHostStatusBuffer: + return Status; + } + ++STATIC ++EFI_STATUS ++EFIAPI ++VirtioBlkReadWriteBlocks ( ++ IN EFI_BLOCK_IO_PROTOCOL *This, ++ IN UINT32 MediaId, ++ IN EFI_LBA Lba, ++ IN UINTN BufferSize, ++ IN OUT VOID *Buffer, ++ IN BOOLEAN RequestIsWrite ++ ) ++{ ++ VBLK_DEV *Dev; ++ EFI_STATUS Status; ++ UINT32 SizeMax; ++ ++ if (BufferSize == 0) { ++ return EFI_SUCCESS; ++ } ++ ++ Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); ++ Status = VerifyReadWriteRequest ( ++ &Dev->BlockIoMedia, ++ Lba, ++ BufferSize, ++ RequestIsWrite ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ SizeMax = Dev->BlockIoMedia.MaxSegmentSize; ++ while (BufferSize >= SizeMax) { ++ Status = SynchronousRequest ( ++ Dev, ++ Lba, ++ SizeMax, ++ Buffer, ++ RequestIsWrite ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ Lba += SizeMax / Dev->BlockIoMedia.BlockSize; ++ BufferSize -= SizeMax; ++ Buffer = (CHAR8 *)Buffer + SizeMax; ++ } ++ ++ if (BufferSize == 0) { ++ return EFI_SUCCESS; ++ } ++ ++ return SynchronousRequest ( ++ Dev, ++ Lba, ++ BufferSize, ++ Buffer, ++ RequestIsWrite ++ ); ++} ++ + /** + + ReadBlocks() operation for virtio-blk. +@@ -487,30 +551,13 @@ VirtioBlkReadBlocks ( + OUT VOID *Buffer + ) + { +- VBLK_DEV *Dev; +- EFI_STATUS Status; +- +- if (BufferSize == 0) { +- return EFI_SUCCESS; +- } +- +- Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); +- Status = VerifyReadWriteRequest ( +- &Dev->BlockIoMedia, +- Lba, +- BufferSize, +- FALSE // RequestIsWrite +- ); +- if (EFI_ERROR (Status)) { +- return Status; +- } +- +- return SynchronousRequest ( +- Dev, ++ return VirtioBlkReadWriteBlocks( ++ This, ++ MediaId, + Lba, + BufferSize, + Buffer, +- FALSE // RequestIsWrite ++ FALSE // RequestIsRead + ); + } + +@@ -541,26 +588,9 @@ VirtioBlkWriteBlocks ( + IN VOID *Buffer + ) + { +- VBLK_DEV *Dev; +- EFI_STATUS Status; +- +- if (BufferSize == 0) { +- return EFI_SUCCESS; +- } +- +- Dev = VIRTIO_BLK_FROM_BLOCK_IO (This); +- Status = VerifyReadWriteRequest ( +- &Dev->BlockIoMedia, +- Lba, +- BufferSize, +- TRUE // RequestIsWrite +- ); +- if (EFI_ERROR (Status)) { +- return Status; +- } +- +- return SynchronousRequest ( +- Dev, ++ return VirtioBlkReadWriteBlocks( ++ This, ++ MediaId, + Lba, + BufferSize, + Buffer, +@@ -716,6 +746,8 @@ VirtioBlkInit ( + UINT8 NextDevStat; + EFI_STATUS Status; + ++ UINT32 MaxSegmentSize; ++ UINT32 MaxSegments; + UINT64 Features; + UINT64 NumSectors; + UINT32 BlockSize; +@@ -814,6 +846,36 @@ VirtioBlkInit ( + BlockSize = 512; + } + ++ if (Features & VIRTIO_BLK_F_SIZE_MAX) { ++ Status = VIRTIO_CFG_READ (Dev, SizeMax, &MaxSegmentSize); ++ if (EFI_ERROR (Status)) { ++ goto Failed; ++ } ++ if (MaxSegmentSize == 0) { ++ // ++ // We need at least one 4KB page. ++ // ++ MaxSegmentSize = SIZE_4KB; ++ } ++ } else { ++ MaxSegmentSize = SIZE_512KB; ++ } ++ ++ if (Features & VIRTIO_BLK_F_SEG_MAX) { ++ Status = VIRTIO_CFG_READ (Dev, SegMax, &MaxSegments); ++ if (EFI_ERROR (Status)) { ++ goto Failed; ++ } ++ if (MaxSegments == 0) { ++ // ++ // We need at least one SG element, whatever they say. ++ // ++ MaxSegments = 1; ++ } ++ } else { ++ MaxSegments = DEFAULT_MAX_SEGMENTS; ++ } ++ + if (Features & VIRTIO_BLK_F_TOPOLOGY) { + Status = VIRTIO_CFG_READ ( + Dev, +@@ -955,6 +1017,8 @@ VirtioBlkInit ( + Dev->BlockIoMedia.ReadOnly = (BOOLEAN)((Features & VIRTIO_BLK_F_RO) != 0); + Dev->BlockIoMedia.WriteCaching = (BOOLEAN)((Features & VIRTIO_BLK_F_FLUSH) != 0); + Dev->BlockIoMedia.BlockSize = BlockSize; ++ Dev->BlockIoMedia.MaxSegments = MaxSegments; ++ Dev->BlockIoMedia.MaxSegmentSize = MaxSegmentSize; + Dev->BlockIoMedia.IoAlign = 0; + Dev->BlockIoMedia.LastBlock = DivU64x32 ( + NumSectors, +@@ -968,6 +1032,8 @@ VirtioBlkInit ( + Dev->BlockIoMedia.BlockSize, + Dev->BlockIoMedia.LastBlock + 1 + )); ++ DEBUG ((DEBUG_INFO, "%a: MaxSegments=0x%x[B] MaxSegmentSize=0x%x[B]\n", ++ __FUNCTION__, Dev->BlockIoMedia.MaxSegments, Dev->BlockIoMedia.MaxSegmentSize)); + + if (Features & VIRTIO_BLK_F_TOPOLOGY) { + Dev->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; +-- +2.43.0 + diff --git a/edk2.spec b/edk2.spec index b9d5b6f..54a5cae 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 15 +Release: 16 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -122,6 +122,11 @@ patch75: 0075-OvmfPkg-BaseMemEncryptLib-Return-SUCCESS-if-not-supp.patch # Fix nesting #VC in mmio check patch76: 0076-OvmfPkg-BaseMemEncryptLib-Save-memory-encrypt-status.patch +# Support vdpa blk/scsi device boot +patch77: 0077-VirtioDxe-add-support-of-MMIO-Bar-for-virtio-devices.patch +patch78: 0078-Virtio-wait-virtio-device-reset-done.patch +patch79: 0079-VirtioBlk-split-large-IO-according-to-segment_size_m.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -391,6 +396,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Fri Nov 29 2024 adttil<2429917001@qq.com> - 202308-16 +- vdpa: support vdpa blk/scsi device boot + * Wed Oct 23 2024 hanliyang - 202308-15 - Add support for live migration of Hygon CSV1/2/3 guests, fix nesting #VC -- Gitee