Skip to content

Commit d69c138

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/kvm: Convert FPU handling to a single swap buffer
For the upcoming AMX support it's necessary to do a proper integration with KVM. Currently KVM allocates two FPU structs which are used for saving the user state of the vCPU thread and restoring the guest state when entering vcpu_run() and doing the reverse operation before leaving vcpu_run(). With the new fpstate mechanism this can be reduced to one extra buffer by swapping the fpstate pointer in current::thread::fpu. This makes the upcoming support for AMX and XFD simpler because then fpstate information (features, sizes, xfd) are always consistent and it does not require any nasty workarounds. Convert the KVM FPU code over to this new scheme. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 69f6ed1 commit d69c138

File tree

5 files changed

+40
-82
lines changed

5 files changed

+40
-82
lines changed

arch/x86/include/asm/fpu/api.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu);
140140
extern int fpu_swap_kvm_fpstate(struct fpu_guest *gfpu, bool enter_guest);
141141
extern void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask);
142142

143-
extern int fpu_copy_kvm_uabi_to_fpstate(struct fpu *fpu, const void *buf, u64 xcr0, u32 *pkru);
144-
extern void fpu_copy_fpstate_to_kvm_uabi(struct fpu *fpu, void *buf, unsigned int size, u32 pkru);
143+
extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf, unsigned int size, u32 pkru);
144+
extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru);
145145

146146
static inline void fpstate_set_confidential(struct fpu_guest *gfpu)
147147
{

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -691,11 +691,10 @@ struct kvm_vcpu_arch {
691691
*
692692
* Note that while the PKRU state lives inside the fpu registers,
693693
* it is switched out separately at VMENTER and VMEXIT time. The
694-
* "guest_fpu" state here contains the guest FPU context, with the
694+
* "guest_fpstate" state here contains the guest FPU context, with the
695695
* host PRKU bits.
696696
*/
697-
struct fpu *user_fpu;
698-
struct fpu *guest_fpu;
697+
struct fpu_guest guest_fpu;
699698

700699
u64 xcr0;
701700
u64 guest_supported_xcr0;
@@ -1685,8 +1684,6 @@ void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
16851684
int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
16861685
int reason, bool has_error_code, u32 error_code);
16871686

1688-
void kvm_free_guest_fpu(struct kvm_vcpu *vcpu);
1689-
16901687
void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0);
16911688
void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4);
16921689
int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);

arch/x86/kernel/fpu/core.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,10 @@ void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask)
268268
}
269269
EXPORT_SYMBOL_GPL(fpu_swap_kvm_fpu);
270270

271-
void fpu_copy_fpstate_to_kvm_uabi(struct fpu *fpu, void *buf,
272-
unsigned int size, u32 pkru)
271+
void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
272+
unsigned int size, u32 pkru)
273273
{
274-
struct fpstate *kstate = fpu->fpstate;
274+
struct fpstate *kstate = gfpu->fpstate;
275275
union fpregs_state *ustate = buf;
276276
struct membuf mb = { .p = buf, .left = size };
277277

@@ -284,12 +284,12 @@ void fpu_copy_fpstate_to_kvm_uabi(struct fpu *fpu, void *buf,
284284
ustate->xsave.header.xfeatures = XFEATURE_MASK_FPSSE;
285285
}
286286
}
287-
EXPORT_SYMBOL_GPL(fpu_copy_fpstate_to_kvm_uabi);
287+
EXPORT_SYMBOL_GPL(fpu_copy_guest_fpstate_to_uabi);
288288

