diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kvm/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 116 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 587 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 48 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 15 |
5 files changed, 765 insertions, 3 deletions
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile index 27882b35ef04..7275a1aa4ee4 100644 --- a/arch/s390/kvm/Makefile +++ b/arch/s390/kvm/Makefile | |||
@@ -10,5 +10,5 @@ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o) | |||
10 | 10 | ||
11 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm | 11 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm |
12 | 12 | ||
13 | kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o | 13 | kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o |
14 | obj-$(CONFIG_KVM) += kvm.o | 14 | obj-$(CONFIG_KVM) += kvm.o |
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index e757230b982c..7f7347b5f34a 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -18,6 +18,86 @@ | |||
18 | #include <asm/kvm_host.h> | 18 | #include <asm/kvm_host.h> |
19 | 19 | ||
20 | #include "kvm-s390.h" | 20 | #include "kvm-s390.h" |
21 | #include "gaccess.h" | ||
22 | |||
23 | static int handle_lctg(struct kvm_vcpu *vcpu) | ||
24 | { | ||
25 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
26 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
27 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
28 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + | ||
29 | ((vcpu->arch.sie_block->ipb & 0xff00) << 4); | ||
30 | u64 useraddr; | ||
31 | int reg, rc; | ||
32 | |||
33 | vcpu->stat.instruction_lctg++; | ||
34 | if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) | ||
35 | return -ENOTSUPP; | ||
36 | |||
37 | useraddr = disp2; | ||
38 | if (base2) | ||
39 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
40 | |||
41 | reg = reg1; | ||
42 | |||
43 | VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
44 | disp2); | ||
45 | |||
46 | do { | ||
47 | rc = get_guest_u64(vcpu, useraddr, | ||
48 | &vcpu->arch.sie_block->gcr[reg]); | ||
49 | if (rc == -EFAULT) { | ||
50 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
51 | break; | ||
52 | } | ||
53 | useraddr += 8; | ||
54 | if (reg == reg3) | ||
55 | break; | ||
56 | reg = (reg + 1) % 16; | ||
57 | } while (1); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int handle_lctl(struct kvm_vcpu *vcpu) | ||
62 | { | ||
63 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
64 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
65 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
66 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
67 | u64 useraddr; | ||
68 | u32 val = 0; | ||
69 | int reg, rc; | ||
70 | |||
71 | vcpu->stat.instruction_lctl++; | ||
72 | |||
73 | useraddr = disp2; | ||
74 | if (base2) | ||
75 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
76 | |||
77 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
78 | disp2); | ||
79 | |||
80 | reg = reg1; | ||
81 | do { | ||
82 | rc = get_guest_u32(vcpu, useraddr, &val); | ||
83 | if (rc == -EFAULT) { | ||
84 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
85 | break; | ||
86 | } | ||
87 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
88 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
89 | useraddr += 4; | ||
90 | if (reg == reg3) | ||
91 | break; | ||
92 | reg = (reg + 1) % 16; | ||
93 | } while (1); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static intercept_handler_t instruction_handlers[256] = { | ||
98 | [0xb7] = handle_lctl, | ||
99 | [0xeb] = handle_lctg, | ||
100 | }; | ||
21 | 101 | ||
22 | static int handle_noop(struct kvm_vcpu *vcpu) | 102 | static int handle_noop(struct kvm_vcpu *vcpu) |
23 | { | 103 | { |
@@ -58,10 +138,46 @@ static int handle_validity(struct kvm_vcpu *vcpu) | |||
58 | return -ENOTSUPP; | 138 | return -ENOTSUPP; |
59 | } | 139 | } |
60 | 140 | ||
141 | static int handle_instruction(struct kvm_vcpu *vcpu) | ||
142 | { | ||
143 | intercept_handler_t handler; | ||
144 | |||
145 | vcpu->stat.exit_instruction++; | ||
146 | handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; | ||
147 | if (handler) | ||
148 | return handler(vcpu); | ||
149 | return -ENOTSUPP; | ||
150 | } | ||
151 | |||
152 | static int handle_prog(struct kvm_vcpu *vcpu) | ||
153 | { | ||
154 | vcpu->stat.exit_program_interruption++; | ||
155 | return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); | ||
156 | } | ||
157 | |||
158 | static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) | ||
159 | { | ||
160 | int rc, rc2; | ||
161 | |||
162 | vcpu->stat.exit_instr_and_program++; | ||
163 | rc = handle_instruction(vcpu); | ||
164 | rc2 = handle_prog(vcpu); | ||
165 | |||
166 | if (rc == -ENOTSUPP) | ||
167 | vcpu->arch.sie_block->icptcode = 0x04; | ||
168 | if (rc) | ||
169 | return rc; | ||
170 | return rc2; | ||
171 | } | ||
172 | |||
61 | static const intercept_handler_t intercept_funcs[0x48 >> 2] = { | 173 | static const intercept_handler_t intercept_funcs[0x48 >> 2] = { |
62 | [0x00 >> 2] = handle_noop, | 174 | [0x00 >> 2] = handle_noop, |
175 | [0x04 >> 2] = handle_instruction, | ||
176 | [0x08 >> 2] = handle_prog, | ||
177 | [0x0C >> 2] = handle_instruction_and_prog, | ||
63 | [0x10 >> 2] = handle_noop, | 178 | [0x10 >> 2] = handle_noop, |
64 | [0x14 >> 2] = handle_noop, | 179 | [0x14 >> 2] = handle_noop, |
180 | [0x1C >> 2] = kvm_s390_handle_wait, | ||
65 | [0x20 >> 2] = handle_validity, | 181 | [0x20 >> 2] = handle_validity, |
66 | [0x28 >> 2] = handle_stop, | 182 | [0x28 >> 2] = handle_stop, |
67 | }; | 183 | }; |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c new file mode 100644 index 000000000000..f62588cb75f8 --- /dev/null +++ b/arch/s390/kvm/interrupt.c | |||
@@ -0,0 +1,587 @@ | |||
1 | /* | ||
2 | * interrupt.c - handling kvm guest interrupts | ||
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 | |||
13 | #include <asm/lowcore.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <linux/kvm_host.h> | ||
16 | #include "kvm-s390.h" | ||
17 | #include "gaccess.h" | ||
18 | |||
19 | static int psw_extint_disabled(struct kvm_vcpu *vcpu) | ||
20 | { | ||
21 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); | ||
22 | } | ||
23 | |||
24 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) | ||
25 | { | ||
26 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || | ||
27 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) || | ||
28 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT)) | ||
29 | return 0; | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, | ||
34 | struct interrupt_info *inti) | ||
35 | { | ||
36 | switch (inti->type) { | ||
37 | case KVM_S390_INT_EMERGENCY: | ||
38 | if (psw_extint_disabled(vcpu)) | ||
39 | return 0; | ||
40 | if (vcpu->arch.sie_block->gcr[0] & 0x4000ul) | ||
41 | return 1; | ||
42 | return 0; | ||
43 | case KVM_S390_INT_SERVICE: | ||
44 | if (psw_extint_disabled(vcpu)) | ||
45 | return 0; | ||
46 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | ||
47 | return 1; | ||
48 | return 0; | ||
49 | case KVM_S390_INT_VIRTIO: | ||
50 | if (psw_extint_disabled(vcpu)) | ||
51 | return 0; | ||
52 | if (vcpu->arch.sie_block->gcr[0] & 0x200ul) | ||
53 | return 1; | ||
54 | return 0; | ||
55 | case KVM_S390_PROGRAM_INT: | ||
56 | case KVM_S390_SIGP_STOP: | ||
57 | case KVM_S390_SIGP_SET_PREFIX: | ||
58 | case KVM_S390_RESTART: | ||
59 | return 1; | ||
60 | default: | ||
61 | BUG(); | ||
62 | } | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static void __set_cpu_idle(struct kvm_vcpu *vcpu) | ||
67 | { | ||
68 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | ||
69 | atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | ||
70 | set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | ||
71 | } | ||
72 | |||
73 | static void __unset_cpu_idle(struct kvm_vcpu *vcpu) | ||
74 | { | ||
75 | BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1); | ||
76 | atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); | ||
77 | clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); | ||
78 | } | ||
79 | |||
80 | static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) | ||
81 | { | ||
82 | atomic_clear_mask(CPUSTAT_ECALL_PEND | | ||
83 | CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, | ||
84 | &vcpu->arch.sie_block->cpuflags); | ||
85 | vcpu->arch.sie_block->lctl = 0x0000; | ||
86 | } | ||
87 | |||
88 | static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) | ||
89 | { | ||
90 | atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); | ||
91 | } | ||
92 | |||
93 | static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | ||
94 | struct interrupt_info *inti) | ||
95 | { | ||
96 | switch (inti->type) { | ||
97 | case KVM_S390_INT_EMERGENCY: | ||
98 | case KVM_S390_INT_SERVICE: | ||
99 | case KVM_S390_INT_VIRTIO: | ||
100 | if (psw_extint_disabled(vcpu)) | ||
101 | __set_cpuflag(vcpu, CPUSTAT_EXT_INT); | ||
102 | else | ||
103 | vcpu->arch.sie_block->lctl |= LCTL_CR0; | ||
104 | break; | ||
105 | case KVM_S390_SIGP_STOP: | ||
106 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); | ||
107 | break; | ||
108 | default: | ||
109 | BUG(); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | ||
114 | struct interrupt_info *inti) | ||
115 | { | ||
116 | const unsigned short table[] = { 2, 4, 4, 6 }; | ||
117 | int rc, exception = 0; | ||
118 | |||
119 | switch (inti->type) { | ||
120 | case KVM_S390_INT_EMERGENCY: | ||
121 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); | ||
122 | vcpu->stat.deliver_emergency_signal++; | ||
123 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); | ||
124 | if (rc == -EFAULT) | ||
125 | exception = 1; | ||
126 | |||
127 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
128 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
129 | if (rc == -EFAULT) | ||
130 | exception = 1; | ||
131 | |||
132 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
133 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
134 | if (rc == -EFAULT) | ||
135 | exception = 1; | ||
136 | break; | ||
137 | |||
138 | case KVM_S390_INT_SERVICE: | ||
139 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", | ||
140 | inti->ext.ext_params); | ||
141 | vcpu->stat.deliver_service_signal++; | ||
142 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); | ||
143 | if (rc == -EFAULT) | ||
144 | exception = 1; | ||
145 | |||
146 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
147 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
148 | if (rc == -EFAULT) | ||
149 | exception = 1; | ||
150 | |||
151 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
152 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
153 | if (rc == -EFAULT) | ||
154 | exception = 1; | ||
155 | |||
156 | rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); | ||
157 | if (rc == -EFAULT) | ||
158 | exception = 1; | ||
159 | break; | ||
160 | |||
161 | case KVM_S390_INT_VIRTIO: | ||
162 | VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%lx", | ||
163 | inti->ext.ext_params, inti->ext.ext_params2); | ||
164 | vcpu->stat.deliver_virtio_interrupt++; | ||
165 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); | ||
166 | if (rc == -EFAULT) | ||
167 | exception = 1; | ||
168 | |||
169 | rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00); | ||
170 | if (rc == -EFAULT) | ||
171 | exception = 1; | ||
172 | |||
173 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
174 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
175 | if (rc == -EFAULT) | ||
176 | exception = 1; | ||
177 | |||
178 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
179 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
180 | if (rc == -EFAULT) | ||
181 | exception = 1; | ||
182 | |||
183 | rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params); | ||
184 | if (rc == -EFAULT) | ||
185 | exception = 1; | ||
186 | |||
187 | rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM, | ||
188 | inti->ext.ext_params2); | ||
189 | if (rc == -EFAULT) | ||
190 | exception = 1; | ||
191 | break; | ||
192 | |||
193 | case KVM_S390_SIGP_STOP: | ||
194 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); | ||
195 | vcpu->stat.deliver_stop_signal++; | ||
196 | __set_intercept_indicator(vcpu, inti); | ||
197 | break; | ||
198 | |||
199 | case KVM_S390_SIGP_SET_PREFIX: | ||
200 | VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", | ||
201 | inti->prefix.address); | ||
202 | vcpu->stat.deliver_prefix_signal++; | ||
203 | vcpu->arch.sie_block->prefix = inti->prefix.address; | ||
204 | vcpu->arch.sie_block->ihcpu = 0xffff; | ||
205 | break; | ||
206 | |||
207 | case KVM_S390_RESTART: | ||
208 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); | ||
209 | vcpu->stat.deliver_restart_signal++; | ||
210 | rc = copy_to_guest(vcpu, offsetof(struct _lowcore, | ||
211 | restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
212 | if (rc == -EFAULT) | ||
213 | exception = 1; | ||
214 | |||
215 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
216 | offsetof(struct _lowcore, restart_psw), sizeof(psw_t)); | ||
217 | if (rc == -EFAULT) | ||
218 | exception = 1; | ||
219 | break; | ||
220 | |||
221 | case KVM_S390_PROGRAM_INT: | ||
222 | VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x", | ||
223 | inti->pgm.code, | ||
224 | table[vcpu->arch.sie_block->ipa >> 14]); | ||
225 | vcpu->stat.deliver_program_int++; | ||
226 | rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); | ||
227 | if (rc == -EFAULT) | ||
228 | exception = 1; | ||
229 | |||
230 | rc = put_guest_u16(vcpu, __LC_PGM_ILC, | ||
231 | table[vcpu->arch.sie_block->ipa >> 14]); | ||
232 | if (rc == -EFAULT) | ||
233 | exception = 1; | ||
234 | |||
235 | rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW, | ||
236 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
237 | if (rc == -EFAULT) | ||
238 | exception = 1; | ||
239 | |||
240 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
241 | __LC_PGM_NEW_PSW, sizeof(psw_t)); | ||
242 | if (rc == -EFAULT) | ||
243 | exception = 1; | ||
244 | break; | ||
245 | |||
246 | default: | ||
247 | BUG(); | ||
248 | } | ||
249 | |||
250 | if (exception) { | ||
251 | VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" | ||
252 | " interrupt"); | ||
253 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
254 | if (inti->type == KVM_S390_PROGRAM_INT) { | ||
255 | printk(KERN_WARNING "kvm: recursive program check\n"); | ||
256 | BUG(); | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu) | ||
262 | { | ||
263 | int rc, exception = 0; | ||
264 | |||
265 | if (psw_extint_disabled(vcpu)) | ||
266 | return 0; | ||
267 | if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul)) | ||
268 | return 0; | ||
269 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004); | ||
270 | if (rc == -EFAULT) | ||
271 | exception = 1; | ||
272 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
273 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
274 | if (rc == -EFAULT) | ||
275 | exception = 1; | ||
276 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
277 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
278 | if (rc == -EFAULT) | ||
279 | exception = 1; | ||
280 | |||
281 | if (exception) { | ||
282 | VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \ | ||
283 | " ckc interrupt"); | ||
284 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | return 1; | ||
289 | } | ||
290 | |||
291 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) | ||
292 | { | ||
293 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
294 | struct float_interrupt *fi = vcpu->arch.local_int.float_int; | ||
295 | struct interrupt_info *inti; | ||
296 | int rc = 0; | ||
297 | |||
298 | if (atomic_read(&li->active)) { | ||
299 | spin_lock_bh(&li->lock); | ||
300 | list_for_each_entry(inti, &li->list, list) | ||
301 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
302 | rc = 1; | ||
303 | break; | ||
304 | } | ||
305 | spin_unlock_bh(&li->lock); | ||
306 | } | ||
307 | |||
308 | if ((!rc) && atomic_read(&fi->active)) { | ||
309 | spin_lock_bh(&fi->lock); | ||
310 | list_for_each_entry(inti, &fi->list, list) | ||
311 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
312 | rc = 1; | ||
313 | break; | ||
314 | } | ||
315 | spin_unlock_bh(&fi->lock); | ||
316 | } | ||
317 | |||
318 | if ((!rc) && (vcpu->arch.sie_block->ckc < | ||
319 | get_clock() + vcpu->arch.sie_block->epoch)) { | ||
320 | if ((!psw_extint_disabled(vcpu)) && | ||
321 | (vcpu->arch.sie_block->gcr[0] & 0x800ul)) | ||
322 | rc = 1; | ||
323 | } | ||
324 | |||
325 | return rc; | ||
326 | } | ||
327 | |||
328 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) | ||
329 | { | ||
330 | u64 now, sltime; | ||
331 | DECLARE_WAITQUEUE(wait, current); | ||
332 | |||
333 | vcpu->stat.exit_wait_state++; | ||
334 | if (kvm_cpu_has_interrupt(vcpu)) | ||
335 | return 0; | ||
336 | |||
337 | if (psw_interrupts_disabled(vcpu)) { | ||
338 | VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); | ||
339 | __unset_cpu_idle(vcpu); | ||
340 | return -ENOTSUPP; /* disabled wait */ | ||
341 | } | ||
342 | |||
343 | if (psw_extint_disabled(vcpu) || | ||
344 | (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) { | ||
345 | VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); | ||
346 | goto no_timer; | ||
347 | } | ||
348 | |||
349 | now = get_clock() + vcpu->arch.sie_block->epoch; | ||
350 | if (vcpu->arch.sie_block->ckc < now) { | ||
351 | __unset_cpu_idle(vcpu); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1; | ||
356 | |||
357 | vcpu->arch.ckc_timer.expires = jiffies + sltime; | ||
358 | |||
359 | add_timer(&vcpu->arch.ckc_timer); | ||
360 | VCPU_EVENT(vcpu, 5, "enabled wait timer:%lx jiffies", sltime); | ||
361 | no_timer: | ||
362 | spin_lock_bh(&vcpu->arch.local_int.float_int->lock); | ||
363 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
364 | __set_cpu_idle(vcpu); | ||
365 | vcpu->arch.local_int.timer_due = 0; | ||
366 | add_wait_queue(&vcpu->arch.local_int.wq, &wait); | ||
367 | while (list_empty(&vcpu->arch.local_int.list) && | ||
368 | list_empty(&vcpu->arch.local_int.float_int->list) && | ||
369 | (!vcpu->arch.local_int.timer_due) && | ||
370 | !signal_pending(current)) { | ||
371 | set_current_state(TASK_INTERRUPTIBLE); | ||
372 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
373 | spin_unlock_bh(&vcpu->arch.local_int.float_int->lock); | ||
374 | vcpu_put(vcpu); | ||
375 | schedule(); | ||
376 | vcpu_load(vcpu); | ||
377 | spin_lock_bh(&vcpu->arch.local_int.float_int->lock); | ||
378 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
379 | } | ||
380 | __unset_cpu_idle(vcpu); | ||
381 | __set_current_state(TASK_RUNNING); | ||
382 | remove_wait_queue(&vcpu->wq, &wait); | ||
383 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
384 | spin_unlock_bh(&vcpu->arch.local_int.float_int->lock); | ||
385 | del_timer(&vcpu->arch.ckc_timer); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | void kvm_s390_idle_wakeup(unsigned long data) | ||
390 | { | ||
391 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; | ||
392 | |||
393 | spin_lock_bh(&vcpu->arch.local_int.lock); | ||
394 | vcpu->arch.local_int.timer_due = 1; | ||
395 | if (waitqueue_active(&vcpu->arch.local_int.wq)) | ||
396 | wake_up_interruptible(&vcpu->arch.local_int.wq); | ||
397 | spin_unlock_bh(&vcpu->arch.local_int.lock); | ||
398 | } | ||
399 | |||
400 | |||
401 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | ||
402 | { | ||
403 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
404 | struct float_interrupt *fi = vcpu->arch.local_int.float_int; | ||
405 | struct interrupt_info *n, *inti = NULL; | ||
406 | int deliver; | ||
407 | |||
408 | __reset_intercept_indicators(vcpu); | ||
409 | if (atomic_read(&li->active)) { | ||
410 | do { | ||
411 | deliver = 0; | ||
412 | spin_lock_bh(&li->lock); | ||
413 | list_for_each_entry_safe(inti, n, &li->list, list) { | ||
414 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
415 | list_del(&inti->list); | ||
416 | deliver = 1; | ||
417 | break; | ||
418 | } | ||
419 | __set_intercept_indicator(vcpu, inti); | ||
420 | } | ||
421 | if (list_empty(&li->list)) | ||
422 | atomic_set(&li->active, 0); | ||
423 | spin_unlock_bh(&li->lock); | ||
424 | if (deliver) { | ||
425 | __do_deliver_interrupt(vcpu, inti); | ||
426 | kfree(inti); | ||
427 | } | ||
428 | } while (deliver); | ||
429 | } | ||
430 | |||
431 | if ((vcpu->arch.sie_block->ckc < | ||
432 | get_clock() + vcpu->arch.sie_block->epoch)) | ||
433 | __try_deliver_ckc_interrupt(vcpu); | ||
434 | |||
435 | if (atomic_read(&fi->active)) { | ||
436 | do { | ||
437 | deliver = 0; | ||
438 | spin_lock_bh(&fi->lock); | ||
439 | list_for_each_entry_safe(inti, n, &fi->list, list) { | ||
440 | if (__interrupt_is_deliverable(vcpu, inti)) { | ||
441 | list_del(&inti->list); | ||
442 | deliver = 1; | ||
443 | break; | ||
444 | } | ||
445 | __set_intercept_indicator(vcpu, inti); | ||
446 | } | ||
447 | if (list_empty(&fi->list)) | ||
448 | atomic_set(&fi->active, 0); | ||
449 | spin_unlock_bh(&fi->lock); | ||
450 | if (deliver) { | ||
451 | __do_deliver_interrupt(vcpu, inti); | ||
452 | kfree(inti); | ||
453 | } | ||
454 | } while (deliver); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) | ||
459 | { | ||
460 | struct local_interrupt *li = &vcpu->arch.local_int; | ||
461 | struct interrupt_info *inti; | ||
462 | |||
463 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
464 | if (!inti) | ||
465 | return -ENOMEM; | ||
466 | |||
467 | inti->type = KVM_S390_PROGRAM_INT;; | ||
468 | inti->pgm.code = code; | ||
469 | |||
470 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); | ||
471 | spin_lock_bh(&li->lock); | ||
472 | list_add(&inti->list, &li->list); | ||
473 | atomic_set(&li->active, 1); | ||
474 | BUG_ON(waitqueue_active(&li->wq)); | ||
475 | spin_unlock_bh(&li->lock); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | int kvm_s390_inject_vm(struct kvm *kvm, | ||
480 | struct kvm_s390_interrupt *s390int) | ||
481 | { | ||
482 | struct local_interrupt *li; | ||
483 | struct float_interrupt *fi; | ||
484 | struct interrupt_info *inti; | ||
485 | int sigcpu; | ||
486 | |||
487 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
488 | if (!inti) | ||
489 | return -ENOMEM; | ||
490 | |||
491 | switch (s390int->type) { | ||
492 | case KVM_S390_INT_VIRTIO: | ||
493 | VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%lx", | ||
494 | s390int->parm, s390int->parm64); | ||
495 | inti->type = s390int->type; | ||
496 | inti->ext.ext_params = s390int->parm; | ||
497 | inti->ext.ext_params2 = s390int->parm64; | ||
498 | break; | ||
499 | case KVM_S390_INT_SERVICE: | ||
500 | VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm); | ||
501 | inti->type = s390int->type; | ||
502 | inti->ext.ext_params = s390int->parm; | ||
503 | break; | ||
504 | case KVM_S390_PROGRAM_INT: | ||
505 | case KVM_S390_SIGP_STOP: | ||
506 | case KVM_S390_INT_EMERGENCY: | ||
507 | default: | ||
508 | kfree(inti); | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | mutex_lock(&kvm->lock); | ||
513 | fi = &kvm->arch.float_int; | ||
514 | spin_lock_bh(&fi->lock); | ||
515 | list_add_tail(&inti->list, &fi->list); | ||
516 | atomic_set(&fi->active, 1); | ||
517 | sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); | ||
518 | if (sigcpu == KVM_MAX_VCPUS) { | ||
519 | do { | ||
520 | sigcpu = fi->next_rr_cpu++; | ||
521 | if (sigcpu == KVM_MAX_VCPUS) | ||
522 | sigcpu = fi->next_rr_cpu = 0; | ||
523 | } while (fi->local_int[sigcpu] == NULL); | ||
524 | } | ||
525 | li = fi->local_int[sigcpu]; | ||
526 | spin_lock_bh(&li->lock); | ||
527 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
528 | if (waitqueue_active(&li->wq)) | ||
529 | wake_up_interruptible(&li->wq); | ||
530 | spin_unlock_bh(&li->lock); | ||
531 | spin_unlock_bh(&fi->lock); | ||
532 | mutex_unlock(&kvm->lock); | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | ||
537 | struct kvm_s390_interrupt *s390int) | ||
538 | { | ||
539 | struct local_interrupt *li; | ||
540 | struct interrupt_info *inti; | ||
541 | |||
542 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
543 | if (!inti) | ||
544 | return -ENOMEM; | ||
545 | |||
546 | switch (s390int->type) { | ||
547 | case KVM_S390_PROGRAM_INT: | ||
548 | if (s390int->parm & 0xffff0000) { | ||
549 | kfree(inti); | ||
550 | return -EINVAL; | ||
551 | } | ||
552 | inti->type = s390int->type; | ||
553 | inti->pgm.code = s390int->parm; | ||
554 | VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)", | ||
555 | s390int->parm); | ||
556 | break; | ||
557 | case KVM_S390_SIGP_STOP: | ||
558 | case KVM_S390_RESTART: | ||
559 | case KVM_S390_SIGP_SET_PREFIX: | ||
560 | case KVM_S390_INT_EMERGENCY: | ||
561 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | ||
562 | inti->type = s390int->type; | ||
563 | break; | ||
564 | case KVM_S390_INT_VIRTIO: | ||
565 | case KVM_S390_INT_SERVICE: | ||
566 | default: | ||
567 | kfree(inti); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | mutex_lock(&vcpu->kvm->lock); | ||
572 | li = &vcpu->arch.local_int; | ||
573 | spin_lock_bh(&li->lock); | ||
574 | if (inti->type == KVM_S390_PROGRAM_INT) | ||
575 | list_add(&inti->list, &li->list); | ||
576 | else | ||
577 | list_add_tail(&inti->list, &li->list); | ||
578 | atomic_set(&li->active, 1); | ||
579 | if (inti->type == KVM_S390_SIGP_STOP) | ||
580 | li->action_bits |= ACTION_STOP_ON_STOP; | ||
581 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
582 | if (waitqueue_active(&li->wq)) | ||
583 | wake_up_interruptible(&vcpu->arch.local_int.wq); | ||
584 | spin_unlock_bh(&li->lock); | ||
585 | mutex_unlock(&vcpu->kvm->lock); | ||
586 | return 0; | ||
587 | } | ||
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index a906499214bb..5e3473c9a639 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/kvm_host.h> | 20 | #include <linux/kvm_host.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/timer.h> | ||
23 | #include <asm/lowcore.h> | 24 | #include <asm/lowcore.h> |
24 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
25 | 26 | ||
@@ -34,6 +35,19 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
34 | { "exit_stop_request", VCPU_STAT(exit_stop_request) }, | 35 | { "exit_stop_request", VCPU_STAT(exit_stop_request) }, |
35 | { "exit_external_request", VCPU_STAT(exit_external_request) }, | 36 | { "exit_external_request", VCPU_STAT(exit_external_request) }, |
36 | { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, | 37 | { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, |
38 | { "exit_instruction", VCPU_STAT(exit_instruction) }, | ||
39 | { "exit_program_interruption", VCPU_STAT(exit_program_interruption) }, | ||
40 | { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, | ||
41 | { "instruction_lctg", VCPU_STAT(instruction_lctg) }, | ||
42 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | ||
43 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | ||
44 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | ||
45 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, | ||
46 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, | ||
47 | { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, | ||
48 | { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, | ||
49 | { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, | ||
50 | { "exit_wait_state", VCPU_STAT(exit_wait_state) }, | ||
37 | { NULL } | 51 | { NULL } |
38 | }; | 52 | }; |
39 | 53 | ||
@@ -106,6 +120,15 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
106 | int r; | 120 | int r; |
107 | 121 | ||
108 | switch (ioctl) { | 122 | switch (ioctl) { |
123 | case KVM_S390_INTERRUPT: { | ||
124 | struct kvm_s390_interrupt s390int; | ||
125 | |||
126 | r = -EFAULT; | ||
127 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
128 | break; | ||
129 | r = kvm_s390_inject_vm(kvm, &s390int); | ||
130 | break; | ||
131 | } | ||
109 | default: | 132 | default: |
110 | r = -EINVAL; | 133 | r = -EINVAL; |
111 | } | 134 | } |
@@ -138,6 +161,9 @@ struct kvm *kvm_arch_create_vm(void) | |||
138 | if (!kvm->arch.dbf) | 161 | if (!kvm->arch.dbf) |
139 | goto out_nodbf; | 162 | goto out_nodbf; |
140 | 163 | ||
164 | spin_lock_init(&kvm->arch.float_int.lock); | ||
165 | INIT_LIST_HEAD(&kvm->arch.float_int.list); | ||
166 | |||
141 | debug_register_view(kvm->arch.dbf, &debug_sprintf_view); | 167 | debug_register_view(kvm->arch.dbf, &debug_sprintf_view); |
142 | VM_EVENT(kvm, 3, "%s", "vm created"); | 168 | VM_EVENT(kvm, 3, "%s", "vm created"); |
143 | 169 | ||
@@ -218,7 +244,8 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | |||
218 | vcpu->arch.sie_block->gmsor = 0x000000000000; | 244 | vcpu->arch.sie_block->gmsor = 0x000000000000; |
219 | vcpu->arch.sie_block->ecb = 2; | 245 | vcpu->arch.sie_block->ecb = 2; |
220 | vcpu->arch.sie_block->eca = 0xC1002001U; | 246 | vcpu->arch.sie_block->eca = 0xC1002001U; |
221 | 247 | setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, | |
248 | (unsigned long) vcpu); | ||
222 | return 0; | 249 | return 0; |
223 | } | 250 | } |
224 | 251 | ||
@@ -243,6 +270,14 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | |||
243 | vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); | 270 | vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); |
244 | vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; | 271 | vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; |
245 | 272 | ||
273 | spin_lock_init(&vcpu->arch.local_int.lock); | ||
274 | INIT_LIST_HEAD(&vcpu->arch.local_int.list); | ||
275 | vcpu->arch.local_int.float_int = &kvm->arch.float_int; | ||
276 | spin_lock_bh(&kvm->arch.float_int.lock); | ||
277 | kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int; | ||
278 | init_waitqueue_head(&vcpu->arch.local_int.wq); | ||
279 | spin_unlock_bh(&kvm->arch.float_int.lock); | ||
280 | |||
246 | rc = kvm_vcpu_init(vcpu, kvm, id); | 281 | rc = kvm_vcpu_init(vcpu, kvm, id); |
247 | if (rc) | 282 | if (rc) |
248 | goto out_free_cpu; | 283 | goto out_free_cpu; |
@@ -395,6 +430,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
395 | 430 | ||
396 | atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | 431 | atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); |
397 | 432 | ||
433 | BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL); | ||
434 | |||
398 | switch (kvm_run->exit_reason) { | 435 | switch (kvm_run->exit_reason) { |
399 | case KVM_EXIT_S390_SIEIC: | 436 | case KVM_EXIT_S390_SIEIC: |
400 | vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; | 437 | vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; |
@@ -410,8 +447,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
410 | might_sleep(); | 447 | might_sleep(); |
411 | 448 | ||
412 | do { | 449 | do { |
450 | kvm_s390_deliver_pending_interrupts(vcpu); | ||
413 | __vcpu_run(vcpu); | 451 | __vcpu_run(vcpu); |
414 | |||
415 | rc = kvm_handle_sie_intercept(vcpu); | 452 | rc = kvm_handle_sie_intercept(vcpu); |
416 | } while (!signal_pending(current) && !rc); | 453 | } while (!signal_pending(current) && !rc); |
417 | 454 | ||
@@ -538,6 +575,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
538 | void __user *argp = (void __user *)arg; | 575 | void __user *argp = (void __user *)arg; |
539 | 576 | ||
540 | switch (ioctl) { | 577 | switch (ioctl) { |
578 | case KVM_S390_INTERRUPT: { | ||
579 | struct kvm_s390_interrupt s390int; | ||
580 | |||
581 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
582 | return -EFAULT; | ||
583 | return kvm_s390_inject_vcpu(vcpu, &s390int); | ||
584 | } | ||
541 | case KVM_S390_STORE_STATUS: | 585 | case KVM_S390_STORE_STATUS: |
542 | return kvm_s390_vcpu_store_status(vcpu, arg); | 586 | return kvm_s390_vcpu_store_status(vcpu, arg); |
543 | case KVM_S390_SET_INITIAL_PSW: { | 587 | case KVM_S390_SET_INITIAL_PSW: { |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 5b82527b7f86..8df745bc08db 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #ifndef ARCH_S390_KVM_S390_H | 14 | #ifndef ARCH_S390_KVM_S390_H |
15 | #define ARCH_S390_KVM_S390_H | 15 | #define ARCH_S390_KVM_S390_H |
16 | 16 | ||
17 | #include <linux/kvm.h> | ||
17 | #include <linux/kvm_host.h> | 18 | #include <linux/kvm_host.h> |
18 | 19 | ||
19 | typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); | 20 | typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu); |
@@ -33,4 +34,18 @@ do { \ | |||
33 | d_vcpu->arch.sie_block->gpsw.mask, d_vcpu->arch.sie_block->gpsw.addr,\ | 34 | d_vcpu->arch.sie_block->gpsw.mask, d_vcpu->arch.sie_block->gpsw.addr,\ |
34 | d_args); \ | 35 | d_args); \ |
35 | } while (0) | 36 | } while (0) |
37 | |||
38 | static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu) | ||
39 | { | ||
40 | return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT; | ||
41 | } | ||
42 | |||
43 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); | ||
44 | void kvm_s390_idle_wakeup(unsigned long data); | ||
45 | void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); | ||
46 | int kvm_s390_inject_vm(struct kvm *kvm, | ||
47 | struct kvm_s390_interrupt *s390int); | ||
48 | int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | ||
49 | struct kvm_s390_interrupt *s390int); | ||
50 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); | ||
36 | #endif | 51 | #endif |