]>
Commit | Line | Data |
---|---|---|
ba5c1e9b | 1 | /* |
a53c8fab | 2 | * handling kvm guest interrupts |
ba5c1e9b CO |
3 | * |
4 | * Copyright IBM Corp. 2008 | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License (version 2 only) | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * Author(s): Carsten Otte <cotte@de.ibm.com> | |
11 | */ | |
12 | ||
ca872302 | 13 | #include <linux/interrupt.h> |
ba5c1e9b | 14 | #include <linux/kvm_host.h> |
cbb870c8 | 15 | #include <linux/hrtimer.h> |
3cd61299 | 16 | #include <linux/signal.h> |
5a0e3ad6 | 17 | #include <linux/slab.h> |
cbb870c8 HC |
18 | #include <asm/asm-offsets.h> |
19 | #include <asm/uaccess.h> | |
ba5c1e9b CO |
20 | #include "kvm-s390.h" |
21 | #include "gaccess.h" | |
ade38c31 | 22 | #include "trace-s390.h" |
ba5c1e9b | 23 | |
d8346b7d CH |
24 | #define IOINT_SCHID_MASK 0x0000ffff |
25 | #define IOINT_SSID_MASK 0x00030000 | |
26 | #define IOINT_CSSID_MASK 0x03fc0000 | |
27 | #define IOINT_AI_MASK 0x04000000 | |
28 | ||
29 | static int is_ioint(u64 type) | |
30 | { | |
31 | return ((type & 0xfffe0000u) != 0xfffe0000u); | |
32 | } | |
33 | ||
ba5c1e9b CO |
34 | static int psw_extint_disabled(struct kvm_vcpu *vcpu) |
35 | { | |
36 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); | |
37 | } | |
38 | ||
d8346b7d CH |
39 | static int psw_ioint_disabled(struct kvm_vcpu *vcpu) |
40 | { | |
41 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); | |
42 | } | |
43 | ||
48a3e950 CH |
44 | static int psw_mchk_disabled(struct kvm_vcpu *vcpu) |
45 | { | |
46 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK); | |
47 | } | |
48 | ||
ba5c1e9b CO |
49 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) |
50 | { | |
51 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || | |
52 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) || | |
53 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT)) | |
54 | return 0; | |
55 | return 1; | |
56 | } | |
57 | ||
79fd50c6 CH |
58 | static u64 int_word_to_isc_bits(u32 int_word) |
59 | { | |
60 | u8 isc = (int_word & 0x38000000) >> 27; | |
61 | ||
62 | return (0x80 >> isc) << 24; | |
63 | } | |
64 | ||
ba5c1e9b | 65 | static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, |
180c12fb | 66 | struct kvm_s390_interrupt_info *inti) |
ba5c1e9b CO |
67 | { |
68 | switch (inti->type) { | |
7697e71f CE |
69 | case KVM_S390_INT_EXTERNAL_CALL: |
70 | if (psw_extint_disabled(vcpu)) | |
71 | return 0; | |
72 | if (vcpu->arch.sie_block->gcr[0] & 0x2000ul) | |
73 | return 1; | |
ba5c1e9b CO |
74 | case KVM_S390_INT_EMERGENCY: |
75 | if (psw_extint_disabled(vcpu)) | |
76 | return 0; | |
77 | if (vcpu->arch.sie_block->gcr[0] & 0x4000ul) | |
78 | return 1; | |
79 | return 0; | |
80 | case KVM_S390_INT_SERVICE: | |
81 | if (psw_extint_disabled(vcpu)) | |
82 | return 0; | |
83 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | |
84 | return 1; | |
85 | return 0; | |
86 | case KVM_S390_INT_VIRTIO: | |
87 | if (psw_extint_disabled(vcpu)) | |
88 | return 0; | |
89 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | |
90 | return 1; | |
91 | return 0; | |
92 | case KVM_S390_PROGRAM_INT: | |
93 | case KVM_S390_SIGP_STOP: | |
94 | case KVM_S390_SIGP_SET_PREFIX: | |
95 | case KVM_S390_RESTART: | |
96 | return 1; | |
48a3e950 CH |
97 | case KVM_S390_MCHK: |
98 | if (psw_mchk_disabled(vcpu)) | |
99 | return 0; | |
100 | if (vcpu->arch.sie_block->gcr[14] & inti->mchk.cr14) | |
101 | return 1; | |
102 | return 0; | |
d8346b7d CH |
103 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
104 | if (psw_ioint_disabled(vcpu)) | |
105 | return 0; | |
79fd50c6 CH |
106 | if (vcpu->arch.sie_block->gcr[6] & |
107 | int_word_to_isc_bits(inti->io.io_int_word)) | |
d8346b7d CH |
108 | return 1; |
109 | return 0; | |
ba5c1e9b | 110 | default: |
d8346b7d CH |
111 | printk(KERN_WARNING "illegal interrupt type %llx\n", |
112 | inti->type); | |
ba5c1e9b CO |
113 | BUG(); |
114 | } | |
115 | return 0; | |
116 | } | |
117 | ||
118 | static void __set_cpu_idle(struct kvm_vcpu *vcpu) | |
119 | { | |
120 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | |
121 | atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | |
122 | set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | |
123 | } | |
124 | ||
125 | static void __unset_cpu_idle(struct kvm_vcpu *vcpu) | |
126 | { | |
127 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | |
128 | atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | |
129 | clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | |
130 | } | |
131 | ||
132 | static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) | |
133 | { | |
134 | atomic_clear_mask(CPUSTAT_ECALL_PEND | | |
135 | CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, | |
136 | &vcpu->arch.sie_block->cpuflags); | |
137 | vcpu->arch.sie_block->lctl = 0x0000; | |
48a3e950 | 138 | vcpu->arch.sie_block->ictl &= ~ICTL_LPSW; |
ba5c1e9b CO |
139 | } |
140 | ||
141 | static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) | |
142 | { | |
143 | atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); | |
144 | } | |
145 | ||
146 | static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | |
180c12fb | 147 | struct kvm_s390_interrupt_info *inti) |
ba5c1e9b CO |
148 | { |
149 | switch (inti->type) { | |
7697e71f | 150 | case KVM_S390_INT_EXTERNAL_CALL: |
ba5c1e9b CO |
151 | case KVM_S390_INT_EMERGENCY: |
152 | case KVM_S390_INT_SERVICE: | |
153 | case KVM_S390_INT_VIRTIO: | |
154 | if (psw_extint_disabled(vcpu)) | |
155 | __set_cpuflag(vcpu, CPUSTAT_EXT_INT); | |
156 | else | |
157 | vcpu->arch.sie_block->lctl |= LCTL_CR0; | |
158 | break; | |
159 | case KVM_S390_SIGP_STOP: | |
160 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); | |
161 | break; | |
48a3e950 CH |
162 | case KVM_S390_MCHK: |
163 | if (psw_mchk_disabled(vcpu)) | |
164 | vcpu->arch.sie_block->ictl |= ICTL_LPSW; | |
165 | else | |
166 | vcpu->arch.sie_block->lctl |= LCTL_CR14; | |
167 | break; | |
d8346b7d CH |
168 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
169 | if (psw_ioint_disabled(vcpu)) | |
170 | __set_cpuflag(vcpu, CPUSTAT_IO_INT); | |
171 | else | |
172 | vcpu->arch.sie_block->lctl |= LCTL_CR6; | |
173 | break; | |
ba5c1e9b CO |
174 | default: |
175 | BUG(); | |
176 | } | |
177 | } | |
178 | ||
179 | static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | |
180c12fb | 180 | struct kvm_s390_interrupt_info *inti) |
ba5c1e9b CO |
181 | { |
182 | const unsigned short table[] = { 2, 4, 4, 6 }; | |
dc5008b9 | 183 | int rc = 0; |
ba5c1e9b CO |
184 | |
185 | switch (inti->type) { | |
186 | case KVM_S390_INT_EMERGENCY: | |
187 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); | |
188 | vcpu->stat.deliver_emergency_signal++; | |
ade38c31 CH |
189 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
190 | inti->emerg.code, 0); | |
0a75ca27 | 191 | rc = put_guest(vcpu, 0x1201, (u16 __user *)__LC_EXT_INT_CODE); |
396083a9 | 192 | rc |= put_guest(vcpu, inti->emerg.code, |
0a75ca27 | 193 | (u16 __user *)__LC_EXT_CPU_ADDR); |
dc5008b9 HC |
194 | rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, |
195 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
196 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
197 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | |
ba5c1e9b | 198 | break; |
7697e71f CE |
199 | case KVM_S390_INT_EXTERNAL_CALL: |
200 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); | |
201 | vcpu->stat.deliver_external_call++; | |
ade38c31 CH |
202 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
203 | inti->extcall.code, 0); | |
0a75ca27 | 204 | rc = put_guest(vcpu, 0x1202, (u16 __user *)__LC_EXT_INT_CODE); |
396083a9 | 205 | rc |= put_guest(vcpu, inti->extcall.code, |
0a75ca27 | 206 | (u16 __user *)__LC_EXT_CPU_ADDR); |
dc5008b9 HC |
207 | rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, |
208 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
209 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
210 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | |
7697e71f | 211 | break; |
ba5c1e9b CO |
212 | case KVM_S390_INT_SERVICE: |
213 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", | |
214 | inti->ext.ext_params); | |
215 | vcpu->stat.deliver_service_signal++; | |
ade38c31 CH |
216 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
217 | inti->ext.ext_params, 0); | |
0a75ca27 | 218 | rc = put_guest(vcpu, 0x2401, (u16 __user *)__LC_EXT_INT_CODE); |
dc5008b9 HC |
219 | rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, |
220 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
221 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
222 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | |
396083a9 | 223 | rc |= put_guest(vcpu, inti->ext.ext_params, |
0a75ca27 | 224 | (u32 __user *)__LC_EXT_PARAMS); |
ba5c1e9b | 225 | break; |
ba5c1e9b | 226 | case KVM_S390_INT_VIRTIO: |
33e19115 | 227 | VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", |
ba5c1e9b CO |
228 | inti->ext.ext_params, inti->ext.ext_params2); |
229 | vcpu->stat.deliver_virtio_interrupt++; | |
ade38c31 CH |
230 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
231 | inti->ext.ext_params, | |
232 | inti->ext.ext_params2); | |
0a75ca27 HC |
233 | rc = put_guest(vcpu, 0x2603, (u16 __user *)__LC_EXT_INT_CODE); |
234 | rc |= put_guest(vcpu, 0x0d00, (u16 __user *)__LC_EXT_CPU_ADDR); | |
dc5008b9 HC |
235 | rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, |
236 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
237 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
238 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | |
396083a9 | 239 | rc |= put_guest(vcpu, inti->ext.ext_params, |
0a75ca27 | 240 | (u32 __user *)__LC_EXT_PARAMS); |
396083a9 | 241 | rc |= put_guest(vcpu, inti->ext.ext_params2, |
0a75ca27 | 242 | (u64 __user *)__LC_EXT_PARAMS2); |
ba5c1e9b | 243 | break; |
ba5c1e9b CO |
244 | case KVM_S390_SIGP_STOP: |
245 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); | |
246 | vcpu->stat.deliver_stop_signal++; | |
ade38c31 CH |
247 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
248 | 0, 0); | |
ba5c1e9b CO |
249 | __set_intercept_indicator(vcpu, inti); |
250 | break; | |
251 | ||
252 | case KVM_S390_SIGP_SET_PREFIX: | |
253 | VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", | |
254 | inti->prefix.address); | |
255 | vcpu->stat.deliver_prefix_signal++; | |
ade38c31 CH |
256 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
257 | inti->prefix.address, 0); | |
8d26cf7b | 258 | kvm_s390_set_prefix(vcpu, inti->prefix.address); |
ba5c1e9b CO |
259 | break; |
260 | ||
261 | case KVM_S390_RESTART: | |
262 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); | |
263 | vcpu->stat.deliver_restart_signal++; | |
ade38c31 CH |
264 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
265 | 0, 0); | |
dc5008b9 HC |
266 | rc = copy_to_guest(vcpu, |
267 | offsetof(struct _lowcore, restart_old_psw), | |
268 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
269 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
270 | offsetof(struct _lowcore, restart_psw), | |
271 | sizeof(psw_t)); | |
9e6dabef | 272 | atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); |
ba5c1e9b | 273 | break; |
ba5c1e9b CO |
274 | case KVM_S390_PROGRAM_INT: |
275 | VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", | |
276 | inti->pgm.code, | |
277 | table[vcpu->arch.sie_block->ipa >> 14]); | |
278 | vcpu->stat.deliver_program_int++; | |
ade38c31 CH |
279 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
280 | inti->pgm.code, 0); | |
0a75ca27 | 281 | rc = put_guest(vcpu, inti->pgm.code, (u16 __user *)__LC_PGM_INT_CODE); |
396083a9 | 282 | rc |= put_guest(vcpu, table[vcpu->arch.sie_block->ipa >> 14], |
0a75ca27 | 283 | (u16 __user *)__LC_PGM_ILC); |
dc5008b9 HC |
284 | rc |= copy_to_guest(vcpu, __LC_PGM_OLD_PSW, |
285 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
286 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
287 | __LC_PGM_NEW_PSW, sizeof(psw_t)); | |
ba5c1e9b CO |
288 | break; |
289 | ||
48a3e950 CH |
290 | case KVM_S390_MCHK: |
291 | VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx", | |
292 | inti->mchk.mcic); | |
293 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, | |
294 | inti->mchk.cr14, | |
295 | inti->mchk.mcic); | |
dc5008b9 HC |
296 | rc = kvm_s390_vcpu_store_status(vcpu, |
297 | KVM_S390_STORE_STATUS_PREFIXED); | |
0a75ca27 | 298 | rc |= put_guest(vcpu, inti->mchk.mcic, (u64 __user *) __LC_MCCK_CODE); |
dc5008b9 HC |
299 | rc |= copy_to_guest(vcpu, __LC_MCK_OLD_PSW, |
300 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
301 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
302 | __LC_MCK_NEW_PSW, sizeof(psw_t)); | |
48a3e950 CH |
303 | break; |
304 | ||
d8346b7d CH |
305 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
306 | { | |
307 | __u32 param0 = ((__u32)inti->io.subchannel_id << 16) | | |
308 | inti->io.subchannel_nr; | |
309 | __u64 param1 = ((__u64)inti->io.io_int_parm << 32) | | |
310 | inti->io.io_int_word; | |
311 | VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type); | |
312 | vcpu->stat.deliver_io_int++; | |
313 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, | |
314 | param0, param1); | |
396083a9 | 315 | rc = put_guest(vcpu, inti->io.subchannel_id, |
0a75ca27 | 316 | (u16 __user *) __LC_SUBCHANNEL_ID); |
396083a9 | 317 | rc |= put_guest(vcpu, inti->io.subchannel_nr, |
0a75ca27 | 318 | (u16 __user *) __LC_SUBCHANNEL_NR); |
396083a9 | 319 | rc |= put_guest(vcpu, inti->io.io_int_parm, |
0a75ca27 | 320 | (u32 __user *) __LC_IO_INT_PARM); |
396083a9 | 321 | rc |= put_guest(vcpu, inti->io.io_int_word, |
0a75ca27 | 322 | (u32 __user *) __LC_IO_INT_WORD); |
dc5008b9 HC |
323 | rc |= copy_to_guest(vcpu, __LC_IO_OLD_PSW, |
324 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
325 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
326 | __LC_IO_NEW_PSW, sizeof(psw_t)); | |
d8346b7d CH |
327 | break; |
328 | } | |
ba5c1e9b CO |
329 | default: |
330 | BUG(); | |
331 | } | |
dc5008b9 | 332 | if (rc) { |
3cd61299 | 333 | printk("kvm: The guest lowcore is not mapped during interrupt " |
dc5008b9 | 334 | "delivery, killing userspace\n"); |
3cd61299 | 335 | do_exit(SIGKILL); |
ba5c1e9b CO |
336 | } |
337 | } | |
338 | ||
339 | static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) | |
340 | { | |
dc5008b9 | 341 | int rc; |
ba5c1e9b CO |
342 | |
343 | if (psw_extint_disabled(vcpu)) | |
344 | return 0; | |
345 | if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) | |
346 | return 0; | |
0a75ca27 | 347 | rc = put_guest(vcpu, 0x1004, (u16 __user *)__LC_EXT_INT_CODE); |
dc5008b9 HC |
348 | rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW, |
349 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | |
350 | rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | |
351 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | |
352 | if (rc) { | |
3cd61299 CB |
353 | printk("kvm: The guest lowcore is not mapped during interrupt " |
354 | "delivery, killing userspace\n"); | |
355 | do_exit(SIGKILL); | |
ba5c1e9b | 356 | } |
ba5c1e9b CO |
357 | return 1; |
358 | } | |
359 | ||
a1b37100 | 360 | static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) |
ba5c1e9b | 361 | { |
180c12fb CB |
362 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
363 | struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; | |
364 | struct kvm_s390_interrupt_info *inti; | |
ba5c1e9b CO |
365 | int rc = 0; |
366 | ||
367 | if (atomic_read(&li->active)) { | |
368 | spin_lock_bh(&li->lock); | |
369 | list_for_each_entry(inti, &li->list, list) | |
370 | if (__interrupt_is_deliverable(vcpu, inti)) { | |
371 | rc = 1; | |
372 | break; | |
373 | } | |
374 | spin_unlock_bh(&li->lock); | |
375 | } | |
376 | ||
377 | if ((!rc) && atomic_read(&fi->active)) { | |
b037a4f3 | 378 | spin_lock(&fi->lock); |
ba5c1e9b CO |
379 | list_for_each_entry(inti, &fi->list, list) |
380 | if (__interrupt_is_deliverable(vcpu, inti)) { | |
381 | rc = 1; | |
382 | break; | |
383 | } | |
b037a4f3 | 384 | spin_unlock(&fi->lock); |
ba5c1e9b CO |
385 | } |
386 | ||
387 | if ((!rc) && (vcpu->arch.sie_block->ckc < | |
8c071b0f | 388 | get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) { |
ba5c1e9b CO |
389 | if ((!psw_extint_disabled(vcpu)) && |
390 | (vcpu->arch.sie_block->gcr[0] & 0x800ul)) | |
391 | rc = 1; | |
392 | } | |
393 | ||
394 | return rc; | |
395 | } | |
396 | ||
3d80840d MT |
397 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) |
398 | { | |
399 | return 0; | |
400 | } | |
401 | ||
ba5c1e9b CO |
402 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) |
403 | { | |
404 | u64 now, sltime; | |
405 | DECLARE_WAITQUEUE(wait, current); | |
406 | ||
407 | vcpu->stat.exit_wait_state++; | |
408 | if (kvm_cpu_has_interrupt(vcpu)) | |
409 | return 0; | |
410 | ||
e52b2af5 CO |
411 | __set_cpu_idle(vcpu); |
412 | spin_lock_bh(&vcpu->arch.local_int.lock); | |
413 | vcpu->arch.local_int.timer_due = 0; | |
414 | spin_unlock_bh(&vcpu->arch.local_int.lock); | |
415 | ||
ba5c1e9b CO |
416 | if (psw_interrupts_disabled(vcpu)) { |
417 | VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); | |
418 | __unset_cpu_idle(vcpu); | |
b8e660b8 | 419 | return -EOPNOTSUPP; /* disabled wait */ |
ba5c1e9b CO |
420 | } |
421 | ||
422 | if (psw_extint_disabled(vcpu) || | |
423 | (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) { | |
424 | VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); | |
425 | goto no_timer; | |
426 | } | |
427 | ||
8c071b0f | 428 | now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch; |
ba5c1e9b CO |
429 | if (vcpu->arch.sie_block->ckc < now) { |
430 | __unset_cpu_idle(vcpu); | |
431 | return 0; | |
432 | } | |
433 | ||
ed4f2094 | 434 | sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); |
ba5c1e9b | 435 | |
ca872302 CB |
436 | hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); |
437 | VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); | |
ba5c1e9b | 438 | no_timer: |
800c1065 | 439 | srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); |
b037a4f3 | 440 | spin_lock(&vcpu->arch.local_int.float_int->lock); |
ba5c1e9b | 441 | spin_lock_bh(&vcpu->arch.local_int.lock); |
d0321a24 | 442 | add_wait_queue(&vcpu->wq, &wait); |
ba5c1e9b CO |
443 | while (list_empty(&vcpu->arch.local_int.list) && |
444 | list_empty(&vcpu->arch.local_int.float_int->list) && | |
445 | (!vcpu->arch.local_int.timer_due) && | |
446 | !signal_pending(current)) { | |
447 | set_current_state(TASK_INTERRUPTIBLE); | |
448 | spin_unlock_bh(&vcpu->arch.local_int.lock); | |
b037a4f3 | 449 | spin_unlock(&vcpu->arch.local_int.float_int->lock); |
ba5c1e9b | 450 | schedule(); |
b037a4f3 | 451 | spin_lock(&vcpu->arch.local_int.float_int->lock); |
ba5c1e9b CO |
452 | spin_lock_bh(&vcpu->arch.local_int.lock); |
453 | } | |
454 | __unset_cpu_idle(vcpu); | |
455 | __set_current_state(TASK_RUNNING); | |
d0321a24 | 456 | remove_wait_queue(&vcpu->wq, &wait); |
ba5c1e9b | 457 | spin_unlock_bh(&vcpu->arch.local_int.lock); |
b037a4f3 | 458 | spin_unlock(&vcpu->arch.local_int.float_int->lock); |
800c1065 TH |
459 | vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); |
460 | ||
ca872302 | 461 | hrtimer_try_to_cancel(&vcpu->arch.ckc_timer); |
ba5c1e9b CO |
462 | return 0; |
463 | } | |
464 | ||
ca872302 | 465 | void kvm_s390_tasklet(unsigned long parm) |
ba5c1e9b | 466 | { |
ca872302 | 467 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *) parm; |
ba5c1e9b | 468 | |
ca872302 | 469 | spin_lock(&vcpu->arch.local_int.lock); |
ba5c1e9b | 470 | vcpu->arch.local_int.timer_due = 1; |
d0321a24 CB |
471 | if (waitqueue_active(&vcpu->wq)) |
472 | wake_up_interruptible(&vcpu->wq); | |
ca872302 | 473 | spin_unlock(&vcpu->arch.local_int.lock); |
ba5c1e9b CO |
474 | } |
475 | ||
ca872302 CB |
476 | /* |
477 | * low level hrtimer wake routine. Because this runs in hardirq context | |
478 | * we schedule a tasklet to do the real work. | |
479 | */ | |
480 | enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer) | |
481 | { | |
482 | struct kvm_vcpu *vcpu; | |
483 | ||
484 | vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer); | |
485 | tasklet_schedule(&vcpu->arch.tasklet); | |
486 | ||
487 | return HRTIMER_NORESTART; | |
488 | } | |
ba5c1e9b CO |
489 | |
490 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | |
491 | { | |
180c12fb CB |
492 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
493 | struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; | |
494 | struct kvm_s390_interrupt_info *n, *inti = NULL; | |
ba5c1e9b CO |
495 | int deliver; |
496 | ||
497 | __reset_intercept_indicators(vcpu); | |
498 | if (atomic_read(&li->active)) { | |
499 | do { | |
500 | deliver = 0; | |
501 | spin_lock_bh(&li->lock); | |
502 | list_for_each_entry_safe(inti, n, &li->list, list) { | |
503 | if (__interrupt_is_deliverable(vcpu, inti)) { | |
504 | list_del(&inti->list); | |
505 | deliver = 1; | |
506 | break; | |
507 | } | |
508 | __set_intercept_indicator(vcpu, inti); | |
509 | } | |
510 | if (list_empty(&li->list)) | |
511 | atomic_set(&li->active, 0); | |
512 | spin_unlock_bh(&li->lock); | |
513 | if (deliver) { | |
514 | __do_deliver_interrupt(vcpu, inti); | |
515 | kfree(inti); | |
516 | } | |
517 | } while (deliver); | |
518 | } | |
519 | ||
520 | if ((vcpu->arch.sie_block->ckc < | |
8c071b0f | 521 | get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) |
ba5c1e9b CO |
522 | __try_deliver_ckc_interrupt(vcpu); |
523 | ||
524 | if (atomic_read(&fi->active)) { | |
525 | do { | |
526 | deliver = 0; | |
b037a4f3 | 527 | spin_lock(&fi->lock); |
ba5c1e9b CO |
528 | list_for_each_entry_safe(inti, n, &fi->list, list) { |
529 | if (__interrupt_is_deliverable(vcpu, inti)) { | |
530 | list_del(&inti->list); | |
531 | deliver = 1; | |
532 | break; | |
533 | } | |
534 | __set_intercept_indicator(vcpu, inti); | |
535 | } | |
536 | if (list_empty(&fi->list)) | |
537 | atomic_set(&fi->active, 0); | |
b037a4f3 | 538 | spin_unlock(&fi->lock); |
ba5c1e9b CO |
539 | if (deliver) { |
540 | __do_deliver_interrupt(vcpu, inti); | |
541 | kfree(inti); | |
542 | } | |
543 | } while (deliver); | |
544 | } | |
545 | } | |
546 | ||
48a3e950 CH |
547 | void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu) |
548 | { | |
549 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | |
550 | struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int; | |
551 | struct kvm_s390_interrupt_info *n, *inti = NULL; | |
552 | int deliver; | |
553 | ||
554 | __reset_intercept_indicators(vcpu); | |
555 | if (atomic_read(&li->active)) { | |
556 | do { | |
557 | deliver = 0; | |
558 | spin_lock_bh(&li->lock); | |
559 | list_for_each_entry_safe(inti, n, &li->list, list) { | |
560 | if ((inti->type == KVM_S390_MCHK) && | |
561 | __interrupt_is_deliverable(vcpu, inti)) { | |
562 | list_del(&inti->list); | |
563 | deliver = 1; | |
564 | break; | |
565 | } | |
566 | __set_intercept_indicator(vcpu, inti); | |
567 | } | |
568 | if (list_empty(&li->list)) | |
569 | atomic_set(&li->active, 0); | |
570 | spin_unlock_bh(&li->lock); | |
571 | if (deliver) { | |
572 | __do_deliver_interrupt(vcpu, inti); | |
573 | kfree(inti); | |
574 | } | |
575 | } while (deliver); | |
576 | } | |
577 | ||
578 | if (atomic_read(&fi->active)) { | |
579 | do { | |
580 | deliver = 0; | |
581 | spin_lock(&fi->lock); | |
582 | list_for_each_entry_safe(inti, n, &fi->list, list) { | |
583 | if ((inti->type == KVM_S390_MCHK) && | |
584 | __interrupt_is_deliverable(vcpu, inti)) { | |
585 | list_del(&inti->list); | |
586 | deliver = 1; | |
587 | break; | |
588 | } | |
589 | __set_intercept_indicator(vcpu, inti); | |
590 | } | |
591 | if (list_empty(&fi->list)) | |
592 | atomic_set(&fi->active, 0); | |
593 | spin_unlock(&fi->lock); | |
594 | if (deliver) { | |
595 | __do_deliver_interrupt(vcpu, inti); | |
596 | kfree(inti); | |
597 | } | |
598 | } while (deliver); | |
599 | } | |
600 | } | |
601 | ||
ba5c1e9b CO |
602 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) |
603 | { | |
180c12fb CB |
604 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
605 | struct kvm_s390_interrupt_info *inti; | |
ba5c1e9b CO |
606 | |
607 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | |
608 | if (!inti) | |
609 | return -ENOMEM; | |
610 | ||
a419aef8 | 611 | inti->type = KVM_S390_PROGRAM_INT; |
ba5c1e9b CO |
612 | inti->pgm.code = code; |
613 | ||
614 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); | |
ade38c31 | 615 | trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1); |
ba5c1e9b CO |
616 | spin_lock_bh(&li->lock); |
617 | list_add(&inti->list, &li->list); | |
618 | atomic_set(&li->active, 1); | |
d0321a24 | 619 | BUG_ON(waitqueue_active(li->wq)); |
ba5c1e9b CO |
620 | spin_unlock_bh(&li->lock); |
621 | return 0; | |
622 | } | |
623 | ||
fa6b7fe9 CH |
624 | struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, |
625 | u64 cr6, u64 schid) | |
626 | { | |
627 | struct kvm_s390_float_interrupt *fi; | |
628 | struct kvm_s390_interrupt_info *inti, *iter; | |
629 | ||
630 | if ((!schid && !cr6) || (schid && cr6)) | |
631 | return NULL; | |
632 | mutex_lock(&kvm->lock); | |
633 | fi = &kvm->arch.float_int; | |
634 | spin_lock(&fi->lock); | |
635 | inti = NULL; | |
636 | list_for_each_entry(iter, &fi->list, list) { | |
637 | if (!is_ioint(iter->type)) | |
638 | continue; | |
79fd50c6 CH |
639 | if (cr6 && |
640 | ((cr6 & int_word_to_isc_bits(iter->io.io_int_word)) == 0)) | |
fa6b7fe9 CH |
641 | continue; |
642 | if (schid) { | |
643 | if (((schid & 0x00000000ffff0000) >> 16) != | |
644 | iter->io.subchannel_id) | |
645 | continue; | |
646 | if ((schid & 0x000000000000ffff) != | |
647 | iter->io.subchannel_nr) | |
648 | continue; | |
649 | } | |
650 | inti = iter; | |
651 | break; | |
652 | } | |
653 | if (inti) | |
654 | list_del_init(&inti->list); | |
655 | if (list_empty(&fi->list)) | |
656 | atomic_set(&fi->active, 0); | |
657 | spin_unlock(&fi->lock); | |
658 | mutex_unlock(&kvm->lock); | |
659 | return inti; | |
660 | } | |
ba5c1e9b | 661 | |
c05c4186 | 662 | static void __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) |
ba5c1e9b | 663 | { |
180c12fb CB |
664 | struct kvm_s390_local_interrupt *li; |
665 | struct kvm_s390_float_interrupt *fi; | |
c05c4186 | 666 | struct kvm_s390_interrupt_info *iter; |
ba5c1e9b CO |
667 | int sigcpu; |
668 | ||
c05c4186 JF |
669 | mutex_lock(&kvm->lock); |
670 | fi = &kvm->arch.float_int; | |
671 | spin_lock(&fi->lock); | |
672 | if (!is_ioint(inti->type)) { | |
673 | list_add_tail(&inti->list, &fi->list); | |
674 | } else { | |
675 | u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word); | |
676 | ||
677 | /* Keep I/O interrupts sorted in isc order. */ | |
678 | list_for_each_entry(iter, &fi->list, list) { | |
679 | if (!is_ioint(iter->type)) | |
680 | continue; | |
681 | if (int_word_to_isc_bits(iter->io.io_int_word) | |
682 | <= isc_bits) | |
683 | continue; | |
684 | break; | |
685 | } | |
686 | list_add_tail(&inti->list, &iter->list); | |
687 | } | |
688 | atomic_set(&fi->active, 1); | |
689 | sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); | |
690 | if (sigcpu == KVM_MAX_VCPUS) { | |
691 | do { | |
692 | sigcpu = fi->next_rr_cpu++; | |
693 | if (sigcpu == KVM_MAX_VCPUS) | |
694 | sigcpu = fi->next_rr_cpu = 0; | |
695 | } while (fi->local_int[sigcpu] == NULL); | |
696 | } | |
697 | li = fi->local_int[sigcpu]; | |
698 | spin_lock_bh(&li->lock); | |
699 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | |
700 | if (waitqueue_active(li->wq)) | |
701 | wake_up_interruptible(li->wq); | |
702 | spin_unlock_bh(&li->lock); | |
703 | spin_unlock(&fi->lock); | |
704 | mutex_unlock(&kvm->lock); | |
705 | } | |
706 | ||
707 | int kvm_s390_inject_vm(struct kvm *kvm, | |
708 | struct kvm_s390_interrupt *s390int) | |
709 | { | |
710 | struct kvm_s390_interrupt_info *inti; | |
711 | ||
ba5c1e9b CO |
712 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); |
713 | if (!inti) | |
714 | return -ENOMEM; | |
715 | ||
c05c4186 JF |
716 | inti->type = s390int->type; |
717 | switch (inti->type) { | |
ba5c1e9b | 718 | case KVM_S390_INT_VIRTIO: |
33e19115 | 719 | VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx", |
ba5c1e9b | 720 | s390int->parm, s390int->parm64); |
ba5c1e9b CO |
721 | inti->ext.ext_params = s390int->parm; |
722 | inti->ext.ext_params2 = s390int->parm64; | |
723 | break; | |
724 | case KVM_S390_INT_SERVICE: | |
725 | VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm); | |
ba5c1e9b CO |
726 | inti->ext.ext_params = s390int->parm; |
727 | break; | |
48a3e950 CH |
728 | case KVM_S390_MCHK: |
729 | VM_EVENT(kvm, 5, "inject: machine check parm64:%llx", | |
730 | s390int->parm64); | |
48a3e950 CH |
731 | inti->mchk.cr14 = s390int->parm; /* upper bits are not used */ |
732 | inti->mchk.mcic = s390int->parm64; | |
733 | break; | |
d8346b7d | 734 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
c05c4186 | 735 | if (inti->type & IOINT_AI_MASK) |
d8346b7d CH |
736 | VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); |
737 | else | |
738 | VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x", | |
739 | s390int->type & IOINT_CSSID_MASK, | |
740 | s390int->type & IOINT_SSID_MASK, | |
741 | s390int->type & IOINT_SCHID_MASK); | |
d8346b7d CH |
742 | inti->io.subchannel_id = s390int->parm >> 16; |
743 | inti->io.subchannel_nr = s390int->parm & 0x0000ffffu; | |
744 | inti->io.io_int_parm = s390int->parm64 >> 32; | |
745 | inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull; | |
746 | break; | |
ba5c1e9b CO |
747 | default: |
748 | kfree(inti); | |
749 | return -EINVAL; | |
750 | } | |
ade38c31 CH |
751 | trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, |
752 | 2); | |
ba5c1e9b | 753 | |
c05c4186 | 754 | __inject_vm(kvm, inti); |
ba5c1e9b CO |
755 | return 0; |
756 | } | |
757 | ||
758 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | |
759 | struct kvm_s390_interrupt *s390int) | |
760 | { | |
180c12fb CB |
761 | struct kvm_s390_local_interrupt *li; |
762 | struct kvm_s390_interrupt_info *inti; | |
ba5c1e9b CO |
763 | |
764 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | |
765 | if (!inti) | |
766 | return -ENOMEM; | |
767 | ||
768 | switch (s390int->type) { | |
769 | case KVM_S390_PROGRAM_INT: | |
770 | if (s390int->parm & 0xffff0000) { | |
771 | kfree(inti); | |
772 | return -EINVAL; | |
773 | } | |
774 | inti->type = s390int->type; | |
775 | inti->pgm.code = s390int->parm; | |
776 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", | |
777 | s390int->parm); | |
778 | break; | |
b7e6e4d3 CB |
779 | case KVM_S390_SIGP_SET_PREFIX: |
780 | inti->prefix.address = s390int->parm; | |
781 | inti->type = s390int->type; | |
782 | VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)", | |
783 | s390int->parm); | |
784 | break; | |
ba5c1e9b CO |
785 | case KVM_S390_SIGP_STOP: |
786 | case KVM_S390_RESTART: | |
82a12737 JH |
787 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); |
788 | inti->type = s390int->type; | |
789 | break; | |
7697e71f | 790 | case KVM_S390_INT_EXTERNAL_CALL: |
82a12737 JH |
791 | if (s390int->parm & 0xffff0000) { |
792 | kfree(inti); | |
793 | return -EINVAL; | |
794 | } | |
795 | VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u", | |
796 | s390int->parm); | |
797 | inti->type = s390int->type; | |
798 | inti->extcall.code = s390int->parm; | |
799 | break; | |
ba5c1e9b | 800 | case KVM_S390_INT_EMERGENCY: |
82a12737 JH |
801 | if (s390int->parm & 0xffff0000) { |
802 | kfree(inti); | |
803 | return -EINVAL; | |
804 | } | |
805 | VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm); | |
ba5c1e9b | 806 | inti->type = s390int->type; |
82a12737 | 807 | inti->emerg.code = s390int->parm; |
ba5c1e9b | 808 | break; |
48a3e950 CH |
809 | case KVM_S390_MCHK: |
810 | VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx", | |
811 | s390int->parm64); | |
812 | inti->type = s390int->type; | |
813 | inti->mchk.mcic = s390int->parm64; | |
814 | break; | |
ba5c1e9b CO |
815 | case KVM_S390_INT_VIRTIO: |
816 | case KVM_S390_INT_SERVICE: | |
d8346b7d | 817 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
ba5c1e9b CO |
818 | default: |
819 | kfree(inti); | |
820 | return -EINVAL; | |
821 | } | |
ade38c31 CH |
822 | trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm, |
823 | s390int->parm64, 2); | |
ba5c1e9b CO |
824 | |
825 | mutex_lock(&vcpu->kvm->lock); | |
826 | li = &vcpu->arch.local_int; | |
827 | spin_lock_bh(&li->lock); | |
828 | if (inti->type == KVM_S390_PROGRAM_INT) | |
829 | list_add(&inti->list, &li->list); | |
830 | else | |
831 | list_add_tail(&inti->list, &li->list); | |
832 | atomic_set(&li->active, 1); | |
833 | if (inti->type == KVM_S390_SIGP_STOP) | |
834 | li->action_bits |= ACTION_STOP_ON_STOP; | |
835 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | |
d0321a24 CB |
836 | if (waitqueue_active(&vcpu->wq)) |
837 | wake_up_interruptible(&vcpu->wq); | |
ba5c1e9b CO |
838 | spin_unlock_bh(&li->lock); |
839 | mutex_unlock(&vcpu->kvm->lock); | |
840 | return 0; | |
841 | } | |
c05c4186 JF |
842 | |
843 | static void clear_floating_interrupts(struct kvm *kvm) | |
844 | { | |
845 | struct kvm_s390_float_interrupt *fi; | |
846 | struct kvm_s390_interrupt_info *n, *inti = NULL; | |
847 | ||
848 | mutex_lock(&kvm->lock); | |
849 | fi = &kvm->arch.float_int; | |
850 | spin_lock(&fi->lock); | |
851 | list_for_each_entry_safe(inti, n, &fi->list, list) { | |
852 | list_del(&inti->list); | |
853 | kfree(inti); | |
854 | } | |
855 | atomic_set(&fi->active, 0); | |
856 | spin_unlock(&fi->lock); | |
857 | mutex_unlock(&kvm->lock); | |
858 | } | |
859 | ||
860 | static inline int copy_irq_to_user(struct kvm_s390_interrupt_info *inti, | |
861 | u8 *addr) | |
862 | { | |
863 | struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; | |
864 | struct kvm_s390_irq irq = {0}; | |
865 | ||
866 | irq.type = inti->type; | |
867 | switch (inti->type) { | |
868 | case KVM_S390_INT_VIRTIO: | |
869 | case KVM_S390_INT_SERVICE: | |
870 | irq.u.ext = inti->ext; | |
871 | break; | |
872 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | |
873 | irq.u.io = inti->io; | |
874 | break; | |
875 | case KVM_S390_MCHK: | |
876 | irq.u.mchk = inti->mchk; | |
877 | break; | |
878 | default: | |
879 | return -EINVAL; | |
880 | } | |
881 | ||
882 | if (copy_to_user(uptr, &irq, sizeof(irq))) | |
883 | return -EFAULT; | |
884 | ||
885 | return 0; | |
886 | } | |
887 | ||
888 | static int get_all_floating_irqs(struct kvm *kvm, __u8 *buf, __u64 len) | |
889 | { | |
890 | struct kvm_s390_interrupt_info *inti; | |
891 | struct kvm_s390_float_interrupt *fi; | |
892 | int ret = 0; | |
893 | int n = 0; | |
894 | ||
895 | mutex_lock(&kvm->lock); | |
896 | fi = &kvm->arch.float_int; | |
897 | spin_lock(&fi->lock); | |
898 | ||
899 | list_for_each_entry(inti, &fi->list, list) { | |
900 | if (len < sizeof(struct kvm_s390_irq)) { | |
901 | /* signal userspace to try again */ | |
902 | ret = -ENOMEM; | |
903 | break; | |
904 | } | |
905 | ret = copy_irq_to_user(inti, buf); | |
906 | if (ret) | |
907 | break; | |
908 | buf += sizeof(struct kvm_s390_irq); | |
909 | len -= sizeof(struct kvm_s390_irq); | |
910 | n++; | |
911 | } | |
912 | ||
913 | spin_unlock(&fi->lock); | |
914 | mutex_unlock(&kvm->lock); | |
915 | ||
916 | return ret < 0 ? ret : n; | |
917 | } | |
918 | ||
919 | static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | |
920 | { | |
921 | int r; | |
922 | ||
923 | switch (attr->group) { | |
924 | case KVM_DEV_FLIC_GET_ALL_IRQS: | |
925 | r = get_all_floating_irqs(dev->kvm, (u8 *) attr->addr, | |
926 | attr->attr); | |
927 | break; | |
928 | default: | |
929 | r = -EINVAL; | |
930 | } | |
931 | ||
932 | return r; | |
933 | } | |
934 | ||
935 | static inline int copy_irq_from_user(struct kvm_s390_interrupt_info *inti, | |
936 | u64 addr) | |
937 | { | |
938 | struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; | |
939 | void *target = NULL; | |
940 | void __user *source; | |
941 | u64 size; | |
942 | ||
943 | if (get_user(inti->type, (u64 __user *)addr)) | |
944 | return -EFAULT; | |
945 | ||
946 | switch (inti->type) { | |
947 | case KVM_S390_INT_VIRTIO: | |
948 | case KVM_S390_INT_SERVICE: | |
949 | target = (void *) &inti->ext; | |
950 | source = &uptr->u.ext; | |
951 | size = sizeof(inti->ext); | |
952 | break; | |
953 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | |
954 | target = (void *) &inti->io; | |
955 | source = &uptr->u.io; | |
956 | size = sizeof(inti->io); | |
957 | break; | |
958 | case KVM_S390_MCHK: | |
959 | target = (void *) &inti->mchk; | |
960 | source = &uptr->u.mchk; | |
961 | size = sizeof(inti->mchk); | |
962 | break; | |
963 | default: | |
964 | return -EINVAL; | |
965 | } | |
966 | ||
967 | if (copy_from_user(target, source, size)) | |
968 | return -EFAULT; | |
969 | ||
970 | return 0; | |
971 | } | |
972 | ||
973 | static int enqueue_floating_irq(struct kvm_device *dev, | |
974 | struct kvm_device_attr *attr) | |
975 | { | |
976 | struct kvm_s390_interrupt_info *inti = NULL; | |
977 | int r = 0; | |
978 | int len = attr->attr; | |
979 | ||
980 | if (len % sizeof(struct kvm_s390_irq) != 0) | |
981 | return -EINVAL; | |
982 | else if (len > KVM_S390_FLIC_MAX_BUFFER) | |
983 | return -EINVAL; | |
984 | ||
985 | while (len >= sizeof(struct kvm_s390_irq)) { | |
986 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | |
987 | if (!inti) | |
988 | return -ENOMEM; | |
989 | ||
990 | r = copy_irq_from_user(inti, attr->addr); | |
991 | if (r) { | |
992 | kfree(inti); | |
993 | return r; | |
994 | } | |
995 | __inject_vm(dev->kvm, inti); | |
996 | len -= sizeof(struct kvm_s390_irq); | |
997 | attr->addr += sizeof(struct kvm_s390_irq); | |
998 | } | |
999 | ||
1000 | return r; | |
1001 | } | |
1002 | ||
1003 | static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | |
1004 | { | |
1005 | int r = 0; | |
1006 | ||
1007 | switch (attr->group) { | |
1008 | case KVM_DEV_FLIC_ENQUEUE: | |
1009 | r = enqueue_floating_irq(dev, attr); | |
1010 | break; | |
1011 | case KVM_DEV_FLIC_CLEAR_IRQS: | |
1012 | r = 0; | |
1013 | clear_floating_interrupts(dev->kvm); | |
1014 | break; | |
1015 | default: | |
1016 | r = -EINVAL; | |
1017 | } | |
1018 | ||
1019 | return r; | |
1020 | } | |
1021 | ||
1022 | static int flic_create(struct kvm_device *dev, u32 type) | |
1023 | { | |
1024 | if (!dev) | |
1025 | return -EINVAL; | |
1026 | if (dev->kvm->arch.flic) | |
1027 | return -EINVAL; | |
1028 | dev->kvm->arch.flic = dev; | |
1029 | return 0; | |
1030 | } | |
1031 | ||
1032 | static void flic_destroy(struct kvm_device *dev) | |
1033 | { | |
1034 | dev->kvm->arch.flic = NULL; | |
1035 | kfree(dev); | |
1036 | } | |
1037 | ||
1038 | /* s390 floating irq controller (flic) */ | |
1039 | struct kvm_device_ops kvm_flic_ops = { | |
1040 | .name = "kvm-flic", | |
1041 | .get_attr = flic_get_attr, | |
1042 | .set_attr = flic_set_attr, | |
1043 | .create = flic_create, | |
1044 | .destroy = flic_destroy, | |
1045 | }; |