KVM: SVM: Export MSR_AMD64_SEV_ES_GHCB to userspace for CSV2 guest
Upstream: no VMCB.control.ghcb_gpa contains necessary info to support runtime CSV2 guest. At present, it includes the following points: 1. For GHCB MSR protocol, ghcb_gpa stores the negotiation result 2. For GHCB page protocol, ghcb_gpa stores the GPA of GHCB page In addition, AP VCPU's SIPI state and GHCB page mapping state are temporarily stored in KVM. When CSV2 guest was migrated to the recipient, KVM needs to restore VMCB.control.ghcb_gpa, VCPU's SIPI state and GHCB page mapping state on the source side. This patch is to support export MSR_AMD64_SEV_ES_GHCB to userspace. KVM can collect all the infos dictated above and return to userspace if userspace request to get MSR_AMD64_SEV_ES_GHCB, and KVM can restore all the infos dictated above if userspace request to set MSR_AMD64_SEV_ES_GHCB. Signed-off-by: hanliyang <hanliyang@hygon.cn>
This commit is contained in:
parent
b75a26008d
commit
0d648c30f0
|
@ -855,6 +855,124 @@ static int csv_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int csv2_map_ghcb_gpa(struct vcpu_svm *svm, u64 ghcb_gpa)
|
||||
{
|
||||
if (kvm_vcpu_map(&svm->vcpu, ghcb_gpa >> PAGE_SHIFT, &svm->sev_es.ghcb_map)) {
|
||||
/* Unable to map GHCB from guest */
|
||||
vcpu_unimpl(&svm->vcpu, "Missing GHCB [%#llx] from guest\n",
|
||||
ghcb_gpa);
|
||||
|
||||
svm->sev_es.receiver_ghcb_map_fail = true;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
svm->sev_es.ghcb = svm->sev_es.ghcb_map.hva;
|
||||
svm->sev_es.receiver_ghcb_map_fail = false;
|
||||
|
||||
pr_info("Mapping GHCB [%#llx] from guest at recipient\n", ghcb_gpa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_ghcb_msr_protocol(u64 ghcb_val)
|
||||
{
|
||||
return !!(ghcb_val & GHCB_MSR_INFO_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* csv_get_msr return msr data to the userspace.
|
||||
*
|
||||
* Return 0 if get msr success.
|
||||
*/
|
||||
int csv_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
switch (msr_info->index) {
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* Only support userspace get from vmcb.control.ghcb_gpa */
|
||||
if (!msr_info->host_initiated || !sev_es_guest(vcpu->kvm))
|
||||
return 1;
|
||||
|
||||
msr_info->data = svm->vmcb->control.ghcb_gpa;
|
||||
|
||||
/* Only set status bits when using GHCB page protocol */
|
||||
if (msr_info->data &&
|
||||
!is_ghcb_msr_protocol(msr_info->data)) {
|
||||
if (svm->sev_es.ghcb)
|
||||
msr_info->data |= GHCB_MSR_MAPPED_MASK;
|
||||
|
||||
if (svm->sev_es.received_first_sipi)
|
||||
msr_info->data |=
|
||||
GHCB_MSR_RECEIVED_FIRST_SIPI_MASK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* csv_set_msr set msr data from the userspace.
|
||||
*
|
||||
* Return 0 if set msr success.
|
||||
*/
|
||||
int csv_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
u32 ecx = msr_info->index;
|
||||
u64 data = msr_info->data;
|
||||
|
||||
switch (ecx) {
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* Only support userspace set to vmcb.control.ghcb_gpa */
|
||||
if (!msr_info->host_initiated || !sev_es_guest(vcpu->kvm))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Value 0 means uninitialized userspace MSR data, userspace
|
||||
* need get the initial MSR data afterwards.
|
||||
*/
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
/* Extract status info when using GHCB page protocol */
|
||||
if (!is_ghcb_msr_protocol(data)) {
|
||||
if (!svm->sev_es.ghcb && (data & GHCB_MSR_MAPPED_MASK)) {
|
||||
/*
|
||||
* This happened on the recipient of migration,
|
||||
* should return error if cannot map the ghcb
|
||||
* page.
|
||||
*/
|
||||
if (csv2_map_ghcb_gpa(to_svm(vcpu),
|
||||
data & ~GHCB_MSR_KVM_STATUS_MASK))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (data & GHCB_MSR_RECEIVED_FIRST_SIPI_MASK)
|
||||
svm->sev_es.received_first_sipi = true;
|
||||
|
||||
data &= ~GHCB_MSR_KVM_STATUS_MASK;
|
||||
}
|
||||
|
||||
svm->vmcb->control.ghcb_gpa = data;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool csv_has_emulated_ghcb_msr(struct kvm *kvm)
|
||||
{
|
||||
/* this should be determined after KVM_CREATE_VM. */
|
||||
if (kvm && !sev_es_guest(kvm))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void csv_exit(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -59,6 +59,15 @@ void csv_exit(void);
|
|||
|
||||
int csv_alloc_trans_mempool(void);
|
||||
void csv_free_trans_mempool(void);
|
||||
int csv_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
|
||||
int csv_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
|
||||
bool csv_has_emulated_ghcb_msr(struct kvm *kvm);
|
||||
|
||||
static inline bool csv2_state_unstable(struct vcpu_svm *svm)
|
||||
{
|
||||
return svm->sev_es.receiver_ghcb_map_fail;
|
||||
}
|
||||
|
||||
|
||||
#else /* !CONFIG_HYGON_CSV */
|
||||
|
||||
|
@ -67,7 +76,48 @@ static inline void csv_exit(void) { }
|
|||
|
||||
static inline int csv_alloc_trans_mempool(void) { return 0; }
|
||||
static inline void csv_free_trans_mempool(void) { }
|
||||
static inline
|
||||
int csv_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { return 1; }
|
||||
static inline
|
||||
int csv_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { return 1; }
|
||||
static inline bool csv_has_emulated_ghcb_msr(struct kvm *kvm) { return false; }
|
||||
static inline bool csv2_state_unstable(struct vcpu_svm *svm) { return false; }
|
||||
|
||||
#endif /* CONFIG_HYGON_CSV */
|
||||
|
||||
#include <asm/sev-common.h>
|
||||
|
||||
/*
|
||||
* CSV2 live migration support:
|
||||
* If MSR_AMD64_SEV_ES_GHCB in migration didn't apply GHCB MSR protocol,
|
||||
* reuse bits [52-63] to indicate vcpu status. The following status are
|
||||
* currently included:
|
||||
* * ghcb_map: indicate whether GHCB page was mapped. The mapped GHCB
|
||||
* page may be filled with GPRs before VMRUN, so we must
|
||||
* remap GHCB page on the recipient's side.
|
||||
* * received_first_sipi: indicate AP's INIT-SIPI-SIPI stage. Reuse
|
||||
* these bits for received_first_sipi is acceptable cause
|
||||
* runtime stage of guest's linux only applies GHCB page
|
||||
* protocol.
|
||||
* It's unlikely that the migration encounter other stages
|
||||
* of guest's linux. Once encountered, AP bringup may fail
|
||||
* which will not impact user payload.
|
||||
* Otherbits keep their's original meaning. (See GHCB Spec 2.3.1 for detail)
|
||||
*/
|
||||
#define GHCB_MSR_KVM_STATUS_POS 52
|
||||
#define GHCB_MSR_KVM_STATUS_BITS 12
|
||||
#define GHCB_MSR_KVM_STATUS_MASK \
|
||||
((BIT_ULL(GHCB_MSR_KVM_STATUS_BITS) - 1) \
|
||||
<< GHCB_MSR_KVM_STATUS_POS)
|
||||
#define GHCB_MSR_MAPPED_POS 63
|
||||
#define GHCB_MSR_MAPPED_BITS 1
|
||||
#define GHCB_MSR_MAPPED_MASK \
|
||||
((BIT_ULL(GHCB_MSR_MAPPED_BITS) - 1) \
|
||||
<< GHCB_MSR_MAPPED_POS)
|
||||
#define GHCB_MSR_RECEIVED_FIRST_SIPI_POS 62
|
||||
#define GHCB_MSR_RECEIVED_FIRST_SIPI_BITS 1
|
||||
#define GHCB_MSR_RECEIVED_FIRST_SIPI_MASK \
|
||||
((BIT_ULL(GHCB_MSR_RECEIVED_FIRST_SIPI_BITS) - 1) \
|
||||
<< GHCB_MSR_RECEIVED_FIRST_SIPI_POS)
|
||||
|
||||
#endif /* __SVM_CSV_H */
|
||||
|
|
|
@ -2947,6 +2947,12 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
case MSR_AMD64_DE_CFG:
|
||||
msr_info->data = svm->msr_decfg;
|
||||
break;
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* HYGON CSV2 support export this MSR to userspace */
|
||||
if (is_x86_vendor_hygon())
|
||||
return csv_get_msr(vcpu, msr_info);
|
||||
else
|
||||
return 1;
|
||||
default:
|
||||
return kvm_get_msr_common(vcpu, msr_info);
|
||||
}
|
||||
|
@ -3182,6 +3188,12 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
|||
svm->msr_decfg = data;
|
||||
break;
|
||||
}
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* HYGON CSV2 support update this MSR from userspace */
|
||||
if (is_x86_vendor_hygon())
|
||||
return csv_set_msr(vcpu, msr);
|
||||
else
|
||||
return 1;
|
||||
default:
|
||||
return kvm_set_msr_common(vcpu, msr);
|
||||
}
|
||||
|
@ -4137,6 +4149,19 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
|
|||
|
||||
trace_kvm_entry(vcpu);
|
||||
|
||||
/*
|
||||
* For receipient side of CSV2 guest, fake the exit code as SVM_EXIT_ERR
|
||||
* and return directly if failed to mapping the necessary GHCB page.
|
||||
* When handling the exit code afterwards, it can exit to userspace and
|
||||
* stop the guest.
|
||||
*/
|
||||
if (is_x86_vendor_hygon() && sev_es_guest(vcpu->kvm)) {
|
||||
if (csv2_state_unstable(svm)) {
|
||||
svm->vmcb->control.exit_code = SVM_EXIT_ERR;
|
||||
return EXIT_FASTPATH_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
|
||||
svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
|
||||
svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
|
||||
|
@ -4311,6 +4336,12 @@ static bool svm_has_emulated_msr(struct kvm *kvm, u32 index)
|
|||
if (kvm && sev_es_guest(kvm))
|
||||
return false;
|
||||
break;
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* HYGON CSV2 support emulate this MSR */
|
||||
if (is_x86_vendor_hygon())
|
||||
return csv_has_emulated_ghcb_msr(kvm);
|
||||
else
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -202,6 +202,11 @@ struct vcpu_sev_es_state {
|
|||
u32 ghcb_sa_len;
|
||||
bool ghcb_sa_sync;
|
||||
bool ghcb_sa_free;
|
||||
|
||||
#ifdef CONFIG_HYGON_CSV
|
||||
/* migrated ghcb mapping state for HYGON CSV2 */
|
||||
bool receiver_ghcb_map_fail;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct vcpu_svm {
|
||||
|
|
|
@ -7068,6 +7068,7 @@ static bool vmx_has_emulated_msr(struct kvm *kvm, u32 index)
|
|||
return nested;
|
||||
case MSR_AMD64_VIRT_SPEC_CTRL:
|
||||
case MSR_AMD64_TSC_RATIO:
|
||||
case MSR_AMD64_SEV_ES_GHCB:
|
||||
/* This is AMD only. */
|
||||
return false;
|
||||
default:
|
||||
|
|
|
@ -1567,6 +1567,8 @@ static const u32 emulated_msrs_all[] = {
|
|||
|
||||
MSR_K7_HWCR,
|
||||
MSR_KVM_POLL_CONTROL,
|
||||
|
||||
MSR_AMD64_SEV_ES_GHCB,
|
||||
};
|
||||
|
||||
static u32 emulated_msrs[ARRAY_SIZE(emulated_msrs_all)];
|
||||
|
@ -4639,6 +4641,17 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||
case KVM_CAP_X86_NOTIFY_VMEXIT:
|
||||
r = kvm_caps.has_notify_vmexit;
|
||||
break;
|
||||
case KVM_CAP_SEV_ES_GHCB:
|
||||
r = 0;
|
||||
|
||||
/* Both CSV2 and SEV-ES guests support MSR_AMD64_SEV_ES_GHCB,
|
||||
* but only CSV2 guest support export to emulate
|
||||
* MSR_AMD64_SEV_ES_GHCB.
|
||||
*/
|
||||
if (is_x86_vendor_hygon())
|
||||
r = static_call(kvm_x86_has_emulated_msr)(kvm,
|
||||
MSR_AMD64_SEV_ES_GHCB);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1201,6 +1201,8 @@ struct kvm_ppc_resize_hpt {
|
|||
#define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228
|
||||
#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229
|
||||
|
||||
#define KVM_CAP_SEV_ES_GHCB 500
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
struct kvm_irq_routing_irqchip {
|
||||
|
|
Loading…
Reference in New Issue