diff options
author | He, Qing <qing.he@intel.com> | 2007-07-26 04:05:18 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:25 -0400 |
commit | 6ceb9d791eeeb0a5493958f5d6d4dc7d91e59cf7 (patch) | |
tree | 8cef21acf9346fdbea36075029dc007fe969b51e | |
parent | 9cf98828d12285d1fb43e774c8c100a55f8f34e1 (diff) |
KVM: Add get/set irqchip ioctls for in-kernel PIC live migration support
This patch adds two new ioctls to dump and write kernel irqchips for
save/restore and live migration. PIC s/r and l/m is implemented in this
patch.
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com>
Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
-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 | ||||
-rw-r--r-- | include/linux/kvm.h | 36 |
4 files changed, 124 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) | |||
119 | s->irq_request(s->irq_request_opaque, 0); | 119 | s->irq_request(s->irq_request_opaque, 0); |
120 | } | 120 | } |
121 | 121 | ||
122 | void kvm_pic_update_irq(struct kvm_pic *s) | ||
123 | { | ||
124 | pic_update_irq(s); | ||
125 | } | ||
126 | |||
122 | void kvm_pic_set_irq(void *opaque, int irq, int level) | 127 | void kvm_pic_set_irq(void *opaque, int irq, int level) |
123 | { | 128 | { |
124 | struct kvm_pic *s = opaque; | 129 | 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); | |||
59 | int kvm_pic_read_irq(struct kvm_pic *s); | 59 | int kvm_pic_read_irq(struct kvm_pic *s); |
60 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v); | 60 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v); |
61 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v); | 61 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v); |
62 | void kvm_pic_update_irq(struct kvm_pic *s); | ||
62 | 63 | ||
63 | #define IOAPIC_NUM_PINS 24 | 64 | #define IOAPIC_NUM_PINS 24 |
64 | #define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ | 65 | #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: | |||
897 | return r; | 897 | return r; |
898 | } | 898 | } |
899 | 899 | ||
900 | static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | ||
901 | { | ||
902 | int r; | ||
903 | |||
904 | r = 0; | ||
905 | switch (chip->chip_id) { | ||
906 | case KVM_IRQCHIP_PIC_MASTER: | ||
907 | memcpy (&chip->chip.pic, | ||
908 | &pic_irqchip(kvm)->pics[0], | ||
909 | sizeof(struct kvm_pic_state)); | ||
910 | break; | ||
911 | case KVM_IRQCHIP_PIC_SLAVE: | ||
912 | memcpy (&chip->chip.pic, | ||
913 | &pic_irqchip(kvm)->pics[1], | ||
914 | sizeof(struct kvm_pic_state)); | ||
915 | break; | ||
916 | default: | ||
917 | r = -EINVAL; | ||
918 | break; | ||
919 | } | ||
920 | return r; | ||
921 | } | ||
922 | |||
923 | static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) | ||
924 | { | ||
925 | int r; | ||
926 | |||
927 | r = 0; | ||
928 | switch (chip->chip_id) { | ||
929 | case KVM_IRQCHIP_PIC_MASTER: | ||
930 | memcpy (&pic_irqchip(kvm)->pics[0], | ||
931 | &chip->chip.pic, | ||
932 | sizeof(struct kvm_pic_state)); | ||
933 | break; | ||
934 | case KVM_IRQCHIP_PIC_SLAVE: | ||
935 | memcpy (&pic_irqchip(kvm)->pics[1], | ||
936 | &chip->chip.pic, | ||
937 | sizeof(struct kvm_pic_state)); | ||
938 | break; | ||
939 | default: | ||
940 | r = -EINVAL; | ||
941 | break; | ||
942 | } | ||
943 | kvm_pic_update_irq(pic_irqchip(kvm)); | ||
944 | return r; | ||
945 | } | ||
946 | |||
900 | static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | 947 | static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) |
901 | { | 948 | { |
902 | int i; | 949 | int i; |
@@ -2835,6 +2882,41 @@ static long kvm_vm_ioctl(struct file *filp, | |||
2835 | } | 2882 | } |
2836 | break; | 2883 | break; |
2837 | } | 2884 | } |
2885 | case KVM_GET_IRQCHIP: { | ||
2886 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
2887 | struct kvm_irqchip chip; | ||
2888 | |||
2889 | r = -EFAULT; | ||
2890 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
2891 | goto out; | ||
2892 | r = -ENXIO; | ||
2893 | if (!irqchip_in_kernel(kvm)) | ||
2894 | goto out; | ||
2895 | r = kvm_vm_ioctl_get_irqchip(kvm, &chip); | ||
2896 | if (r) | ||
2897 | goto out; | ||
2898 | r = -EFAULT; | ||
2899 | if (copy_to_user(argp, &chip, sizeof chip)) | ||
2900 | goto out; | ||
2901 | r = 0; | ||
2902 | break; | ||
2903 | } | ||
2904 | case KVM_SET_IRQCHIP: { | ||
2905 | /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ | ||
2906 | struct kvm_irqchip chip; | ||
2907 | |||
2908 | r = -EFAULT; | ||
2909 | if (copy_from_user(&chip, argp, sizeof chip)) | ||
2910 | goto out; | ||
2911 | r = -ENXIO; | ||
2912 | if (!irqchip_in_kernel(kvm)) | ||
2913 | goto out; | ||
2914 | r = kvm_vm_ioctl_set_irqchip(kvm, &chip); | ||
2915 | if (r) | ||
2916 | goto out; | ||
2917 | r = 0; | ||
2918 | break; | ||
2919 | } | ||
2838 | default: | 2920 | default: |
2839 | ; | 2921 | ; |
2840 | } | 2922 | } |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index b0a13d1b34c..6560f11870f 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -45,6 +45,40 @@ struct kvm_irq_level { | |||
45 | __u32 level; | 45 | __u32 level; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* for KVM_GET_IRQCHIP / KVM_SET_IRQCHIP */ | ||
49 | struct kvm_pic_state { | ||
50 | __u8 last_irr; /* edge detection */ | ||
51 | __u8 irr; /* interrupt request register */ | ||
52 | __u8 imr; /* interrupt mask register */ | ||
53 | __u8 isr; /* interrupt service register */ | ||
54 | __u8 priority_add; /* highest irq priority */ | ||
55 | __u8 irq_base; | ||
56 | __u8 read_reg_select; | ||
57 | __u8 poll; | ||
58 | __u8 special_mask; | ||
59 | __u8 init_state; | ||
60 | __u8 auto_eoi; | ||
61 | __u8 rotate_on_auto_eoi; | ||
62 | __u8 special_fully_nested_mode; | ||
63 | __u8 init4; /* true if 4 byte init */ | ||
64 | __u8 elcr; /* PIIX edge/trigger selection */ | ||
65 | __u8 elcr_mask; | ||
66 | }; | ||
67 | |||
68 | enum kvm_irqchip_id { | ||
69 | KVM_IRQCHIP_PIC_MASTER = 0, | ||
70 | KVM_IRQCHIP_PIC_SLAVE = 1, | ||
71 | }; | ||
72 | |||
73 | struct kvm_irqchip { | ||
74 | __u32 chip_id; | ||
75 | __u32 pad; | ||
76 | union { | ||
77 | char dummy[512]; /* reserving space */ | ||
78 | struct kvm_pic_state pic; | ||
79 | } chip; | ||
80 | }; | ||
81 | |||
48 | enum kvm_exit_reason { | 82 | enum kvm_exit_reason { |
49 | KVM_EXIT_UNKNOWN = 0, | 83 | KVM_EXIT_UNKNOWN = 0, |
50 | KVM_EXIT_EXCEPTION = 1, | 84 | KVM_EXIT_EXCEPTION = 1, |
@@ -299,6 +333,8 @@ struct kvm_signal_mask { | |||
299 | /* Device model IOC */ | 333 | /* Device model IOC */ |
300 | #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) | 334 | #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) |
301 | #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) | 335 | #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) |
336 | #define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip) | ||
337 | #define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip) | ||
302 | 338 | ||
303 | /* | 339 | /* |
304 | * ioctls for vcpu fds | 340 | * ioctls for vcpu fds |