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 #include "tcg_s390x.h" 19 #if !defined(CONFIG_USER_ONLY) 20 #include "hw/s390x/s390_flic.h" 21 #endif 22 23 /* Ensure to exit the TB after this call! */ 24 void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) 25 { 26 CPUState *cs = CPU(s390_env_get_cpu(env)); 27 28 cs->exception_index = EXCP_PGM; 29 env->int_pgm_code = code; 30 env->int_pgm_ilen = ilen; 31 } 32 33 void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, 34 uintptr_t ra) 35 { 36 S390CPU *cpu = s390_env_get_cpu(env); 37 38 if (kvm_enabled()) { 39 kvm_s390_program_interrupt(cpu, code); 40 } else if (tcg_enabled()) { 41 tcg_s390_program_interrupt(env, code, ilen, ra); 42 } else { 43 g_assert_not_reached(); 44 } 45 } 46 47 #if !defined(CONFIG_USER_ONLY) 48 void cpu_inject_clock_comparator(S390CPU *cpu) 49 { 50 CPUS390XState *env = &cpu->env; 51 52 env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; 53 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 54 } 55 56 void cpu_inject_cpu_timer(S390CPU *cpu) 57 { 58 CPUS390XState *env = &cpu->env; 59 60 env->pending_int |= INTERRUPT_EXT_CPU_TIMER; 61 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 62 } 63 64 void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr) 65 { 66 CPUS390XState *env = &cpu->env; 67 68 g_assert(src_cpu_addr < S390_MAX_CPUS); 69 set_bit(src_cpu_addr, env->emergency_signals); 70 71 env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL; 72 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 73 } 74 75 int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr) 76 { 77 CPUS390XState *env = &cpu->env; 78 79 g_assert(src_cpu_addr < S390_MAX_CPUS); 80 if (env->pending_int & INTERRUPT_EXTERNAL_CALL) { 81 return -EBUSY; 82 } 83 env->external_call_addr = src_cpu_addr; 84 85 env->pending_int |= INTERRUPT_EXTERNAL_CALL; 86 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 87 return 0; 88 } 89 90 void cpu_inject_restart(S390CPU *cpu) 91 { 92 CPUS390XState *env = &cpu->env; 93 94 if (kvm_enabled()) { 95 kvm_s390_restart_interrupt(cpu); 96 return; 97 } 98 99 env->pending_int |= INTERRUPT_RESTART; 100 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 101 } 102 103 void cpu_inject_stop(S390CPU *cpu) 104 { 105 CPUS390XState *env = &cpu->env; 106 107 if (kvm_enabled()) { 108 kvm_s390_stop_interrupt(cpu); 109 return; 110 } 111 112 env->pending_int |= INTERRUPT_STOP; 113 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 114 } 115 116 /* 117 * All of the following interrupts are floating, i.e. not per-vcpu. 118 * We just need a dummy cpustate in order to be able to inject in the 119 * non-kvm case. 120 */ 121 void s390_sclp_extint(uint32_t parm) 122 { 123 S390FLICState *fs = s390_get_flic(); 124 S390FLICStateClass *fsc = s390_get_flic_class(fs); 125 126 fsc->inject_service(fs, parm); 127 } 128 129 void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 130 uint32_t io_int_parm, uint32_t io_int_word) 131 { 132 S390FLICState *fs = s390_get_flic(); 133 S390FLICStateClass *fsc = s390_get_flic_class(fs); 134 135 fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word); 136 } 137 138 void s390_crw_mchk(void) 139 { 140 S390FLICState *fs = s390_get_flic(); 141 S390FLICStateClass *fsc = s390_get_flic_class(fs); 142 143 fsc->inject_crw_mchk(fs); 144 } 145 146 bool s390_cpu_has_mcck_int(S390CPU *cpu) 147 { 148 QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 149 CPUS390XState *env = &cpu->env; 150 151 if (!(env->psw.mask & PSW_MASK_MCHECK)) { 152 return false; 153 } 154 155 /* for now we only support channel report machine checks (floating) */ 156 if (qemu_s390_flic_has_crw_mchk(flic) && 157 (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) { 158 return true; 159 } 160 161 return false; 162 } 163 164 bool s390_cpu_has_ext_int(S390CPU *cpu) 165 { 166 QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 167 CPUS390XState *env = &cpu->env; 168 169 if (!(env->psw.mask & PSW_MASK_EXT)) { 170 return false; 171 } 172 173 if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) && 174 (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) { 175 return true; 176 } 177 178 if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 179 (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 180 return true; 181 } 182 183 if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 184 (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 185 return true; 186 } 187 188 if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) && 189 (env->cregs[0] & CR0_CKC_SC)) { 190 return true; 191 } 192 193 if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) && 194 (env->cregs[0] & CR0_CPU_TIMER_SC)) { 195 return true; 196 } 197 198 if (qemu_s390_flic_has_service(flic) && 199 (env->cregs[0] & CR0_SERVICE_SC)) { 200 return true; 201 } 202 203 return false; 204 } 205 206 bool s390_cpu_has_io_int(S390CPU *cpu) 207 { 208 QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 209 CPUS390XState *env = &cpu->env; 210 211 if (!(env->psw.mask & PSW_MASK_IO)) { 212 return false; 213 } 214 215 return qemu_s390_flic_has_io(flic, env->cregs[6]); 216 } 217 218 bool s390_cpu_has_restart_int(S390CPU *cpu) 219 { 220 CPUS390XState *env = &cpu->env; 221 222 return env->pending_int & INTERRUPT_RESTART; 223 } 224 225 bool s390_cpu_has_stop_int(S390CPU *cpu) 226 { 227 CPUS390XState *env = &cpu->env; 228 229 return env->pending_int & INTERRUPT_STOP; 230 } 231 #endif 232 233 bool s390_cpu_has_int(S390CPU *cpu) 234 { 235 #ifndef CONFIG_USER_ONLY 236 if (!tcg_enabled()) { 237 return false; 238 } 239 return s390_cpu_has_mcck_int(cpu) || 240 s390_cpu_has_ext_int(cpu) || 241 s390_cpu_has_io_int(cpu) || 242 s390_cpu_has_restart_int(cpu) || 243 s390_cpu_has_stop_int(cpu); 244 #else 245 return false; 246 #endif 247 } 248