289-
int fpu_copy_kvm_uabi_to_fpstate(struct fpu *fpu, const void *buf, u64 xcr0,
290-
u32 *vpkru)
289+
int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
290+
u64 xcr0, u32 *vpkru)
291291
{
292-
struct fpstate *kstate = fpu->fpstate;
292+
struct fpstate *kstate = gfpu->fpstate;
293293
const union fpregs_state *ustate = buf;
294294
struct pkru_state *xpkru;
295295
int ret;
@@ -320,7 +320,7 @@ int fpu_copy_kvm_uabi_to_fpstate(struct fpu *fpu, const void *buf, u64 xcr0,
320320
xstate_init_xcomp_bv(&kstate->regs.xsave, kstate->xfeatures);
321321
return 0;
322322
}
323-
EXPORT_SYMBOL_GPL(fpu_copy_kvm_uabi_to_fpstate);
323+
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
324324
#endif /* CONFIG_KVM */
325325

326326
void kernel_fpu_begin_mask(unsigned int kfpu_mask)

arch/x86/kvm/svm/svm.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <asm/spec-ctrl.h>
3737
#include <asm/cpu_device_id.h>
3838
#include <asm/traps.h>
39+
#include <asm/fpu/api.h>
3940

4041
#include <asm/virtext.h>
4142
#include "trace.h"
@@ -1346,10 +1347,10 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
13461347
/*
13471348
* SEV-ES guests maintain an encrypted version of their FPU
13481349
* state which is restored and saved on VMRUN and VMEXIT.
1349-
* Free the fpu structure to prevent KVM from attempting to
1350-
* access the FPU state.
1350+
* Mark vcpu->arch.guest_fpu->fpstate as scratch so it won't
1351+
* do xsave/xrstor on it.
13511352
*/
1352-
kvm_free_guest_fpu(vcpu);
1353+
fpstate_set_confidential(&vcpu->arch.guest_fpu);
13531354
}
13541355

13551356
err = avic_init_vcpu(svm);

arch/x86/kvm/x86.c

Lines changed: 24 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,6 @@ u64 __read_mostly host_xcr0;
295295
u64 __read_mostly supported_xcr0;
296296
EXPORT_SYMBOL_GPL(supported_xcr0);
297297

298-
static struct kmem_cache *x86_fpu_cache;
299-
300298
static struct kmem_cache *x86_emulator_cache;
301299

