xref: /kvm-unit-tests/lib/s390x/interrupt.c (revision 3db880b678844124f87f5ec06b8ff26f89ad3305)
14da93626SDavid Hildenbrand /*
24da93626SDavid Hildenbrand  * s390x interrupt handling
34da93626SDavid Hildenbrand  *
44da93626SDavid Hildenbrand  * Copyright (c) 2017 Red Hat Inc
54da93626SDavid Hildenbrand  *
64da93626SDavid Hildenbrand  * Authors:
74da93626SDavid Hildenbrand  *  David Hildenbrand <david@redhat.com>
84da93626SDavid Hildenbrand  *
94da93626SDavid Hildenbrand  * This code is free software; you can redistribute it and/or modify it
104da93626SDavid Hildenbrand  * under the terms of the GNU Library General Public License version 2.
114da93626SDavid Hildenbrand  */
124da93626SDavid Hildenbrand #include <libcflat.h>
134da93626SDavid Hildenbrand #include <asm/interrupt.h>
144da93626SDavid Hildenbrand #include <asm/barrier.h>
154da93626SDavid Hildenbrand 
164da93626SDavid Hildenbrand static bool pgm_int_expected;
174da93626SDavid Hildenbrand static struct lowcore *lc;
184da93626SDavid Hildenbrand 
194da93626SDavid Hildenbrand void expect_pgm_int(void)
204da93626SDavid Hildenbrand {
214da93626SDavid Hildenbrand 	pgm_int_expected = true;
224da93626SDavid Hildenbrand 	lc->pgm_int_code = 0;
234da93626SDavid Hildenbrand 	mb();
244da93626SDavid Hildenbrand }
254da93626SDavid Hildenbrand 
26*3db880b6SDavid Hildenbrand uint16_t clear_pgm_int(void)
27*3db880b6SDavid Hildenbrand {
28*3db880b6SDavid Hildenbrand 	uint16_t code;
29*3db880b6SDavid Hildenbrand 
30*3db880b6SDavid Hildenbrand 	mb();
31*3db880b6SDavid Hildenbrand 	code = lc->pgm_int_code;
32*3db880b6SDavid Hildenbrand 	lc->pgm_int_code = 0;
33*3db880b6SDavid Hildenbrand 	pgm_int_expected = false;
34*3db880b6SDavid Hildenbrand 	return code;
35*3db880b6SDavid Hildenbrand }
36*3db880b6SDavid Hildenbrand 
374da93626SDavid Hildenbrand void check_pgm_int_code(uint16_t code)
384da93626SDavid Hildenbrand {
394da93626SDavid Hildenbrand 	mb();
404da93626SDavid Hildenbrand 	report("Program interrupt: expected(%d) == received(%d)",
414da93626SDavid Hildenbrand 	       code == lc->pgm_int_code, code, lc->pgm_int_code);
424da93626SDavid Hildenbrand }
434da93626SDavid Hildenbrand 
444da93626SDavid Hildenbrand static void fixup_pgm_int(void)
454da93626SDavid Hildenbrand {
464da93626SDavid Hildenbrand 	switch (lc->pgm_int_code) {
474da93626SDavid Hildenbrand 	case PGM_INT_CODE_SEGMENT_TRANSLATION:
484da93626SDavid Hildenbrand 	case PGM_INT_CODE_PAGE_TRANSLATION:
494da93626SDavid Hildenbrand 	case PGM_INT_CODE_TRACE_TABLE:
504da93626SDavid Hildenbrand 	case PGM_INT_CODE_AFX_TRANSLATION:
514da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASX_TRANSLATION:
524da93626SDavid Hildenbrand 	case PGM_INT_CODE_LX_TRANSLATION:
534da93626SDavid Hildenbrand 	case PGM_INT_CODE_EX_TRANSLATION:
544da93626SDavid Hildenbrand 	case PGM_INT_CODE_PRIMARY_AUTHORITY:
554da93626SDavid Hildenbrand 	case PGM_INT_CODE_SECONDARY_AUTHORITY:
564da93626SDavid Hildenbrand 	case PGM_INT_CODE_LFX_TRANSLATION:
574da93626SDavid Hildenbrand 	case PGM_INT_CODE_LSX_TRANSLATION:
584da93626SDavid Hildenbrand 	case PGM_INT_CODE_ALEN_TRANSLATION:
594da93626SDavid Hildenbrand 	case PGM_INT_CODE_ALE_SEQUENCE:
604da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_VALIDITY:
614da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_SEQUENCE:
624da93626SDavid Hildenbrand 	case PGM_INT_CODE_EXTENDED_AUTHORITY:
634da93626SDavid Hildenbrand 	case PGM_INT_CODE_LSTE_SEQUENCE:
644da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASTE_INSTANCE:
654da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_FULL:
664da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_EMPTY:
674da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_SPECIFICATION:
684da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_TYPE:
694da93626SDavid Hildenbrand 	case PGM_INT_CODE_STACK_OPERATION:
704da93626SDavid Hildenbrand 	case PGM_INT_CODE_ASCE_TYPE:
714da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_FIRST_TRANS:
724da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_SECOND_TRANS:
734da93626SDavid Hildenbrand 	case PGM_INT_CODE_REGION_THIRD_TRANS:
744da93626SDavid Hildenbrand 	case PGM_INT_CODE_PER:
754da93626SDavid Hildenbrand 	case PGM_INT_CODE_CRYPTO_OPERATION:
764da93626SDavid Hildenbrand 		/* The interrupt was nullified, the old PSW points at the
774da93626SDavid Hildenbrand 		 * responsible instruction. Forward the PSW so we don't loop.
784da93626SDavid Hildenbrand 		 */
794da93626SDavid Hildenbrand 		lc->pgm_old_psw.addr += lc->pgm_int_id;
804da93626SDavid Hildenbrand 	}
814da93626SDavid Hildenbrand 	/* suppressed/terminated/completed point already at the next address */
824da93626SDavid Hildenbrand }
834da93626SDavid Hildenbrand 
844da93626SDavid Hildenbrand void handle_pgm_int(void)
854da93626SDavid Hildenbrand {
864da93626SDavid Hildenbrand 	if (!pgm_int_expected)
874da93626SDavid Hildenbrand 		report_abort("Unexpected program interrupt: %d at %#lx, ilen %d\n",
884da93626SDavid Hildenbrand 			     lc->pgm_int_code, lc->pgm_old_psw.addr,
894da93626SDavid Hildenbrand 			     lc->pgm_int_id);
904da93626SDavid Hildenbrand 
914da93626SDavid Hildenbrand 	pgm_int_expected = false;
924da93626SDavid Hildenbrand 	fixup_pgm_int();
934da93626SDavid Hildenbrand }
94