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 0000000000000000000000000000000000000000..351440eade192de9a402e395b675bb0fd4d76b3d --- /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 0000000000000000000000000000000000000000..462dfc0a0027ef89010e716f750ca635ead876aa --- /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 0000000000000000000000000000000000000000..f2131b19900c7a869e6c744cd3495a12cfe9a422 --- /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 0000000000000000000000000000000000000000..c1d3f811a253ce421051aa25b649b679cb863099 --- /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 0000000000000000000000000000000000000000..8ced9eafe8d8be4507e9f6d0dbf7665090a41c9c --- /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 0000000000000000000000000000000000000000..9c027acf325843648d84e513bc2e08658a8e5f00 --- /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 0000000000000000000000000000000000000000..94b9e3c68f19c33e1f8781f701d5e5545985f2f4 --- /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 0000000000000000000000000000000000000000..fd3f25f7e2cbd28ef93c2717085935e89600b257 --- /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 0000000000000000000000000000000000000000..3180390885c42f24ac51d07e037f5785bd0c0212 --- /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/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 0000000000000000000000000000000000000000..ff96d20f0eb991a0c138cf637ce317dc0f47190c --- /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 0000000000000000000000000000000000000000..d60a9fe38aef5920d3d9853f09b1583fd8ba8444 --- /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 0000000000000000000000000000000000000000..4977b5a9a75e7fd909392c14663122a8f29b99b2 --- /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 637a950a35ffbe1b94aa44398d15b1a376810475..54a5cae4c54df433b6c575f08ebf6af9ee74d34a 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 14 +Release: 16 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -110,6 +110,23 @@ 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 + +# 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 @@ -379,6 +396,12 @@ 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 + * Tue Nov 12 2024 hanliyang - 202308-14 - Add support for running in Hygon CSV3 guest