Skip to content
Snippets Groups Projects
x86.c 107 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	vfree(entries);
    out:
    	return r;
    }
    
    
    int kvm_dev_ioctl_check_extension(long ext)
    {
    	int r;
    
    	switch (ext) {
    	case KVM_CAP_IRQCHIP:
    	case KVM_CAP_HLT:
    	case KVM_CAP_MMU_SHADOW_CACHE_CONTROL:
    	case KVM_CAP_SET_TSS_ADDR:
    
    	case KVM_CAP_EXT_CPUID:
    
    	case KVM_CAP_CLOCKSOURCE:
    
    Sheng Yang's avatar
    Sheng Yang committed
    	case KVM_CAP_PIT:
    
    	case KVM_CAP_NOP_IO_DELAY:
    
    	case KVM_CAP_MP_STATE:
    
    	case KVM_CAP_SYNC_MMU:
    
    	case KVM_CAP_REINJECT_CONTROL:
    
    	case KVM_CAP_COALESCED_MMIO:
    		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
    		break;
    
    	case KVM_CAP_VAPIC:
    		r = !kvm_x86_ops->cpu_has_accelerated_tpr();
    		break;
    
    	case KVM_CAP_NR_VCPUS:
    		r = KVM_MAX_VCPUS;
    		break;
    
    	case KVM_CAP_NR_MEMSLOTS:
    		r = KVM_MEMORY_SLOTS;
    		break;
    
    	case KVM_CAP_PV_MMU:
    		r = !tdp_enabled;
    		break;
    
    	case KVM_CAP_IOMMU:
    
    		r = iommu_found();
    
    long kvm_arch_dev_ioctl(struct file *filp,
    			unsigned int ioctl, unsigned long arg)
    {
    	void __user *argp = (void __user *)arg;
    	long r;
    
    	switch (ioctl) {
    	case KVM_GET_MSR_INDEX_LIST: {
    		struct kvm_msr_list __user *user_msr_list = argp;
    		struct kvm_msr_list msr_list;
    		unsigned n;
    
    		r = -EFAULT;
    		if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
    			goto out;
    		n = msr_list.nmsrs;
    		msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs);
    		if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
    			goto out;
    		r = -E2BIG;
    		if (n < num_msrs_to_save)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(user_msr_list->indices, &msrs_to_save,
    				 num_msrs_to_save * sizeof(u32)))
    			goto out;
    		if (copy_to_user(user_msr_list->indices
    				 + num_msrs_to_save * sizeof(u32),
    				 &emulated_msrs,
    				 ARRAY_SIZE(emulated_msrs) * sizeof(u32)))
    			goto out;
    		r = 0;
    		break;
    	}
    
    	case KVM_GET_SUPPORTED_CPUID: {
    		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_dev_ioctl_get_supported_cpuid(&cpuid,
    
    						      cpuid_arg->entries);
    
    		if (r)
    			goto out;
    
    		r = -EFAULT;
    		if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid))
    			goto out;
    		r = 0;
    		break;
    	}
    
    void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
    {
    	kvm_x86_ops->vcpu_load(vcpu, cpu);
    
    	kvm_request_guest_time_update(vcpu);
    
    }
    
    void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
    {
    	kvm_x86_ops->vcpu_put(vcpu);
    
    static int is_efer_nx(void)
    
    {
    	u64 efer;
    
    	rdmsrl(MSR_EFER, efer);
    
    	return efer & EFER_NX;
    }
    
    static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
    {
    	int i;
    	struct kvm_cpuid_entry2 *e, *entry;
    
    
    	entry = NULL;
    
    	for (i = 0; i < vcpu->arch.cpuid_nent; ++i) {
    		e = &vcpu->arch.cpuid_entries[i];
    
    		if (e->function == 0x80000001) {
    			entry = e;
    			break;
    		}
    	}
    
    	if (entry && (entry->edx & (1 << 20)) && !is_efer_nx()) {
    
    		entry->edx &= ~(1 << 20);
    		printk(KERN_INFO "kvm: guest NX capability removed\n");
    	}
    }
    
    
    /* when an old userspace process fills a new kernel module */
    
    static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
    				    struct kvm_cpuid *cpuid,
    				    struct kvm_cpuid_entry __user *entries)
    
    {
    	int r, i;
    	struct kvm_cpuid_entry *cpuid_entries;
    
    	r = -E2BIG;
    	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
    		goto out;
    	r = -ENOMEM;
    	cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry) * cpuid->nent);
    	if (!cpuid_entries)
    		goto out;
    	r = -EFAULT;
    	if (copy_from_user(cpuid_entries, entries,
    			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
    		goto out_free;
    	for (i = 0; i < cpuid->nent; i++) {
    
    		vcpu->arch.cpuid_entries[i].function = cpuid_entries[i].function;
    		vcpu->arch.cpuid_entries[i].eax = cpuid_entries[i].eax;
    		vcpu->arch.cpuid_entries[i].ebx = cpuid_entries[i].ebx;
    		vcpu->arch.cpuid_entries[i].ecx = cpuid_entries[i].ecx;
    		vcpu->arch.cpuid_entries[i].edx = cpuid_entries[i].edx;
    		vcpu->arch.cpuid_entries[i].index = 0;
    		vcpu->arch.cpuid_entries[i].flags = 0;
    		vcpu->arch.cpuid_entries[i].padding[0] = 0;
    		vcpu->arch.cpuid_entries[i].padding[1] = 0;
    		vcpu->arch.cpuid_entries[i].padding[2] = 0;
    	}
    	vcpu->arch.cpuid_nent = cpuid->nent;
    
    	cpuid_fix_nx_cap(vcpu);
    	r = 0;
    
    out_free:
    	vfree(cpuid_entries);
    out:
    	return r;
    }
    
    static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
    
    				     struct kvm_cpuid2 *cpuid,
    				     struct kvm_cpuid_entry2 __user *entries)
    
    {
    	int r;
    
    	r = -E2BIG;
    	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
    		goto out;
    	r = -EFAULT;
    
    	if (copy_from_user(&vcpu->arch.cpuid_entries, entries,
    
    			   cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
    
    	vcpu->arch.cpuid_nent = cpuid->nent;
    
    static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
    
    				     struct kvm_cpuid2 *cpuid,
    				     struct kvm_cpuid_entry2 __user *entries)
    
    	if (cpuid->nent < vcpu->arch.cpuid_nent)
    
    		goto out;
    	r = -EFAULT;
    
    	if (copy_to_user(entries, &vcpu->arch.cpuid_entries,
    
    			 vcpu->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2)))
    
    	cpuid->nent = vcpu->arch.cpuid_nent;
    
    	return r;
    }
    
    static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
    
    {
    	entry->function = function;
    	entry->index = index;
    	cpuid_count(entry->function, entry->index,
    
    		    &entry->eax, &entry->ebx, &entry->ecx, &entry->edx);
    
    	entry->flags = 0;
    }
    
    static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
    			 u32 index, int *nent, int maxnent)
    {
    	const u32 kvm_supported_word0_x86_features = bit(X86_FEATURE_FPU) |
    		bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) |
    		bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) |
    		bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) |
    		bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) |
    		bit(X86_FEATURE_SEP) | bit(X86_FEATURE_PGE) |
    		bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) |
    		bit(X86_FEATURE_CLFLSH) | bit(X86_FEATURE_MMX) |
    		bit(X86_FEATURE_FXSR) | bit(X86_FEATURE_XMM) |
    		bit(X86_FEATURE_XMM2) | bit(X86_FEATURE_SELFSNOOP);
    	const u32 kvm_supported_word1_x86_features = bit(X86_FEATURE_FPU) |
    		bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) |
    		bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) |
    		bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) |
    		bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) |
    		bit(X86_FEATURE_PGE) |
    		bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) |
    		bit(X86_FEATURE_MMX) | bit(X86_FEATURE_FXSR) |
    		bit(X86_FEATURE_SYSCALL) |
    		(bit(X86_FEATURE_NX) && is_efer_nx()) |
    #ifdef CONFIG_X86_64
    		bit(X86_FEATURE_LM) |
    #endif
    
    Alexander Graf's avatar
    Alexander Graf committed
    		bit(X86_FEATURE_FXSR_OPT) |
    
    		bit(X86_FEATURE_MMXEXT) |
    		bit(X86_FEATURE_3DNOWEXT) |
    		bit(X86_FEATURE_3DNOW);
    	const u32 kvm_supported_word3_x86_features =
    		bit(X86_FEATURE_XMM3) | bit(X86_FEATURE_CX16);
    	const u32 kvm_supported_word6_x86_features =
    
    		bit(X86_FEATURE_LAHF_LM) | bit(X86_FEATURE_CMP_LEGACY) |
    		bit(X86_FEATURE_SVM);
    
    	/* all calls to cpuid_count() should be made on the same cpu */
    
    	get_cpu();
    	do_cpuid_1_ent(entry, function, index);
    	++*nent;
    
    	switch (function) {
    	case 0:
    		entry->eax = min(entry->eax, (u32)0xb);
    		break;
    	case 1:
    		entry->edx &= kvm_supported_word0_x86_features;
    		entry->ecx &= kvm_supported_word3_x86_features;
    		break;
    	/* function 2 entries are STATEFUL. That is, repeated cpuid commands
    	 * may return different values. This forces us to get_cpu() before
    	 * issuing the first command, and also to emulate this annoying behavior
    	 * in kvm_emulate_cpuid() using KVM_CPUID_FLAG_STATE_READ_NEXT */
    	case 2: {
    		int t, times = entry->eax & 0xff;
    
    		entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
    
    		entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT;
    
    		for (t = 1; t < times && *nent < maxnent; ++t) {
    			do_cpuid_1_ent(&entry[t], function, 0);
    			entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC;
    			++*nent;
    		}
    		break;
    	}
    	/* function 4 and 0xb have additional index. */
    	case 4: {
    
    		int i, cache_type;
    
    
    		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
    		/* read more entries until cache_type is zero */
    
    		for (i = 1; *nent < maxnent; ++i) {
    			cache_type = entry[i - 1].eax & 0x1f;
    
    			if (!cache_type)
    				break;
    
    			do_cpuid_1_ent(&entry[i], function, i);
    			entry[i].flags |=
    
    			       KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
    			++*nent;
    		}
    		break;
    	}
    	case 0xb: {
    
    		int i, level_type;
    
    
    		entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
    		/* read more entries until level_type is zero */
    
    		for (i = 1; *nent < maxnent; ++i) {
    
    			level_type = entry[i - 1].ecx & 0xff00;
    
    			if (!level_type)
    				break;
    
    			do_cpuid_1_ent(&entry[i], function, i);
    			entry[i].flags |=
    
    			       KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
    			++*nent;
    		}
    		break;
    	}
    	case 0x80000000:
    		entry->eax = min(entry->eax, 0x8000001a);
    		break;
    	case 0x80000001:
    		entry->edx &= kvm_supported_word1_x86_features;
    		entry->ecx &= kvm_supported_word6_x86_features;
    		break;
    	}
    	put_cpu();
    }
    
    
    static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
    
    				     struct kvm_cpuid_entry2 __user *entries)
    
    {
    	struct kvm_cpuid_entry2 *cpuid_entries;
    	int limit, nent = 0, r = -E2BIG;
    	u32 func;
    
    	if (cpuid->nent < 1)
    		goto out;
    	r = -ENOMEM;
    	cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent);
    	if (!cpuid_entries)
    		goto out;
    
    	do_cpuid_ent(&cpuid_entries[0], 0, 0, &nent, cpuid->nent);
    	limit = cpuid_entries[0].eax;
    	for (func = 1; func <= limit && nent < cpuid->nent; ++func)
    		do_cpuid_ent(&cpuid_entries[nent], func, 0,
    
    			     &nent, cpuid->nent);
    
    	r = -E2BIG;
    	if (nent >= cpuid->nent)
    		goto out_free;
    
    	do_cpuid_ent(&cpuid_entries[nent], 0x80000000, 0, &nent, cpuid->nent);
    	limit = cpuid_entries[nent - 1].eax;
    	for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
    		do_cpuid_ent(&cpuid_entries[nent], func, 0,
    
    			     &nent, cpuid->nent);
    
    	r = -EFAULT;
    	if (copy_to_user(entries, cpuid_entries,
    
    			 nent * sizeof(struct kvm_cpuid_entry2)))
    
    		goto out_free;
    	cpuid->nent = nent;
    	r = 0;
    
    out_free:
    	vfree(cpuid_entries);
    out:
    	return r;
    }
    
    
    static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
    				    struct kvm_lapic_state *s)
    {
    	vcpu_load(vcpu);
    
    	memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
    
    	vcpu_put(vcpu);
    
    	return 0;
    }
    
    static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
    				    struct kvm_lapic_state *s)
    {
    	vcpu_load(vcpu);
    
    	memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
    
    	kvm_apic_post_state_restore(vcpu);
    	vcpu_put(vcpu);
    
    	return 0;
    }
    
    
    static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
    				    struct kvm_interrupt *irq)
    {
    	if (irq->irq < 0 || irq->irq >= 256)
    		return -EINVAL;
    	if (irqchip_in_kernel(vcpu->kvm))
    		return -ENXIO;
    	vcpu_load(vcpu);
    
    
    	set_bit(irq->irq, vcpu->arch.irq_pending);
    	set_bit(irq->irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
    
    static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
    {
    	vcpu_load(vcpu);
    	kvm_inject_nmi(vcpu);
    	vcpu_put(vcpu);
    
    	return 0;
    }
    
    
    static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
    					   struct kvm_tpr_access_ctl *tac)
    {
    	if (tac->flags)
    		return -EINVAL;
    	vcpu->arch.tpr_access_reporting = !!tac->enabled;
    	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;
    
    	struct kvm_lapic_state *lapic = NULL;
    
    
    	switch (ioctl) {
    	case KVM_GET_LAPIC: {
    
    		lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
    
    		r = -ENOMEM;
    		if (!lapic)
    			goto out;
    		r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic);
    
    		if (r)
    			goto out;
    		r = -EFAULT;
    
    		if (copy_to_user(argp, lapic, sizeof(struct kvm_lapic_state)))
    
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_LAPIC: {
    
    		lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
    		r = -ENOMEM;
    		if (!lapic)
    			goto out;
    
    		r = -EFAULT;
    
    		if (copy_from_user(lapic, argp, sizeof(struct kvm_lapic_state)))
    
    		r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic);
    
    		if (r)
    			goto out;
    		r = 0;
    		break;
    	}
    
    	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);
    		if (r)
    			goto out;
    		r = 0;
    		break;
    	}
    
    	case KVM_NMI: {
    		r = kvm_vcpu_ioctl_nmi(vcpu);
    		if (r)
    			goto out;
    		r = 0;
    		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);
    		if (r)
    			goto out;
    		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);
    
    		if (r)
    			goto out;
    		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;
    	}
    
    	default:
    		r = -EINVAL;
    	}
    out:
    
    	if (lapic)
    		kfree(lapic);
    
    static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
    {
    	int ret;
    
    	if (addr > (unsigned int)(-3 * PAGE_SIZE))
    		return -1;
    	ret = kvm_x86_ops->set_tss_addr(kvm, addr);
    	return ret;
    }
    
    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;
    
    
    
    	kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
    
    	kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
    
    	return 0;
    }
    
    static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
    {
    
    	return kvm->arch.n_alloc_mmu_pages;
    
    gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
    {
    	int i;
    	struct kvm_mem_alias *alias;
    
    
    	for (i = 0; i < kvm->arch.naliases; ++i) {
    		alias = &kvm->arch.aliases[i];
    
    		if (gfn >= alias->base_gfn
    		    && gfn < alias->base_gfn + alias->npages)
    			return alias->target_gfn + gfn - alias->base_gfn;
    	}
    	return gfn;
    }
    
    
    /*
     * Set a new alias region.  Aliases map a portion of physical memory into
     * another portion.  This is useful for memory windows, for example the PC
     * VGA region.
     */
    static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
    					 struct kvm_memory_alias *alias)
    {
    	int r, n;
    	struct kvm_mem_alias *p;
    
    	r = -EINVAL;
    	/* General sanity checks */
    	if (alias->memory_size & (PAGE_SIZE - 1))
    		goto out;
    	if (alias->guest_phys_addr & (PAGE_SIZE - 1))
    		goto out;
    	if (alias->slot >= KVM_ALIAS_SLOTS)
    		goto out;
    	if (alias->guest_phys_addr + alias->memory_size
    	    < alias->guest_phys_addr)
    		goto out;
    	if (alias->target_phys_addr + alias->memory_size
    	    < alias->target_phys_addr)
    		goto out;
    
    
    	spin_lock(&kvm->mmu_lock);
    
    	p = &kvm->arch.aliases[alias->slot];
    
    	p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
    	p->npages = alias->memory_size >> PAGE_SHIFT;
    	p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
    
    	for (n = KVM_ALIAS_SLOTS; n > 0; --n)
    
    		if (kvm->arch.aliases[n - 1].npages)
    
    	spin_unlock(&kvm->mmu_lock);
    
    	kvm_mmu_zap_all(kvm);
    
    
    
    	return 0;
    
    out:
    	return r;
    }
    
    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:
    		memcpy(&chip->chip.ioapic,
    			ioapic_irqchip(kvm),
    			sizeof(struct kvm_ioapic_state));
    		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:
    		memcpy(&pic_irqchip(kvm)->pics[0],
    			&chip->chip.pic,
    			sizeof(struct kvm_pic_state));
    		break;
    	case KVM_IRQCHIP_PIC_SLAVE:
    		memcpy(&pic_irqchip(kvm)->pics[1],
    			&chip->chip.pic,
    			sizeof(struct kvm_pic_state));
    		break;
    	case KVM_IRQCHIP_IOAPIC:
    		memcpy(ioapic_irqchip(kvm),
    			&chip->chip.ioapic,
    			sizeof(struct kvm_ioapic_state));
    		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;
    
    	memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state));
    	return r;
    }
    
    static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
    {
    	int r = 0;
    
    	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
    	kvm_pit_load_count(kvm, 0, ps->channels[0].count);
    	return r;
    }
    
    
    static int kvm_vm_ioctl_reinject(struct kvm *kvm,
    				 struct kvm_reinject_control *control)
    {
    	if (!kvm->arch.vpit)
    		return -ENXIO;
    	kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject;
    	return 0;
    }
    
    
    /*
     * Get (and clear) the dirty memory log for a memory slot.
     */
    int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
    				      struct kvm_dirty_log *log)
    {
    	int r;
    	int n;
    	struct kvm_memory_slot *memslot;
    	int is_dirty = 0;
    
    
    
    	r = kvm_get_dirty_log(kvm, log, &is_dirty);
    	if (r)
    		goto out;
    
    	/* If nothing is dirty, don't bother messing with page tables. */
    	if (is_dirty) {
    		kvm_mmu_slot_remove_write_access(kvm, log->slot);
    		kvm_flush_remote_tlbs(kvm);
    		memslot = &kvm->memslots[log->slot];
    		n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
    		memset(memslot->dirty_bitmap, 0, n);
    	}
    	r = 0;
    out:
    
    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 = -EINVAL;
    
    	/*
    	 * 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_memory_alias alias;
    	} u;
    
    
    	switch (ioctl) {
    	case KVM_SET_TSS_ADDR:
    		r = kvm_vm_ioctl_set_tss_addr(kvm, arg);
    		if (r < 0)
    			goto out;
    		break;
    	case KVM_SET_MEMORY_REGION: {
    		struct kvm_memory_region kvm_mem;
    		struct kvm_userspace_memory_region kvm_userspace_mem;
    
    		r = -EFAULT;
    		if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
    			goto out;
    		kvm_userspace_mem.slot = kvm_mem.slot;
    		kvm_userspace_mem.flags = kvm_mem.flags;
    		kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
    		kvm_userspace_mem.memory_size = kvm_mem.memory_size;
    		r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
    		if (r)
    			goto out;
    		break;
    	}
    	case KVM_SET_NR_MMU_PAGES:
    		r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
    		if (r)
    			goto out;
    		break;
    	case KVM_GET_NR_MMU_PAGES:
    		r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
    		break;
    
    	case KVM_SET_MEMORY_ALIAS:
    
    		if (copy_from_user(&u.alias, argp, sizeof(struct kvm_memory_alias)))
    
    		r = kvm_vm_ioctl_set_memory_alias(kvm, &u.alias);
    
    		if (r)
    			goto out;
    		break;
    	case KVM_CREATE_IRQCHIP:
    		r = -ENOMEM;
    
    		kvm->arch.vpic = kvm_create_pic(kvm);
    		if (kvm->arch.vpic) {
    
    			r = kvm_ioapic_init(kvm);
    			if (r) {
    
    				kfree(kvm->arch.vpic);
    				kvm->arch.vpic = NULL;
    
    				goto out;
    			}
    		} else
    			goto out;
    
    		r = kvm_setup_default_irq_routing(kvm);
    		if (r) {
    			kfree(kvm->arch.vpic);
    			kfree(kvm->arch.vioapic);
    			goto out;
    		}
    
    Sheng Yang's avatar
    Sheng Yang committed
    	case KVM_CREATE_PIT:
    
    		mutex_lock(&kvm->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);
    		if (kvm->arch.vpit)
    			r = 0;
    
    	create_pit_unlock:
    		mutex_unlock(&kvm->lock);
    
    Sheng Yang's avatar
    Sheng Yang committed
    		break;
    
    	case KVM_IRQ_LINE: {
    		struct kvm_irq_level irq_event;
    
    		r = -EFAULT;
    		if (copy_from_user(&irq_event, argp, sizeof irq_event))
    			goto out;
    		if (irqchip_in_kernel(kvm)) {
    			mutex_lock(&kvm->lock);
    
    			kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
    				    irq_event.irq, irq_event.level);
    
    			mutex_unlock(&kvm->lock);
    			r = 0;
    		}
    		break;
    	}
    	case KVM_GET_IRQCHIP: {
    		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
    
    		struct kvm_irqchip *chip = kmalloc(sizeof(*chip), GFP_KERNEL);
    
    		r = -EFAULT;
    		if (copy_from_user(chip, argp, sizeof *chip))
    			goto get_irqchip_out;
    
    		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);
    		if (r)
    			goto out;
    
    		break;
    	}
    	case KVM_SET_IRQCHIP: {
    		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
    
    		struct kvm_irqchip *chip = kmalloc(sizeof(*chip), GFP_KERNEL);
    
    		r = -EFAULT;
    		if (copy_from_user(chip, argp, sizeof *chip))
    			goto set_irqchip_out;
    
    		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);
    		if (r)
    			goto out;
    
    	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_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);
    		if (r)
    			goto out;
    		r = 0;
    		break;
    	}
    
    static void kvm_init_msr_list(void)
    
    {
    	u32 dummy[2];
    	unsigned i, j;
    
    	for (i = j = 0; 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];