302300
/*
@@ -4705,23 +4703,24 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
47054703
static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
47064704
struct kvm_xsave *guest_xsave)
47074705
{
4708-
if (!vcpu->arch.guest_fpu)
4706+
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
47094707
return;
47104708

4711-
fpu_copy_fpstate_to_kvm_uabi(vcpu->arch.guest_fpu, guest_xsave->region,
4712-
sizeof(guest_xsave->region),
4713-
vcpu->arch.pkru);
4709+
fpu_copy_guest_fpstate_to_uabi(&vcpu->arch.guest_fpu,
4710+
guest_xsave->region,
4711+
sizeof(guest_xsave->region),
4712+
vcpu->arch.pkru);
47144713
}
47154714

47164715
static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
47174716
struct kvm_xsave *guest_xsave)
47184717
{
4719-
if (!vcpu->arch.guest_fpu)
4718+
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
47204719
return 0;
47214720

4722-
return fpu_copy_kvm_uabi_to_fpstate(vcpu->arch.guest_fpu,
4723-
guest_xsave->region,
4724-
supported_xcr0, &vcpu->arch.pkru);
4721+
return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu,
4722+
guest_xsave->region,
4723+
supported_xcr0, &vcpu->arch.pkru);
47254724
}
47264725

47274726
static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
@@ -8301,18 +8300,11 @@ int kvm_arch_init(void *opaque)
83018300
}
83028301

83038302
r = -ENOMEM;
8304-
x86_fpu_cache = kmem_cache_create("x86_fpu", sizeof(struct fpu),
8305-
__alignof__(struct fpu), SLAB_ACCOUNT,
8306-
NULL);
8307-
if (!x86_fpu_cache) {
8308-
printk(KERN_ERR "kvm: failed to allocate cache for x86 fpu\n");
8309-
goto out;
8310-
}
83118303

83128304
x86_emulator_cache = kvm_alloc_emulator_cache();
83138305
if (!x86_emulator_cache) {
83148306
pr_err("kvm: failed to allocate cache for x86 emulator\n");
8315-
goto out_free_x86_fpu_cache;
8307+
goto out;
83168308
}
83178309

83188310
user_return_msrs = alloc_percpu(struct kvm_user_return_msrs);
@@ -8350,8 +8342,6 @@ int kvm_arch_init(void *opaque)
83508342
free_percpu(user_return_msrs);
83518343
out_free_x86_emulator_cache:
83528344
kmem_cache_destroy(x86_emulator_cache);
8353-
out_free_x86_fpu_cache:
8354-
kmem_cache_destroy(x86_fpu_cache);
83558345
out:
83568346
return r;
83578347
}
@@ -8378,7 +8368,6 @@ void kvm_arch_exit(void)
83788368
kvm_mmu_module_exit();
83798369
free_percpu(user_return_msrs);
83808370
kmem_cache_destroy(x86_emulator_cache);
8381-
kmem_cache_destroy(x86_fpu_cache);
83828371
#ifdef CONFIG_KVM_XEN
83838372
static_key_deferred_flush(&kvm_xen_enabled);
83848373
WARN_ON(static_branch_unlikely(&kvm_xen_enabled.key));
@@ -9801,23 +9790,17 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
98019790
static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
98029791
{
98039792
/*
9804-
* Guests with protected state have guest_fpu == NULL which makes
9805-
* the swap only save the host state. Exclude PKRU from restore as
9806-
* it is restored separately in kvm_x86_ops.run().
9793+
* Exclude PKRU from restore as restored separately in
9794+
* kvm_x86_ops.run().
98079795
*/
9808-
fpu_swap_kvm_fpu(vcpu->arch.user_fpu, vcpu->arch.guest_fpu,
9809-
~XFEATURE_MASK_PKRU);
9796+
fpu_swap_kvm_fpstate(&vcpu->arch.guest_fpu, true);
98109797
trace_kvm_fpu(1);
98119798
}
98129799

