[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240329225835.400662-20-michael.roth@amd.com>
Date: Fri, 29 Mar 2024 17:58:25 -0500
From: Michael Roth <michael.roth@....com>
To: <kvm@...r.kernel.org>
CC: <linux-coco@...ts.linux.dev>, <linux-mm@...ck.org>,
<linux-crypto@...r.kernel.org>, <x86@...nel.org>,
<linux-kernel@...r.kernel.org>, <tglx@...utronix.de>, <mingo@...hat.com>,
<jroedel@...e.de>, <thomas.lendacky@....com>, <hpa@...or.com>,
<ardb@...nel.org>, <pbonzini@...hat.com>, <seanjc@...gle.com>,
<vkuznets@...hat.com>, <jmattson@...gle.com>, <luto@...nel.org>,
<dave.hansen@...ux.intel.com>, <slp@...hat.com>, <pgonda@...gle.com>,
<peterz@...radead.org>, <srinivas.pandruvada@...ux.intel.com>,
<rientjes@...gle.com>, <dovmurik@...ux.ibm.com>, <tobin@....com>,
<bp@...en8.de>, <vbabka@...e.cz>, <kirill@...temov.name>,
<ak@...ux.intel.com>, <tony.luck@...el.com>,
<sathyanarayanan.kuppuswamy@...ux.intel.com>, <alpergun@...gle.com>,
<jarkko@...nel.org>, <ashish.kalra@....com>, <nikunj.dadhania@....com>,
<pankaj.gupta@....com>, <liam.merwick@...cle.com>, Brijesh Singh
<brijesh.singh@....com>
Subject: [PATCH v12 19/29] KVM: SEV: Support SEV-SNP AP Creation NAE event
From: Tom Lendacky <thomas.lendacky@....com>
Add support for the SEV-SNP AP Creation NAE event. This allows SEV-SNP
guests to alter the register state of the APs on their own. This allows
the guest a way of simulating INIT-SIPI.
A new event, KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, is created and used
so as to avoid updating the VMSA pointer while the vCPU is running.
For CREATE
The guest supplies the GPA of the VMSA to be used for the vCPU with
the specified APIC ID. The GPA is saved in the svm struct of the
target vCPU, the KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event is added
to the vCPU and then the vCPU is kicked.
For CREATE_ON_INIT:
The guest supplies the GPA of the VMSA to be used for the vCPU with
the specified APIC ID the next time an INIT is performed. The GPA is
saved in the svm struct of the target vCPU.
For DESTROY:
The guest indicates it wishes to stop the vCPU. The GPA is cleared
from the svm struct, the KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event is
added to vCPU and then the vCPU is kicked.
The KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event handler will be invoked
as a result of the event or as a result of an INIT. If a new VMSA is to
be installed, the VMSA guest page is set as the VMSA in the vCPU VMCB
and the vCPU state is set to KVM_MP_STATE_RUNNABLE. If a new VMSA is not
to be installed, the VMSA is cleared in the vCPU VMCB and the vCPU state
is set to KVM_MP_STATE_HALTED to prevent it from being run.
Signed-off-by: Tom Lendacky <thomas.lendacky@....com>
Signed-off-by: Brijesh Singh <brijesh.singh@....com>
Signed-off-by: Ashish Kalra <ashish.kalra@....com>
[mdr: add handling for gmem, move MP_STATE_UNINITIALIZED -> RUNNABLE
transition to target vCPU side rather than setting vcpu->arch.mp_state
remotely]
Signed-off-by: Michael Roth <michael.roth@....com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/include/asm/svm.h | 6 +
arch/x86/kvm/svm/sev.c | 217 +++++++++++++++++++++++++++++++-
arch/x86/kvm/svm/svm.c | 11 +-
arch/x86/kvm/svm/svm.h | 8 ++
arch/x86/kvm/x86.c | 11 ++
6 files changed, 252 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 49b294a8d917..0fdacacd6e8e 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -121,6 +121,7 @@
KVM_ARCH_REQ_FLAGS(31, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_HV_TLB_FLUSH \
KVM_ARCH_REQ_FLAGS(32, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE KVM_ARCH_REQ(34)
#define CR0_RESERVED_BITS \
(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 544a43c1cf11..f0dea3750ca9 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -286,8 +286,14 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_
#define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF)
#define SVM_SEV_FEAT_SNP_ACTIVE BIT(0)
+#define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3)
+#define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4)
#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5)
+#define SVM_SEV_FEAT_INT_INJ_MODES \
+ (SVM_SEV_FEAT_RESTRICTED_INJECTION | \
+ SVM_SEV_FEAT_ALTERNATE_INJECTION)
+
struct vmcb_seg {
u16 selector;
u16 attrib;
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index ce1c727bad23..7dfbf12b454b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -37,7 +37,7 @@
#define GHCB_VERSION_MAX 2ULL
#define GHCB_VERSION_MIN 1ULL
-#define GHCB_HV_FT_SUPPORTED GHCB_HV_FT_SNP
+#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION)
/* enable/disable SEV support */
static bool sev_enabled = true;
@@ -3203,6 +3203,11 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
if (!kvm_ghcb_sw_scratch_is_valid(svm))
goto vmgexit_err;
break;
+ case SVM_VMGEXIT_AP_CREATION:
+ if (lower_32_bits(control->exit_info_1) != SVM_VMGEXIT_AP_DESTROY)
+ if (!kvm_ghcb_rax_is_valid(svm))
+ goto vmgexit_err;
+ break;
case SVM_VMGEXIT_NMI_COMPLETE:
case SVM_VMGEXIT_AP_HLT_LOOP:
case SVM_VMGEXIT_AP_JUMP_TABLE:
@@ -3443,6 +3448,195 @@ static int snp_complete_psc(struct kvm_vcpu *vcpu)
return 1; /* resume guest */
}
+static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ WARN_ON(!mutex_is_locked(&svm->sev_es.snp_vmsa_mutex));
+
+ /* Mark the vCPU as offline and not runnable */
+ vcpu->arch.pv.pv_unhalted = false;
+ vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
+
+ /* Clear use of the VMSA */
+ svm->sev_es.vmsa_pa = INVALID_PAGE;
+ svm->vmcb->control.vmsa_pa = INVALID_PAGE;
+
+ if (VALID_PAGE(svm->sev_es.snp_vmsa_gpa)) {
+ gfn_t gfn = gpa_to_gfn(svm->sev_es.snp_vmsa_gpa);
+ struct kvm_memory_slot *slot;
+ kvm_pfn_t pfn;
+
+ slot = gfn_to_memslot(vcpu->kvm, gfn);
+ if (!slot)
+ return -EINVAL;
+
+ /*
+ * The new VMSA will be private memory guest memory, so
+ * retrieve the PFN from the gmem backend.
+ */
+ if (kvm_gmem_get_pfn(vcpu->kvm, slot, gfn, &pfn, NULL))
+ return -EINVAL;
+
+ /* Use the new VMSA */
+ svm->sev_es.vmsa_pa = pfn_to_hpa(pfn);
+ svm->vmcb->control.vmsa_pa = svm->sev_es.vmsa_pa;
+
+ /* Mark the vCPU as runnable */
+ vcpu->arch.pv.pv_unhalted = false;
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+
+ svm->sev_es.snp_vmsa_gpa = INVALID_PAGE;
+
+ /*
+ * gmem pages aren't currently migratable, but if this ever
+ * changes then care should be taken to ensure
+ * svm->sev_es.vmsa_pa is pinned through some other means.
+ */
+ kvm_release_pfn_clean(pfn);
+ }
+
+ /*
+ * When replacing the VMSA during SEV-SNP AP creation,
+ * mark the VMCB dirty so that full state is always reloaded.
+ */
+ vmcb_mark_all_dirty(svm->vmcb);
+
+ return 0;
+}
+
+/*
+ * Invoked as part of svm_vcpu_reset() processing of an init event.
+ */
+void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int ret;
+
+ if (!sev_snp_guest(vcpu->kvm))
+ return;
+
+ mutex_lock(&svm->sev_es.snp_vmsa_mutex);
+
+ if (!svm->sev_es.snp_ap_create)
+ goto unlock;
+
+ svm->sev_es.snp_ap_create = false;
+
+ ret = __sev_snp_update_protected_guest_state(vcpu);
+ if (ret)
+ vcpu_unimpl(vcpu, "snp: AP state update on init failed\n");
+
+unlock:
+ mutex_unlock(&svm->sev_es.snp_vmsa_mutex);
+}
+
+static int sev_snp_ap_creation(struct vcpu_svm *svm)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(svm->vcpu.kvm)->sev_info;
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ struct kvm_vcpu *target_vcpu;
+ struct vcpu_svm *target_svm;
+ unsigned int request;
+ unsigned int apic_id;
+ bool kick;
+ int ret;
+
+ request = lower_32_bits(svm->vmcb->control.exit_info_1);
+ apic_id = upper_32_bits(svm->vmcb->control.exit_info_1);
+
+ /* Validate the APIC ID */
+ target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, apic_id);
+ if (!target_vcpu) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP APIC ID [%#x] from guest\n",
+ apic_id);
+ return -EINVAL;
+ }
+
+ ret = 0;
+
+ target_svm = to_svm(target_vcpu);
+
+ /*
+ * The target vCPU is valid, so the vCPU will be kicked unless the
+ * request is for CREATE_ON_INIT. For any errors at this stage, the
+ * kick will place the vCPU in an non-runnable state.
+ */
+ kick = true;
+
+ mutex_lock(&target_svm->sev_es.snp_vmsa_mutex);
+
+ target_svm->sev_es.snp_vmsa_gpa = INVALID_PAGE;
+ target_svm->sev_es.snp_ap_create = true;
+
+ /* Interrupt injection mode shouldn't change for AP creation */
+ if (request < SVM_VMGEXIT_AP_DESTROY) {
+ u64 sev_features;
+
+ sev_features = vcpu->arch.regs[VCPU_REGS_RAX];
+ sev_features ^= sev->vmsa_features;
+
+ if (sev_features & SVM_SEV_FEAT_INT_INJ_MODES) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP injection mode [%#lx] from guest\n",
+ vcpu->arch.regs[VCPU_REGS_RAX]);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ switch (request) {
+ case SVM_VMGEXIT_AP_CREATE_ON_INIT:
+ kick = false;
+ fallthrough;
+ case SVM_VMGEXIT_AP_CREATE:
+ if (!page_address_valid(vcpu, svm->vmcb->control.exit_info_2)) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP VMSA address [%#llx] from guest\n",
+ svm->vmcb->control.exit_info_2);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Malicious guest can RMPADJUST a large page into VMSA which
+ * will hit the SNP erratum where the CPU will incorrectly signal
+ * an RMP violation #PF if a hugepage collides with the RMP entry
+ * of VMSA page, reject the AP CREATE request if VMSA address from
+ * guest is 2M aligned.
+ */
+ if (IS_ALIGNED(svm->vmcb->control.exit_info_2, PMD_SIZE)) {
+ vcpu_unimpl(vcpu,
+ "vmgexit: AP VMSA address [%llx] from guest is unsafe as it is 2M aligned\n",
+ svm->vmcb->control.exit_info_2);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2;
+ break;
+ case SVM_VMGEXIT_AP_DESTROY:
+ break;
+ default:
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n",
+ request);
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ if (kick) {
+ kvm_make_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, target_vcpu);
+
+ if (target_vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
+ kvm_make_request(KVM_REQ_UNBLOCK, target_vcpu);
+
+ kvm_vcpu_kick(target_vcpu);
+ }
+
+ mutex_unlock(&target_svm->sev_es.snp_vmsa_mutex);
+
+ return ret;
+}
+
static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3686,6 +3880,15 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
vcpu->run->vmgexit.psc.shared_gpa = svm->sev_es.sw_scratch;
vcpu->arch.complete_userspace_io = snp_complete_psc;
break;
+ case SVM_VMGEXIT_AP_CREATION:
+ ret = sev_snp_ap_creation(svm);
+ if (ret) {
+ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT);
+ }
+
+ ret = 1;
+ break;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
vcpu_unimpl(vcpu,
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
@@ -3852,6 +4055,8 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)
set_ghcb_msr(svm, GHCB_MSR_SEV_INFO(GHCB_VERSION_MAX,
GHCB_VERSION_MIN,
sev_enc_bit));
+
+ mutex_init(&svm->sev_es.snp_vmsa_mutex);
}
void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
@@ -3963,6 +4168,16 @@ struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu)
return p;
}
+void sev_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ if (!sev_snp_guest(vcpu->kvm))
+ return;
+
+ if (kvm_test_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu) &&
+ vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+}
+
void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code)
{
struct kvm_memory_slot *slot;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index e036a8927717..a895d3f07cb8 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1398,6 +1398,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
svm->spec_ctrl = 0;
svm->virt_spec_ctrl = 0;
+ if (init_event)
+ sev_snp_init_protected_guest_state(vcpu);
+
init_vmcb(vcpu);
if (!init_event)
@@ -4937,6 +4940,12 @@ static void *svm_alloc_apic_backing_page(struct kvm_vcpu *vcpu)
return page_address(page);
}
+static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ sev_vcpu_unblocking(vcpu);
+ avic_vcpu_unblocking(vcpu);
+}
+
static struct kvm_x86_ops svm_x86_ops __initdata = {
.name = KBUILD_MODNAME,
@@ -4959,7 +4968,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
.vcpu_blocking = avic_vcpu_blocking,
- .vcpu_unblocking = avic_vcpu_unblocking,
+ .vcpu_unblocking = svm_vcpu_unblocking,
.update_exception_bitmap = svm_update_exception_bitmap,
.get_msr_feature = svm_get_msr_feature,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 8cce3315b46c..0cdcd0759fe0 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -211,6 +211,10 @@ struct vcpu_sev_es_state {
bool ghcb_sa_free;
u64 ghcb_registered_gpa;
+
+ struct mutex snp_vmsa_mutex; /* Used to handle concurrent updates of VMSA */
+ gpa_t snp_vmsa_gpa;
+ bool snp_ap_create;
};
struct vcpu_svm {
@@ -724,6 +728,8 @@ int sev_cpu_init(struct svm_cpu_data *sd);
int sev_dev_get_attr(u64 attr, u64 *val);
extern unsigned int max_sev_asid;
void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code);
+void sev_vcpu_unblocking(struct kvm_vcpu *vcpu);
+void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu);
#else
static inline struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) {
return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
@@ -738,6 +744,8 @@ static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; }
static inline int sev_dev_get_attr(u64 attr, u64 *val) { return -ENXIO; }
#define max_sev_asid 0
static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {}
+static inline void sev_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+static inline void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) {}
#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f85735b6235d..617c38656757 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10943,6 +10943,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_UPDATE_CPU_DIRTY_LOGGING, vcpu))
static_call(kvm_x86_update_cpu_dirty_logging)(vcpu);
+
+ if (kvm_check_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu)) {
+ kvm_vcpu_reset(vcpu, true);
+ if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) {
+ r = 1;
+ goto out;
+ }
+ }
}
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||
@@ -13150,6 +13158,9 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
if (kvm_test_request(KVM_REQ_PMI, vcpu))
return true;
+ if (kvm_test_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu))
+ return true;
+
if (kvm_arch_interrupt_allowed(vcpu) &&
(kvm_cpu_has_interrupt(vcpu) ||
kvm_guest_apic_has_interrupt(vcpu)))
--
2.25.1
X-sender: <linux-kernel+bounces-125499-steffen.klassert=secunet.com@...r.kernel.org>
X-Receiver: <steffen.klassert@...unet.com> ORCPT=rfc822;steffen.klassert@...unet.com; X-ExtendedProps=DwA1AAAATWljcm9zb2Z0LkV4Y2hhbmdlLlRyYW5zcG9ydC5EaXJlY3RvcnlEYXRhLklzUmVzb3VyY2UCAAAFABUAFgACAAAABQAUABEA8MUJLbkECUOS0gjaDTZ+uAUAagAJAAEAAAAAAAAABQAWAAIAAAUAQwACAAAFAEYABwADAAAABQBHAAIAAAUAEgAPAGIAAAAvbz1zZWN1bmV0L291PUV4Y2hhbmdlIEFkbWluaXN0cmF0aXZlIEdyb3VwIChGWURJQk9IRjIzU1BETFQpL2NuPVJlY2lwaWVudHMvY249U3RlZmZlbiBLbGFzc2VydDY4YwUACwAXAL4AAACheZxkHSGBRqAcAp3ukbifQ049REI2LENOPURhdGFiYXNlcyxDTj1FeGNoYW5nZSBBZG1pbmlzdHJhdGl2ZSBHcm91cCAoRllESUJPSEYyM1NQRExUKSxDTj1BZG1pbmlzdHJhdGl2ZSBHcm91cHMsQ049c2VjdW5ldCxDTj1NaWNyb3NvZnQgRXhjaGFuZ2UsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1zZWN1bmV0LERDPWRlBQAOABEABiAS9uuMOkqzwmEZDvWNNQUAHQAPAAwAAABtYngtZXNzZW4tMDIFADwAAgAADwA2AAAATWljcm9zb2Z0LkV4Y2hhbmdlLlRyYW5zcG9ydC5NYWlsUmVjaXBpZW50LkRpc3BsYXlOYW1lDwARAAAAS2xhc3NlcnQsIFN0ZWZmZW4FAGwAAgAABQBYABcASgAAAPDFCS25BAlDktII2g02frhDTj1LbGFzc2VydCBTdGVmZmVuLE9VPVVzZXJzLE9VPU1pZ3JhdGlvbixEQz1zZWN1bmV0LERDPWRlBQAMAAIAAAUAJgACAAEFACIADwAxAAAAQXV0b1Jlc3BvbnNlU3VwcHJlc3M6IDANClRyYW5zbWl0SGlzdG9yeTogRmFsc2UNCg8ALwAAAE1pY3Jvc29mdC5FeGNoYW5nZS5UcmFuc3BvcnQuRXhwYW5zaW9uR3JvdXBUeXBlDwAVAAAATWVtYmVyc0dyb3VwRXhwYW5zaW9uBQAjAAIAAQ==
X-CreatedBy: MSExchange15
X-HeloDomain: b.mx.secunet.com
X-ExtendedProps: BQBjAAoAs0mmlidQ3AgFAGEACAABAAAABQA3AAIAAA8APAAAAE1pY3Jvc29mdC5FeGNoYW5nZS5UcmFuc3BvcnQuTWFpbFJlY2lwaWVudC5Pcmdhbml6YXRpb25TY29wZREAAAAAAAAAAAAAAAAAAAAAAAUASQACAAEFAAQAFCABAAAAHAAAAHN0ZWZmZW4ua2xhc3NlcnRAc2VjdW5ldC5jb20FAAYAAgABDwAqAAAATWljcm9zb2Z0LkV4Y2hhbmdlLlRyYW5zcG9ydC5SZXN1Ym1pdENvdW50BwACAAAADwAJAAAAQ0lBdWRpdGVkAgABBQACAAcAAQAAAAUAAwAHAAAAAAAFAAUAAgABBQBiAAoAMQAAAM6KAAAFAGQADwADAAAASHViBQApAAIAAQ8APwAAAE1pY3Jvc29mdC5FeGNoYW5nZS5UcmFuc3BvcnQuRGlyZWN0b3J5RGF0YS5NYWlsRGVsaXZlcnlQcmlvcml0eQ8AAwAAAExvdw==
X-Source: SMTP:Default MBX-ESSEN-02
X-SourceIPAddress: 62.96.220.37
X-EndOfInjectedXHeaders: 40815
Received: from cas-essen-02.secunet.de (10.53.40.202) by
mbx-essen-02.secunet.de (10.53.40.198) with Microsoft SMTP Server
(version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id
15.1.2507.37; Sat, 30 Mar 2024 00:03:27 +0100
Received: from b.mx.secunet.com (62.96.220.37) by cas-essen-02.secunet.de
(10.53.40.202) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend
Transport; Sat, 30 Mar 2024 00:03:27 +0100
Received: from localhost (localhost [127.0.0.1])
by b.mx.secunet.com (Postfix) with ESMTP id CD9122032C
for <steffen.klassert@...unet.com>; Sat, 30 Mar 2024 00:03:27 +0100 (CET)
X-Virus-Scanned: by secunet
X-Spam-Flag: NO
X-Spam-Score: -5.15
X-Spam-Level:
X-Spam-Status: No, score=-5.15 tagged_above=-999 required=2.1
tests=[BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.099, DKIM_SIGNED=0.1,
DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,
HEADER_FROM_DIFFERENT_DOMAINS=0.249, MAILING_LIST_MULTI=-1,
RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001]
autolearn=unavailable autolearn_force=no
Authentication-Results: a.mx.secunet.com (amavisd-new);
dkim=pass (1024-bit key) header.d=amd.com
Received: from b.mx.secunet.com ([127.0.0.1])
by localhost (a.mx.secunet.com [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id VyZR681U1qTQ for <steffen.klassert@...unet.com>;
Sat, 30 Mar 2024 00:03:26 +0100 (CET)
Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=139.178.88.99; helo=sv.mirrors.kernel.org; envelope-from=linux-kernel+bounces-125499-steffen.klassert=secunet.com@...r.kernel.org; receiver=steffen.klassert@...unet.com
DKIM-Filter: OpenDKIM Filter v2.11.0 b.mx.secunet.com 7E62A200BB
Authentication-Results: b.mx.secunet.com;
dkim=pass (1024-bit key) header.d=amd.com header.i=@....com header.b="tsg2jqS4"
Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org [139.178.88.99])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by b.mx.secunet.com (Postfix) with ESMTPS id 7E62A200BB
for <steffen.klassert@...unet.com>; Sat, 30 Mar 2024 00:03:26 +0100 (CET)
Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by sv.mirrors.kernel.org (Postfix) with ESMTPS id C69C228254E
for <steffen.klassert@...unet.com>; Fri, 29 Mar 2024 23:03:24 +0000 (UTC)
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
by smtp.subspace.kernel.org (Postfix) with ESMTP id 1B81C13E880;
Fri, 29 Mar 2024 23:03:06 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (1024-bit key) header.d=amd.com header.i=@....com header.b="tsg2jqS4"
Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2041.outbound.protection.outlook.com [40.107.236.41])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id B658F24B21;
Fri, 29 Mar 2024 23:02:57 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.236.41
ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
t=1711753381; cv=fail; b=ASgCoc4pmkz2vBzguIaJLZZVNBJMtLdJT8A1j5Gp2plNuevF713OSNn7k7u/Xh/j5x7jv9jH1DiJ3uwERThruOXukCQucQ9R8C6BHTb7FcGVSyi9jobpRzt1p3sMEWB7AWrsDnGzohE/u8V1LOrYE2kekbT8zRBwOVdw8bs5eGM=
ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org;
s=arc-20240116; t=1711753381; c=relaxed/simple;
bh=KHHF/vBYV5yB+doCUDT2LqJVpn4wXbjwTAFdd/Tr7hw=;
h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:
MIME-Version:Content-Type; b=V+ChY87+uuO2tjKr3OWfY++p39GWLb5XEFU/ybYb8lwg0vZ9LskG3nCjTUkEAp1ui1xTIQAbcvc+gIipheM8dIptkLBE257HhTf038ApMGog29pcErKE7IM4gsVOb0kvRSpB0ymOIbwnQfmKj4CH8Z5mmMeOnuq69gMbm001NzU=
ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@....com header.b=tsg2jqS4; arc=fail smtp.client-ip=40.107.236.41
Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com
Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com
ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;
b=lLYVJ2rjiBRdW+iXdllNqIZgZPbKY5JUZuXz84I0MYkGHI2+isS0se4oi/xUVAb7WCpukPlEZ4EnA/TAf/47O5YwigfjX4z64qW0n65Liq7pSTRVQbZIg6hQDzMtF5tAemszDQ9S54y77SMSCrbFO0vgBz/6K8M9xwc2D3JNhOwb1vfNLhsWvLaDKUBNwSndlN7au8+Ihklcg0z97qJpnWdvu2IkGMHsNfwxMYkX01MV0m/RciFc31h98MB/qP7LwW8yrDdBe8bgE1tqE6GfC1TjmwKVJQ6vSnqXRv9sTL0qQZa1HjoTdPMAWEWJX2El0kVFYa/Y94IWHm1Ro9ZmSg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;
s=arcselector9901;
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;
bh=hYDUOsZ8oSqdDjPaR5Xc/ME9UC8/Zi2qVp0/kTJliSw=;
b=JZR18khJWPFbqxfvnhDfSz6vzkLIVM7g+WZGEqcJXuCxovLzBVdk2SVcaEonPSC5OIgWVMSRDRTbWA1quhM5G1ZajXm5cBNlvHTLl8EiqNwjn9MefAshE6md3MR6r9r7EOfPcnn3R8XMJkwBu6c6RDoTcNKIBW07GaJ2LDup6PZSeTpFSz9nc7MxpyZf2UUtgMfj/sKbCcHkMh+66FhpJMXwTo3PBqJPKBKw8ZGizPykZT7zyqdMnXDuAfx0JXEfqvu5mQ8O4c87jxmoOywcragCJynnAOQnF/Oh99uwkrFNFpZ3JZubcu3uOGkPJAlTBu1TX3SSyBS0+fjfurKuPw==
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is
165.204.84.17) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=amd.com;
dmarc=pass (p=quarantine sp=quarantine pct=100) action=none
header.from=amd.com; dkim=none (message not signed); arc=none (0)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1;
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
bh=hYDUOsZ8oSqdDjPaR5Xc/ME9UC8/Zi2qVp0/kTJliSw=;
b=tsg2jqS42wTV0w9yTC7xM2MdaeE+6YTCo02pkCeadOlCLdUzOWEv9Cdbny0qli+q9EOFf18R1n+DFSolN88DcIl+p17LPAZCmBMVf83MvzKXZRO89mIaSyNP3VQhPVpOuMmISAhQyrR+6eCZtW27hj4N8M0imnZzJJTqoJlBzo0=
Received: from SJ0PR03CA0153.namprd03.prod.outlook.com (2603:10b6:a03:338::8)
by PH0PR12MB8032.namprd12.prod.outlook.com (2603:10b6:510:26f::15) with
Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.42; Fri, 29 Mar
2024 23:02:52 +0000
Received: from SJ1PEPF00001CE2.namprd05.prod.outlook.com
(2603:10b6:a03:338:cafe::d5) by SJ0PR03CA0153.outlook.office365.com
(2603:10b6:a03:338::8) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.40 via Frontend
Transport; Fri, 29 Mar 2024 23:02:52 +0000
X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17)
smtp.mailfrom=amd.com; dkim=none (message not signed)
header.d=none;dmarc=pass action=none header.from=amd.com;
Received-SPF: Pass (protection.outlook.com: domain of amd.com designates
165.204.84.17 as permitted sender) receiver=protection.outlook.com;
client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C
Received: from SATLEXMB04.amd.com (165.204.84.17) by
SJ1PEPF00001CE2.mail.protection.outlook.com (10.167.242.10) with Microsoft
SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id
15.20.7409.10 via Frontend Transport; Fri, 29 Mar 2024 23:02:52 +0000
Received: from localhost (10.180.168.240) by SATLEXMB04.amd.com
(10.181.40.145) with Microsoft SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 29 Mar
2024 18:02:51 -0500
From: Michael Roth <michael.roth@....com>
To: <kvm@...r.kernel.org>
CC: <linux-coco@...ts.linux.dev>, <linux-mm@...ck.org>,
<linux-crypto@...r.kernel.org>, <x86@...nel.org>,
<linux-kernel@...r.kernel.org>, <tglx@...utronix.de>, <mingo@...hat.com>,
<jroedel@...e.de>, <thomas.lendacky@....com>, <hpa@...or.com>,
<ardb@...nel.org>, <pbonzini@...hat.com>, <seanjc@...gle.com>,
<vkuznets@...hat.com>, <jmattson@...gle.com>, <luto@...nel.org>,
<dave.hansen@...ux.intel.com>, <slp@...hat.com>, <pgonda@...gle.com>,
<peterz@...radead.org>, <srinivas.pandruvada@...ux.intel.com>,
<rientjes@...gle.com>, <dovmurik@...ux.ibm.com>, <tobin@....com>,
<bp@...en8.de>, <vbabka@...e.cz>, <kirill@...temov.name>,
<ak@...ux.intel.com>, <tony.luck@...el.com>,
<sathyanarayanan.kuppuswamy@...ux.intel.com>, <alpergun@...gle.com>,
<jarkko@...nel.org>, <ashish.kalra@....com>, <nikunj.dadhania@....com>,
<pankaj.gupta@....com>, <liam.merwick@...cle.com>, Brijesh Singh
<brijesh.singh@....com>
Subject: [PATCH v12 19/29] KVM: SEV: Support SEV-SNP AP Creation NAE event
Date: Fri, 29 Mar 2024 17:58:25 -0500
Message-ID: <20240329225835.400662-20-michael.roth@....com>
X-Mailer: git-send-email 2.25.1
In-Reply-To: <20240329225835.400662-1-michael.roth@....com>
References: <20240329225835.400662-1-michael.roth@....com>
Precedence: bulk
X-Mailing-List: linux-kernel@...r.kernel.org
List-Id: <linux-kernel.vger.kernel.org>
List-Subscribe: <mailto:linux-kernel+subscribe@...r.kernel.org>
List-Unsubscribe: <mailto:linux-kernel+unsubscribe@...r.kernel.org>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Content-Type: text/plain
X-ClientProxiedBy: SATLEXMB03.amd.com (10.181.40.144) To SATLEXMB04.amd.com
(10.181.40.145)
X-EOPAttributedMessage: 0
X-MS-PublicTrafficType: Email
X-MS-TrafficTypeDiagnostic: SJ1PEPF00001CE2:EE_|PH0PR12MB8032:EE_
X-MS-Office365-Filtering-Correlation-Id: 551edada-c896-4c34-cb0b-08dc50445cac
X-MS-Exchange-SenderADCheck: 1
X-MS-Exchange-AntiSpam-Relay: 0
X-Microsoft-Antispam: BCL:0;
X-Microsoft-Antispam-Message-Info: bjuWmA2FmMrZm/Lj19E04lIhHLtbd7tQjfPwsVQo3kXbjdq069bgIoUjxkhgx8Aog4T4A3SqnXW08ioGCt1IlNphfNVzzruiUNNzLQ2rfJL4u7yg38WZSlbesKmiUQF9+h3hAMV3iEaGIMxQLMiF8/pLqaxrl2T3bnXGI1CY0ZQvFM4cb+jZsMMExqzSFSd2yrWlrsz2v7jxs5jn5GlS3RkBz46l3THP9KVizrwjINvqJ+b7q+DryORFCc74jHbXHwevPI9WRn7c2UINnUyX3Tixqx+JC3wZ53Mu2LAnGHcXCDjY2972TsOFRQ4w2Oopu/P7sFSNb82qrAEqvRiK0UgOzYkkclLrdqjoXVXXHse0DMPB7APNjMriX0HkXip3reXUbUs9eYjYKpvLIXvvDBsrodbz+GFat/Lg2ri8HqMnsu1hyGo++bXUr4Srgtv8wS9ymx6EGwKP0SXqxqrwf8sFmyAfI9ZDuoaQkiTL6hra+gLdWzsb+PrYu/GYSlTGCEKCVH9tQ+j5mGyLi48LciiqqIKfQ8gm1SAmZ5uXUVi6sLHDrFfw4Grx8QBURmbKlNX74pmxPa2UEx31cXvdta3+9GihVK3kWW9p18Tfo7ExRMJ+SbP7H7GTGs+FyDi1abkfQ0Bq0woD+mX7w/e9zlIg2s2lsNjktlMkFmns3T+H6j1u+oetS3cP19luVMG3RojbB2cOx7+b47V+AEvF5odxwKPDE6HJK3hneESmFVGYoHX92nA1oPxul0vafabD
X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230031)(1800799015)(7416005)(376005)(82310400014)(36860700004);DIR:OUT;SFP:1101;
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Mar 2024 23:02:52.1344
(UTC)
X-MS-Exchange-CrossTenant-Network-Message-Id: 551edada-c896-4c34-cb0b-08dc50445cac
X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d
X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com]
X-MS-Exchange-CrossTenant-AuthSource: SJ1PEPF00001CE2.namprd05.prod.outlookcom
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem
X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR12MB8032
Return-Path: linux-kernel+bounces-125499-steffen.klassert=secunet.com@...r.kernel.org
X-MS-Exchange-Organization-OriginalArrivalTime: 29 Mar 2024 23:03:27.8753
(UTC)
X-MS-Exchange-Organization-Network-Message-Id: af780292-29d4-4036-a8a6-08dc504471e7
X-MS-Exchange-Organization-OriginalClientIPAddress: 62.96.220.37
X-MS-Exchange-Organization-OriginalServerIPAddress: 10.53.40.202
X-MS-Exchange-Organization-Cross-Premises-Headers-Processed: cas-essen-02.secunet.de
X-MS-Exchange-Organization-OrderedPrecisionLatencyInProgress: LSRV=mbx-essen-02.secunet.de:TOTAL-HUB=33337.492|SMR=0.139(SMRDE=0.005|SMRC=0.133(SMRCL=0.103|X-SMRCR=0.133))|CAT=0.095(CATRESL=0.028
(CATRESLP2R=0.025)|CATORES=0.063(CATRS=0.062(CATRS-Index Routing
Agent=0.061))|CATORT=0.001
(CATRT=0.001))|UNK=0.001|QDM=12182.769|SMSC=0.625(X-SMSDR=0.012)|SMS=5.877(SMSMBXD-INC=5.382
)|UNK=0.001|QDM=20832.499|SMSC=0.010|SMS=1.288(SMSMBXD-INC=1.278)|QDM=309.051|PSC=0.026
|CAT=0.008(CATRESL=0.006(CATRESLP2R=0.001))|QDM=5.350|UNK=0.001|CAT=0.005(CATRESL=0.004
(CATRESLP2R=0.002));2024-03-30T08:19:05.383Z
X-MS-Exchange-Forest-ArrivalHubServer: mbx-essen-02.secunet.de
X-MS-Exchange-Organization-AuthSource: cas-essen-02.secunet.de
X-MS-Exchange-Organization-AuthAs: Anonymous
X-MS-Exchange-Organization-FromEntityHeader: Internet
X-MS-Exchange-Organization-OriginalSize: 26856
X-MS-Exchange-Organization-HygienePolicy: Standard
X-MS-Exchange-Organization-MessageLatency: SRV=cas-essen-02.secunet.de:TOTAL-FE=0.016|SMR=0.010(SMRPI=0.007(SMRPI-FrontendProxyAgent=0.007))|SMS=0.006
X-MS-Exchange-Organization-Recipient-Limit-Verified: True
X-MS-Exchange-Organization-TotalRecipientCount: 1
X-MS-Exchange-Organization-Rules-Execution-History: 0b0cf904-14ac-4724-8bdf-482ee6223cf2%%%fd34672d-751c-45ae-a963-ed177fcabe23%%%d8080257-b0c3-47b4-b0db-23bc0c8ddb3c%%%95e591a2-5d7d-4afa-b1d0-7573d6c0a5d9%%%f7d0f6bc-4dcc-4876-8c5d-b3d6ddbb3d55%%%16355082-c50b-4214-9c7d-d39575f9f79b
X-MS-Exchange-Forest-RulesExecuted: mbx-essen-02
X-MS-Exchange-Organization-RulesExecuted: mbx-essen-02
X-MS-Exchange-Forest-IndexAgent-0: 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
Lp8mUOA3w5RMytcbmjNKu2aWX/9tIhpamFWuKiZ1cJFlck6edi1yIn
OTuBajzCtBdFMinXZjeBigoqAbAyUdUPhaXFkVGr84MHTRdEhxPuEG
yXpW7uZ0U1oFzFse4QLLdNI93xnMmv5UCzMzUtpnJsvckeNJ9W+crS
Zqu9UqNzyIptN8ZBadDaNbUisPhlMvqaoTqaS3nBhETKzeuxV4CUR5
W7WdTyPsrD49hLyeMeOIfC0RUl0fVquxOjWsUKBNOJJJF53iZ71AzS
FBEGKfswNdJOKwAxXKgcZk4wxW7WR0mggZ8MUwnCBH/EB3PYSAmGJM
vN5Z87/LUXk68C1tuTS8kIoK6IDbNbbR2WGa6KKoMzemBEZ3LsOhhT
LjYHXvEoTFycIPHnyDB99TckI+6w5vlvlIufDtGB0WJNTZKDZG53kX
dKwZw+f/AyxJRVqWZQAAAQq9BDw/eG1sIHZlcnNpb249IjEuMCIgZW
5jb2Rpbmc9InV0Zi0xNiI/Pg0KPEVtYWlsU2V0Pg0KICA8VmVyc2lv
bj4xNS4wLjAuMDwvVmVyc2lvbj4NCiAgPEVtYWlscz4NCiAgICA8RW
1haWwgU3RhcnRJbmRleD0iMjAiPg0KICAgICAgPEVtYWlsU3RyaW5n
PnRob21hcy5sZW5kYWNreUBhbWQuY29tPC9FbWFpbFN0cmluZz4NCi
AgICA8L0VtYWlsPg0KICAgIDxFbWFpbCBTdGFydEluZGV4PSIxNTgw
IiBQb3NpdGlvbj0iT3RoZXIiPg0KICAgICAgPEVtYWlsU3RyaW5nPm
JyaWplc2guc2luZ2hAYW1kLmNvbTwvRW1haWxTdHJpbmc+DQogICAg
PC9FbWFpbD4NCiAgICA8RW1haWwgU3RhcnRJbmRleD0iMTYzMyIgUG
9zaXRpb249Ik90aGVyIj4NCiAgICAgIDxFbWFpbFN0cmluZz5hc2hp
c2gua2FscmFAYW1kLmNvbTwvRW1haWxTdHJpbmc+DQogICAgPC9FbW
FpbD4NCiAgICA8RW1haWwgU3RhcnRJbmRleD0iMTg0MCIgUG9zaXRp
b249Ik90aGVyIj4NCiAgICAgIDxFbWFpbFN0cmluZz5taWNoYWVsLn
JvdGhAYW1kLmNvbTwvRW1haWxTdHJpbmc+DQogICAgPC9FbWFpbD4N
CiAgPC9FbWFpbHM+DQo8L0VtYWlsU2V0PgEL2wE8P3htbCB2ZXJzaW
9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtMTYiPz4NCjxVcmxTZXQ+DQog
IDxWZXJzaW9uPjE1LjAuMC4wPC9WZXJzaW9uPg0KICA8VXJscz4NCi
AgICA8VXJsIFN0YXJ0SW5kZXg9IjE3ODQiIFBvc2l0aW9uPSJPdGhl
ciIgVHlwZT0iVXJsIj4NCiAgICAgIDxVcmxTdHJpbmc+YXJjaC5tcD
wvVXJsU3RyaW5nPg0KICAgIDwvVXJsPg0KICA8L1VybHM+DQo8L1Vy
bFNldD4BDtABUmV0cmlldmVyT3BlcmF0b3IsMTAsMTtSZXRyaWV2ZX
JPcGVyYXRvciwxMSw0O1Bvc3REb2NQYXJzZXJPcGVyYXRvciwxMCwx
O1Bvc3REb2NQYXJzZXJPcGVyYXRvciwxMSwwO1Bvc3RXb3JkQnJlYW
tlckRpYWdub3N0aWNPcGVyYXRvciwxMCwxMTtQb3N0V29yZEJyZWFr
ZXJEaWFnbm9zdGljT3BlcmF0b3IsMTEsMDtUcmFuc3BvcnRXcml0ZX JQcm9kdWNlciwyMCwyOQ==
X-MS-Exchange-Forest-IndexAgent: 1 8479
X-MS-Exchange-Forest-EmailMessageHash: F69556A6
X-MS-Exchange-Forest-Language: en
X-MS-Exchange-Organization-Processed-By-Journaling: Journal Agent
X-MS-Exchange-Organization-Transport-Properties: DeliveryPriority=Low
X-MS-Exchange-Organization-Prioritization: 2:RC:REDACTED-af51df60fd698f80b064826f9ee192ca@...unet.com:91/10|SR
X-MS-Exchange-Organization-IncludeInSla: False:RecipientCountThresholdExceeded
From: Tom Lendacky <thomas.lendacky@....com>
Add support for the SEV-SNP AP Creation NAE event. This allows SEV-SNP
guests to alter the register state of the APs on their own. This allows
the guest a way of simulating INIT-SIPI.
A new event, KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, is created and used
so as to avoid updating the VMSA pointer while the vCPU is running.
For CREATE
The guest supplies the GPA of the VMSA to be used for the vCPU with
the specified APIC ID. The GPA is saved in the svm struct of the
target vCPU, the KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event is added
to the vCPU and then the vCPU is kicked.
For CREATE_ON_INIT:
The guest supplies the GPA of the VMSA to be used for the vCPU with
the specified APIC ID the next time an INIT is performed. The GPA is
saved in the svm struct of the target vCPU.
For DESTROY:
The guest indicates it wishes to stop the vCPU. The GPA is cleared
from the svm struct, the KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event is
added to vCPU and then the vCPU is kicked.
The KVM_REQ_UPDATE_PROTECTED_GUEST_STATE event handler will be invoked
as a result of the event or as a result of an INIT. If a new VMSA is to
be installed, the VMSA guest page is set as the VMSA in the vCPU VMCB
and the vCPU state is set to KVM_MP_STATE_RUNNABLE. If a new VMSA is not
to be installed, the VMSA is cleared in the vCPU VMCB and the vCPU state
is set to KVM_MP_STATE_HALTED to prevent it from being run.
Signed-off-by: Tom Lendacky <thomas.lendacky@....com>
Signed-off-by: Brijesh Singh <brijesh.singh@....com>
Signed-off-by: Ashish Kalra <ashish.kalra@....com>
[mdr: add handling for gmem, move MP_STATE_UNINITIALIZED -> RUNNABLE
transition to target vCPU side rather than setting vcpu->arch.mp_state
remotely]
Signed-off-by: Michael Roth <michael.roth@....com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/include/asm/svm.h | 6 +
arch/x86/kvm/svm/sev.c | 217 +++++++++++++++++++++++++++++++-
arch/x86/kvm/svm/svm.c | 11 +-
arch/x86/kvm/svm/svm.h | 8 ++
arch/x86/kvm/x86.c | 11 ++
6 files changed, 252 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 49b294a8d917..0fdacacd6e8e 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -121,6 +121,7 @@
KVM_ARCH_REQ_FLAGS(31, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_HV_TLB_FLUSH \
KVM_ARCH_REQ_FLAGS(32, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+#define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE KVM_ARCH_REQ(34)
#define CR0_RESERVED_BITS \
(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 544a43c1cf11..f0dea3750ca9 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -286,8 +286,14 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_
#define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF)
#define SVM_SEV_FEAT_SNP_ACTIVE BIT(0)
+#define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3)
+#define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4)
#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5)
+#define SVM_SEV_FEAT_INT_INJ_MODES \
+ (SVM_SEV_FEAT_RESTRICTED_INJECTION | \
+ SVM_SEV_FEAT_ALTERNATE_INJECTION)
+
struct vmcb_seg {
u16 selector;
u16 attrib;
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index ce1c727bad23..7dfbf12b454b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -37,7 +37,7 @@
#define GHCB_VERSION_MAX 2ULL
#define GHCB_VERSION_MIN 1ULL
-#define GHCB_HV_FT_SUPPORTED GHCB_HV_FT_SNP
+#define GHCB_HV_FT_SUPPORTED (GHCB_HV_FT_SNP | GHCB_HV_FT_SNP_AP_CREATION)
/* enable/disable SEV support */
static bool sev_enabled = true;
@@ -3203,6 +3203,11 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
if (!kvm_ghcb_sw_scratch_is_valid(svm))
goto vmgexit_err;
break;
+ case SVM_VMGEXIT_AP_CREATION:
+ if (lower_32_bits(control->exit_info_1) != SVM_VMGEXIT_AP_DESTROY)
+ if (!kvm_ghcb_rax_is_valid(svm))
+ goto vmgexit_err;
+ break;
case SVM_VMGEXIT_NMI_COMPLETE:
case SVM_VMGEXIT_AP_HLT_LOOP:
case SVM_VMGEXIT_AP_JUMP_TABLE:
@@ -3443,6 +3448,195 @@ static int snp_complete_psc(struct kvm_vcpu *vcpu)
return 1; /* resume guest */
}
+static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ WARN_ON(!mutex_is_locked(&svm->sev_es.snp_vmsa_mutex));
+
+ /* Mark the vCPU as offline and not runnable */
+ vcpu->arch.pv.pv_unhalted = false;
+ vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
+
+ /* Clear use of the VMSA */
+ svm->sev_es.vmsa_pa = INVALID_PAGE;
+ svm->vmcb->control.vmsa_pa = INVALID_PAGE;
+
+ if (VALID_PAGE(svm->sev_es.snp_vmsa_gpa)) {
+ gfn_t gfn = gpa_to_gfn(svm->sev_es.snp_vmsa_gpa);
+ struct kvm_memory_slot *slot;
+ kvm_pfn_t pfn;
+
+ slot = gfn_to_memslot(vcpu->kvm, gfn);
+ if (!slot)
+ return -EINVAL;
+
+ /*
+ * The new VMSA will be private memory guest memory, so
+ * retrieve the PFN from the gmem backend.
+ */
+ if (kvm_gmem_get_pfn(vcpu->kvm, slot, gfn, &pfn, NULL))
+ return -EINVAL;
+
+ /* Use the new VMSA */
+ svm->sev_es.vmsa_pa = pfn_to_hpa(pfn);
+ svm->vmcb->control.vmsa_pa = svm->sev_es.vmsa_pa;
+
+ /* Mark the vCPU as runnable */
+ vcpu->arch.pv.pv_unhalted = false;
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+
+ svm->sev_es.snp_vmsa_gpa = INVALID_PAGE;
+
+ /*
+ * gmem pages aren't currently migratable, but if this ever
+ * changes then care should be taken to ensure
+ * svm->sev_es.vmsa_pa is pinned through some other means.
+ */
+ kvm_release_pfn_clean(pfn);
+ }
+
+ /*
+ * When replacing the VMSA during SEV-SNP AP creation,
+ * mark the VMCB dirty so that full state is always reloaded.
+ */
+ vmcb_mark_all_dirty(svm->vmcb);
+
+ return 0;
+}
+
+/*
+ * Invoked as part of svm_vcpu_reset() processing of an init event.
+ */
+void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int ret;
+
+ if (!sev_snp_guest(vcpu->kvm))
+ return;
+
+ mutex_lock(&svm->sev_es.snp_vmsa_mutex);
+
+ if (!svm->sev_es.snp_ap_create)
+ goto unlock;
+
+ svm->sev_es.snp_ap_create = false;
+
+ ret = __sev_snp_update_protected_guest_state(vcpu);
+ if (ret)
+ vcpu_unimpl(vcpu, "snp: AP state update on init failed\n");
+
+unlock:
+ mutex_unlock(&svm->sev_es.snp_vmsa_mutex);
+}
+
+static int sev_snp_ap_creation(struct vcpu_svm *svm)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(svm->vcpu.kvm)->sev_info;
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ struct kvm_vcpu *target_vcpu;
+ struct vcpu_svm *target_svm;
+ unsigned int request;
+ unsigned int apic_id;
+ bool kick;
+ int ret;
+
+ request = lower_32_bits(svm->vmcb->control.exit_info_1);
+ apic_id = upper_32_bits(svm->vmcb->control.exit_info_1);
+
+ /* Validate the APIC ID */
+ target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, apic_id);
+ if (!target_vcpu) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP APIC ID [%#x] from guest\n",
+ apic_id);
+ return -EINVAL;
+ }
+
+ ret = 0;
+
+ target_svm = to_svm(target_vcpu);
+
+ /*
+ * The target vCPU is valid, so the vCPU will be kicked unless the
+ * request is for CREATE_ON_INIT. For any errors at this stage, the
+ * kick will place the vCPU in an non-runnable state.
+ */
+ kick = true;
+
+ mutex_lock(&target_svm->sev_es.snp_vmsa_mutex);
+
+ target_svm->sev_es.snp_vmsa_gpa = INVALID_PAGE;
+ target_svm->sev_es.snp_ap_create = true;
+
+ /* Interrupt injection mode shouldn't change for AP creation */
+ if (request < SVM_VMGEXIT_AP_DESTROY) {
+ u64 sev_features;
+
+ sev_features = vcpu->arch.regs[VCPU_REGS_RAX];
+ sev_features ^= sev->vmsa_features;
+
+ if (sev_features & SVM_SEV_FEAT_INT_INJ_MODES) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP injection mode [%#lx] from guest\n",
+ vcpu->arch.regs[VCPU_REGS_RAX]);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ switch (request) {
+ case SVM_VMGEXIT_AP_CREATE_ON_INIT:
+ kick = false;
+ fallthrough;
+ case SVM_VMGEXIT_AP_CREATE:
+ if (!page_address_valid(vcpu, svm->vmcb->control.exit_info_2)) {
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP VMSA address [%#llx] from guest\n",
+ svm->vmcb->control.exit_info_2);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Malicious guest can RMPADJUST a large page into VMSA which
+ * will hit the SNP erratum where the CPU will incorrectly signal
+ * an RMP violation #PF if a hugepage collides with the RMP entry
+ * of VMSA page, reject the AP CREATE request if VMSA address from
+ * guest is 2M aligned.
+ */
+ if (IS_ALIGNED(svm->vmcb->control.exit_info_2, PMD_SIZE)) {
+ vcpu_unimpl(vcpu,
+ "vmgexit: AP VMSA address [%llx] from guest is unsafe as it is 2M aligned\n",
+ svm->vmcb->control.exit_info_2);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ target_svm->sev_es.snp_vmsa_gpa = svm->vmcb->control.exit_info_2;
+ break;
+ case SVM_VMGEXIT_AP_DESTROY:
+ break;
+ default:
+ vcpu_unimpl(vcpu, "vmgexit: invalid AP creation request [%#x] from guest\n",
+ request);
+ ret = -EINVAL;
+ break;
+ }
+
+out:
+ if (kick) {
+ kvm_make_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, target_vcpu);
+
+ if (target_vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
+ kvm_make_request(KVM_REQ_UNBLOCK, target_vcpu);
+
+ kvm_vcpu_kick(target_vcpu);
+ }
+
+ mutex_unlock(&target_svm->sev_es.snp_vmsa_mutex);
+
+ return ret;
+}
+
static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3686,6 +3880,15 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
vcpu->run->vmgexit.psc.shared_gpa = svm->sev_es.sw_scratch;
vcpu->arch.complete_userspace_io = snp_complete_psc;
break;
+ case SVM_VMGEXIT_AP_CREATION:
+ ret = sev_snp_ap_creation(svm);
+ if (ret) {
+ ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
+ ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT);
+ }
+
+ ret = 1;
+ break;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
vcpu_unimpl(vcpu,
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
@@ -3852,6 +4055,8 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm)
set_ghcb_msr(svm, GHCB_MSR_SEV_INFO(GHCB_VERSION_MAX,
GHCB_VERSION_MIN,
sev_enc_bit));
+
+ mutex_init(&svm->sev_es.snp_vmsa_mutex);
}
void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
@@ -3963,6 +4168,16 @@ struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu)
return p;
}
+void sev_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ if (!sev_snp_guest(vcpu->kvm))
+ return;
+
+ if (kvm_test_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu) &&
+ vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
+}
+
void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code)
{
struct kvm_memory_slot *slot;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index e036a8927717..a895d3f07cb8 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1398,6 +1398,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
svm->spec_ctrl = 0;
svm->virt_spec_ctrl = 0;
+ if (init_event)
+ sev_snp_init_protected_guest_state(vcpu);
+
init_vmcb(vcpu);
if (!init_event)
@@ -4937,6 +4940,12 @@ static void *svm_alloc_apic_backing_page(struct kvm_vcpu *vcpu)
return page_address(page);
}
+static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ sev_vcpu_unblocking(vcpu);
+ avic_vcpu_unblocking(vcpu);
+}
+
static struct kvm_x86_ops svm_x86_ops __initdata = {
.name = KBUILD_MODNAME,
@@ -4959,7 +4968,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
.vcpu_blocking = avic_vcpu_blocking,
- .vcpu_unblocking = avic_vcpu_unblocking,
+ .vcpu_unblocking = svm_vcpu_unblocking,
.update_exception_bitmap = svm_update_exception_bitmap,
.get_msr_feature = svm_get_msr_feature,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 8cce3315b46c..0cdcd0759fe0 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -211,6 +211,10 @@ struct vcpu_sev_es_state {
bool ghcb_sa_free;
u64 ghcb_registered_gpa;
+
+ struct mutex snp_vmsa_mutex; /* Used to handle concurrent updates of VMSA */
+ gpa_t snp_vmsa_gpa;
+ bool snp_ap_create;
};
struct vcpu_svm {
@@ -724,6 +728,8 @@ int sev_cpu_init(struct svm_cpu_data *sd);
int sev_dev_get_attr(u64 attr, u64 *val);
extern unsigned int max_sev_asid;
void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code);
+void sev_vcpu_unblocking(struct kvm_vcpu *vcpu);
+void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu);
#else
static inline struct page *snp_safe_alloc_page(struct kvm_vcpu *vcpu) {
return alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
@@ -738,6 +744,8 @@ static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; }
static inline int sev_dev_get_attr(u64 attr, u64 *val) { return -ENXIO; }
#define max_sev_asid 0
static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {}
+static inline void sev_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+static inline void sev_snp_init_protected_guest_state(struct kvm_vcpu *vcpu) {}
#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f85735b6235d..617c38656757 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10943,6 +10943,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_UPDATE_CPU_DIRTY_LOGGING, vcpu))
static_call(kvm_x86_update_cpu_dirty_logging)(vcpu);
+
+ if (kvm_check_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu)) {
+ kvm_vcpu_reset(vcpu, true);
+ if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE) {
+ r = 1;
+ goto out;
+ }
+ }
}
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||
@@ -13150,6 +13158,9 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
if (kvm_test_request(KVM_REQ_PMI, vcpu))
return true;
+ if (kvm_test_request(KVM_REQ_UPDATE_PROTECTED_GUEST_STATE, vcpu))
+ return true;
+
if (kvm_arch_interrupt_allowed(vcpu) &&
(kvm_cpu_has_interrupt(vcpu) ||
kvm_guest_apic_has_interrupt(vcpu)))
--
2.25.1
Powered by blists - more mailing lists