Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bda9020e authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by Avi Kivity
Browse files

KVM: remove in_range from io devices



This changes bus accesses to use high-level kvm_io_bus_read/kvm_io_bus_write
functions. in_range now becomes unused so it is removed from device ops in
favor of read/write callbacks performing range checks internally.

This allows aliasing (mostly for in-kernel virtio), as well as better error
handling by making it possible to pass errors up to userspace.

Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 6c474694
Loading
Loading
Loading
Loading
+8 −20
Original line number Original line Diff line number Diff line
@@ -210,16 +210,6 @@ int kvm_dev_ioctl_check_extension(long ext)


}
}


static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
					gpa_t addr, int len, int is_write)
{
	struct kvm_io_device *dev;

	dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write);

	return dev;
}

static int handle_vm_error(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
static int handle_vm_error(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
{
	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
@@ -231,6 +221,7 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
{
	struct kvm_mmio_req *p;
	struct kvm_mmio_req *p;
	struct kvm_io_device *mmio_dev;
	struct kvm_io_device *mmio_dev;
	int r;


	p = kvm_get_vcpu_ioreq(vcpu);
	p = kvm_get_vcpu_ioreq(vcpu);


@@ -247,16 +238,13 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
	kvm_run->exit_reason = KVM_EXIT_MMIO;
	kvm_run->exit_reason = KVM_EXIT_MMIO;
	return 0;
	return 0;
mmio:
mmio:
	mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir);
	if (p->dir)
	if (mmio_dev) {
		r = kvm_io_bus_read(&vcpu->kvm->mmio_bus, p->addr,
		if (!p->dir)
				    p->size, &p->data);
			kvm_iodevice_write(mmio_dev, p->addr, p->size,
						&p->data);
	else
	else
			kvm_iodevice_read(mmio_dev, p->addr, p->size,
		r = kvm_io_bus_write(&vcpu->kvm->mmio_bus, p->addr,
						&p->data);
				     p->size, &p->data);

	if (r)
	} else
		printk(KERN_ERR"kvm: No iodevice found! addr:%lx\n", p->addr);
		printk(KERN_ERR"kvm: No iodevice found! addr:%lx\n", p->addr);
	p->state = STATE_IORESP_READY;
	p->state = STATE_IORESP_READY;


+26 −23
Original line number Original line Diff line number Diff line
@@ -358,7 +358,13 @@ static inline struct kvm_pit *speaker_to_pit(struct kvm_io_device *dev)
	return container_of(dev, struct kvm_pit, speaker_dev);
	return container_of(dev, struct kvm_pit, speaker_dev);
}
}


static void pit_ioport_write(struct kvm_io_device *this,
static inline int pit_in_range(gpa_t addr)
{
	return ((addr >= KVM_PIT_BASE_ADDRESS) &&
		(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
}

static int pit_ioport_write(struct kvm_io_device *this,
			    gpa_t addr, int len, const void *data)
			    gpa_t addr, int len, const void *data)
{
{
	struct kvm_pit *pit = dev_to_pit(this);
	struct kvm_pit *pit = dev_to_pit(this);
@@ -367,6 +373,8 @@ static void pit_ioport_write(struct kvm_io_device *this,
	int channel, access;
	int channel, access;
	struct kvm_kpit_channel_state *s;
	struct kvm_kpit_channel_state *s;
	u32 val = *(u32 *) data;
	u32 val = *(u32 *) data;
	if (!pit_in_range(addr))
		return -EOPNOTSUPP;


	val  &= 0xff;
	val  &= 0xff;
	addr &= KVM_PIT_CHANNEL_MASK;
	addr &= KVM_PIT_CHANNEL_MASK;
@@ -429,9 +437,10 @@ static void pit_ioport_write(struct kvm_io_device *this,
	}
	}


	mutex_unlock(&pit_state->lock);
	mutex_unlock(&pit_state->lock);
	return 0;
}
}


static void pit_ioport_read(struct kvm_io_device *this,
static int pit_ioport_read(struct kvm_io_device *this,
			   gpa_t addr, int len, void *data)
			   gpa_t addr, int len, void *data)
{
{
	struct kvm_pit *pit = dev_to_pit(this);
	struct kvm_pit *pit = dev_to_pit(this);
@@ -439,6 +448,8 @@ static void pit_ioport_read(struct kvm_io_device *this,
	struct kvm *kvm = pit->kvm;
	struct kvm *kvm = pit->kvm;
	int ret, count;
	int ret, count;
	struct kvm_kpit_channel_state *s;
	struct kvm_kpit_channel_state *s;
	if (!pit_in_range(addr))
		return -EOPNOTSUPP;


	addr &= KVM_PIT_CHANNEL_MASK;
	addr &= KVM_PIT_CHANNEL_MASK;
	s = &pit_state->channels[addr];
	s = &pit_state->channels[addr];
@@ -493,30 +504,27 @@ static void pit_ioport_read(struct kvm_io_device *this,
	memcpy(data, (char *)&ret, len);
	memcpy(data, (char *)&ret, len);


	mutex_unlock(&pit_state->lock);
	mutex_unlock(&pit_state->lock);
	return 0;
}
}


static int pit_in_range(struct kvm_io_device *this, gpa_t addr,
static int speaker_ioport_write(struct kvm_io_device *this,
			int len, int is_write)
{
	return ((addr >= KVM_PIT_BASE_ADDRESS) &&
		(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
}

static void speaker_ioport_write(struct kvm_io_device *this,
				gpa_t addr, int len, const void *data)
				gpa_t addr, int len, const void *data)
{
{
	struct kvm_pit *pit = speaker_to_pit(this);
	struct kvm_pit *pit = speaker_to_pit(this);
	struct kvm_kpit_state *pit_state = &pit->pit_state;
	struct kvm_kpit_state *pit_state = &pit->pit_state;
	struct kvm *kvm = pit->kvm;
	struct kvm *kvm = pit->kvm;
	u32 val = *(u32 *) data;
	u32 val = *(u32 *) data;
	if (addr != KVM_SPEAKER_BASE_ADDRESS)
		return -EOPNOTSUPP;


	mutex_lock(&pit_state->lock);
	mutex_lock(&pit_state->lock);
	pit_state->speaker_data_on = (val >> 1) & 1;
	pit_state->speaker_data_on = (val >> 1) & 1;
	pit_set_gate(kvm, 2, val & 1);
	pit_set_gate(kvm, 2, val & 1);
	mutex_unlock(&pit_state->lock);
	mutex_unlock(&pit_state->lock);
	return 0;
}
}


static void speaker_ioport_read(struct kvm_io_device *this,
static int speaker_ioport_read(struct kvm_io_device *this,
			       gpa_t addr, int len, void *data)
			       gpa_t addr, int len, void *data)
{
{
	struct kvm_pit *pit = speaker_to_pit(this);
	struct kvm_pit *pit = speaker_to_pit(this);
@@ -524,6 +532,8 @@ static void speaker_ioport_read(struct kvm_io_device *this,
	struct kvm *kvm = pit->kvm;
	struct kvm *kvm = pit->kvm;
	unsigned int refresh_clock;
	unsigned int refresh_clock;
	int ret;
	int ret;
	if (addr != KVM_SPEAKER_BASE_ADDRESS)
		return -EOPNOTSUPP;


	/* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
	/* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
	refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1;
	refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1;
@@ -535,12 +545,7 @@ static void speaker_ioport_read(struct kvm_io_device *this,
		len = sizeof(ret);
		len = sizeof(ret);
	memcpy(data, (char *)&ret, len);
	memcpy(data, (char *)&ret, len);
	mutex_unlock(&pit_state->lock);
	mutex_unlock(&pit_state->lock);
}
	return 0;

static int speaker_in_range(struct kvm_io_device *this, gpa_t addr,
			    int len, int is_write)
{
	return (addr == KVM_SPEAKER_BASE_ADDRESS);
}
}


void kvm_pit_reset(struct kvm_pit *pit)
void kvm_pit_reset(struct kvm_pit *pit)
@@ -574,13 +579,11 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
static const struct kvm_io_device_ops pit_dev_ops = {
static const struct kvm_io_device_ops pit_dev_ops = {
	.read     = pit_ioport_read,
	.read     = pit_ioport_read,
	.write    = pit_ioport_write,
	.write    = pit_ioport_write,
	.in_range = pit_in_range,
};
};


static const struct kvm_io_device_ops speaker_dev_ops = {
static const struct kvm_io_device_ops speaker_dev_ops = {
	.read     = speaker_ioport_read,
	.read     = speaker_ioport_read,
	.write    = speaker_ioport_write,
	.write    = speaker_ioport_write,
	.in_range = speaker_in_range,
};
};


/* Caller must have writers lock on slots_lock */
/* Caller must have writers lock on slots_lock */
+12 −8
Original line number Original line Diff line number Diff line
@@ -430,8 +430,7 @@ static u32 elcr_ioport_read(void *opaque, u32 addr1)
	return s->elcr;
	return s->elcr;
}
}


static int picdev_in_range(struct kvm_io_device *this, gpa_t addr,
static int picdev_in_range(gpa_t addr)
			   int len, int is_write)
{
{
	switch (addr) {
	switch (addr) {
	case 0x20:
	case 0x20:
@@ -451,16 +450,18 @@ static inline struct kvm_pic *to_pic(struct kvm_io_device *dev)
	return container_of(dev, struct kvm_pic, dev);
	return container_of(dev, struct kvm_pic, dev);
}
}


static void picdev_write(struct kvm_io_device *this,
static int picdev_write(struct kvm_io_device *this,
			 gpa_t addr, int len, const void *val)
			 gpa_t addr, int len, const void *val)
{
{
	struct kvm_pic *s = to_pic(this);
	struct kvm_pic *s = to_pic(this);
	unsigned char data = *(unsigned char *)val;
	unsigned char data = *(unsigned char *)val;
	if (!picdev_in_range(addr))
		return -EOPNOTSUPP;


	if (len != 1) {
	if (len != 1) {
		if (printk_ratelimit())
		if (printk_ratelimit())
			printk(KERN_ERR "PIC: non byte write\n");
			printk(KERN_ERR "PIC: non byte write\n");
		return;
		return 0;
	}
	}
	pic_lock(s);
	pic_lock(s);
	switch (addr) {
	switch (addr) {
@@ -476,18 +477,21 @@ static void picdev_write(struct kvm_io_device *this,
		break;
		break;
	}
	}
	pic_unlock(s);
	pic_unlock(s);
	return 0;
}
}


static void picdev_read(struct kvm_io_device *this,
static int picdev_read(struct kvm_io_device *this,
		       gpa_t addr, int len, void *val)
		       gpa_t addr, int len, void *val)
{
{
	struct kvm_pic *s = to_pic(this);
	struct kvm_pic *s = to_pic(this);
	unsigned char data = 0;
	unsigned char data = 0;
	if (!picdev_in_range(addr))
		return -EOPNOTSUPP;


	if (len != 1) {
	if (len != 1) {
		if (printk_ratelimit())
		if (printk_ratelimit())
			printk(KERN_ERR "PIC: non byte read\n");
			printk(KERN_ERR "PIC: non byte read\n");
		return;
		return 0;
	}
	}
	pic_lock(s);
	pic_lock(s);
	switch (addr) {
	switch (addr) {
@@ -504,6 +508,7 @@ static void picdev_read(struct kvm_io_device *this,
	}
	}
	*(unsigned char *)val = data;
	*(unsigned char *)val = data;
	pic_unlock(s);
	pic_unlock(s);
	return 0;
}
}


/*
/*
@@ -526,7 +531,6 @@ static void pic_irq_request(void *opaque, int level)
static const struct kvm_io_device_ops picdev_ops = {
static const struct kvm_io_device_ops picdev_ops = {
	.read     = picdev_read,
	.read     = picdev_read,
	.write    = picdev_write,
	.write    = picdev_write,
	.in_range = picdev_in_range,
};
};


struct kvm_pic *kvm_create_pic(struct kvm *kvm)
struct kvm_pic *kvm_create_pic(struct kvm *kvm)
+20 −24
Original line number Original line Diff line number Diff line
@@ -546,18 +546,27 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
	return container_of(dev, struct kvm_lapic, dev);
	return container_of(dev, struct kvm_lapic, dev);
}
}


static void apic_mmio_read(struct kvm_io_device *this,
static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
{
	return apic_hw_enabled(apic) &&
	    addr >= apic->base_address &&
	    addr < apic->base_address + LAPIC_MMIO_LENGTH;
}

static int apic_mmio_read(struct kvm_io_device *this,
			  gpa_t address, int len, void *data)
			  gpa_t address, int len, void *data)
{
{
	struct kvm_lapic *apic = to_lapic(this);
	struct kvm_lapic *apic = to_lapic(this);
	unsigned int offset = address - apic->base_address;
	unsigned int offset = address - apic->base_address;
	unsigned char alignment = offset & 0xf;
	unsigned char alignment = offset & 0xf;
	u32 result;
	u32 result;
	if (!apic_mmio_in_range(apic, address))
		return -EOPNOTSUPP;


	if ((alignment + len) > 4) {
	if ((alignment + len) > 4) {
		printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
		printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
		       (unsigned long)address, len);
		       (unsigned long)address, len);
		return;
		return 0;
	}
	}
	result = __apic_read(apic, offset & ~0xf);
	result = __apic_read(apic, offset & ~0xf);


@@ -574,6 +583,7 @@ static void apic_mmio_read(struct kvm_io_device *this,
		       "should be 1,2, or 4 instead\n", len);
		       "should be 1,2, or 4 instead\n", len);
		break;
		break;
	}
	}
	return 0;
}
}


static void update_divide_count(struct kvm_lapic *apic)
static void update_divide_count(struct kvm_lapic *apic)
@@ -629,13 +639,15 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
		apic->vcpu->kvm->arch.vapics_in_nmi_mode--;
		apic->vcpu->kvm->arch.vapics_in_nmi_mode--;
}
}


static void apic_mmio_write(struct kvm_io_device *this,
static int apic_mmio_write(struct kvm_io_device *this,
			   gpa_t address, int len, const void *data)
			   gpa_t address, int len, const void *data)
{
{
	struct kvm_lapic *apic = to_lapic(this);
	struct kvm_lapic *apic = to_lapic(this);
	unsigned int offset = address - apic->base_address;
	unsigned int offset = address - apic->base_address;
	unsigned char alignment = offset & 0xf;
	unsigned char alignment = offset & 0xf;
	u32 val;
	u32 val;
	if (!apic_mmio_in_range(apic, address))
		return -EOPNOTSUPP;


	/*
	/*
	 * APIC register must be aligned on 128-bits boundary.
	 * APIC register must be aligned on 128-bits boundary.
@@ -646,7 +658,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
		/* Don't shout loud, $infamous_os would cause only noise. */
		/* Don't shout loud, $infamous_os would cause only noise. */
		apic_debug("apic write: bad size=%d %lx\n",
		apic_debug("apic write: bad size=%d %lx\n",
			   len, (long)address);
			   len, (long)address);
		return;
		return 0;
	}
	}


	val = *(u32 *) data;
	val = *(u32 *) data;
@@ -729,7 +741,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
		hrtimer_cancel(&apic->lapic_timer.timer);
		hrtimer_cancel(&apic->lapic_timer.timer);
		apic_set_reg(apic, APIC_TMICT, val);
		apic_set_reg(apic, APIC_TMICT, val);
		start_apic_timer(apic);
		start_apic_timer(apic);
		return;
		return 0;


	case APIC_TDCR:
	case APIC_TDCR:
		if (val & 4)
		if (val & 4)
@@ -743,22 +755,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
			   offset);
			   offset);
		break;
		break;
	}
	}

	return 0;
}

static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr,
			   int len, int size)
{
	struct kvm_lapic *apic = to_lapic(this);
	int ret = 0;


	if (apic_hw_enabled(apic) &&
	    (addr >= apic->base_address) &&
	    (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
		ret = 1;

	return ret;
}
}


void kvm_free_lapic(struct kvm_vcpu *vcpu)
void kvm_free_lapic(struct kvm_vcpu *vcpu)
@@ -938,7 +935,6 @@ static struct kvm_timer_ops lapic_timer_ops = {
static const struct kvm_io_device_ops apic_mmio_ops = {
static const struct kvm_io_device_ops apic_mmio_ops = {
	.read     = apic_mmio_read,
	.read     = apic_mmio_read,
	.write    = apic_mmio_write,
	.write    = apic_mmio_write,
	.in_range = apic_mmio_range,
};
};


int kvm_create_lapic(struct kvm_vcpu *vcpu)
int kvm_create_lapic(struct kvm_vcpu *vcpu)
+32 −78
Original line number Original line Diff line number Diff line
@@ -2333,35 +2333,23 @@ static void kvm_init_msr_list(void)
	num_msrs_to_save = j;
	num_msrs_to_save = j;
}
}


/*
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
 * Only apic need an MMIO device hook, so shortcut now..
			   const void *v)
 */
static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
						gpa_t addr, int len,
						int is_write)
{
{
	struct kvm_io_device *dev;
	if (vcpu->arch.apic &&
	    !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
		return 0;


	if (vcpu->arch.apic) {
	return kvm_io_bus_write(&vcpu->kvm->mmio_bus, addr, len, v);
		dev = &vcpu->arch.apic->dev;
		if (kvm_iodevice_in_range(dev, addr, len, is_write))
			return dev;
}
}
	return NULL;
}



static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
						gpa_t addr, int len,
						int is_write)
{
{
	struct kvm_io_device *dev;
	if (vcpu->arch.apic &&
	    !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
		return 0;


	dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write);
	return kvm_io_bus_read(&vcpu->kvm->mmio_bus, addr, len, v);
	if (dev == NULL)
		dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len,
					  is_write);
	return dev;
}
}


static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
@@ -2430,7 +2418,6 @@ static int emulator_read_emulated(unsigned long addr,
				  unsigned int bytes,
				  unsigned int bytes,
				  struct kvm_vcpu *vcpu)
				  struct kvm_vcpu *vcpu)
{
{
	struct kvm_io_device *mmio_dev;
	gpa_t                 gpa;
	gpa_t                 gpa;


	if (vcpu->mmio_read_completed) {
	if (vcpu->mmio_read_completed) {
@@ -2455,13 +2442,8 @@ static int emulator_read_emulated(unsigned long addr,
	/*
	/*
	 * Is this MMIO handled locally?
	 * Is this MMIO handled locally?
	 */
	 */
	mutex_lock(&vcpu->kvm->lock);
	if (!vcpu_mmio_read(vcpu, gpa, bytes, val))
	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0);
	mutex_unlock(&vcpu->kvm->lock);
	if (mmio_dev) {
		kvm_iodevice_read(mmio_dev, gpa, bytes, val);
		return X86EMUL_CONTINUE;
		return X86EMUL_CONTINUE;
	}


	vcpu->mmio_needed = 1;
	vcpu->mmio_needed = 1;
	vcpu->mmio_phys_addr = gpa;
	vcpu->mmio_phys_addr = gpa;
@@ -2488,7 +2470,6 @@ static int emulator_write_emulated_onepage(unsigned long addr,
					   unsigned int bytes,
					   unsigned int bytes,
					   struct kvm_vcpu *vcpu)
					   struct kvm_vcpu *vcpu)
{
{
	struct kvm_io_device *mmio_dev;
	gpa_t                 gpa;
	gpa_t                 gpa;


	gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
	gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr);
@@ -2509,13 +2490,8 @@ static int emulator_write_emulated_onepage(unsigned long addr,
	/*
	/*
	 * Is this MMIO handled locally?
	 * Is this MMIO handled locally?
	 */
	 */
	mutex_lock(&vcpu->kvm->lock);
	if (!vcpu_mmio_write(vcpu, gpa, bytes, val))
	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1);
	mutex_unlock(&vcpu->kvm->lock);
	if (mmio_dev) {
		kvm_iodevice_write(mmio_dev, gpa, bytes, val);
		return X86EMUL_CONTINUE;
		return X86EMUL_CONTINUE;
	}


	vcpu->mmio_needed = 1;
	vcpu->mmio_needed = 1;
	vcpu->mmio_phys_addr = gpa;
	vcpu->mmio_phys_addr = gpa;
@@ -2850,48 +2826,40 @@ int complete_pio(struct kvm_vcpu *vcpu)
	return 0;
	return 0;
}
}


static void kernel_pio(struct kvm_io_device *pio_dev,
static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
		       struct kvm_vcpu *vcpu,
		       void *pd)
{
{
	/* TODO: String I/O for in kernel device */
	/* TODO: String I/O for in kernel device */
	int r;


	if (vcpu->arch.pio.in)
	if (vcpu->arch.pio.in)
		kvm_iodevice_read(pio_dev, vcpu->arch.pio.port,
		r = kvm_io_bus_read(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
				  vcpu->arch.pio.size,
				    vcpu->arch.pio.size, pd);
				  pd);
	else
	else
		kvm_iodevice_write(pio_dev, vcpu->arch.pio.port,
		r = kvm_io_bus_write(&vcpu->kvm->pio_bus, vcpu->arch.pio.port,
				   vcpu->arch.pio.size,
				     vcpu->arch.pio.size, pd);
				   pd);
	return r;
}
}


static void pio_string_write(struct kvm_io_device *pio_dev,
static int pio_string_write(struct kvm_vcpu *vcpu)
			     struct kvm_vcpu *vcpu)
{
{
	struct kvm_pio_request *io = &vcpu->arch.pio;
	struct kvm_pio_request *io = &vcpu->arch.pio;
	void *pd = vcpu->arch.pio_data;
	void *pd = vcpu->arch.pio_data;
	int i;
	int i, r = 0;


	for (i = 0; i < io->cur_count; i++) {
	for (i = 0; i < io->cur_count; i++) {
		kvm_iodevice_write(pio_dev, io->port,
		if (kvm_io_bus_write(&vcpu->kvm->pio_bus,
				   io->size,
				     io->port, io->size, pd)) {
				   pd);
			r = -EOPNOTSUPP;
		pd += io->size;
			break;
		}
		}
		pd += io->size;
	}
	}

	return r;
static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
					       gpa_t addr, int len,
					       int is_write)
{
	return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr, len, is_write);
}
}


int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
		  int size, unsigned port)
		  int size, unsigned port)
{
{
	struct kvm_io_device *pio_dev;
	unsigned long val;
	unsigned long val;


	vcpu->run->exit_reason = KVM_EXIT_IO;
	vcpu->run->exit_reason = KVM_EXIT_IO;
@@ -2911,11 +2879,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
	val = kvm_register_read(vcpu, VCPU_REGS_RAX);
	val = kvm_register_read(vcpu, VCPU_REGS_RAX);
	memcpy(vcpu->arch.pio_data, &val, 4);
	memcpy(vcpu->arch.pio_data, &val, 4);


	mutex_lock(&vcpu->kvm->lock);
	if (!kernel_pio(vcpu, vcpu->arch.pio_data)) {
	pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in);
	mutex_unlock(&vcpu->kvm->lock);
	if (pio_dev) {
		kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data);
		complete_pio(vcpu);
		complete_pio(vcpu);
		return 1;
		return 1;
	}
	}
