2023-02-13 10:34:27

by Jeremi Piotrowski

[permalink] [raw]
Subject: [RFC PATCH v2 0/7] Support nested SNP KVM guests on Hyper-V

This patch series enables SNP-host support when running on Hyper-V, which
allows launching SNP guests while running as a nested hypervisor. This works
with SNP guest side support that was merged in v5.19, and the snp capable qemu
from AMD.

In this scenario the L0 hypervisor is Hyper-V, L1 is KVM, and L2 is an SNP
guest. The code from this patchset runs in L1. L1 is not an SNP guest itself,
SNP guests are not capable of supporting virtualization.

Patch 1 deals with allocating an RMP table which is not provided by
firmware/hypervisor, but is needed by the kernel to keep track of page
assignment to guests and rmp page size. Patch 2 implements MSR-based
rmpupdate/psmash instructions which are meant for virtualized environments.
Patch 3 containts the logic to update the rmp table when rmpupdate/psmash is
issued. Patch 4 makes sure that the kernel does not disable SNP support during
early CPU init. Patch 5 allows SNP initialization to proceed when no iommus
are available. Patch 6 adds a quirk in psp command buffer handling, because of
differences in SNP firmware spec interpretation. Patch 7 adds handling for RMP
faults which occur as NPF and the L0 is not able to resolve the address that
the fault occurred at.

This series depends on:

- "Add AMD Secure Nested Paging (SEV-SNP) Hypervisor Support" (applies on top of RFC v7)
https://lore.kernel.org/lkml/[email protected]/
- "Support ACPI PSP on Hyper-V"
https://lore.kernel.org/lkml/[email protected]/

Changes since v1:
* added handling for rmp page faults that occur during copy_to_user() that
don't come with a proper fault address when running nested.
* fold IS_ENABLED() test into hv_needs_snp_rmp(), and use CONFIG_KVM_AMD_SEV
instead of CONFIG_AMD_MEM_ENCRYPT
* introduce snp_soft_rmptable() wrapper to remove core dependency on hyperv
specific code
* use msr_set_bit for SYSCFG_MEM_ENCRYPT bit instead of open coding

Jeremi Piotrowski (7):
x86/hyperv: Allocate RMP table during boot
x86/sev: Add support for NestedVirtSnpMsr
x86/sev: Maintain shadow rmptable on Hyper-V
x86/amd: Configure necessary MSRs for SNP during CPU init when running
as a guest
iommu/amd: Don't fail snp_enable when running virtualized
crypto: ccp - Introduce quirk to always reclaim pages after SEV-legacy
commands
x86/fault: Handle RMP faults with 0 address when nested

arch/x86/hyperv/hv_init.c | 5 +
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/hyperv-tlfs.h | 3 +
arch/x86/include/asm/mshyperv.h | 3 +
arch/x86/include/asm/msr-index.h | 2 +
arch/x86/include/asm/sev.h | 6 ++
arch/x86/kernel/cpu/amd.c | 5 +-
arch/x86/kernel/cpu/mshyperv.c | 47 +++++++++
arch/x86/kernel/sev.c | 150 ++++++++++++++++++++++++++---
arch/x86/mm/fault.c | 14 +++
drivers/crypto/ccp/sev-dev.c | 6 +-
drivers/crypto/ccp/sp-dev.h | 4 +
drivers/crypto/ccp/sp-platform.c | 1 +
drivers/iommu/amd/init.c | 6 ++
14 files changed, 240 insertions(+), 13 deletions(-)

--
2.25.1



2023-02-13 10:34:54

by Jeremi Piotrowski

[permalink] [raw]
Subject: [RFC PATCH v2 6/7] crypto: ccp - Introduce quirk to always reclaim pages after SEV-legacy commands

On Hyper-V, the rmp_mark_pages_shared() call after a SEV_PLATFORM_STATUS
fails with return code 2 (FAIL_PERMISSION) due to the page having the
immutable bit set in the RMP (SNP has been initialized). The comment
above this spot mentions that firmware automatically clears the
immutable bit, but I can't find any mention of this behavior in the SNP
Firmware ABI Spec.

Introduce a quirk to always attempt the page reclaim and set it for the
platform PSP. It would be possible to make this behavior unconditional
as the firmware spec defines that page reclaim results in success if the
page does not have the immutable bit set.

Signed-off-by: Jeremi Piotrowski <[email protected]>
---
drivers/crypto/ccp/sev-dev.c | 6 +++++-
drivers/crypto/ccp/sp-dev.h | 4 ++++
drivers/crypto/ccp/sp-platform.c | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 6c4fdcaed72b..4719c0cafa28 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -658,8 +658,12 @@ static int __snp_cmd_buf_copy(int cmd, void *cmd_buf, bool to_fw, int fw_err)
* no not need to reclaim the page.
*/
if (from_fw && sev_legacy_cmd_buf_writable(cmd)) {
- if (rmp_mark_pages_shared(__pa(cmd_buf), 1))
+ if (psp_master->vdata->quirks & PSP_QUIRK_ALWAYS_RECLAIM) {
+ if (snp_reclaim_pages(__pa(cmd_buf), 1, true))
+ return -EFAULT;
+ } else if (rmp_mark_pages_shared(__pa(cmd_buf), 1)) {
return -EFAULT;
+ }

/* No need to go further if firmware failed to execute command. */
if (fw_err)
diff --git a/drivers/crypto/ccp/sp-dev.h b/drivers/crypto/ccp/sp-dev.h
index c05f1fa82ff4..d50f274462d4 100644
--- a/drivers/crypto/ccp/sp-dev.h
+++ b/drivers/crypto/ccp/sp-dev.h
@@ -28,6 +28,9 @@
#define CACHE_NONE 0x00
#define CACHE_WB_NO_ALLOC 0xb7

+/* PSP requires a reclaim after every firmware command */
+#define PSP_QUIRK_ALWAYS_RECLAIM BIT(0)
+
/* Structure to hold CCP device data */
struct ccp_device;
struct ccp_vdata {
@@ -59,6 +62,7 @@ struct psp_vdata {
const unsigned int feature_reg;
const unsigned int inten_reg;
const unsigned int intsts_reg;
+ const unsigned int quirks;
};

/* Structure to hold SP device data */
diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c
index 1926efbc7b32..937448f6391a 100644
--- a/drivers/crypto/ccp/sp-platform.c
+++ b/drivers/crypto/ccp/sp-platform.c
@@ -103,6 +103,7 @@ static void sp_platform_fill_vdata(struct sp_dev_vdata *vdata,
.feature_reg = pdata->feature_reg,
.inten_reg = pdata->irq_en_reg,
.intsts_reg = pdata->irq_st_reg,
+ .quirks = PSP_QUIRK_ALWAYS_RECLAIM,
};

memcpy(sev, &sevtmp, sizeof(*sev));
--
2.25.1