xref: /kvm-unit-tests/lib/s390x/interrupt.c (revision 6ca8c283190847bd2ff648232f98f70e4e6d3d0d)
1 /*
2  * s390x interrupt handling
3  *
4  * Copyright (c) 2017 Red Hat Inc
5  *
6  * Authors:
7  *  David Hildenbrand <david@redhat.com>
8  *
9  * This code is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Library General Public License version 2.
11  */
12 #include <libcflat.h>
13 #include <asm/interrupt.h>
14 #include <asm/barrier.h>
15 
16 static bool pgm_int_expected;
17 static struct lowcore *lc;
18 
19 void expect_pgm_int(void)
20 {
21 	pgm_int_expected = true;
22 	lc->pgm_int_code = 0;
23 	mb();
24 }
25 
26 uint16_t clear_pgm_int(void)
27 {
28 	uint16_t code;
29 
30 	mb();
31 	code = lc->pgm_int_code;
32 	lc->pgm_int_code = 0;
33 	pgm_int_expected = false;
34 	return code;
35 }
36 
37 void check_pgm_int_code(uint16_t code)
38 {
39 	mb();
40 	report("Program interrupt: expected(%d) == received(%d)",
41 	       code == lc->pgm_int_code, code, lc->pgm_int_code);
42 }
43 
44 static void fixup_pgm_int(void)
45 {
46 	switch (lc->pgm_int_code) {
47 	case PGM_INT_CODE_PRIVILEGED_OPERATION:
48 		/* Normal operation is in supervisor state, so this exception
49 		 * was produced intentionally and we should return to the
50 		 * supervisor state.
51 		 */
52 		lc->pgm_old_psw.mask &= ~PSW_MASK_PSTATE;
53 		break;
54 	case PGM_INT_CODE_PROTECTION:
55 		/* Handling for iep.c test case. */
56 		if (lc->trans_exc_id & 0x80UL && lc->trans_exc_id & 0x04UL &&
57 		    !(lc->trans_exc_id & 0x08UL))
58 			lc->pgm_old_psw.addr = lc->sw_int_grs[14];
59 		break;
60 	case PGM_INT_CODE_SEGMENT_TRANSLATION:
61 	case PGM_INT_CODE_PAGE_TRANSLATION:
62 	case PGM_INT_CODE_TRACE_TABLE:
63 	case PGM_INT_CODE_AFX_TRANSLATION:
64 	case PGM_INT_CODE_ASX_TRANSLATION:
65 	case PGM_INT_CODE_LX_TRANSLATION:
66 	case PGM_INT_CODE_EX_TRANSLATION:
67 	case PGM_INT_CODE_PRIMARY_AUTHORITY:
68 	case PGM_INT_CODE_SECONDARY_AUTHORITY:
69 	case PGM_INT_CODE_LFX_TRANSLATION:
70 	case PGM_INT_CODE_LSX_TRANSLATION:
71 	case PGM_INT_CODE_ALEN_TRANSLATION:
72 	case PGM_INT_CODE_ALE_SEQUENCE:
73 	case PGM_INT_CODE_ASTE_VALIDITY:
74 	case PGM_INT_CODE_ASTE_SEQUENCE:
75 	case PGM_INT_CODE_EXTENDED_AUTHORITY:
76 	case PGM_INT_CODE_LSTE_SEQUENCE:
77 	case PGM_INT_CODE_ASTE_INSTANCE:
78 	case PGM_INT_CODE_STACK_FULL:
79 	case PGM_INT_CODE_STACK_EMPTY:
80 	case PGM_INT_CODE_STACK_SPECIFICATION:
81 	case PGM_INT_CODE_STACK_TYPE:
82 	case PGM_INT_CODE_STACK_OPERATION:
83 	case PGM_INT_CODE_ASCE_TYPE:
84 	case PGM_INT_CODE_REGION_FIRST_TRANS:
85 	case PGM_INT_CODE_REGION_SECOND_TRANS:
86 	case PGM_INT_CODE_REGION_THIRD_TRANS:
87 	case PGM_INT_CODE_PER:
88 	case PGM_INT_CODE_CRYPTO_OPERATION:
89 		/* The interrupt was nullified, the old PSW points at the
90 		 * responsible instruction. Forward the PSW so we don't loop.
91 		 */
92 		lc->pgm_old_psw.addr += lc->pgm_int_id;
93 	}
94 	/* suppressed/terminated/completed point already at the next address */
95 }
96 
97 void handle_pgm_int(void)
98 {
99 	if (!pgm_int_expected)
100 		report_abort("Unexpected program interrupt: %d at %#lx, ilen %d\n",
101 			     lc->pgm_int_code, lc->pgm_old_psw.addr,
102 			     lc->pgm_int_id);
103 
104 	pgm_int_expected = false;
105 	fixup_pgm_int();
106 }
107 
108 void handle_ext_int(void)
109 {
110 	report_abort("Unexpected external call interrupt: at %#lx",
111 		     lc->ext_old_psw.addr);
112 }
113 
114 void handle_mcck_int(void)
115 {
116 	report_abort("Unexpected machine check interrupt: at %#lx",
117 		     lc->mcck_old_psw.addr);
118 }
119 
120 void handle_io_int(void)
121 {
122 	report_abort("Unexpected io interrupt: at %#lx",
123 		     lc->io_old_psw.addr);
124 }
125 
126 void handle_svc_int(void)
127 {
128 	report_abort("Unexpected supervisor call interrupt: at %#lx",
129 		     lc->svc_old_psw.addr);
130 }
131