From: Robert Hoo <robert.hu@linux.intel.com>
To: pbonzini@redhat.com, seanjc@google.com, vkuznets@redhat.com,
wanpengli@tencent.com, jmattson@google.com, joro@8bytes.org
Cc: chang.seok.bae@intel.com, kvm@vger.kernel.org,
robert.hu@intel.com, Robert Hoo <robert.hu@linux.intel.com>
Subject: [RFC PATCH 05/12] kvm/vmx: Add KVM support on KeyLocker operations
Date: Mon, 25 Jan 2021 17:06:13 +0800 [thread overview]
Message-ID: <1611565580-47718-6-git-send-email-robert.hu@linux.intel.com> (raw)
In-Reply-To: <1611565580-47718-1-git-send-email-robert.hu@linux.intel.com>
Define handle_loadiwkey() VM-Exit handler, which fetch the IWKey guest's
setting and do it onbehalf. Note LOADIWKEY needs CR4.KeyLocker set.
Trap guest write on MSRs of IA32_COPY_LOCAL_TO_PLATFORM and
IA32_COPY_PLATFORM_TO_LOCAL_TO_PLATFORM, emulate IWKey save and restore
operations.
Trap guest read on MSRs of IA32_COPY_STATUS and IA32_IWKEYBACKUP_STATUS,
return their shadow values stored in kvm_vcpu_arch and kvm_arch.
Also, guest CPUID.0x19:EBX[0] is dynamic, its status changes as CR4.KL
changes.
On each VM-Entry, we need to resotre vCPU's IWKey, stored in kvm_vcpu_arch.
Signed-off-by: Robert Hoo <robert.hu@linux.intel.com>
---
arch/x86/include/asm/kvm_host.h | 24 ++++-
arch/x86/kvm/cpuid.c | 11 +++
arch/x86/kvm/cpuid.h | 2 +
arch/x86/kvm/vmx/vmx.c | 189 ++++++++++++++++++++++++++++++++++++++++
arch/x86/kvm/x86.c | 4 +-
arch/x86/kvm/x86.h | 2 +
6 files changed, 229 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7e5f33a..dc09142 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -100,7 +100,7 @@
| X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
| X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
| X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \
- | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP))
+ | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP | X86_CR4_KEYLOCKER))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
@@ -520,6 +520,19 @@ struct kvm_vcpu_hv {
cpumask_t tlb_flush;
};
+#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(CONFIG_CC_HAS_INT128)
+typedef unsigned __int128 u128;
+#else
+typedef struct {
+ u64 reg64[2];
+} u128;
+#endif
+
+struct iwkey {
+ u128 encryption_key[2]; /* 256bit encryption key */
+ u128 integrity_key; /* 128bit integration key */
+};
+
struct kvm_vcpu_arch {
/*
* rip and regs accesses must go through
@@ -805,6 +818,11 @@ struct kvm_vcpu_arch {
*/
bool enforce;
} pv_cpuid;
+
+ /* Intel KeyLocker */
+ bool iwkey_loaded;
+ struct iwkey iwkey;
+ u32 msr_ia32_copy_status;
};
struct kvm_lpage_info {
@@ -931,6 +949,10 @@ struct kvm_arch {
bool apic_access_page_done;
unsigned long apicv_inhibit_reasons;
+ bool iwkey_backup_valid;
+ u32 msr_ia32_iwkey_backup_status;
+ struct iwkey iwkey_backup;
+
gpa_t wall_clock;
bool mwait_in_guest;
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 83637a2..2fbf4af 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -133,6 +133,12 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
cpuid_entry_has(best, X86_FEATURE_XSAVEC)))
best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
+ /* update CPUID.0x19.EBX[0], depends on CR4.KL */
+ best = kvm_find_cpuid_entry(vcpu, 0x19, 0);
+ if (best)
+ cpuid_entry_change(best, X86_FEATURE_KL_INS_ENABLED,
+ kvm_read_cr4_bits(vcpu, X86_CR4_KEYLOCKER));
+
best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0);
if (kvm_hlt_in_guest(vcpu->kvm) && best &&
(best->eax & (1 << KVM_FEATURE_PV_UNHALT)))
@@ -407,6 +413,11 @@ void kvm_set_cpu_caps(void)
if (cpuid_ecx(7) & F(LA57))
kvm_cpu_cap_set(X86_FEATURE_LA57);
+ /* At present, host and guest can only exclusively use KeyLocker */
+ if (!boot_cpu_has(X86_FEATURE_KEYLOCKER) && (cpuid_ecx(0x7) &
+ feature_bit(KEYLOCKER)))
+ kvm_cpu_cap_set(X86_FEATURE_KEYLOCKER);
+
/*
* PKU not yet implemented for shadow paging and requires OSPKE
* to be set on the host. Clear it if that is not the case
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index f7a6e8f..639c647 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -63,6 +63,8 @@ struct cpuid_reg {
[CPUID_8000_0007_EBX] = {0x80000007, 0, CPUID_EBX},
[CPUID_7_EDX] = { 7, 0, CPUID_EDX},
[CPUID_7_1_EAX] = { 7, 1, CPUID_EAX},
+ [CPUID_19_EBX] = { 0x19, 0, CPUID_EBX},
+ [CPUID_19_ECX] = { 0x19, 0, CPUID_ECX},
};
/*
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index d01bbb4..6be6d87 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -47,6 +47,7 @@
#include <asm/spec-ctrl.h>
#include <asm/virtext.h>
#include <asm/vmx.h>
+#include <asm/keylocker.h>
#include "capabilities.h"
#include "cpuid.h"
@@ -1192,6 +1193,106 @@ void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
}
}
+static int get_xmm(int index, u128 *mem_ptr)
+{
+ int ret = 0;
+
+ asm ("cli");
+ switch (index) {
+ case 0:
+ asm ("movdqu %%xmm0, %0" : : "m"(*mem_ptr));
+ break;
+ case 1:
+ asm ("movdqu %%xmm1, %0" : : "m"(*mem_ptr));
+ break;
+ case 2:
+ asm ("movdqu %%xmm2, %0" : : "m"(*mem_ptr));
+ break;
+ case 3:
+ asm ("movdqu %%xmm3, %0" : : "m"(*mem_ptr));
+ break;
+ case 4:
+ asm ("movdqu %%xmm4, %0" : : "m"(*mem_ptr));
+ break;
+ case 5:
+ asm ("movdqu %%xmm5, %0" : : "m"(*mem_ptr));
+ break;
+ case 6:
+ asm ("movdqu %%xmm6, %0" : : "m"(*mem_ptr));
+ break;
+ case 7:
+ asm ("movdqu %%xmm7, %0" : : "m"(*mem_ptr));
+ break;
+#ifdef CONFIG_X86_64
+ case 8:
+ asm ("movdqu %%xmm8, %0" : : "m"(*mem_ptr));
+ break;
+ case 9:
+ asm ("movdqu %%xmm9, %0" : : "m"(*mem_ptr));
+ break;
+ case 10:
+ asm ("movdqu %%xmm10, %0" : : "m"(*mem_ptr));
+ break;
+ case 11:
+ asm ("movdqu %%xmm11, %0" : : "m"(*mem_ptr));
+ break;
+ case 12:
+ asm ("movdqu %%xmm12, %0" : : "m"(*mem_ptr));
+ break;
+ case 13:
+ asm ("movdqu %%xmm13, %0" : : "m"(*mem_ptr));
+ break;
+ case 14:
+ asm ("movdqu %%xmm14, %0" : : "m"(*mem_ptr));
+ break;
+ case 15:
+ asm ("movdqu %%xmm15, %0" : : "m"(*mem_ptr));
+ break;
+#endif
+ default:
+ pr_err_once("xmm index exceeds");
+ ret = -1;
+ break;
+ }
+ asm ("sti");
+
+ return ret;
+}
+
+static void vmx_load_guest_iwkey(struct kvm_vcpu *vcpu)
+{
+ u128 xmm[3] = {0};
+
+ if (vcpu->arch.iwkey_loaded) {
+ bool clear_cr4 = false;
+ /* Save origin %xmm */
+ get_xmm(0, &xmm[0]);
+ get_xmm(1, &xmm[1]);
+ get_xmm(2, &xmm[2]);
+
+ asm ("movdqu %0, %%xmm0;"
+ "movdqu %1, %%xmm1;"
+ "movdqu %2, %%xmm2;"
+ : : "m"(vcpu->arch.iwkey.integrity_key),
+ "m"(vcpu->arch.iwkey.encryption_key[0]),
+ "m"(vcpu->arch.iwkey.encryption_key[1]));
+ if (!(cr4_read_shadow() & X86_CR4_KEYLOCKER)) {
+ cr4_set_bits(X86_CR4_KEYLOCKER);
+ clear_cr4 = true;
+ }
+ asm volatile(LOADIWKEY : : "a" (0x0));
+ if (clear_cr4)
+ cr4_clear_bits(X86_CR4_KEYLOCKER);
+ /* restore %xmm */
+ asm ("movdqu %0, %%xmm0;"
+ "movdqu %1, %%xmm1;"
+ "movdqu %2, %%xmm2;"
+ : : "m"(xmm[0]),
+ "m"(xmm[1]),
+ "m"(xmm[2]));
+ }
+}
+
void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -1260,6 +1361,9 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
#endif
vmx_set_host_fs_gs(host_state, fs_sel, gs_sel, fs_base, gs_base);
+
+ vmx_load_guest_iwkey(vcpu);
+
vmx->guest_state_loaded = true;
}
@@ -1925,6 +2029,19 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
return 1;
goto find_uret_msr;
+ case MSR_IA32_COPY_STATUS:
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_KEYLOCKER))
+ return 1;
+
+ msr_info->data = vcpu->arch.msr_ia32_copy_status;
+ break;
+
+ case MSR_IA32_IWKEYBACKUP_STATUS:
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_KEYLOCKER))
+ return 1;
+
+ msr_info->data = vcpu->kvm->arch.msr_ia32_iwkey_backup_status;
+ break;
default:
find_uret_msr:
msr = vmx_find_uret_msr(vmx, msr_info->index);
@@ -2189,6 +2306,36 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
else
vmx->pt_desc.guest.addr_a[index / 2] = data;
break;
+ case MSR_IA32_COPY_LOCAL_TO_PLATFORM:
+ if (msr_info->data != 1)
+ return 1;
+
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_KEYLOCKER))
+ return 1;
+
+ if (!vcpu->arch.iwkey_loaded)
+ return 1;
+
+ if (!vcpu->kvm->arch.iwkey_backup_valid) {
+ vcpu->kvm->arch.iwkey_backup = vcpu->arch.iwkey;
+ vcpu->kvm->arch.iwkey_backup_valid = true;
+ vcpu->kvm->arch.msr_ia32_iwkey_backup_status = 0x9;
+ }
+ vcpu->arch.msr_ia32_copy_status = 1;
+ break;
+
+ case MSR_IA32_COPY_PLATFORM_TO_LOCAL:
+ if (msr_info->data != 1)
+ return 1;
+
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_KEYLOCKER))
+ return 1;
+ if (!vcpu->kvm->arch.iwkey_backup_valid)
+ return 1;
+ vcpu->arch.iwkey = vcpu->kvm->arch.iwkey_backup;
+ vcpu->arch.msr_ia32_copy_status = 1;
+ break;
+
case MSR_TSC_AUX:
if (!msr_info->host_initiated &&
!guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
@@ -5659,6 +5806,47 @@ static int handle_encls(struct kvm_vcpu *vcpu)
return 1;
}
+static int handle_loadiwkey(struct kvm_vcpu *vcpu)
+{
+ u128 xmm[3] = {0};
+ u32 vmx_instruction_info;
+ int reg1, reg2;
+ int r;
+
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_KEYLOCKER)) {
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+ }
+
+ vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+ reg1 = (vmx_instruction_info & 0x78) >> 3;
+ reg2 = (vmx_instruction_info >> 28) & 0xf;
+
+ /*
+ * vmx instruction info on Current TGL is broken.
+ * Before the microcode fix, we hardcode XMM1 & XMM2 holding
+ * IWKey.encryption_key.
+ */
+ reg1 = 1;
+ reg2 = 2;
+ r = get_xmm(0, &xmm[0]);
+ if (r)
+ return 0;
+ r = get_xmm(reg1, &xmm[1]);
+ if (r)
+ return 0;
+ r = get_xmm(reg2, &xmm[2]);
+ if (r)
+ return 0;
+
+ vcpu->arch.iwkey.integrity_key = xmm[0];
+ vcpu->arch.iwkey.encryption_key[0] = xmm[1];
+ vcpu->arch.iwkey.encryption_key[1] = xmm[2];
+ vcpu->arch.iwkey_loaded = true;
+
+ return kvm_skip_emulated_instruction(vcpu);
+}
+
/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -5715,6 +5903,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_VMFUNC] = handle_vmx_instruction,
[EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer,
[EXIT_REASON_ENCLS] = handle_encls,
+ [EXIT_REASON_LOADIWKEY] = handle_loadiwkey,
};
static const int kvm_vmx_max_exit_handlers =
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e545a8a..fbc839a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1013,7 +1013,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
(!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
kvm_mmu_reset_context(vcpu);
- if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE))
+ if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE | X86_CR4_KEYLOCKER))
kvm_update_cpuid_runtime(vcpu);
return 0;
@@ -9598,7 +9598,7 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) &
- (X86_CR4_OSXSAVE | X86_CR4_PKE));
+ (X86_CR4_OSXSAVE | X86_CR4_PKE | X86_CR4_KEYLOCKER));
kvm_x86_ops.set_cr4(vcpu, sregs->cr4);
if (cpuid_update_needed)
kvm_update_cpuid_runtime(vcpu);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index e7ca622..0e6b826 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -404,6 +404,8 @@ int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r,
__reserved_bits |= X86_CR4_UMIP; \
if (!__cpu_has(__c, X86_FEATURE_VMX)) \
__reserved_bits |= X86_CR4_VMXE; \
+ if (!__cpu_has(__c, X86_FEATURE_KEYLOCKER)) \
+ __reserved_bits |= X86_CR4_KEYLOCKER; \
__reserved_bits; \
})
--
1.8.3.1
next prev parent reply other threads:[~2021-01-26 5:12 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-25 9:06 [RFC PATCH 00/12] KVM: Support Intel KeyLocker Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 01/12] x86/keylocker: Move LOADIWKEY opcode definition from keylocker.c to keylocker.h Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 02/12] x86/cpufeature: Add CPUID.19H:{EBX,ECX} cpuid leaves Robert Hoo
2021-04-05 15:32 ` Sean Christopherson
2021-04-06 3:34 ` Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 03/12] kvm/vmx: Introduce the new tertiary processor-based VM-execution controls Robert Hoo
2021-01-25 9:41 ` Vitaly Kuznetsov
2021-01-26 9:27 ` Robert Hoo
2021-02-03 6:32 ` Robert Hoo
2021-02-03 8:45 ` Vitaly Kuznetsov
2021-04-05 15:38 ` Sean Christopherson
2021-04-06 3:37 ` Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 04/12] kvm/vmx: enable LOADIWKEY vm-exit support in " Robert Hoo
2021-01-25 9:06 ` Robert Hoo [this message]
2021-04-05 16:25 ` [RFC PATCH 05/12] kvm/vmx: Add KVM support on KeyLocker operations Sean Christopherson
2021-04-08 5:44 ` Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 06/12] kvm/cpuid: Enumerate KeyLocker feature in KVM Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 07/12] kvm/vmx/nested: Support new IA32_VMX_PROCBASED_CTLS3 vmx feature control MSR Robert Hoo
2021-04-05 15:44 ` Sean Christopherson
2021-04-08 5:45 ` Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 08/12] kvm/vmx: Refactor vmx_compute_tertiary_exec_control() Robert Hoo
2021-04-05 15:46 ` Sean Christopherson
2021-04-08 5:45 ` Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 09/12] kvm/vmx/vmcs12: Add Tertiary Exec-Control field in vmcs12 Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 10/12] kvm/vmx/nested: Support tertiary VM-Exec control in vmcs02 Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 11/12] kvm/vmx/nested: Support CR4.KL in nested Robert Hoo
2021-01-25 9:06 ` [RFC PATCH 12/12] kvm/vmx/nested: Enable nested LOADIWKey VM-exit Robert Hoo
2021-04-05 16:03 ` [RFC PATCH 00/12] KVM: Support Intel KeyLocker Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1611565580-47718-6-git-send-email-robert.hu@linux.intel.com \
--to=robert.hu@linux.intel.com \
--cc=chang.seok.bae@intel.com \
--cc=jmattson@google.com \
--cc=joro@8bytes.org \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=robert.hu@intel.com \
--cc=seanjc@google.com \
--cc=vkuznets@redhat.com \
--cc=wanpengli@tencent.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).