|
@@ -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;
|
|
|
}
|