KVM: kvm_io_device: extend in_range() to manage len and write attribute
Modify member in_range() of structure kvm_io_device to pass length and the type of the I/O (write or read). This modification allows to use kvm_io_device with coalesced MMIO. Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net> Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
131d82791b
commit
92760499d0
@ -195,11 +195,11 @@ int kvm_dev_ioctl_check_extension(long ext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
|
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
|
||||||
gpa_t addr)
|
gpa_t addr, int len, int is_write)
|
||||||
{
|
{
|
||||||
struct kvm_io_device *dev;
|
struct kvm_io_device *dev;
|
||||||
|
|
||||||
dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
|
dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@ 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);
|
mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir);
|
||||||
if (mmio_dev) {
|
if (mmio_dev) {
|
||||||
if (!p->dir)
|
if (!p->dir)
|
||||||
kvm_iodevice_write(mmio_dev, p->addr, p->size,
|
kvm_iodevice_write(mmio_dev, p->addr, p->size,
|
||||||
|
@ -460,7 +460,8 @@ static void pit_ioport_read(struct kvm_io_device *this,
|
|||||||
mutex_unlock(&pit_state->lock);
|
mutex_unlock(&pit_state->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pit_in_range(struct kvm_io_device *this, gpa_t addr)
|
static int pit_in_range(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
int len, int is_write)
|
||||||
{
|
{
|
||||||
return ((addr >= KVM_PIT_BASE_ADDRESS) &&
|
return ((addr >= KVM_PIT_BASE_ADDRESS) &&
|
||||||
(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
|
(addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
|
||||||
@ -501,7 +502,8 @@ static void speaker_ioport_read(struct kvm_io_device *this,
|
|||||||
mutex_unlock(&pit_state->lock);
|
mutex_unlock(&pit_state->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int speaker_in_range(struct kvm_io_device *this, gpa_t addr)
|
static int speaker_in_range(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
int len, int is_write)
|
||||||
{
|
{
|
||||||
return (addr == KVM_SPEAKER_BASE_ADDRESS);
|
return (addr == KVM_SPEAKER_BASE_ADDRESS);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,8 @@ 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(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
int len, int is_write)
|
||||||
{
|
{
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x20:
|
case 0x20:
|
||||||
|
@ -785,7 +785,8 @@ static void apic_mmio_write(struct kvm_io_device *this,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
|
static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
int len, int size)
|
||||||
{
|
{
|
||||||
struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
|
struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1797,13 +1797,14 @@ static void kvm_init_msr_list(void)
|
|||||||
* Only apic need an MMIO device hook, so shortcut now..
|
* Only apic need an MMIO device hook, so shortcut now..
|
||||||
*/
|
*/
|
||||||
static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
|
static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
|
||||||
gpa_t addr)
|
gpa_t addr, int len,
|
||||||
|
int is_write)
|
||||||
{
|
{
|
||||||
struct kvm_io_device *dev;
|
struct kvm_io_device *dev;
|
||||||
|
|
||||||
if (vcpu->arch.apic) {
|
if (vcpu->arch.apic) {
|
||||||
dev = &vcpu->arch.apic->dev;
|
dev = &vcpu->arch.apic->dev;
|
||||||
if (dev->in_range(dev, addr))
|
if (dev->in_range(dev, addr, len, is_write))
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1811,13 +1812,15 @@ static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
|
|||||||
|
|
||||||
|
|
||||||
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
|
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
|
||||||
gpa_t addr)
|
gpa_t addr, int len,
|
||||||
|
int is_write)
|
||||||
{
|
{
|
||||||
struct kvm_io_device *dev;
|
struct kvm_io_device *dev;
|
||||||
|
|
||||||
dev = vcpu_find_pervcpu_dev(vcpu, addr);
|
dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write);
|
||||||
if (dev == NULL)
|
if (dev == NULL)
|
||||||
dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
|
dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len,
|
||||||
|
is_write);
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1885,7 +1888,7 @@ mmio:
|
|||||||
* Is this MMIO handled locally?
|
* Is this MMIO handled locally?
|
||||||
*/
|
*/
|
||||||
mutex_lock(&vcpu->kvm->lock);
|
mutex_lock(&vcpu->kvm->lock);
|
||||||
mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
|
mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0);
|
||||||
if (mmio_dev) {
|
if (mmio_dev) {
|
||||||
kvm_iodevice_read(mmio_dev, gpa, bytes, val);
|
kvm_iodevice_read(mmio_dev, gpa, bytes, val);
|
||||||
mutex_unlock(&vcpu->kvm->lock);
|
mutex_unlock(&vcpu->kvm->lock);
|
||||||
@ -1940,7 +1943,7 @@ mmio:
|
|||||||
* Is this MMIO handled locally?
|
* Is this MMIO handled locally?
|
||||||
*/
|
*/
|
||||||
mutex_lock(&vcpu->kvm->lock);
|
mutex_lock(&vcpu->kvm->lock);
|
||||||
mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
|
mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1);
|
||||||
if (mmio_dev) {
|
if (mmio_dev) {
|
||||||
kvm_iodevice_write(mmio_dev, gpa, bytes, val);
|
kvm_iodevice_write(mmio_dev, gpa, bytes, val);
|
||||||
mutex_unlock(&vcpu->kvm->lock);
|
mutex_unlock(&vcpu->kvm->lock);
|
||||||
@ -2317,9 +2320,10 @@ static void pio_string_write(struct kvm_io_device *pio_dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
|
static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
|
||||||
gpa_t addr)
|
gpa_t addr, int len,
|
||||||
|
int is_write)
|
||||||
{
|
{
|
||||||
return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
|
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,
|
||||||
@ -2351,7 +2355,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
|
|||||||
|
|
||||||
kvm_x86_ops->skip_emulated_instruction(vcpu);
|
kvm_x86_ops->skip_emulated_instruction(vcpu);
|
||||||
|
|
||||||
pio_dev = vcpu_find_pio_dev(vcpu, port);
|
pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in);
|
||||||
if (pio_dev) {
|
if (pio_dev) {
|
||||||
kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data);
|
kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data);
|
||||||
complete_pio(vcpu);
|
complete_pio(vcpu);
|
||||||
@ -2433,7 +2437,9 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pio_dev = vcpu_find_pio_dev(vcpu, port);
|
pio_dev = vcpu_find_pio_dev(vcpu, port,
|
||||||
|
vcpu->arch.pio.cur_count,
|
||||||
|
!vcpu->arch.pio.in);
|
||||||
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);
|
||||||
|
@ -52,7 +52,8 @@ struct kvm_io_bus {
|
|||||||
|
|
||||||
void kvm_io_bus_init(struct kvm_io_bus *bus);
|
void kvm_io_bus_init(struct kvm_io_bus *bus);
|
||||||
void kvm_io_bus_destroy(struct kvm_io_bus *bus);
|
void kvm_io_bus_destroy(struct kvm_io_bus *bus);
|
||||||
struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
|
struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
|
||||||
|
gpa_t addr, int len, int is_write);
|
||||||
void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
|
void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
|
||||||
struct kvm_io_device *dev);
|
struct kvm_io_device *dev);
|
||||||
|
|
||||||
|
@ -307,7 +307,8 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
|
|||||||
__kvm_ioapic_update_eoi(ioapic, i);
|
__kvm_ioapic_update_eoi(ioapic, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
|
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
int len, int is_write)
|
||||||
{
|
{
|
||||||
struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
|
struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ struct kvm_io_device {
|
|||||||
gpa_t addr,
|
gpa_t addr,
|
||||||
int len,
|
int len,
|
||||||
const void *val);
|
const void *val);
|
||||||
int (*in_range)(struct kvm_io_device *this, gpa_t addr);
|
int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len,
|
||||||
|
int is_write);
|
||||||
void (*destructor)(struct kvm_io_device *this);
|
void (*destructor)(struct kvm_io_device *this);
|
||||||
|
|
||||||
void *private;
|
void *private;
|
||||||
@ -49,9 +50,10 @@ static inline void kvm_iodevice_write(struct kvm_io_device *dev,
|
|||||||
dev->write(dev, addr, len, val);
|
dev->write(dev, addr, len, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
|
static inline int kvm_iodevice_inrange(struct kvm_io_device *dev,
|
||||||
|
gpa_t addr, int len, int is_write)
|
||||||
{
|
{
|
||||||
return dev->in_range(dev, addr);
|
return dev->in_range(dev, addr, len, is_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
|
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
|
||||||
|
@ -1350,14 +1350,15 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
|
struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
|
||||||
|
gpa_t addr, int len, int is_write)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < bus->dev_count; i++) {
|
for (i = 0; i < bus->dev_count; i++) {
|
||||||
struct kvm_io_device *pos = bus->devs[i];
|
struct kvm_io_device *pos = bus->devs[i];
|
||||||
|
|
||||||
if (pos->in_range(pos, addr))
|
if (pos->in_range(pos, addr, len, is_write))
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user