98139800
/* When vcpu_run ends, restore user space FPU context. */
98149801
static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
98159802
{
9816-
/*
9817-
* Guests with protected state have guest_fpu == NULL which makes
9818-
* swap only restore the host state.
9819-
*/
9820-
fpu_swap_kvm_fpu(vcpu->arch.guest_fpu, vcpu->arch.user_fpu, ~0ULL);
9803+
fpu_swap_kvm_fpstate(&vcpu->arch.guest_fpu, false);
98219804
++vcpu->stat.fpu_reload;
98229805
trace_kvm_fpu(0);
98239806
}
@@ -10398,12 +10381,12 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
1039810381
{
1039910382
struct fxregs_state *fxsave;
1040010383

10401-
if (!vcpu->arch.guest_fpu)
10384+
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
1040210385
return 0;
1040310386

1040410387
vcpu_load(vcpu);
1040510388

10406-
fxsave = &vcpu->arch.guest_fpu->fpstate->regs.fxsave;
10389+
fxsave = &vcpu->arch.guest_fpu.fpstate->regs.fxsave;
1040710390
memcpy(fpu->fpr, fxsave->st_space, 128);
1040810391
fpu->fcw = fxsave->cwd;
1040910392
fpu->fsw = fxsave->swd;
@@ -10421,12 +10404,12 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
1042110404
{
1042210405
struct fxregs_state *fxsave;
1042310406

10424-
if (!vcpu->arch.guest_fpu)
10407+
if (fpstate_is_confidential(&vcpu->arch.guest_fpu))
1042510408
return 0;
1042610409

1042710410
vcpu_load(vcpu);
1042810411

10429-
fxsave = &vcpu->arch.guest_fpu->fpstate->regs.fxsave;
10412+
fxsave = &vcpu->arch.guest_fpu.fpstate->regs.fxsave;
1043010413

1043110414
memcpy(fxsave->st_space, fpu->fpr, 128);
1043210415
fxsave->cwd = fpu->fcw;
@@ -10487,15 +10470,6 @@ static void fx_init(struct kvm_vcpu *vcpu)
1048710470
vcpu->arch.cr0 |= X86_CR0_ET;
1048810471
}
1048910472

10490-
void kvm_free_guest_fpu(struct kvm_vcpu *vcpu)
10491-
{
10492-
if (vcpu->arch.guest_fpu) {
10493-
kmem_cache_free(x86_fpu_cache, vcpu->arch.guest_fpu);
10494-
vcpu->arch.guest_fpu = NULL;
10495-
}
10496-
}
10497-
EXPORT_SYMBOL_GPL(kvm_free_guest_fpu);
10498-
1049910473
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
1050010474
{
1050110475
if (kvm_check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0)
@@ -10552,22 +10526,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
1055210526
if (!alloc_emulate_ctxt(vcpu))
1055310527
goto free_wbinvd_dirty_mask;
1055410528

10555-
vcpu->arch.user_fpu = kmem_cache_zalloc(x86_fpu_cache,
10556-
GFP_KERNEL_ACCOUNT);
10557-
if (!vcpu->arch.user_fpu) {
10558-
pr_err("kvm: failed to allocate userspace's fpu\n");
10559-
goto free_emulate_ctxt;
10560-
}
10561-
10562-
vcpu->arch.guest_fpu = kmem_cache_zalloc(x86_fpu_cache,
10563-
GFP_KERNEL_ACCOUNT);
10564-
if (!vcpu->arch.guest_fpu) {
10529+
if (!fpu_alloc_guest_fpstate(&vcpu->arch.guest_fpu)) {
1056510530
pr_err("kvm: failed to allocate vcpu's fpu\n");
10566-
goto free_user_fpu;
10531+
goto free_emulate_ctxt;
1056710532
}
1056810533

10569-
fpu_init_fpstate_user(vcpu->arch.user_fpu);
10570-
fpu_init_fpstate_user(vcpu->arch.guest_fpu);
1057110534
fx_init(vcpu);
1057210535

1057310536
vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
@@ -10600,9 +10563,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
1060010563
return 0;
1060110564

1060210565
free_guest_fpu:
10603-
kvm_free_guest_fpu(vcpu);
10604-
free_user_fpu:
10605-
kmem_cache_free(x86_fpu_cache, vcpu->arch.user_fpu);
10566+
fpu_free_guest_fpstate(&vcpu->arch.guest_fpu);
1060610567
free_emulate_ctxt:
1060710568
kmem_cache_free(x86_emulator_cache, vcpu->arch.emulate_ctxt);
1060810569
free_wbinvd_dirty_mask:
@@ -10651,8 +10612,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
1065110612

1065210613
kmem_cache_free(x86_emulator_cache, vcpu->arch.emulate_ctxt);
1065310614
free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
10654-
kmem_cache_free(x86_fpu_cache, vcpu->arch.user_fpu);
10655-
kvm_free_guest_fpu(vcpu);
10615+
fpu_free_guest_fpstate(&vcpu->arch.guest_fpu);
1065610616

1065710617
kvm_hv_vcpu_uninit(vcpu);
1065810618
kvm_pmu_destroy(vcpu);
@@ -10704,8 +10664,8 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
1070410664
kvm_async_pf_hash_reset(vcpu);
1070510665
vcpu->arch.apf.halted = false;
1070610666

10707-
if (vcpu->arch.guest_fpu && kvm_mpx_supported()) {
10708-
struct fpstate *fpstate = vcpu->arch.guest_fpu->fpstate;
10667+
if (vcpu->arch.guest_fpu.fpstate && kvm_mpx_supported()) {
10668+
struct fpstate *fpstate = vcpu->arch.guest_fpu.fpstate;
1070910669

1071010670
/*
1071110671
* To avoid have the INIT path from kvm_apic_has_events() that be

0 commit comments

Comments
 (0)