KVM: ia64: stack get/restore patch
Jes Sorensen [Thu, 18 Dec 2008 11:17:51 +0000 (12:17 +0100)]
Implement KVM_IA64_VCPU_[GS]ET_STACK ioctl calls. This is required
for live migrations.

Patch is based on previous implementation that was part of old
GET/SET_REGS ioctl calls.

Signed-off-by: Jes Sorensen <jes@sgi.com>
Signed-off-by: Avi Kivity <avi@redhat.com>

arch/ia64/include/asm/kvm.h
arch/ia64/include/asm/kvm_host.h
arch/ia64/kvm/kvm-ia64.c
include/linux/kvm.h

index be3fdb8..b514578 100644 (file)
@@ -214,6 +214,13 @@ struct kvm_sregs {
 struct kvm_fpu {
 };
 
+#define KVM_IA64_VCPU_STACK_SHIFT      16
+#define KVM_IA64_VCPU_STACK_SIZE       (1UL << KVM_IA64_VCPU_STACK_SHIFT)
+
+struct kvm_ia64_vcpu_stack {
+       unsigned char stack[KVM_IA64_VCPU_STACK_SIZE];
+};
+
 struct kvm_debug_exit_arch {
 };
 
index 3486636..7da0c09 100644 (file)
 #define VCPU_STRUCT_SHIFT      16
 #define VCPU_STRUCT_SIZE       (__IA64_UL_CONST(1) << VCPU_STRUCT_SHIFT)
 
-#define KVM_STK_OFFSET         VCPU_STRUCT_SIZE
+/*
+ * This must match KVM_IA64_VCPU_STACK_{SHIFT,SIZE} arch/ia64/include/asm/kvm.h
+ */
+#define KVM_STK_SHIFT          16
+#define KVM_STK_OFFSET         (__IA64_UL_CONST(1)<< KVM_STK_SHIFT)
 
 #define KVM_VM_STRUCT_SHIFT    19
 #define KVM_VM_STRUCT_SIZE     (__IA64_UL_CONST(1) << KVM_VM_STRUCT_SHIFT)
index de47467..1477f91 100644 (file)
@@ -1421,6 +1421,23 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        return 0;
 }
 
+int kvm_arch_vcpu_ioctl_get_stack(struct kvm_vcpu *vcpu,
+                                 struct kvm_ia64_vcpu_stack *stack)
+{
+       memcpy(stack, vcpu, sizeof(struct kvm_ia64_vcpu_stack));
+       return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_stack(struct kvm_vcpu *vcpu,
+                                 struct kvm_ia64_vcpu_stack *stack)
+{
+       memcpy(vcpu + 1, &stack->stack[0] + sizeof(struct kvm_vcpu),
+              sizeof(struct kvm_ia64_vcpu_stack) - sizeof(struct kvm_vcpu));
+
+       vcpu->arch.exit_data = ((struct kvm_vcpu *)stack)->arch.exit_data;
+       return 0;
+}
+
 void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
 
@@ -1430,9 +1447,78 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 
 
 long kvm_arch_vcpu_ioctl(struct file *filp,
-               unsigned int ioctl, unsigned long arg)
+                        unsigned int ioctl, unsigned long arg)
 {
-       return -EINVAL;
+       struct kvm_vcpu *vcpu = filp->private_data;
+       void __user *argp = (void __user *)arg;
+       struct kvm_ia64_vcpu_stack *stack = NULL;
+       long r;
+
+       switch (ioctl) {
+       case KVM_IA64_VCPU_GET_STACK: {
+               struct kvm_ia64_vcpu_stack __user *user_stack;
+               void __user *first_p = argp;
+
+               r = -EFAULT;
+               if (copy_from_user(&user_stack, first_p, sizeof(void *)))
+                       goto out;
+
+               if (!access_ok(VERIFY_WRITE, user_stack,
+                              sizeof(struct kvm_ia64_vcpu_stack))) {
+                       printk(KERN_INFO "KVM_IA64_VCPU_GET_STACK: "
+                              "Illegal user destination address for stack\n");
+                       goto out;
+               }
+               stack = kzalloc(sizeof(struct kvm_ia64_vcpu_stack), GFP_KERNEL);
+               if (!stack) {
+                       r = -ENOMEM;
+                       goto out;
+               }
+
+               r = kvm_arch_vcpu_ioctl_get_stack(vcpu, stack);
+               if (r)
+                       goto out;
+
+               if (copy_to_user(user_stack, stack,
+                                sizeof(struct kvm_ia64_vcpu_stack)))
+                       goto out;
+
+               break;
+       }
+       case KVM_IA64_VCPU_SET_STACK: {
+               struct kvm_ia64_vcpu_stack __user *user_stack;
+               void __user *first_p = argp;
+
+               r = -EFAULT;
+               if (copy_from_user(&user_stack, first_p, sizeof(void *)))
+                       goto out;
+
+               if (!access_ok(VERIFY_READ, user_stack,
+                           sizeof(struct kvm_ia64_vcpu_stack))) {
+                       printk(KERN_INFO "KVM_IA64_VCPU_SET_STACK: "
+                              "Illegal user address for stack\n");
+                       goto out;
+               }
+               stack = kmalloc(sizeof(struct kvm_ia64_vcpu_stack), GFP_KERNEL);
+               if (!stack) {
+                       r = -ENOMEM;
+                       goto out;
+               }
+               if (copy_from_user(stack, user_stack,
+                                  sizeof(struct kvm_ia64_vcpu_stack)))
+                       goto out;
+
+               r = kvm_arch_vcpu_ioctl_set_stack(vcpu, stack);
+               break;
+       }
+
+       default:
+               r = -EINVAL;
+       }
+
+out:
+       kfree(stack);
+       return r;
 }
 
 int kvm_arch_set_memory_region(struct kvm *kvm,
@@ -1472,7 +1558,7 @@ void kvm_arch_flush_shadow(struct kvm *kvm)
 }
 
 long kvm_arch_dev_ioctl(struct file *filp,
-               unsigned int ioctl, unsigned long arg)
+                       unsigned int ioctl, unsigned long arg)
 {
        return -EINVAL;
 }
index 429a2ce..28582fc 100644 (file)
@@ -489,6 +489,9 @@ struct kvm_debug_guest {
 
 #define __KVM_DEPRECATED_DEBUG_GUEST _IOW(KVMIO,  0x87, struct kvm_debug_guest)
 
+#define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
+#define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
+
 #define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
 #define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
 #define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)