@@ -2929,7 +2893,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
{
{
	unsigned now, in_page;
	unsigned now, in_page;
	int ret = 0;
	int ret = 0;
	struct kvm_io_device *pio_dev;


	vcpu->run->exit_reason = KVM_EXIT_IO;
	vcpu->run->exit_reason = KVM_EXIT_IO;
	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -2973,12 +2936,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,


	vcpu->arch.pio.guest_gva = address;
	vcpu->arch.pio.guest_gva = address;


	mutex_lock(&vcpu->kvm->lock);
	pio_dev = vcpu_find_pio_dev(vcpu, port,
				    vcpu->arch.pio.cur_count,
				    !vcpu->arch.pio.in);
	mutex_unlock(&vcpu->kvm->lock);

	if (!vcpu->arch.pio.in) {
	if (!vcpu->arch.pio.in) {
		/* string PIO write */
		/* string PIO write */
		ret = pio_copy_data(vcpu);
		ret = pio_copy_data(vcpu);
@@ -2986,16 +2943,13 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
			kvm_inject_gp(vcpu, 0);
			kvm_inject_gp(vcpu, 0);
			return 1;
			return 1;
		}
		}
		if (ret == 0 && pio_dev) {
		if (ret == 0 && !pio_string_write(vcpu)) {
			pio_string_write(pio_dev, vcpu);
			complete_pio(vcpu);
			complete_pio(vcpu);
			if (vcpu->arch.pio.count == 0)
			if (vcpu->arch.pio.count == 0)
				ret = 1;
				ret = 1;
		}
		}
	} else if (pio_dev)
	}
		pr_unimpl(vcpu, "no string pio read support yet, "
	/* no string PIO read support yet */
		       "port %x size %d count %ld\n",
			port, size, count);


	return ret;
	return ret;
}
}
Loading