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 static void cpu_inject_service(S390CPU *cpu, uint32_t param) 58 { 59 CPUS390XState *env = &cpu->env; 60 61 /* multiplexing is good enough for sclp - kvm does it internally as well*/ 62 env->service_param |= param; 63 64 env->pending_int |= INTERRUPT_EXT_SERVICE; 65 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 66 } 67 68 void cpu_inject_clock_comparator(S390CPU *cpu) 69 { 70 CPUS390XState *env = &cpu->env; 71 72 env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; 73 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 74 } 75 76 void cpu_inject_cpu_timer(S390CPU *cpu) 77 { 78 CPUS390XState *env = &cpu->env; 79 80 env->pending_int |= INTERRUPT_EXT_CPU_TIMER; 81 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 82 } 83 84 void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr) 85 { 86 CPUS390XState *env = &cpu->env; 87 88 g_assert(src_cpu_addr < S390_MAX_CPUS); 89 set_bit(src_cpu_addr, env->emergency_signals); 90 91 env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL; 92 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 93 } 94 95 int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr) 96 { 97 CPUS390XState *env = &cpu->env; 98 99 g_assert(src_cpu_addr < S390_MAX_CPUS); 100 if (env->pending_int & INTERRUPT_EXTERNAL_CALL) { 101 return -EBUSY; 102 } 103 env->external_call_addr = src_cpu_addr; 104 105 env->pending_int |= INTERRUPT_EXTERNAL_CALL; 106 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 107 return 0; 108 } 109 110 void cpu_inject_restart(S390CPU *cpu) 111 { 112 CPUS390XState *env = &cpu->env; 113 114 if (kvm_enabled()) { 115 kvm_s390_restart_interrupt(cpu); 116 return; 117 } 118 119 env->pending_int |= INTERRUPT_RESTART; 120 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 121 } 122 123 void cpu_inject_stop(S390CPU *cpu) 124 { 125 CPUS390XState *env = &cpu->env; 126 127 if (kvm_enabled()) { 128 kvm_s390_stop_interrupt(cpu); 129 return; 130 } 131 132 env->pending_int |= INTERRUPT_STOP; 133 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 134 } 135 136 static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 137 uint16_t subchannel_number, 138 uint32_t io_int_parm, uint32_t io_int_word) 139 { 140 CPUS390XState *env = &cpu->env; 141 int isc = IO_INT_WORD_ISC(io_int_word); 142 143 if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 144 /* ugh - can't queue anymore. Let's drop. */ 145 return; 146 } 147 148 env->io_index[isc]++; 149 assert(env->io_index[isc] < MAX_IO_QUEUE); 150 151 env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 152 env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 153 env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 154 env->io_queue[env->io_index[isc]][isc].word = io_int_word; 155 156 env->pending_int |= INTERRUPT_IO; 157 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 158 } 159 160 static void cpu_inject_crw_mchk(S390CPU *cpu) 161 { 162 CPUS390XState *env = &cpu->env; 163 164 if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 165 /* ugh - can't queue anymore. Let's drop. */ 166 return; 167 } 168 169 env->mchk_index++; 170 assert(env->mchk_index < MAX_MCHK_QUEUE); 171 172 env->mchk_queue[env->mchk_index].type = 1; 173 174 env->pending_int |= INTERRUPT_MCHK; 175 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 176 } 177 178 /* 179 * All of the following interrupts are floating, i.e. not per-vcpu. 180 * We just need a dummy cpustate in order to be able to inject in the 181 * non-kvm case. 182 */ 183 void s390_sclp_extint(uint32_t parm) 184 { 185 if (kvm_enabled()) { 186 kvm_s390_service_interrupt(parm); 187 } else { 188 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 189 190 cpu_inject_service(dummy_cpu, parm); 191 } 192 } 193 194 void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 195 uint32_t io_int_parm, uint32_t io_int_word) 196 { 197 if (kvm_enabled()) { 198 kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 199 io_int_word); 200 } else { 201 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 202 203 cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 204 io_int_word); 205 } 206 } 207 208 void s390_crw_mchk(void) 209 { 210 if (kvm_enabled()) { 211 kvm_s390_crw_mchk(); 212 } else { 213 S390CPU *dummy_cpu = s390_cpu_addr2state(0); 214 215 cpu_inject_crw_mchk(dummy_cpu); 216 } 217 } 218 219 bool s390_cpu_has_mcck_int(S390CPU *cpu) 220 { 221 CPUS390XState *env = &cpu->env; 222 223 if (!(env->psw.mask & PSW_MASK_MCHECK)) { 224 return false; 225 } 226 227 return env->pending_int & INTERRUPT_MCHK; 228 } 229 230 bool s390_cpu_has_ext_int(S390CPU *cpu) 231 { 232 CPUS390XState *env = &cpu->env; 233 234 if (!(env->psw.mask & PSW_MASK_EXT)) { 235 return false; 236 } 237 238 if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) && 239 (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) { 240 return true; 241 } 242 243 if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 244 (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 245 return true; 246 } 247 248 if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 249 (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 250 return true; 251 } 252 253 if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) && 254 (env->cregs[0] & CR0_CKC_SC)) { 255 return true; 256 } 257 258 if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) && 259 (env->cregs[0] & CR0_CPU_TIMER_SC)) { 260 return true; 261 } 262 263 if ((env->pending_int & INTERRUPT_EXT_SERVICE) && 264 (env->cregs[0] & CR0_SERVICE_SC)) { 265 return true; 266 } 267 268 return false; 269 } 270 271 bool s390_cpu_has_io_int(S390CPU *cpu) 272 { 273 CPUS390XState *env = &cpu->env; 274 275 if (!(env->psw.mask & PSW_MASK_IO)) { 276 return false; 277 } 278 279 return env->pending_int & INTERRUPT_IO; 280 } 281 282 bool s390_cpu_has_restart_int(S390CPU *cpu) 283 { 284 CPUS390XState *env = &cpu->env; 285 286 return env->pending_int & INTERRUPT_RESTART; 287 } 288 289 bool s390_cpu_has_stop_int(S390CPU *cpu) 290 { 291 CPUS390XState *env = &cpu->env; 292 293 return env->pending_int & INTERRUPT_STOP; 294 } 295 #endif 296 297 bool s390_cpu_has_int(S390CPU *cpu) 298 { 299 #ifndef CONFIG_USER_ONLY 300 if (!tcg_enabled()) { 301 return false; 302 } 303 return s390_cpu_has_mcck_int(cpu) || 304 s390_cpu_has_ext_int(cpu) || 305 s390_cpu_has_io_int(cpu) || 306 s390_cpu_has_restart_int(cpu) || 307 s390_cpu_has_stop_int(cpu); 308 #else 309 return false; 310 #endif 311 } 312