diff options
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 6 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 110 |
2 files changed, 107 insertions, 9 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index b8c808192893..5e5a14db8c21 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -102,6 +102,12 @@ struct kvm_s390_sie_block { | |||
102 | #define ICTL_RRBE 0x00001000 | 102 | #define ICTL_RRBE 0x00001000 |
103 | __u32 ictl; /* 0x0048 */ | 103 | __u32 ictl; /* 0x0048 */ |
104 | __u32 eca; /* 0x004c */ | 104 | __u32 eca; /* 0x004c */ |
105 | #define ICPT_INST 0x04 | ||
106 | #define ICPT_PROGI 0x08 | ||
107 | #define ICPT_INSTPROGI 0x0C | ||
108 | #define ICPT_OPEREXC 0x2C | ||
109 | #define ICPT_PARTEXEC 0x38 | ||
110 | #define ICPT_IOINST 0x40 | ||
105 | __u8 icptcode; /* 0x0050 */ | 111 | __u8 icptcode; /* 0x0050 */ |
106 | __u8 reserved51; /* 0x0051 */ | 112 | __u8 reserved51; /* 0x0051 */ |
107 | __u16 ihcpu; /* 0x0052 */ | 113 | __u16 ihcpu; /* 0x0052 */ |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 1c74bb92329b..c49b4d4d310a 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -174,6 +174,106 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | |||
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | static int __deliver_prog_irq(struct kvm_vcpu *vcpu, | ||
178 | struct kvm_s390_pgm_info *pgm_info) | ||
179 | { | ||
180 | const unsigned short table[] = { 2, 4, 4, 6 }; | ||
181 | int rc = 0; | ||
182 | |||
183 | switch (pgm_info->code & ~PGM_PER) { | ||
184 | case PGM_AFX_TRANSLATION: | ||
185 | case PGM_ASX_TRANSLATION: | ||
186 | case PGM_EX_TRANSLATION: | ||
187 | case PGM_LFX_TRANSLATION: | ||
188 | case PGM_LSTE_SEQUENCE: | ||
189 | case PGM_LSX_TRANSLATION: | ||
190 | case PGM_LX_TRANSLATION: | ||
191 | case PGM_PRIMARY_AUTHORITY: | ||
192 | case PGM_SECONDARY_AUTHORITY: | ||
193 | case PGM_SPACE_SWITCH: | ||
194 | rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, | ||
195 | (u64 *)__LC_TRANS_EXC_CODE); | ||
196 | break; | ||
197 | case PGM_ALEN_TRANSLATION: | ||
198 | case PGM_ALE_SEQUENCE: | ||
199 | case PGM_ASTE_INSTANCE: | ||
200 | case PGM_ASTE_SEQUENCE: | ||
201 | case PGM_ASTE_VALIDITY: | ||
202 | case PGM_EXTENDED_AUTHORITY: | ||
203 | rc = put_guest_lc(vcpu, pgm_info->exc_access_id, | ||
204 | (u8 *)__LC_EXC_ACCESS_ID); | ||
205 | break; | ||
206 | case PGM_ASCE_TYPE: | ||
207 | case PGM_PAGE_TRANSLATION: | ||
208 | case PGM_REGION_FIRST_TRANS: | ||
209 | case PGM_REGION_SECOND_TRANS: | ||
210 | case PGM_REGION_THIRD_TRANS: | ||
211 | case PGM_SEGMENT_TRANSLATION: | ||
212 | rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, | ||
213 | (u64 *)__LC_TRANS_EXC_CODE); | ||
214 | rc |= put_guest_lc(vcpu, pgm_info->exc_access_id, | ||
215 | (u8 *)__LC_EXC_ACCESS_ID); | ||
216 | rc |= put_guest_lc(vcpu, pgm_info->op_access_id, | ||
217 | (u8 *)__LC_OP_ACCESS_ID); | ||
218 | break; | ||
219 | case PGM_MONITOR: | ||
220 | rc = put_guest_lc(vcpu, pgm_info->mon_class_nr, | ||
221 | (u64 *)__LC_MON_CLASS_NR); | ||
222 | rc |= put_guest_lc(vcpu, pgm_info->mon_code, | ||
223 | (u64 *)__LC_MON_CODE); | ||
224 | break; | ||
225 | case PGM_DATA: | ||
226 | rc = put_guest_lc(vcpu, pgm_info->data_exc_code, | ||
227 | (u32 *)__LC_DATA_EXC_CODE); | ||
228 | break; | ||
229 | case PGM_PROTECTION: | ||
230 | rc = put_guest_lc(vcpu, pgm_info->trans_exc_code, | ||
231 | (u64 *)__LC_TRANS_EXC_CODE); | ||
232 | rc |= put_guest_lc(vcpu, pgm_info->exc_access_id, | ||
233 | (u8 *)__LC_EXC_ACCESS_ID); | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | if (pgm_info->code & PGM_PER) { | ||
238 | rc |= put_guest_lc(vcpu, pgm_info->per_code, | ||
239 | (u8 *) __LC_PER_CODE); | ||
240 | rc |= put_guest_lc(vcpu, pgm_info->per_atmid, | ||
241 | (u8 *)__LC_PER_ATMID); | ||
242 | rc |= put_guest_lc(vcpu, pgm_info->per_address, | ||
243 | (u64 *) __LC_PER_ADDRESS); | ||
244 | rc |= put_guest_lc(vcpu, pgm_info->per_access_id, | ||
245 | (u8 *) __LC_PER_ACCESS_ID); | ||
246 | } | ||
247 | |||
248 | switch (vcpu->arch.sie_block->icptcode) { | ||
249 | case ICPT_INST: | ||
250 | case ICPT_INSTPROGI: | ||
251 | case ICPT_OPEREXC: | ||
252 | case ICPT_PARTEXEC: | ||
253 | case ICPT_IOINST: | ||
254 | /* last instruction only stored for these icptcodes */ | ||
255 | rc |= put_guest_lc(vcpu, table[vcpu->arch.sie_block->ipa >> 14], | ||
256 | (u16 *) __LC_PGM_ILC); | ||
257 | break; | ||
258 | case ICPT_PROGI: | ||
259 | rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->pgmilc, | ||
260 | (u16 *) __LC_PGM_ILC); | ||
261 | break; | ||
262 | default: | ||
263 | rc |= put_guest_lc(vcpu, 0, | ||
264 | (u16 *) __LC_PGM_ILC); | ||
265 | } | ||
266 | |||
267 | rc |= put_guest_lc(vcpu, pgm_info->code, | ||
268 | (u16 *)__LC_PGM_INT_CODE); | ||
269 | rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW, | ||
270 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
271 | rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW, | ||
272 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
273 | |||
274 | return rc; | ||
275 | } | ||
276 | |||
177 | static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | 277 | static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, |
178 | struct kvm_s390_interrupt_info *inti) | 278 | struct kvm_s390_interrupt_info *inti) |
179 | { | 279 | { |
@@ -305,15 +405,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | |||
305 | vcpu->stat.deliver_program_int++; | 405 | vcpu->stat.deliver_program_int++; |
306 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, | 406 | trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
307 | inti->pgm.code, 0); | 407 | inti->pgm.code, 0); |
308 | rc = put_guest_lc(vcpu, inti->pgm.code, | 408 | rc = __deliver_prog_irq(vcpu, &inti->pgm); |
309 | (u16 __user *)__LC_PGM_INT_CODE); | ||
310 | rc |= put_guest_lc(vcpu, table[vcpu->arch.sie_block->ipa >> 14], | ||
311 | (u16 __user *)__LC_PGM_ILC); | ||
312 | rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW, | ||
313 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
314 | rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW, | ||
315 | &vcpu->arch.sie_block->gpsw, | ||
316 | sizeof(psw_t)); | ||
317 | break; | 409 | break; |
318 | 410 | ||
319 | case KVM_S390_MCHK: | 411 | case KVM_S390_MCHK: |