Skip to content
Snippets Groups Projects
x86.c 187 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			vcpu->arch.guest_xstate_size);
    		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] &=
    			vcpu->arch.guest_supported_xcr0 | XSTATE_FPSSE;
    	} else {
    
    		memcpy(guest_xsave->region,
    			&vcpu->arch.guest_fpu.state->fxsave,
    			sizeof(struct i387_fxsave_struct));
    		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] =
    			XSTATE_FPSSE;
    	}
    }
    
    static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
    					struct kvm_xsave *guest_xsave)
    {
    	u64 xstate_bv =
    		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
    
    
    	if (cpu_has_xsave) {
    		/*
    		 * Here we allow setting states that are not present in
    		 * CPUID leaf 0xD, index 0, EDX:EAX.  This is for compatibility
    		 * with old userspace.
    		 */
    		if (xstate_bv & ~KVM_SUPPORTED_XCR0)
    			return -EINVAL;
    		if (xstate_bv & ~host_xcr0)
    			return -EINVAL;
    
    		memcpy(&vcpu->arch.guest_fpu.state->xsave,
    
    			guest_xsave->region, vcpu->arch.guest_xstate_size);
    
    		if (xstate_bv & ~XSTATE_FPSSE)
    			return -EINVAL;
    		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
    			guest_xsave->region, sizeof(struct i387_fxsave_struct));
    	}
    	return 0;
    }
    
    static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
    					struct kvm_xcrs *guest_xcrs)
    {
    	if (!cpu_has_xsave) {
    		guest_xcrs->nr_xcrs = 0;
    		return;
    	}
    
    	guest_xcrs->nr_xcrs = 1;
    	guest_xcrs->flags = 0;
    	guest_xcrs->xcrs[0].xcr = XCR_XFEATURE_ENABLED_MASK;
    	guest_xcrs->xcrs[0].value = vcpu->arch.xcr0;
    }
    
    static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
    				       struct kvm_xcrs *guest_xcrs)
    {
    	int i, r = 0;
    
    	if (!cpu_has_xsave)
    		return -EINVAL;
    
    	if (guest_xcrs->nr_xcrs > KVM_MAX_XCRS || guest_xcrs->flags)
    		return -EINVAL;
    
    	for (i = 0; i < guest_xcrs->nr_xcrs; i++)
    		/* Only support XCR0 currently */
    
    		if (guest_xcrs->xcrs[i].xcr == XCR_XFEATURE_ENABLED_MASK) {
    
    			r = __kvm_set_xcr(vcpu, XCR_XFEATURE_ENABLED_MASK,
    
    				guest_xcrs->xcrs[i].value);
    
    /*
     * kvm_set_guest_paused() indicates to the guest kernel that it has been
     * stopped by the hypervisor.  This function will be called from the host only.
     * EINVAL is returned when the host attempts to set the flag for a guest that
     * does not support pv clocks.
     */
    static int kvm_set_guest_paused(struct kvm_vcpu *vcpu)
    {
    
    		return -EINVAL;
    
    	vcpu->arch.pvclock_set_guest_stopped_request = true;
    
    	kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
    	return 0;
    }
    
    
    long kvm_arch_vcpu_ioctl(struct file *filp,
    			 unsigned int ioctl, unsigned long arg)
    {
    	struct kvm_vcpu *vcpu = filp->private_data;
    	void __user *argp = (void __user *)arg;
    	int r;
    
    	union {
    		struct kvm_lapic_state *lapic;
    		struct kvm_xsave *xsave;
    		struct kvm_xcrs *xcrs;
    		void *buffer;
    	} u;
    
    	u.buffer = NULL;
    
    	switch (ioctl) {
    	case KVM_GET_LAPIC: {
    
    		u.lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
    
    		r = kvm_vcpu_ioctl_get_lapic(vcpu, u.lapic);
    
    		if (r)
    			goto out;
    		r = -EFAULT;
    
    		if (copy_to_user(argp, u.lapic, sizeof(struct kvm_lapic_state)))
    
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_LAPIC: {
    
    		u.lapic = memdup_user(argp, sizeof(*u.lapic));
    
    		if (IS_ERR(u.lapic))
    			return PTR_ERR(u.lapic);
    
    		r = kvm_vcpu_ioctl_set_lapic(vcpu, u.lapic);
    
    	case KVM_INTERRUPT: {
    		struct kvm_interrupt irq;
    
    		r = -EFAULT;
    		if (copy_from_user(&irq, argp, sizeof irq))
    			goto out;
    		r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
    		break;
    	}
    
    	case KVM_NMI: {
    		r = kvm_vcpu_ioctl_nmi(vcpu);
    		break;
    	}
    
    	case KVM_SET_CPUID: {
    		struct kvm_cpuid __user *cpuid_arg = argp;
    		struct kvm_cpuid cpuid;
    
    		r = -EFAULT;
    		if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
    			goto out;
    		r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries);
    		break;
    	}
    
    	case KVM_SET_CPUID2: {
    		struct kvm_cpuid2 __user *cpuid_arg = argp;
    		struct kvm_cpuid2 cpuid;
    
    		r = -EFAULT;
    		if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
    			goto out;
    		r = kvm_vcpu_ioctl_set_cpuid2(vcpu, &cpuid,
    
    					      cpuid_arg->entries);
    
    		break;
    	}
    	case KVM_GET_CPUID2: {
    		struct kvm_cpuid2 __user *cpuid_arg = argp;
    		struct kvm_cpuid2 cpuid;
    
    		r = -EFAULT;
    		if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
    			goto out;
    		r = kvm_vcpu_ioctl_get_cpuid2(vcpu, &cpuid,
    
    					      cpuid_arg->entries);
    
    		if (r)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid))
    			goto out;
    		r = 0;
    		break;
    	}
    
    	case KVM_GET_MSRS:
    		r = msr_io(vcpu, argp, kvm_get_msr, 1);
    		break;
    	case KVM_SET_MSRS:
    		r = msr_io(vcpu, argp, do_set_msr, 0);
    		break;
    
    	case KVM_TPR_ACCESS_REPORTING: {
    		struct kvm_tpr_access_ctl tac;
    
    		r = -EFAULT;
    		if (copy_from_user(&tac, argp, sizeof tac))
    			goto out;
    		r = vcpu_ioctl_tpr_access_reporting(vcpu, &tac);
    		if (r)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(argp, &tac, sizeof tac))
    			goto out;
    		r = 0;
    		break;
    	};
    
    	case KVM_SET_VAPIC_ADDR: {
    		struct kvm_vapic_addr va;
    
    		r = -EINVAL;
    		if (!irqchip_in_kernel(vcpu->kvm))
    			goto out;
    		r = -EFAULT;
    		if (copy_from_user(&va, argp, sizeof va))
    			goto out;
    		r = 0;
    		kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
    		break;
    	}
    
    Huang Ying's avatar
    Huang Ying committed
    	case KVM_X86_SETUP_MCE: {
    		u64 mcg_cap;
    
    		r = -EFAULT;
    		if (copy_from_user(&mcg_cap, argp, sizeof mcg_cap))
    			goto out;
    		r = kvm_vcpu_ioctl_x86_setup_mce(vcpu, mcg_cap);
    		break;
    	}
    	case KVM_X86_SET_MCE: {
    		struct kvm_x86_mce mce;
    
    		r = -EFAULT;
    		if (copy_from_user(&mce, argp, sizeof mce))
    			goto out;
    		r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce);
    		break;
    	}
    
    	case KVM_GET_VCPU_EVENTS: {
    		struct kvm_vcpu_events events;
    
    		kvm_vcpu_ioctl_x86_get_vcpu_events(vcpu, &events);
    
    		r = -EFAULT;
    		if (copy_to_user(argp, &events, sizeof(struct kvm_vcpu_events)))
    			break;
    		r = 0;
    		break;
    	}
    	case KVM_SET_VCPU_EVENTS: {
    		struct kvm_vcpu_events events;
    
    		r = -EFAULT;
    		if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events)))
    			break;
    
    		r = kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events);
    		break;
    	}
    
    	case KVM_GET_DEBUGREGS: {
    		struct kvm_debugregs dbgregs;
    
    		kvm_vcpu_ioctl_x86_get_debugregs(vcpu, &dbgregs);
    
    		r = -EFAULT;
    		if (copy_to_user(argp, &dbgregs,
    				 sizeof(struct kvm_debugregs)))
    			break;
    		r = 0;
    		break;
    	}
    	case KVM_SET_DEBUGREGS: {
    		struct kvm_debugregs dbgregs;
    
    		r = -EFAULT;
    		if (copy_from_user(&dbgregs, argp,
    				   sizeof(struct kvm_debugregs)))
    			break;
    
    		r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs);
    		break;
    	}
    
    	case KVM_GET_XSAVE: {
    
    		u.xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
    
    		kvm_vcpu_ioctl_x86_get_xsave(vcpu, u.xsave);
    
    		if (copy_to_user(argp, u.xsave, sizeof(struct kvm_xsave)))
    
    			break;
    		r = 0;
    		break;
    	}
    	case KVM_SET_XSAVE: {
    
    		u.xsave = memdup_user(argp, sizeof(*u.xsave));
    
    		if (IS_ERR(u.xsave))
    			return PTR_ERR(u.xsave);
    
    		r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, u.xsave);
    
    		break;
    	}
    	case KVM_GET_XCRS: {
    
    		u.xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL);
    
    		kvm_vcpu_ioctl_x86_get_xcrs(vcpu, u.xcrs);
    
    		if (copy_to_user(argp, u.xcrs,
    
    				 sizeof(struct kvm_xcrs)))
    			break;
    		r = 0;
    		break;
    	}
    	case KVM_SET_XCRS: {
    
    		u.xcrs = memdup_user(argp, sizeof(*u.xcrs));
    
    		if (IS_ERR(u.xcrs))
    			return PTR_ERR(u.xcrs);
    
    		r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
    
    	case KVM_SET_TSC_KHZ: {
    		u32 user_tsc_khz;
    
    		r = -EINVAL;
    		user_tsc_khz = (u32)arg;
    
    		if (user_tsc_khz >= kvm_max_guest_tsc_khz)
    			goto out;
    
    
    		if (user_tsc_khz == 0)
    			user_tsc_khz = tsc_khz;
    
    		kvm_set_tsc_khz(vcpu, user_tsc_khz);
    
    	case KVM_KVMCLOCK_CTRL: {
    		r = kvm_set_guest_paused(vcpu);
    		goto out;
    	}
    
    	default:
    		r = -EINVAL;
    	}
    out:
    
    int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
    {
    	return VM_FAULT_SIGBUS;
    }
    
    
    static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
    {
    	int ret;
    
    	if (addr > (unsigned int)(-3 * PAGE_SIZE))
    
    	ret = kvm_x86_ops->set_tss_addr(kvm, addr);
    	return ret;
    }
    
    
    static int kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm,
    					      u64 ident_addr)
    {
    	kvm->arch.ept_identity_map_addr = ident_addr;
    	return 0;
    }
    
    
    static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
    					  u32 kvm_nr_mmu_pages)
    {
    	if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES)
    		return -EINVAL;
    
    
    	mutex_lock(&kvm->slots_lock);
    
    
    	kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
    
    	kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
    
    	mutex_unlock(&kvm->slots_lock);
    
    	return 0;
    }
    
    static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
    {
    
    	return kvm->arch.n_max_mmu_pages;
    
    }
    
    static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
    {
    	int r;
    
    	r = 0;
    	switch (chip->chip_id) {
    	case KVM_IRQCHIP_PIC_MASTER:
    		memcpy(&chip->chip.pic,
    			&pic_irqchip(kvm)->pics[0],
    			sizeof(struct kvm_pic_state));
    		break;
    	case KVM_IRQCHIP_PIC_SLAVE:
    		memcpy(&chip->chip.pic,
    			&pic_irqchip(kvm)->pics[1],
    			sizeof(struct kvm_pic_state));
    		break;
    	case KVM_IRQCHIP_IOAPIC:
    
    		r = kvm_get_ioapic(kvm, &chip->chip.ioapic);
    
    		break;
    	default:
    		r = -EINVAL;
    		break;
    	}
    	return r;
    }
    
    static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
    {
    	int r;
    
    	r = 0;
    	switch (chip->chip_id) {
    	case KVM_IRQCHIP_PIC_MASTER:
    
    		spin_lock(&pic_irqchip(kvm)->lock);
    
    		memcpy(&pic_irqchip(kvm)->pics[0],
    			&chip->chip.pic,
    			sizeof(struct kvm_pic_state));
    
    		spin_unlock(&pic_irqchip(kvm)->lock);
    
    		break;
    	case KVM_IRQCHIP_PIC_SLAVE:
    
    		spin_lock(&pic_irqchip(kvm)->lock);
    
    		memcpy(&pic_irqchip(kvm)->pics[1],
    			&chip->chip.pic,
    			sizeof(struct kvm_pic_state));
    
    		spin_unlock(&pic_irqchip(kvm)->lock);
    
    		break;
    	case KVM_IRQCHIP_IOAPIC:
    
    		r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
    
    		break;
    	default:
    		r = -EINVAL;
    		break;
    	}
    	kvm_pic_update_irq(pic_irqchip(kvm));
    	return r;
    }
    
    
    static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
    {
    	int r = 0;
    
    
    	mutex_lock(&kvm->arch.vpit->pit_state.lock);
    
    	memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state));
    
    	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
    
    	return r;
    }
    
    static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
    {
    	int r = 0;
    
    
    	mutex_lock(&kvm->arch.vpit->pit_state.lock);
    
    	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
    
    	kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
    	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
    	return r;
    }
    
    static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
    {
    	int r = 0;
    
    	mutex_lock(&kvm->arch.vpit->pit_state.lock);
    	memcpy(ps->channels, &kvm->arch.vpit->pit_state.channels,
    		sizeof(ps->channels));
    	ps->flags = kvm->arch.vpit->pit_state.flags;
    	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
    
    	memset(&ps->reserved, 0, sizeof(ps->reserved));
    
    	return r;
    }
    
    static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
    {
    	int r = 0, start = 0;
    	u32 prev_legacy, cur_legacy;
    	mutex_lock(&kvm->arch.vpit->pit_state.lock);
    	prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
    	cur_legacy = ps->flags & KVM_PIT_FLAGS_HPET_LEGACY;
    	if (!prev_legacy && cur_legacy)
    		start = 1;
    	memcpy(&kvm->arch.vpit->pit_state.channels, &ps->channels,
    	       sizeof(kvm->arch.vpit->pit_state.channels));
    	kvm->arch.vpit->pit_state.flags = ps->flags;
    	kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
    
    	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
    
    static int kvm_vm_ioctl_reinject(struct kvm *kvm,
    				 struct kvm_reinject_control *control)
    {
    	if (!kvm->arch.vpit)
    		return -ENXIO;
    
    	mutex_lock(&kvm->arch.vpit->pit_state.lock);
    
    	kvm->arch.vpit->pit_state.reinject = control->pit_reinject;
    
    	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
    
     * kvm_vm_ioctl_get_dirty_log - get and clear the log of dirty pages in a slot
     * @kvm: kvm instance
     * @log: slot id and address to which we copy the log
    
     * We need to keep it in mind that VCPU threads can write to the bitmap
     * concurrently.  So, to avoid losing data, we keep the following order for
     * each bit:
    
     *   1. Take a snapshot of the bit and clear it if needed.
     *   2. Write protect the corresponding page.
     *   3. Flush TLB's if needed.
     *   4. Copy the snapshot to the userspace.
    
     * Between 2 and 3, the guest may write to the page using the remaining TLB
     * entry.  This is not a problem because the page will be reported dirty at
     * step 4 using the snapshot taken before and step 3 ensures that successive
     * writes will be logged for the next call.
    
    int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
    
    	unsigned long n, i;
    	unsigned long *dirty_bitmap;
    	unsigned long *dirty_bitmap_buffer;
    	bool is_dirty = false;
    
    	mutex_lock(&kvm->slots_lock);
    
    	r = -EINVAL;
    
    	if (log->slot >= KVM_USER_MEM_SLOTS)
    
    	memslot = id_to_memslot(kvm->memslots, log->slot);
    
    
    	dirty_bitmap = memslot->dirty_bitmap;
    
    	r = -ENOENT;
    
    	if (!dirty_bitmap)
    
    	n = kvm_dirty_bitmap_bytes(memslot);
    
    	dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long);
    	memset(dirty_bitmap_buffer, 0, n);
    
    	spin_lock(&kvm->mmu_lock);
    
    	for (i = 0; i < n / sizeof(long); i++) {
    		unsigned long mask;
    		gfn_t offset;
    
    		if (!dirty_bitmap[i])
    			continue;
    
    		is_dirty = true;
    
    		mask = xchg(&dirty_bitmap[i], 0);
    		dirty_bitmap_buffer[i] = mask;
    
    		offset = i * BITS_PER_LONG;
    		kvm_mmu_write_protect_pt_masked(kvm, memslot, offset, mask);
    
    	if (is_dirty)
    		kvm_flush_remote_tlbs(kvm);
    
    	spin_unlock(&kvm->mmu_lock);
    
    	r = -EFAULT;
    	if (copy_to_user(log->dirty_bitmap, dirty_bitmap_buffer, n))
    		goto out;
    
    	mutex_unlock(&kvm->slots_lock);
    
    int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
    			bool line_status)
    
    {
    	if (!irqchip_in_kernel(kvm))
    		return -ENXIO;
    
    	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
    
    					irq_event->irq, irq_event->level,
    					line_status);
    
    long kvm_arch_vm_ioctl(struct file *filp,
    		       unsigned int ioctl, unsigned long arg)
    {
    	struct kvm *kvm = filp->private_data;
    	void __user *argp = (void __user *)arg;
    
    	int r = -ENOTTY;
    
    	/*
    	 * This union makes it completely explicit to gcc-3.x
    	 * that these two variables' stack usage should be
    	 * combined, not added together.
    	 */
    	union {
    		struct kvm_pit_state ps;
    
    		struct kvm_pit_state2 ps2;
    
    		struct kvm_pit_config pit_config;
    
    
    	switch (ioctl) {
    	case KVM_SET_TSS_ADDR:
    		r = kvm_vm_ioctl_set_tss_addr(kvm, arg);
    		break;
    
    	case KVM_SET_IDENTITY_MAP_ADDR: {
    		u64 ident_addr;
    
    		r = -EFAULT;
    		if (copy_from_user(&ident_addr, argp, sizeof ident_addr))
    			goto out;
    		r = kvm_vm_ioctl_set_identity_map_addr(kvm, ident_addr);
    		break;
    	}
    
    	case KVM_SET_NR_MMU_PAGES:
    		r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
    		break;
    	case KVM_GET_NR_MMU_PAGES:
    		r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
    		break;
    
    	case KVM_CREATE_IRQCHIP: {
    		struct kvm_pic *vpic;
    
    		mutex_lock(&kvm->lock);
    		r = -EEXIST;
    		if (kvm->arch.vpic)
    			goto create_irqchip_unlock;
    
    		r = -EINVAL;
    		if (atomic_read(&kvm->online_vcpus))
    			goto create_irqchip_unlock;
    
    		vpic = kvm_create_pic(kvm);
    		if (vpic) {
    
    			r = kvm_ioapic_init(kvm);
    			if (r) {
    
    				mutex_lock(&kvm->slots_lock);
    
    				kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
    
    							  &vpic->dev_master);
    				kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
    							  &vpic->dev_slave);
    				kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS,
    							  &vpic->dev_eclr);
    
    				mutex_unlock(&kvm->slots_lock);
    
    				kfree(vpic);
    				goto create_irqchip_unlock;
    
    			goto create_irqchip_unlock;
    		smp_wmb();
    		kvm->arch.vpic = vpic;
    		smp_wmb();
    
    		r = kvm_setup_default_irq_routing(kvm);
    		if (r) {
    
    			mutex_lock(&kvm->slots_lock);
    
    			mutex_lock(&kvm->irq_lock);
    
    			kvm_ioapic_destroy(kvm);
    			kvm_destroy_pic(kvm);
    
    			mutex_unlock(&kvm->irq_lock);
    
    			mutex_unlock(&kvm->slots_lock);
    
    	create_irqchip_unlock:
    		mutex_unlock(&kvm->lock);
    
    Sheng Yang's avatar
    Sheng Yang committed
    	case KVM_CREATE_PIT:
    
    		u.pit_config.flags = KVM_PIT_SPEAKER_DUMMY;
    		goto create_pit;
    	case KVM_CREATE_PIT2:
    		r = -EFAULT;
    		if (copy_from_user(&u.pit_config, argp,
    				   sizeof(struct kvm_pit_config)))
    			goto out;
    	create_pit:
    
    		mutex_lock(&kvm->slots_lock);
    
    		r = -EEXIST;
    		if (kvm->arch.vpit)
    			goto create_pit_unlock;
    
    Sheng Yang's avatar
    Sheng Yang committed
    		r = -ENOMEM;
    
    		kvm->arch.vpit = kvm_create_pit(kvm, u.pit_config.flags);
    
    Sheng Yang's avatar
    Sheng Yang committed
    		if (kvm->arch.vpit)
    			r = 0;
    
    	create_pit_unlock:
    
    		mutex_unlock(&kvm->slots_lock);
    
    Sheng Yang's avatar
    Sheng Yang committed
    		break;
    
    	case KVM_GET_IRQCHIP: {
    		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
    
    		struct kvm_irqchip *chip;
    
    		chip = memdup_user(argp, sizeof(*chip));
    		if (IS_ERR(chip)) {
    			r = PTR_ERR(chip);
    
    		r = -ENXIO;
    		if (!irqchip_in_kernel(kvm))
    
    			goto get_irqchip_out;
    		r = kvm_vm_ioctl_get_irqchip(kvm, chip);
    
    			goto get_irqchip_out;
    
    		if (copy_to_user(argp, chip, sizeof *chip))
    			goto get_irqchip_out;
    
    	get_irqchip_out:
    		kfree(chip);
    
    		break;
    	}
    	case KVM_SET_IRQCHIP: {
    		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
    
    		struct kvm_irqchip *chip;
    
    		chip = memdup_user(argp, sizeof(*chip));
    		if (IS_ERR(chip)) {
    			r = PTR_ERR(chip);
    
    		r = -ENXIO;
    		if (!irqchip_in_kernel(kvm))
    
    			goto set_irqchip_out;
    		r = kvm_vm_ioctl_set_irqchip(kvm, chip);
    
    			goto set_irqchip_out;
    
    	set_irqchip_out:
    		kfree(chip);
    
    	case KVM_GET_PIT: {
    		r = -EFAULT;
    
    		if (copy_from_user(&u.ps, argp, sizeof(struct kvm_pit_state)))
    
    			goto out;
    		r = -ENXIO;
    		if (!kvm->arch.vpit)
    			goto out;
    
    		r = kvm_vm_ioctl_get_pit(kvm, &u.ps);
    
    		if (r)
    			goto out;
    		r = -EFAULT;
    
    		if (copy_to_user(argp, &u.ps, sizeof(struct kvm_pit_state)))
    
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_PIT: {
    		r = -EFAULT;
    
    		if (copy_from_user(&u.ps, argp, sizeof u.ps))
    
    			goto out;
    		r = -ENXIO;
    		if (!kvm->arch.vpit)
    			goto out;
    
    		r = kvm_vm_ioctl_set_pit(kvm, &u.ps);
    
    	case KVM_GET_PIT2: {
    		r = -ENXIO;
    		if (!kvm->arch.vpit)
    			goto out;
    		r = kvm_vm_ioctl_get_pit2(kvm, &u.ps2);
    		if (r)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(argp, &u.ps2, sizeof(u.ps2)))
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_PIT2: {
    		r = -EFAULT;
    		if (copy_from_user(&u.ps2, argp, sizeof(u.ps2)))
    			goto out;
    		r = -ENXIO;
    		if (!kvm->arch.vpit)
    			goto out;
    		r = kvm_vm_ioctl_set_pit2(kvm, &u.ps2);
    		break;
    	}
    
    	case KVM_REINJECT_CONTROL: {
    		struct kvm_reinject_control control;
    		r =  -EFAULT;
    		if (copy_from_user(&control, argp, sizeof(control)))
    			goto out;
    		r = kvm_vm_ioctl_reinject(kvm, &control);
    		break;
    	}
    
    	case KVM_XEN_HVM_CONFIG: {
    		r = -EFAULT;
    		if (copy_from_user(&kvm->arch.xen_hvm_config, argp,
    				   sizeof(struct kvm_xen_hvm_config)))
    			goto out;
    		r = -EINVAL;
    		if (kvm->arch.xen_hvm_config.flags)
    			goto out;
    		r = 0;
    		break;
    	}
    
    	case KVM_SET_CLOCK: {
    		struct kvm_clock_data user_ns;
    		u64 now_ns;
    		s64 delta;
    
    		r = -EFAULT;
    		if (copy_from_user(&user_ns, argp, sizeof(user_ns)))
    			goto out;
    
    		r = -EINVAL;
    		if (user_ns.flags)
    			goto out;
    
    		r = 0;
    
    		local_irq_disable();
    
    		now_ns = get_kernel_ns();
    
    		delta = user_ns.clock - now_ns;
    
    		local_irq_enable();
    
    		kvm->arch.kvmclock_offset = delta;
    
    		break;
    	}
    	case KVM_GET_CLOCK: {
    		struct kvm_clock_data user_ns;
    		u64 now_ns;
    
    
    		local_irq_disable();
    
    		now_ns = get_kernel_ns();
    
    		user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
    
    		local_irq_enable();
    
    		user_ns.flags = 0;
    
    		memset(&user_ns.pad, 0, sizeof(user_ns.pad));
    
    
    		r = -EFAULT;
    		if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
    			goto out;
    		r = 0;
    		break;
    	}
    
    
    static void kvm_init_msr_list(void)
    
    	/* skip the first msrs in the list. KVM-specific */
    	for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) {
    
    		if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
    			continue;
    		if (j < i)
    			msrs_to_save[j] = msrs_to_save[i];
    		j++;
    	}
    	num_msrs_to_save = j;
    }
    
    
    static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
    			   const void *v)
    
    	int handled = 0;
    	int n;
    
    	do {
    		n = min(len, 8);
    		if (!(vcpu->arch.apic &&
    		      !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, n, v))
    		    && kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
    			break;
    		handled += n;
    		addr += n;
    		len -= n;
    		v += n;
    	} while (len);
    
    static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
    
    	int handled = 0;
    	int n;
    
    	do {
    		n = min(len, 8);
    		if (!(vcpu->arch.apic &&
    		      !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, n, v))
    		    && kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
    			break;
    		trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
    		handled += n;
    		addr += n;
    		len -= n;
    		v += n;
    	} while (len);
    
    static void kvm_set_segment(struct kvm_vcpu *vcpu,
    			struct kvm_segment *var, int seg)
    {
    	kvm_x86_ops->set_segment(vcpu, var, seg);
    }
    
    void kvm_get_segment(struct kvm_vcpu *vcpu,
    		     struct kvm_segment *var, int seg)
    {
    	kvm_x86_ops->get_segment(vcpu, var, seg);
    }
    
    
    gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access)
    
    	struct x86_exception exception;
    
    
    	BUG_ON(!mmu_is_nested(vcpu));
    
    	/* NPT walks are always user-walks */
    	access |= PFERR_USER_MASK;
    
    	t_gpa  = vcpu->arch.mmu.gva_to_gpa(vcpu, gpa, access, &exception);
    
    gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva,
    			      struct x86_exception *exception)
    
    {
    	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
    
    	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception);
    
     gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva,
    				struct x86_exception *exception)
    
    {
    	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
    	access |= PFERR_FETCH_MASK;
    
    	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception);
    
    gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
    			       struct x86_exception *exception)
    
    {
    	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
    	access |= PFERR_WRITE_MASK;
    
    	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception);
    
    }
    
    /* uses this to access any guest's mapped memory without checking CPL */
    
    gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
    				struct x86_exception *exception)
    
    	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, 0, exception);
    
    }
    
    static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
    				      struct kvm_vcpu *vcpu, u32 access,
    
    	int r = X86EMUL_CONTINUE;
    
    		gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, access,
    
    		unsigned offset = addr & (PAGE_SIZE-1);
    
    		unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);