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