xref: /kvm-unit-tests/lib/s390x/interrupt.c (revision 4da93626ac589ebc37e3edaa34c2b70b415688ae)
1*4da93626SDavid Hildenbrand /*
2*4da93626SDavid Hildenbrand  * s390x interrupt handling
3*4da93626SDavid Hildenbrand  *
4*4da93626SDavid Hildenbrand  * Copyright (c) 2017 Red Hat Inc
5*4da93626SDavid Hildenbrand  *
6*4da93626SDavid Hildenbrand  * Authors:
7*4da93626SDavid Hildenbrand  *  David Hildenbrand <david@redhat.com>
8*4da93626SDavid Hildenbrand  *
9*4da93626SDavid Hildenbrand  * This code is free software; you can redistribute it and/or modify it
10*4da93626SDavid Hildenbrand  * under the terms of the GNU Library General Public License version 2.
11*4da93626SDavid Hildenbrand  */
12*4da93626SDavid Hildenbrand #include <libcflat.h>
13*4da93626SDavid Hildenbrand #include <asm/interrupt.h>
14*4da93626SDavid Hildenbrand #include <asm/barrier.h>
15*4da93626SDavid Hildenbrand 
16*4da93626SDavid Hildenbrand static bool pgm_int_expected;
17*4da93626SDavid Hildenbrand static struct lowcore *lc;
18*4da93626SDavid Hildenbrand 
19*4da93626SDavid Hildenbrand void expect_pgm_int(void)
20*4da93626SDavid Hildenbrand {
21*4da93626SDavid Hildenbrand 	pgm_int_expected = true;
22*4da93626SDavid Hildenbrand 	lc->pgm_int_code = 0;
23*4da93626SDavid Hildenbrand 	mb();
24*4da93626SDavid Hildenbrand }
25*4da93626SDavid Hildenbrand 
26*4da93626SDavid Hildenbrand void check_pgm_int_code(uint16_t code)
27*4da93626SDavid Hildenbrand {
28*4da93626SDavid Hildenbrand 	mb();
29*4da93626SDavid Hildenbrand 	report("Program interrupt: expected(%d) == received(%d)",
30*4da93626SDavid Hildenbrand 	       code == lc->pgm_int_code, code, lc->pgm_int_code);
31*4da93626SDavid Hildenbrand }
32*4da93626SDavid Hildenbrand 
33*4da93626SDavid Hildenbrand static void fixup_pgm_int(void)
34*4da93626SDavid Hildenbrand {
35*4da93626SDavid Hildenbrand 	switch (lc->pgm_int_code) {
36*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_SEGMENT_TRANSLATION:
37*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_PAGE_TRANSLATION:
38*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_TRACE_TABLE:
39*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_AFX_TRANSLATION:
40*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASX_TRANSLATION:
41*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_LX_TRANSLATION:
42*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_EX_TRANSLATION:
43*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_PRIMARY_AUTHORITY:
44*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_SECONDARY_AUTHORITY:
45*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_LFX_TRANSLATION:
46*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_LSX_TRANSLATION:
47*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ALEN_TRANSLATION:
48*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ALE_SEQUENCE:
49*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_VALIDITY:
50*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_SEQUENCE:
51*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_EXTENDED_AUTHORITY:
52*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_LSTE_SEQUENCE:
53*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_INSTANCE:
54*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_FULL:
55*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_EMPTY:
56*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_SPECIFICATION:
57*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_TYPE:
58*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_OPERATION:
59*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASCE_TYPE:
60*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_FIRST_TRANS:
61*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_SECOND_TRANS:
62*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_THIRD_TRANS:
63*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_PER:
64*4da93626SDavid Hildenbrand 	case PGM_INT_CODE_CRYPTO_OPERATION:
65*4da93626SDavid Hildenbrand 		/* The interrupt was nullified, the old PSW points at the
66*4da93626SDavid Hildenbrand 		 * responsible instruction. Forward the PSW so we don't loop.
67*4da93626SDavid Hildenbrand 		 */
68*4da93626SDavid Hildenbrand 		lc->pgm_old_psw.addr += lc->pgm_int_id;
69*4da93626SDavid Hildenbrand 	}
70*4da93626SDavid Hildenbrand 	/* suppressed/terminated/completed point already at the next address */
71*4da93626SDavid Hildenbrand }
72*4da93626SDavid Hildenbrand 
73*4da93626SDavid Hildenbrand void handle_pgm_int(void)
74*4da93626SDavid Hildenbrand {
75*4da93626SDavid Hildenbrand 	if (!pgm_int_expected)
76*4da93626SDavid Hildenbrand 		report_abort("Unexpected program interrupt: %d at %#lx, ilen %d\n",
77*4da93626SDavid Hildenbrand 			     lc->pgm_int_code, lc->pgm_old_psw.addr,
78*4da93626SDavid Hildenbrand 			     lc->pgm_int_id);
79*4da93626SDavid Hildenbrand 
80*4da93626SDavid Hildenbrand 	pgm_int_expected = false;
81*4da93626SDavid Hildenbrand 	fixup_pgm_int();
82*4da93626SDavid Hildenbrand }
83