1 /* 2 * QEMU S/390 Interrupt support 3 * 4 * Copyright IBM Corp. 2012, 2014 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 7 * option) any later version. See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/log.h" 12 #include "cpu.h" 13 #include "kvm_s390x.h" 14 #include "internal.h" 15 #include "exec/exec-all.h" 16 #include "sysemu/kvm.h" 17 #include "hw/s390x/ioinst.h" 18 19 /* Ensure to exit the TB after this call! */ 20 void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) 21 { 22 CPUState *cs = CPU(s390_env_get_cpu(env)); 23 24 cs->exception_index = EXCP_PGM; 25 env->int_pgm_code = code; 26 env->int_pgm_ilen = ilen; 27 } 28 29 static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code, 30 int ilen) 31 { 32 #ifdef CONFIG_TCG 33 trigger_pgm_exception(env, code, ilen); 34 cpu_loop_exit(CPU(s390_env_get_cpu(env))); 35 #else 36 g_assert_not_reached(); 37 #endif 38 } 39 40 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 41 { 42 S390CPU *cpu = s390_env_get_cpu(env); 43 44 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 45 env->psw.addr); 46 47 if (kvm_enabled()) { 48 kvm_s390_program_interrupt(cpu, code); 49 } else if (tcg_enabled()) { 50 tcg_s390_program_interrupt(env, code, ilen); 51 } else { 52 g_assert_not_reached(); 53 } 54 } 55 56 #if !defined(CONFIG_USER_ONLY) 57 void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, 58 uint64_t param64) 59 { 60 CPUS390XState *env = &cpu->env; 61 62 if (env->ext_index == MAX_EXT_QUEUE - 1) { 63 /* ugh - can't queue anymore. Let's drop. */ 64 return; 65 } 66 67 env->ext_index++; 68 assert(env->ext_index < MAX_EXT_QUEUE); 69 70 env->ext_queue[env->ext_index].code = code; 71 env->ext_queue[env->ext_index].param = param; 72 env->ext_queue[env->ext_index].param64 = param64; 73 74 env->pending_int |= INTERRUPT_EXT; 75 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 76 } 77 78 static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 79 uint16_t subchannel_number, 80 uint32_t io_int_parm, uint32_t io_int_word) 81 { 82 CPUS390XState *env = &cpu->env; 83 int isc = IO_INT_WORD_ISC(io_int_word); 84 85 if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 86 /* ugh - can't queue anymore. Let's drop. */ 87 return; 88 } 89 90 env->io_index[isc]++; 91 assert(env->io_index[isc] < MAX_IO_QUEUE); 92 93 env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 94 env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 95 env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 96 env->io_queue[env->io_index[isc]][isc].word = io_int_word; 97 98 env->pending_int |= INTERRUPT_IO; 99 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 100 } 101 102 static void cpu_inject_crw_mchk(S390CPU *cpu) 103 { 104 CPUS390XState *env = &cpu->env; 105 106 if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 107 /* ugh - can't queue anymore. Let's drop. */ 108 return; 109 } 110 111 env->mchk_index++; 112 assert(env->mchk_index < MAX_MCHK_QUEUE); 113 114 env->mchk_queue[env->mchk_index].type = 1; 115 116 env->pending_int |= INTERRUPT_MCHK; 117 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 118 } 119 120 /* 121 * All of the following interrupts are floating, i.e. not per-vcpu. 122 * We just need a dummy cpustate in order to be able to inject in the 123 * non-kvm case. 124 */ 125 void s390_sclp_extint(uint32_t parm) 126 { 127 if (kvm_enabled()) { 128 kvm_s390_service_interrupt(parm); 129 } else { 130 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 131 132 cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); 133 } 134 } 135 136 void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 137 uint32_t io_int_parm, uint32_t io_int_word) 138 { 139 if (kvm_enabled()) { 140 kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 141 io_int_word); 142 } else { 143 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 144 145 cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 146 io_int_word); 147 } 148 } 149 150 void s390_crw_mchk(void) 151 { 152 if (kvm_enabled()) { 153 kvm_s390_crw_mchk(); 154 } else { 155 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 156 157 cpu_inject_crw_mchk(dummy_cpu); 158 } 159 } 160 161 #endif 162