This patch adds support to migrate vcpu interrupts. Two new vcpu ioctls are added which get/set the complete status of pending interrupts in one go. The ioctls are marked as available with the new capability KVM_CAP_S390_IRQ_STATE. We can not use a ONEREG, as the number of pending local interrupts is not constant and depends on the number of CPUs. To retrieve the interrupt state we add an ioctl KVM_S390_GET_IRQ_STATE. Its input parameter is a pointer to a struct kvm_s390_irq_state which has a buffer and length. For all currently pending interrupts, we copy a struct kvm_s390_irq into the buffer and pass it to userspace. To store interrupt state into a buffer provided by userspace, we add an ioctl KVM_S390_SET_IRQ_STATE. It passes a struct kvm_s390_irq_state into the kernel and injects all interrupts contained in the buffer.
Unified · Split
| @@ -2875,6 +2875,67 @@ KVM_S390_MCHK - machine check interrupt; parameters in .mchk · 2874 unmodified lines | ||
| 2875 | 2875 | |
| 2876 | 2876 | Note that the vcpu ioctl is asynchronous to vcpu execution. |
| 2877 | 2877 | |
| 2878 | +4.94 KVM_S390_GET_IRQ_STATE | |
| 2879 | + | |
| 2880 | +Capability: KVM_CAP_S390_IRQ_STATE | |
| 2881 | +Architectures: s390 | |
| 2882 | +Type: vcpu ioctl | |
| 2883 | +Parameters: struct kvm_s390_irq_state (out) | |
| 2884 | +Returns: >= number of bytes copied into buffer, | |
| 2885 | + -EINVAL if buffer size is 0, | |
| 2886 | + -ENOBUFS if buffer size is too small to fit all pending interrupts, | |
| 2887 | + -EFAULT if the buffer address was invalid | |
| 2888 | + | |
| 2889 | +This ioctl allows userspace to retrieve the complete state of all currently | |
| 2890 | +pending interrupts in a single buffer. Use cases include migration | |
| 2891 | +and introspection. The parameter structure contains the address of a | |
| 2892 | +userspace buffer and its length: | |
| 2893 | + | |
| 2894 | +struct kvm_s390_irq_state { | |
| 2895 | + __u64 buf; | |
| 2896 | + __u32 flags; | |
| 2897 | + __u32 len; | |
| 2898 | + __u32 reserved[4]; | |
| 2899 | +}; | |
| 2900 | + | |
| 2901 | +Userspace passes in the above struct and for each pending interrupt a | |
| 2902 | +struct kvm_s390_irq is copied to the provided buffer. | |
| 2903 | + | |
| 2904 | +If -ENOBUFS is returned the buffer provided was too small and userspace | |
| 2905 | +may retry with a bigger buffer. | |
| 2906 | + | |
| 2907 | +4.95 KVM_S390_SET_IRQ_STATE | |
| 2908 | + | |
| 2909 | +Capability: KVM_CAP_S390_IRQ_STATE | |
| 2910 | +Architectures: s390 | |
| 2911 | +Type: vcpu ioctl | |
| 2912 | +Parameters: struct kvm_s390_irq_state (in) | |
| 2913 | +Returns: 0 on success, | |
| 2914 | + -EFAULT if the buffer address was invalid, | |
| 2915 | + -EINVAL for an invalid buffer length (see below), | |
| 2916 | + -EBUSY if there were already interrupts pending, | |
| 2917 | + errors occurring when actually injecting the | |
| 2918 | + interrupt. See KVM_S390_IRQ. | |
| 2919 | + | |
| 2920 | +This ioctl allows userspace to set the complete state of all cpu-local | |
| 2921 | +interrupts currently pending for the vcpu. It is intended for restoring | |
| 2922 | +interrupt state after a migration. The input parameter is a userspace buffer | |
| 2923 | +containing a struct kvm_s390_irq_state: | |
| 2924 | + | |
| 2925 | +struct kvm_s390_irq_state { | |
| 2926 | + __u64 buf; | |
| 2927 | + __u32 len; | |
| 2928 | + __u32 pad; | |
| 2929 | +}; | |
| 2930 | + | |
| 2931 | +The userspace memory referenced by buf contains a struct kvm_s390_irq | |
| 2932 | +for each interrupt to be injected into the guest. | |
| 2933 | +If one of the interrupts could not be injected for some reason the | |
| 2934 | +ioctl aborts. | |
| 2935 | + | |
| 2936 | +len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0 | |
| 2937 | +and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq), | |
| 2938 | +which is the maximum number of possibly pending cpu-local interrupts. | |
| 2878 | 2939 | |
| 2879 | 2940 | 5. The kvm_run structure |
| 2880 | 2941 | ------------------------ |
| @@ -2123,3 +2123,143 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, · 2122 unmodified lines | ||
| 2123 | 2123 | { |
| 2124 | 2124 | return -EINVAL; |
| 2125 | 2125 | } |
| 2126 | + | |
| 2127 | +int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len) | |
| 2128 | +{ | |
| 2129 | + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | |
| 2130 | + struct kvm_s390_irq *buf; | |
| 2131 | + int r = 0; | |
| 2132 | + int n; | |
| 2133 | + | |
| 2134 | + buf = vmalloc(len); | |
| 2135 | + if (!buf) | |
| 2136 | + return -ENOMEM; | |
| 2137 | + | |
| 2138 | + if (copy_from_user((void *) buf, irqstate, len)) { | |
| 2139 | + r = -EFAULT; | |
| 2140 | + goto out_free; | |
| 2141 | + } | |
| 2142 | + | |
| 2143 | + /* | |
| 2144 | + * Don't allow setting the interrupt state | |
| 2145 | + * when there are already interrupts pending | |
| 2146 | + */ | |
| 2147 | + spin_lock(&li->lock); | |
| 2148 | + if (li->pending_irqs) { | |
| 2149 | + r = -EBUSY; | |
| 2150 | + goto out_unlock; | |
| 2151 | + } | |
| 2152 | + | |
| 2153 | + for (n = 0; n < len / sizeof(*buf); n++) { | |
| 2154 | + r = do_inject_vcpu(vcpu, &buf[n]); | |
| 2155 | + if (r) | |
| 2156 | + break; | |
| 2157 | + } | |
| 2158 | + | |
| 2159 | +out_unlock: | |
| 2160 | + spin_unlock(&li->lock); | |
| 2161 | +out_free: | |
| 2162 | + vfree(buf); | |
| 2163 | + | |
| 2164 | + return r; | |
| 2165 | +} | |
| 2166 | + | |
| 2167 | +static void store_local_irq(struct kvm_s390_local_interrupt *li, | |
| 2168 | + struct kvm_s390_irq *irq, | |
| 2169 | + unsigned long irq_type) | |
| 2170 | +{ | |
| 2171 | + switch (irq_type) { | |
| 2172 | + case IRQ_PEND_MCHK_EX: | |
| 2173 | + case IRQ_PEND_MCHK_REP: | |
| 2174 | + irq->type = KVM_S390_MCHK; | |
| 2175 | + irq->u.mchk = li->irq.mchk; | |
| 2176 | + break; | |
| 2177 | + case IRQ_PEND_PROG: | |
| 2178 | + irq->type = KVM_S390_PROGRAM_INT; | |
| 2179 | + irq->u.pgm = li->irq.pgm; | |
| 2180 | + break; | |
| 2181 | + case IRQ_PEND_PFAULT_INIT: | |
| 2182 | + irq->type = KVM_S390_INT_PFAULT_INIT; | |
| 2183 | + irq->u.ext = li->irq.ext; | |
| 2184 | + break; | |
| 2185 | + case IRQ_PEND_EXT_EXTERNAL: | |
| 2186 | + irq->type = KVM_S390_INT_EXTERNAL_CALL; | |
| 2187 | + irq->u.extcall = li->irq.extcall; | |
| 2188 | + break; | |
| 2189 | + case IRQ_PEND_EXT_CLOCK_COMP: | |
| 2190 | + irq->type = KVM_S390_INT_CLOCK_COMP; | |
| 2191 | + break; | |
| 2192 | + case IRQ_PEND_EXT_CPU_TIMER: | |
| 2193 | + irq->type = KVM_S390_INT_CPU_TIMER; | |
| 2194 | + break; | |
| 2195 | + case IRQ_PEND_SIGP_STOP: | |
| 2196 | + irq->type = KVM_S390_SIGP_STOP; | |
| 2197 | + irq->u.stop = li->irq.stop; | |
| 2198 | + break; | |
| 2199 | + case IRQ_PEND_RESTART: | |
| 2200 | + irq->type = KVM_S390_RESTART; | |
| 2201 | + break; | |
| 2202 | + case IRQ_PEND_SET_PREFIX: | |
| 2203 | + irq->type = KVM_S390_SIGP_SET_PREFIX; | |
| 2204 | + irq->u.prefix = li->irq.prefix; | |
| 2205 | + break; | |
| 2206 | + } | |
| 2207 | +} | |
| 2208 | + | |
| 2209 | +int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len) | |
| 2210 | +{ | |
| 2211 | + uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl; | |
| 2212 | + unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)]; | |
| 2213 | + struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | |
| 2214 | + unsigned long pending_irqs; | |
| 2215 | + struct kvm_s390_irq irq; | |
| 2216 | + unsigned long irq_type; | |
| 2217 | + int cpuaddr; | |
| 2218 | + int n = 0; | |
| 2219 | + | |
| 2220 | + spin_lock(&li->lock); | |
| 2221 | + pending_irqs = li->pending_irqs; | |
| 2222 | + memcpy(&sigp_emerg_pending, &li->sigp_emerg_pending, | |
| 2223 | + sizeof(sigp_emerg_pending)); | |
| 2224 | + spin_unlock(&li->lock); | |
| 2225 | + | |
| 2226 | + for_each_set_bit(irq_type, &pending_irqs, IRQ_PEND_COUNT) { | |
| 2227 | + memset(&irq, 0, sizeof(irq)); | |
| 2228 | + if (irq_type == IRQ_PEND_EXT_EMERGENCY) | |
| 2229 | + continue; | |
| 2230 | + if (n + sizeof(irq) > len) | |
| 2231 | + return -ENOBUFS; | |
| 2232 | + store_local_irq(&vcpu->arch.local_int, &irq, irq_type); | |
| 2233 | + if (copy_to_user(&buf[n], &irq, sizeof(irq))) | |
| 2234 | + return -EFAULT; | |
| 2235 | + n += sizeof(irq); | |
| 2236 | + } | |
| 2237 | + | |
| 2238 | + if (test_bit(IRQ_PEND_EXT_EMERGENCY, &pending_irqs)) { | |
| 2239 | + for_each_set_bit(cpuaddr, sigp_emerg_pending, KVM_MAX_VCPUS) { | |
| 2240 | + memset(&irq, 0, sizeof(irq)); | |
| 2241 | + if (n + sizeof(irq) > len) | |
| 2242 | + return -ENOBUFS; | |
| 2243 | + irq.type = KVM_S390_INT_EMERGENCY; | |
| 2244 | + irq.u.emerg.code = cpuaddr; | |
| 2245 | + if (copy_to_user(&buf[n], &irq, sizeof(irq))) | |
| 2246 | + return -EFAULT; | |
| 2247 | + n += sizeof(irq); | |
| 2248 | + } | |
| 2249 | + } | |
| 2250 | + | |
| 2251 | + if ((sigp_ctrl & SIGP_CTRL_C) && | |
| 2252 | + (atomic_read(&vcpu->arch.sie_block->cpuflags) & | |
| 2253 | + CPUSTAT_ECALL_PEND)) { | |
| 2254 | + if (n + sizeof(irq) > len) | |
| 2255 | + return -ENOBUFS; | |
| 2256 | + memset(&irq, 0, sizeof(irq)); | |
| 2257 | + irq.type = KVM_S390_INT_EXTERNAL_CALL; | |
| 2258 | + irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK; | |
| 2259 | + if (copy_to_user(&buf[n], &irq, sizeof(irq))) | |
| 2260 | + return -EFAULT; | |
| 2261 | + n += sizeof(irq); | |
| 2262 | + } | |
| 2263 | + | |
| 2264 | + return n; | |
| 2265 | +} | |
| @@ -41,6 +41,9 @@ · 40 unmodified lines | ||
| 41 | 41 | #include "trace-s390.h" |
| 42 | 42 | |
| 43 | 43 | #define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ |
| 44 | +#define LOCAL_IRQS 32 | |
| 45 | +#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \ | |
| 46 | + (KVM_MAX_VCPUS + LOCAL_IRQS)) | |
| 44 | 47 | |
| 45 | 48 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU |
| 46 | 49 | |
| @@ -181,6 +184,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 134 unmodified lines | ||
| 181 | 184 | case KVM_CAP_S390_USER_SIGP: |
| 182 | 185 | case KVM_CAP_S390_USER_STSI: |
| 183 | 186 | case KVM_CAP_S390_SKEYS: |
| 187 | + case KVM_CAP_S390_IRQ_STATE: | |
| 184 | 188 | r = 1; |
| 185 | 189 | break; |
| 186 | 190 | case KVM_CAP_S390_MEM_OP: |
| @@ -2500,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 2313 unmodified lines | ||
| 2500 | 2504 | r = -EFAULT; |
| 2501 | 2505 | break; |
| 2502 | 2506 | } |
| 2507 | + case KVM_S390_SET_IRQ_STATE: { | |
| 2508 | + struct kvm_s390_irq_state irq_state; | |
| 2509 | + | |
| 2510 | + r = -EFAULT; | |
| 2511 | + if (copy_from_user(&irq_state, argp, sizeof(irq_state))) | |
| 2512 | + break; | |
| 2513 | + if (irq_state.len > VCPU_IRQS_MAX_BUF || | |
| 2514 | + irq_state.len == 0 || | |
| 2515 | + irq_state.len % sizeof(struct kvm_s390_irq) > 0) { | |
| 2516 | + r = -EINVAL; | |
| 2517 | + break; | |
| 2518 | + } | |
| 2519 | + r = kvm_s390_set_irq_state(vcpu, | |
| 2520 | + (void __user *) irq_state.buf, | |
| 2521 | + irq_state.len); | |
| 2522 | + break; | |
| 2523 | + } | |
| 2524 | + case KVM_S390_GET_IRQ_STATE: { | |
| 2525 | + struct kvm_s390_irq_state irq_state; | |
| 2526 | + | |
| 2527 | + r = -EFAULT; | |
| 2528 | + if (copy_from_user(&irq_state, argp, sizeof(irq_state))) | |
| 2529 | + break; | |
| 2530 | + if (irq_state.len == 0) { | |
| 2531 | + r = -EINVAL; | |
| 2532 | + break; | |
| 2533 | + } | |
| 2534 | + r = kvm_s390_get_irq_state(vcpu, | |
| 2535 | + (__u8 __user *) irq_state.buf, | |
| 2536 | + irq_state.len); | |
| 2537 | + break; | |
| 2538 | + } | |
| 2503 | 2539 | default: |
| 2504 | 2540 | r = -ENOTTY; |
| 2505 | 2541 | } |
| @@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu); · 271 unmodified lines | ||
| 272 | 272 | extern struct kvm_device_ops kvm_flic_ops; |
| 273 | 273 | int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu); |
| 274 | 274 | void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu); |
| 275 | +int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, | |
| 276 | + void __user *buf, int len); | |
| 277 | +int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, | |
| 278 | + __u8 __user *buf, int len); | |
| 275 | 279 | |
| 276 | 280 | /* implemented in guestdbg.c */ |
| 277 | 281 | void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); |
| @@ -558,6 +558,13 @@ struct kvm_s390_irq { · 557 unmodified lines | ||
| 558 | 558 | } u; |
| 559 | 559 | }; |
| 560 | 560 | |
| 561 | +struct kvm_s390_irq_state { | |
| 562 | + __u64 buf; | |
| 563 | + __u32 flags; | |
| 564 | + __u32 len; | |
| 565 | + __u32 reserved[4]; | |
| 566 | +}; | |
| 567 | + | |
| 561 | 568 | /* for KVM_SET_GUEST_DEBUG */ |
| 562 | 569 | |
| 563 | 570 | #define KVM_GUESTDBG_ENABLE 0x00000001 |
| @@ -803,6 +810,7 @@ struct kvm_ppc_smmu_info { · 239 unmodified lines | ||
| 803 | 810 | #define KVM_CAP_S390_USER_STSI 109 |
| 804 | 811 | #define KVM_CAP_S390_SKEYS 110 |
| 805 | 812 | #define KVM_CAP_S390_INJECT_IRQ 113 |
| 813 | +#define KVM_CAP_S390_IRQ_STATE 114 | |
| 806 | 814 | |
| 807 | 815 | #ifdef KVM_CAP_IRQ_ROUTING |
| 808 | 816 | |
| @@ -1185,6 +1193,9 @@ struct kvm_s390_ucas_mapping { · 376 unmodified lines | ||
| 1185 | 1193 | #define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys) |
| 1186 | 1194 | /* Available with KVM_CAP_S390_INJECT_IRQ */ |
| 1187 | 1195 | #define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq) |
| 1196 | +/* Available with KVM_CAP_S390_IRQ_STATE */ | |
| 1197 | +#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state) | |
| 1198 | +#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state) | |
| 1188 | 1199 | |
| 1189 | 1200 | #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) |
| 1190 | 1201 | #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) |