Skip to content
Snippets Groups Projects
x86.c 73 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		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);
    
    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;
    
    	switch (ioctl) {
    	case KVM_GET_LAPIC: {
    		struct kvm_lapic_state lapic;
    
    		memset(&lapic, 0, sizeof lapic);
    		r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
    		if (r)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(argp, &lapic, sizeof lapic))
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_LAPIC: {
    		struct kvm_lapic_state lapic;
    
    		r = -EFAULT;
    		if (copy_from_user(&lapic, argp, sizeof lapic))
    			goto out;
    		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_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;
    	default:
    		r = -EINVAL;
    	}
    out:
    	return r;
    }
    
    
    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;
    
    	mutex_lock(&kvm->lock);
    
    	kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
    
    	kvm->arch.n_requested_mmu_pages = kvm_nr_mmu_pages;
    
    
    	mutex_unlock(&kvm->lock);
    	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;
    
    	mutex_lock(&kvm->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)
    
    
    	kvm_mmu_zap_all(kvm);
    
    	mutex_unlock(&kvm->lock);
    
    	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;
    }
    
    
    /*
     * 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;
    
    	mutex_lock(&kvm->lock);
    
    	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:
    	mutex_unlock(&kvm->lock);
    	return r;
    }
    
    
    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;
    
    	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: {
    		struct kvm_memory_alias alias;
    
    		r = -EFAULT;
    		if (copy_from_user(&alias, argp, sizeof alias))
    			goto out;
    		r = kvm_vm_ioctl_set_memory_alias(kvm, &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;
    		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);
    			if (irq_event.irq < 16)
    				kvm_pic_set_irq(pic_irqchip(kvm),
    					irq_event.irq,
    					irq_event.level);
    
    			kvm_ioapic_set_irq(kvm->arch.vioapic,
    
    					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;
    
    		r = -EFAULT;
    		if (copy_from_user(&chip, argp, sizeof chip))
    			goto out;
    		r = -ENXIO;
    		if (!irqchip_in_kernel(kvm))
    			goto out;
    		r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
    		if (r)
    			goto out;
    		r = -EFAULT;
    		if (copy_to_user(argp, &chip, sizeof chip))
    			goto out;
    		r = 0;
    		break;
    	}
    	case KVM_SET_IRQCHIP: {
    		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
    		struct kvm_irqchip chip;
    
    		r = -EFAULT;
    		if (copy_from_user(&chip, argp, sizeof chip))
    			goto out;
    		r = -ENXIO;
    		if (!irqchip_in_kernel(kvm))
    			goto out;
    		r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
    		if (r)
    			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_vm_ioctl_get_supported_cpuid(kvm, &cpuid,
    			cpuid_arg->entries);
    		if (r)
    			goto out;
    
    		r = -EFAULT;
    		if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid))
    			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];
    		j++;
    	}
    	num_msrs_to_save = j;
    }
    
    
    /*
     * Only apic need an MMIO device hook, so shortcut now..
     */
    static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
    						gpa_t addr)
    {
    	struct kvm_io_device *dev;
    
    
    	if (vcpu->arch.apic) {
    		dev = &vcpu->arch.apic->dev;
    
    		if (dev->in_range(dev, addr))
    			return dev;
    	}
    	return NULL;
    }
    
    
    static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
    						gpa_t addr)
    {
    	struct kvm_io_device *dev;
    
    	dev = vcpu_find_pervcpu_dev(vcpu, addr);
    	if (dev == NULL)
    		dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
    	return dev;
    }
    
    int emulator_read_std(unsigned long addr,
    			     void *val,
    			     unsigned int bytes,
    			     struct kvm_vcpu *vcpu)
    {
    	void *data = val;
    
    	while (bytes) {
    
    		gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
    
    		unsigned offset = addr & (PAGE_SIZE-1);
    		unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
    		int ret;
    
    		if (gpa == UNMAPPED_GVA)
    			return X86EMUL_PROPAGATE_FAULT;
    		ret = kvm_read_guest(vcpu->kvm, gpa, data, tocopy);
    		if (ret < 0)
    			return X86EMUL_UNHANDLEABLE;
    
    		bytes -= tocopy;
    		data += tocopy;
    		addr += tocopy;
    	}
    
    	return X86EMUL_CONTINUE;
    }
    EXPORT_SYMBOL_GPL(emulator_read_std);
    
    static int emulator_read_emulated(unsigned long addr,
    				  void *val,
    				  unsigned int bytes,
    				  struct kvm_vcpu *vcpu)
    {
    	struct kvm_io_device *mmio_dev;
    	gpa_t                 gpa;
    
    	if (vcpu->mmio_read_completed) {
    		memcpy(val, vcpu->mmio_data, bytes);
    		vcpu->mmio_read_completed = 0;
    		return X86EMUL_CONTINUE;
    	}
    
    
    	gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
    
    
    	/* For APIC access vmexit */
    	if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
    		goto mmio;
    
    	if (emulator_read_std(addr, val, bytes, vcpu)
    			== X86EMUL_CONTINUE)
    		return X86EMUL_CONTINUE;
    	if (gpa == UNMAPPED_GVA)
    		return X86EMUL_PROPAGATE_FAULT;
    
    mmio:
    	/*
    	 * Is this MMIO handled locally?
    	 */
    	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
    	if (mmio_dev) {
    		kvm_iodevice_read(mmio_dev, gpa, bytes, val);
    		return X86EMUL_CONTINUE;
    	}
    
    	vcpu->mmio_needed = 1;
    	vcpu->mmio_phys_addr = gpa;
    	vcpu->mmio_size = bytes;
    	vcpu->mmio_is_write = 0;
    
    	return X86EMUL_UNHANDLEABLE;
    }
    
    static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
    			       const void *val, int bytes)
    {
    	int ret;
    
    	ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes);
    	if (ret < 0)
    		return 0;
    	kvm_mmu_pte_write(vcpu, gpa, val, bytes);
    	return 1;
    }
    
    static int emulator_write_emulated_onepage(unsigned long addr,
    					   const void *val,
    					   unsigned int bytes,
    					   struct kvm_vcpu *vcpu)
    {
    	struct kvm_io_device *mmio_dev;
    
    	gpa_t                 gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
    
    		kvm_inject_page_fault(vcpu, addr, 2);
    
    		return X86EMUL_PROPAGATE_FAULT;
    	}
    
    	/* For APIC access vmexit */
    	if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
    		goto mmio;
    
    	if (emulator_write_phys(vcpu, gpa, val, bytes))
    		return X86EMUL_CONTINUE;
    
    mmio:
    	/*
    	 * Is this MMIO handled locally?
    	 */
    	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
    	if (mmio_dev) {
    		kvm_iodevice_write(mmio_dev, gpa, bytes, val);
    		return X86EMUL_CONTINUE;
    	}
    
    	vcpu->mmio_needed = 1;
    	vcpu->mmio_phys_addr = gpa;
    	vcpu->mmio_size = bytes;
    	vcpu->mmio_is_write = 1;
    	memcpy(vcpu->mmio_data, val, bytes);
    
    	return X86EMUL_CONTINUE;
    }
    
    int emulator_write_emulated(unsigned long addr,
    				   const void *val,
    				   unsigned int bytes,
    				   struct kvm_vcpu *vcpu)
    {
    	/* Crossing a page boundary? */
    	if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
    		int rc, now;
    
    		now = -addr & ~PAGE_MASK;
    		rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
    		if (rc != X86EMUL_CONTINUE)
    			return rc;
    		addr += now;
    		val += now;
    		bytes -= now;
    	}
    	return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
    }
    EXPORT_SYMBOL_GPL(emulator_write_emulated);
    
    static int emulator_cmpxchg_emulated(unsigned long addr,
    				     const void *old,
    				     const void *new,
    				     unsigned int bytes,
    				     struct kvm_vcpu *vcpu)
    {
    	static int reported;
    
    	if (!reported) {
    		reported = 1;
    		printk(KERN_WARNING "kvm: emulating exchange as write\n");
    	}
    
    #ifndef CONFIG_X86_64
    	/* guests cmpxchg8b have to be emulated atomically */
    	if (bytes == 8) {
    
    		gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
    
    		struct page *page;
    		char *addr;
    		u64 val;
    
    		if (gpa == UNMAPPED_GVA ||
    		   (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
    			goto emul_write;
    
    		if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
    			goto emul_write;
    
    		val = *(u64 *)new;
    		page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
    		addr = kmap_atomic(page, KM_USER0);
    		set_64bit((u64 *)(addr + offset_in_page(gpa)), val);
    		kunmap_atomic(addr, KM_USER0);
    		kvm_release_page_dirty(page);
    	}
    emul_write:
    #endif
    
    
    	return emulator_write_emulated(addr, new, bytes, vcpu);
    }
    
    static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
    {
    	return kvm_x86_ops->get_segment_base(vcpu, seg);
    }
    
    int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
    {
    	return X86EMUL_CONTINUE;
    }
    
    int emulate_clts(struct kvm_vcpu *vcpu)
    {
    
    	kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 & ~X86_CR0_TS);
    
    	return X86EMUL_CONTINUE;
    }
    
    int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
    {
    	struct kvm_vcpu *vcpu = ctxt->vcpu;
    
    	switch (dr) {
    	case 0 ... 3:
    		*dest = kvm_x86_ops->get_dr(vcpu, dr);
    		return X86EMUL_CONTINUE;
    	default:
    		pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
    		return X86EMUL_UNHANDLEABLE;
    	}
    }
    
    int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
    {
    	unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
    	int exception;
    
    	kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
    	if (exception) {
    		/* FIXME: better handling */
    		return X86EMUL_UNHANDLEABLE;
    	}
    	return X86EMUL_CONTINUE;
    }
    
    void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
    {
    	static int reported;
    	u8 opcodes[4];
    
    	unsigned long rip = vcpu->arch.rip;
    
    	unsigned long rip_linear;
    
    	rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
    
    	if (reported)
    		return;
    
    	emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
    
    	printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
    	       context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
    	reported = 1;
    }
    EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
    
    struct x86_emulate_ops emulate_ops = {
    	.read_std            = emulator_read_std,
    	.read_emulated       = emulator_read_emulated,
    	.write_emulated      = emulator_write_emulated,
    	.cmpxchg_emulated    = emulator_cmpxchg_emulated,
    };
    
    int emulate_instruction(struct kvm_vcpu *vcpu,
    			struct kvm_run *run,
    			unsigned long cr2,
    			u16 error_code,
    			int no_decode)
    {
    	int r;
    
    
    	vcpu->arch.mmio_fault_cr2 = cr2;
    
    	kvm_x86_ops->cache_regs(vcpu);
    
    	vcpu->mmio_is_write = 0;
    
    	vcpu->arch.pio.string = 0;
    
    
    	if (!no_decode) {
    		int cs_db, cs_l;
    		kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
    
    
    		vcpu->arch.emulate_ctxt.vcpu = vcpu;
    		vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
    		vcpu->arch.emulate_ctxt.mode =
    			(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
    
    			? X86EMUL_MODE_REAL : cs_l
    			? X86EMUL_MODE_PROT64 :	cs_db
    			? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
    
    
    		if (vcpu->arch.emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
    			vcpu->arch.emulate_ctxt.cs_base = 0;
    			vcpu->arch.emulate_ctxt.ds_base = 0;
    			vcpu->arch.emulate_ctxt.es_base = 0;
    			vcpu->arch.emulate_ctxt.ss_base = 0;
    
    			vcpu->arch.emulate_ctxt.cs_base =
    
    					get_segment_base(vcpu, VCPU_SREG_CS);
    
    			vcpu->arch.emulate_ctxt.ds_base =
    
    					get_segment_base(vcpu, VCPU_SREG_DS);
    
    			vcpu->arch.emulate_ctxt.es_base =
    
    					get_segment_base(vcpu, VCPU_SREG_ES);
    
    			vcpu->arch.emulate_ctxt.ss_base =
    
    		vcpu->arch.emulate_ctxt.gs_base =
    
    					get_segment_base(vcpu, VCPU_SREG_GS);
    
    		vcpu->arch.emulate_ctxt.fs_base =
    
    					get_segment_base(vcpu, VCPU_SREG_FS);
    
    
    		r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
    
    		++vcpu->stat.insn_emulation;
    
    			++vcpu->stat.insn_emulation_fail;
    
    			if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
    				return EMULATE_DONE;
    			return EMULATE_FAIL;
    		}
    	}
    
    
    	r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
    
    	if (vcpu->arch.pio.string)
    
    		return EMULATE_DO_MMIO;
    
    	if ((r || vcpu->mmio_is_write) && run) {
    		run->exit_reason = KVM_EXIT_MMIO;
    		run->mmio.phys_addr = vcpu->mmio_phys_addr;
    		memcpy(run->mmio.data, vcpu->mmio_data, 8);
    		run->mmio.len = vcpu->mmio_size;
    		run->mmio.is_write = vcpu->mmio_is_write;
    	}
    
    	if (r) {
    		if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
    			return EMULATE_DONE;
    		if (!vcpu->mmio_needed) {
    			kvm_report_emulation_failure(vcpu, "mmio");
    			return EMULATE_FAIL;
    		}
    		return EMULATE_DO_MMIO;
    	}
    
    	kvm_x86_ops->decache_regs(vcpu);
    
    	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
    
    
    	if (vcpu->mmio_is_write) {
    		vcpu->mmio_needed = 0;
    		return EMULATE_DO_MMIO;
    	}
    
    	return EMULATE_DONE;
    }
    EXPORT_SYMBOL_GPL(emulate_instruction);
    
    
    static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
    {
    	int i;
    
    
    	for (i = 0; i < ARRAY_SIZE(vcpu->arch.pio.guest_pages); ++i)
    		if (vcpu->arch.pio.guest_pages[i]) {
    			kvm_release_page_dirty(vcpu->arch.pio.guest_pages[i]);
    			vcpu->arch.pio.guest_pages[i] = NULL;
    
    		}
    }
    
    static int pio_copy_data(struct kvm_vcpu *vcpu)
    {
    
    	void *p = vcpu->arch.pio_data;
    
    	int nr_pages = vcpu->arch.pio.guest_pages[1] ? 2 : 1;
    
    	q = vmap(vcpu->arch.pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
    
    		 PAGE_KERNEL);
    	if (!q) {
    		free_pio_guest_pages(vcpu);
    		return -ENOMEM;
    	}
    
    	q += vcpu->arch.pio.guest_page_offset;
    	bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count;
    	if (vcpu->arch.pio.in)
    
    		memcpy(q, p, bytes);
    	else
    		memcpy(p, q, bytes);
    
    	q -= vcpu->arch.pio.guest_page_offset;
    
    	vunmap(q);
    	free_pio_guest_pages(vcpu);
    	return 0;
    }
    
    int complete_pio(struct kvm_vcpu *vcpu)
    {
    
    	struct kvm_pio_request *io = &vcpu->arch.pio;
    
    	long delta;
    	int r;
    
    	kvm_x86_ops->cache_regs(vcpu);
    
    	if (!io->string) {
    		if (io->in)
    
    			memcpy(&vcpu->arch.regs[VCPU_REGS_RAX], vcpu->arch.pio_data,
    
    			       io->size);
    	} else {
    		if (io->in) {
    			r = pio_copy_data(vcpu);
    			if (r) {
    				kvm_x86_ops->cache_regs(vcpu);
    				return r;
    			}
    		}
    
    		delta = 1;
    		if (io->rep) {
    			delta *= io->cur_count;
    			/*
    			 * The size of the register should really depend on
    			 * current address size.
    			 */
    
    			vcpu->arch.regs[VCPU_REGS_RCX] -= delta;
    
    		}
    		if (io->down)
    			delta = -delta;
    		delta *= io->size;
    		if (io->in)
    
    			vcpu->arch.regs[VCPU_REGS_RDI] += delta;
    
    			vcpu->arch.regs[VCPU_REGS_RSI] += delta;
    
    	}
    
    	kvm_x86_ops->decache_regs(vcpu);
    
    	io->count -= io->cur_count;
    	io->cur_count = 0;
    
    	return 0;
    }
    
    static void kernel_pio(struct kvm_io_device *pio_dev,
    		       struct kvm_vcpu *vcpu,
    		       void *pd)
    {
    	/* TODO: String I/O for in kernel device */
    
    	mutex_lock(&vcpu->kvm->lock);
    
    	if (vcpu->arch.pio.in)
    		kvm_iodevice_read(pio_dev, vcpu->arch.pio.port,
    				  vcpu->arch.pio.size,
    
    		kvm_iodevice_write(pio_dev, vcpu->arch.pio.port,
    				   vcpu->arch.pio.size,
    
    				   pd);
    	mutex_unlock(&vcpu->kvm->lock);
    }
    
    static void pio_string_write(struct kvm_io_device *pio_dev,
    			     struct kvm_vcpu *vcpu)
    {
    
    	struct kvm_pio_request *io = &vcpu->arch.pio;
    	void *pd = vcpu->arch.pio_data;
    
    	int i;
    
    	mutex_lock(&vcpu->kvm->lock);
    	for (i = 0; i < io->cur_count; i++) {
    		kvm_iodevice_write(pio_dev, io->port,
    				   io->size,
    				   pd);
    		pd += io->size;
    	}
    	mutex_unlock(&vcpu->kvm->lock);
    }
    
    static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
    					       gpa_t addr)
    {
    	return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
    }
    
    int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
    		  int size, unsigned port)
    {
    	struct kvm_io_device *pio_dev;
    
    	vcpu->run->exit_reason = KVM_EXIT_IO;
    	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
    
    	vcpu->run->io.size = vcpu->arch.pio.size = size;