diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/i8259.c | 5 | ||||
-rw-r--r-- | drivers/kvm/irq.h | 1 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 82 |
3 files changed, 88 insertions, 0 deletions
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c index ee6030dc5c0..a679157bc59 100644 --- a/drivers/kvm/i8259.c +++ b/drivers/kvm/i8259.c @@ -119,6 +119,11 @@ static void pic_update_irq(struct kvm_pic *s) s->irq_request(s->irq_request_opaque, 0); } +void kvm_pic_update_irq(struct kvm_pic *s) +{ + pic_update_irq(s); +} + void kvm_pic_set_irq(void *opaque, int irq, int level) { struct kvm_pic *s = opaque; diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h index 6ed856a41e2..4034f6576cd 100644 --- a/drivers/kvm/irq.h +++ b/drivers/kvm/irq.h @@ -59,6 +59,7 @@ void kvm_pic_set_irq(void *opaque, int irq, int level); int kvm_pic_read_irq(struct kvm_pic *s); int kvm_cpu_get_interrupt(struct kvm_vcpu *v); int kvm_cpu_has_interrupt(struct kvm_vcpu *v); +void kvm_pic_update_irq(struct kvm_pic *s); #define IOAPIC_NUM_PINS 24 #define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 5063b3addbb..6e2c5f3f33f 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -897,6 +897,53 @@ 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; + 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; + default: + r = -EINVAL; + break; + } + kvm_pic_update_irq(pic_irqchip(kvm)); + return r; +} + static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { int i; @@ -2835,6 +2882,41 @@ static long kvm_vm_ioctl(struct file *filp, } 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; + } default: ; } |