aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/kvm_host.h6
-rw-r--r--arch/s390/kvm/interrupt.c110
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
177static 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
177static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, 277static 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: