[PATCH 2/2] Use alignment properties of vcpu to simplify FPU ops

Rusty Russell
2007-07-30T11:13:43Z

Now we use a kmem cache for allocating vcpus, we can get the 16-byte
alignment required by fxsave & fxrstor instructions, and avoid
manually aligning the buffer.

Signed-off-by: Rusty Russell <rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>

diff -r 39421cbc0486 drivers/kvm/kvm.h
--- a/drivers/kvm/kvm.h Mon Jul 30 15:01:44 2007 +1000
+++ b/drivers/kvm/kvm.h Mon Jul 30 15:09:54 2007 +1000
@@ -43,10 +43,6 @@
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
#define KVM_MAX_CPUID_ENTRIES 40
-
-#define FX_IMAGE_SIZE 512
-#define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)

#define DE_VECTOR 0
#define NM_VECTOR 7
@@ -339,9 +335,8 @@ struct kvm_vcpu {

struct kvm_guest_debug guest_debug;

- char fx_buf[FX_BUF_SIZE];
- char *host_fx_image;
- char *guest_fx_image;
+ struct i387_fxsave_struct host_fx_image;
+ struct i387_fxsave_struct guest_fx_image;
int fpu_active;
int guest_fpu_loaded;

@@ -697,12 +692,12 @@ static inline unsigned long read_msr(uns
}
#endif

-static inline void fx_save(void *image)
+static inline void fx_save(struct i387_fxsave_struct *image)
{
asm ("fxsave (%0)":: "r" (image));
}

-static inline void fx_restore(void *image)
+static inline void fx_restore(struct i387_fxsave_struct *image)
{
asm ("fxrstor (%0)":: "r" (image));
}
diff -r 39421cbc0486 drivers/kvm/kvm_main.c
--- a/drivers/kvm/kvm_main.c Mon Jul 30 15:01:44 2007 +1000
+++ b/drivers/kvm/kvm_main.c Mon Jul 30 15:10:09 2007 +1000
@@ -218,8 +218,8 @@ void kvm_load_guest_fpu(struct kvm_vcpu
return;

vcpu->guest_fpu_loaded = 1;
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ fx_save(&vcpu->host_fx_image);
+ fx_restore(&vcpu->guest_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);

@@ -229,8 +229,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *
return;

vcpu->guest_fpu_loaded = 0;
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);

@@ -317,10 +317,6 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu,
goto fail_free_run;
}
vcpu->pio_data = page_address(page);
-
- vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
- FX_IMAGE_ALIGN);
- vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;

r = kvm_mmu_create(vcpu);
if (r < 0)
@@ -672,30 +668,20 @@ EXPORT_SYMBOL_GPL(set_cr8);

void fx_init(struct kvm_vcpu *vcpu)
{
- struct __attribute__ ((__packed__)) fx_image_s {
- u16 control; //fcw
- u16 status; //fsw
- u16 tag; // ftw
- u16 opcode; //fop
- u64 ip; // fpu ip
- u64 operand;// fpu dp
- u32 mxcsr;
- u32 mxcsr_mask;
-
- } *fx_image;
+ unsigned after_mxcsr_mask;

/* Initialize guest FPU by resetting ours and saving into guest's */
preempt_disable();
- fx_save(vcpu->host_fx_image);
+ fx_save(&vcpu->host_fx_image);
fpu_init();
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
preempt_enable();

- fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
- fx_image->mxcsr = 0x1f80;
- memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
- 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+ after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
+ vcpu->guest_fx_image.mxcsr = 0x1f80;
+ memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
+ 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
}
EXPORT_SYMBOL_GPL(fx_init);

@@ -2414,6 +2400,9 @@ static int kvm_vm_ioctl_create_vcpu(stru
if (IS_ERR(vcpu))
return PTR_ERR(vcpu);

+ /* We do fxsave: this must be aligned. */
+ BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
+
vcpu_load(vcpu);
r = kvm_mmu_setup(vcpu);
vcpu_put(vcpu);
@@ -2526,7 +2515,7 @@ struct fxsave {

static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;

vcpu_load(vcpu);

@@ -2546,7 +2535,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct

static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;

vcpu_load(vcpu);

diff -r 39421cbc0486 drivers/kvm/svm.c
--- a/drivers/kvm/svm.c Mon Jul 30 15:01:44 2007 +1000
+++ b/drivers/kvm/svm.c Mon Jul 30 15:09:54 2007 +1000
@@ -1540,8 +1541,8 @@ again:
}

if (vcpu->fpu_active) {
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ fx_save(&vcpu->host_fx_image);
+ fx_restore(&vcpu->guest_fx_image);
}

asm volatile (
@@ -1653,8 +1654,8 @@ again:
vcpu->guest_mode = 0;

if (vcpu->fpu_active) {
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
}

if ((svm->vmcb->save.dr7 & 0xff))