|
@@ -459,15 +459,9 @@ static int picdev_in_range(gpa_t addr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline struct kvm_pic *to_pic(struct kvm_io_device *dev)
|
|
|
-{
|
|
|
- return container_of(dev, struct kvm_pic, dev);
|
|
|
-}
|
|
|
-
|
|
|
-static int picdev_write(struct kvm_io_device *this,
|
|
|
+static int picdev_write(struct kvm_pic *s,
|
|
|
gpa_t addr, int len, const void *val)
|
|
|
{
|
|
|
- struct kvm_pic *s = to_pic(this);
|
|
|
unsigned char data = *(unsigned char *)val;
|
|
|
if (!picdev_in_range(addr))
|
|
|
return -EOPNOTSUPP;
|
|
@@ -494,10 +488,9 @@ static int picdev_write(struct kvm_io_device *this,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int picdev_read(struct kvm_io_device *this,
|
|
|
+static int picdev_read(struct kvm_pic *s,
|
|
|
gpa_t addr, int len, void *val)
|
|
|
{
|
|
|
- struct kvm_pic *s = to_pic(this);
|
|
|
unsigned char data = 0;
|
|
|
if (!picdev_in_range(addr))
|
|
|
return -EOPNOTSUPP;
|
|
@@ -525,6 +518,48 @@ static int picdev_read(struct kvm_io_device *this,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int picdev_master_write(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, const void *val)
|
|
|
+{
|
|
|
+ return picdev_write(container_of(dev, struct kvm_pic, dev_master),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int picdev_master_read(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, void *val)
|
|
|
+{
|
|
|
+ return picdev_read(container_of(dev, struct kvm_pic, dev_master),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int picdev_slave_write(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, const void *val)
|
|
|
+{
|
|
|
+ return picdev_write(container_of(dev, struct kvm_pic, dev_slave),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int picdev_slave_read(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, void *val)
|
|
|
+{
|
|
|
+ return picdev_read(container_of(dev, struct kvm_pic, dev_slave),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int picdev_eclr_write(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, const void *val)
|
|
|
+{
|
|
|
+ return picdev_write(container_of(dev, struct kvm_pic, dev_eclr),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
+static int picdev_eclr_read(struct kvm_io_device *dev,
|
|
|
+ gpa_t addr, int len, void *val)
|
|
|
+{
|
|
|
+ return picdev_read(container_of(dev, struct kvm_pic, dev_eclr),
|
|
|
+ addr, len, val);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* callback when PIC0 irq status changed
|
|
|
*/
|
|
@@ -537,9 +572,19 @@ static void pic_irq_request(struct kvm *kvm, int level)
|
|
|
s->output = level;
|
|
|
}
|
|
|
|
|
|
-static const struct kvm_io_device_ops picdev_ops = {
|
|
|
- .read = picdev_read,
|
|
|
- .write = picdev_write,
|
|
|
+static const struct kvm_io_device_ops picdev_master_ops = {
|
|
|
+ .read = picdev_master_read,
|
|
|
+ .write = picdev_master_write,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct kvm_io_device_ops picdev_slave_ops = {
|
|
|
+ .read = picdev_slave_read,
|
|
|
+ .write = picdev_slave_write,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct kvm_io_device_ops picdev_eclr_ops = {
|
|
|
+ .read = picdev_eclr_read,
|
|
|
+ .write = picdev_eclr_write,
|
|
|
};
|
|
|
|
|
|
struct kvm_pic *kvm_create_pic(struct kvm *kvm)
|
|
@@ -560,16 +605,39 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
|
|
|
/*
|
|
|
* Initialize PIO device
|
|
|
*/
|
|
|
- kvm_iodevice_init(&s->dev, &picdev_ops);
|
|
|
+ kvm_iodevice_init(&s->dev_master, &picdev_master_ops);
|
|
|
+ kvm_iodevice_init(&s->dev_slave, &picdev_slave_ops);
|
|
|
+ kvm_iodevice_init(&s->dev_eclr, &picdev_eclr_ops);
|
|
|
mutex_lock(&kvm->slots_lock);
|
|
|
- ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &s->dev);
|
|
|
+ ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x20, 2,
|
|
|
+ &s->dev_master);
|
|
|
+ if (ret < 0)
|
|
|
+ goto fail_unlock;
|
|
|
+
|
|
|
+ ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0xa0, 2, &s->dev_slave);
|
|
|
+ if (ret < 0)
|
|
|
+ goto fail_unreg_2;
|
|
|
+
|
|
|
+ ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, 0x4d0, 2, &s->dev_eclr);
|
|
|
+ if (ret < 0)
|
|
|
+ goto fail_unreg_1;
|
|
|
+
|
|
|
mutex_unlock(&kvm->slots_lock);
|
|
|
- if (ret < 0) {
|
|
|
- kfree(s);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
|
|
|
return s;
|
|
|
+
|
|
|
+fail_unreg_1:
|
|
|
+ kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_slave);
|
|
|
+
|
|
|
+fail_unreg_2:
|
|
|
+ kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &s->dev_master);
|
|
|
+
|
|
|
+fail_unlock:
|
|
|
+ mutex_unlock(&kvm->slots_lock);
|
|
|
+
|
|
|
+ kfree(s);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
void kvm_destroy_pic(struct kvm *kvm)
|
|
@@ -577,7 +645,9 @@ void kvm_destroy_pic(struct kvm *kvm)
|
|
|
struct kvm_pic *vpic = kvm->arch.vpic;
|
|
|
|
|
|
if (vpic) {
|
|
|
- kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev);
|
|
|
+ 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);
|
|
|
kvm->arch.vpic = NULL;
|
|
|
kfree(vpic);
|
|
|
}
|