1000a1a38SChristian Borntraeger /* 2000a1a38SChristian Borntraeger * QEMU S/390 Interrupt support 3000a1a38SChristian Borntraeger * 479afc36dSCornelia Huck * Copyright IBM Corp. 2012, 2014 5000a1a38SChristian Borntraeger * 6000a1a38SChristian Borntraeger * This work is licensed under the terms of the GNU GPL, version 2 or (at your 7000a1a38SChristian Borntraeger * option) any later version. See the COPYING file in the top-level directory. 8000a1a38SChristian Borntraeger */ 9000a1a38SChristian Borntraeger 109615495aSPeter Maydell #include "qemu/osdep.h" 11e3cfd926SThomas Huth #include "qemu/log.h" 12000a1a38SChristian Borntraeger #include "cpu.h" 13f16bbb9bSDavid Hildenbrand #include "kvm_s390x.h" 144e58b838SDavid Hildenbrand #include "internal.h" 15e3cfd926SThomas Huth #include "exec/exec-all.h" 169c17d615SPaolo Bonzini #include "sysemu/kvm.h" 17bd3f16acSPaolo Bonzini #include "hw/s390x/ioinst.h" 18e6505d53SDavid Hildenbrand #if !defined(CONFIG_USER_ONLY) 19e6505d53SDavid Hildenbrand #include "hw/s390x/s390_flic.h" 20e6505d53SDavid Hildenbrand #endif 21bd3f16acSPaolo Bonzini 22e3cfd926SThomas Huth /* Ensure to exit the TB after this call! */ 23e3cfd926SThomas Huth void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) 24e3cfd926SThomas Huth { 25e3cfd926SThomas Huth CPUState *cs = CPU(s390_env_get_cpu(env)); 26e3cfd926SThomas Huth 27e3cfd926SThomas Huth cs->exception_index = EXCP_PGM; 28e3cfd926SThomas Huth env->int_pgm_code = code; 29e3cfd926SThomas Huth env->int_pgm_ilen = ilen; 30e3cfd926SThomas Huth } 31e3cfd926SThomas Huth 32e3cfd926SThomas Huth static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code, 3351dcdbd3SDavid Hildenbrand int ilen, uintptr_t ra) 34e3cfd926SThomas Huth { 35e3cfd926SThomas Huth #ifdef CONFIG_TCG 36e3cfd926SThomas Huth trigger_pgm_exception(env, code, ilen); 3751dcdbd3SDavid Hildenbrand cpu_loop_exit_restore(CPU(s390_env_get_cpu(env)), ra); 38e3cfd926SThomas Huth #else 39e3cfd926SThomas Huth g_assert_not_reached(); 40e3cfd926SThomas Huth #endif 41e3cfd926SThomas Huth } 42e3cfd926SThomas Huth 4351dcdbd3SDavid Hildenbrand void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, 4451dcdbd3SDavid Hildenbrand uintptr_t ra) 45e3cfd926SThomas Huth { 46e3cfd926SThomas Huth S390CPU *cpu = s390_env_get_cpu(env); 47e3cfd926SThomas Huth 48e3cfd926SThomas Huth qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 49e3cfd926SThomas Huth env->psw.addr); 50e3cfd926SThomas Huth 51e3cfd926SThomas Huth if (kvm_enabled()) { 52e3cfd926SThomas Huth kvm_s390_program_interrupt(cpu, code); 53e3cfd926SThomas Huth } else if (tcg_enabled()) { 5451dcdbd3SDavid Hildenbrand tcg_s390_program_interrupt(env, code, ilen, ra); 55e3cfd926SThomas Huth } else { 56e3cfd926SThomas Huth g_assert_not_reached(); 57e3cfd926SThomas Huth } 58e3cfd926SThomas Huth } 59e3cfd926SThomas Huth 60bd3f16acSPaolo Bonzini #if !defined(CONFIG_USER_ONLY) 616482b0ffSDavid Hildenbrand void cpu_inject_clock_comparator(S390CPU *cpu) 626482b0ffSDavid Hildenbrand { 636482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 646482b0ffSDavid Hildenbrand 656482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; 666482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 676482b0ffSDavid Hildenbrand } 686482b0ffSDavid Hildenbrand 696482b0ffSDavid Hildenbrand void cpu_inject_cpu_timer(S390CPU *cpu) 706482b0ffSDavid Hildenbrand { 716482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 726482b0ffSDavid Hildenbrand 736482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CPU_TIMER; 74bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 75bd3f16acSPaolo Bonzini } 76bd3f16acSPaolo Bonzini 7714ca122eSDavid Hildenbrand void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr) 7814ca122eSDavid Hildenbrand { 7914ca122eSDavid Hildenbrand CPUS390XState *env = &cpu->env; 8014ca122eSDavid Hildenbrand 8114ca122eSDavid Hildenbrand g_assert(src_cpu_addr < S390_MAX_CPUS); 8214ca122eSDavid Hildenbrand set_bit(src_cpu_addr, env->emergency_signals); 8314ca122eSDavid Hildenbrand 8414ca122eSDavid Hildenbrand env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL; 8514ca122eSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 8614ca122eSDavid Hildenbrand } 8714ca122eSDavid Hildenbrand 8814ca122eSDavid Hildenbrand int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr) 8914ca122eSDavid Hildenbrand { 9014ca122eSDavid Hildenbrand CPUS390XState *env = &cpu->env; 9114ca122eSDavid Hildenbrand 9214ca122eSDavid Hildenbrand g_assert(src_cpu_addr < S390_MAX_CPUS); 9314ca122eSDavid Hildenbrand if (env->pending_int & INTERRUPT_EXTERNAL_CALL) { 9414ca122eSDavid Hildenbrand return -EBUSY; 9514ca122eSDavid Hildenbrand } 9614ca122eSDavid Hildenbrand env->external_call_addr = src_cpu_addr; 9714ca122eSDavid Hildenbrand 9814ca122eSDavid Hildenbrand env->pending_int |= INTERRUPT_EXTERNAL_CALL; 9914ca122eSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 10014ca122eSDavid Hildenbrand return 0; 10114ca122eSDavid Hildenbrand } 10214ca122eSDavid Hildenbrand 103eabcea18SDavid Hildenbrand void cpu_inject_restart(S390CPU *cpu) 104eabcea18SDavid Hildenbrand { 105b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env; 106b1ab5f60SDavid Hildenbrand 107eabcea18SDavid Hildenbrand if (kvm_enabled()) { 108eabcea18SDavid Hildenbrand kvm_s390_restart_interrupt(cpu); 109eabcea18SDavid Hildenbrand return; 110eabcea18SDavid Hildenbrand } 111b1ab5f60SDavid Hildenbrand 112b1ab5f60SDavid Hildenbrand env->pending_int |= INTERRUPT_RESTART; 113b1ab5f60SDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 114eabcea18SDavid Hildenbrand } 115eabcea18SDavid Hildenbrand 116eabcea18SDavid Hildenbrand void cpu_inject_stop(S390CPU *cpu) 117eabcea18SDavid Hildenbrand { 118b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env; 119b1ab5f60SDavid Hildenbrand 120eabcea18SDavid Hildenbrand if (kvm_enabled()) { 121eabcea18SDavid Hildenbrand kvm_s390_stop_interrupt(cpu); 122eabcea18SDavid Hildenbrand return; 123eabcea18SDavid Hildenbrand } 124b1ab5f60SDavid Hildenbrand 125b1ab5f60SDavid Hildenbrand env->pending_int |= INTERRUPT_STOP; 126b1ab5f60SDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 127eabcea18SDavid Hildenbrand } 128eabcea18SDavid Hildenbrand 12979afc36dSCornelia Huck /* 13079afc36dSCornelia Huck * All of the following interrupts are floating, i.e. not per-vcpu. 131de13d216SCornelia Huck * We just need a dummy cpustate in order to be able to inject in the 132de13d216SCornelia Huck * non-kvm case. 13379afc36dSCornelia Huck */ 134000a1a38SChristian Borntraeger void s390_sclp_extint(uint32_t parm) 135000a1a38SChristian Borntraeger { 136e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic(); 137e6505d53SDavid Hildenbrand S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); 138000a1a38SChristian Borntraeger 139e6505d53SDavid Hildenbrand fsc->inject_service(fs, parm); 140000a1a38SChristian Borntraeger } 14179afc36dSCornelia Huck 142de13d216SCornelia Huck void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 143de13d216SCornelia Huck uint32_t io_int_parm, uint32_t io_int_word) 14479afc36dSCornelia Huck { 145e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic(); 146e6505d53SDavid Hildenbrand S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); 147de13d216SCornelia Huck 148e6505d53SDavid Hildenbrand fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word); 14979afc36dSCornelia Huck } 15079afc36dSCornelia Huck 151de13d216SCornelia Huck void s390_crw_mchk(void) 15279afc36dSCornelia Huck { 153e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic(); 154e6505d53SDavid Hildenbrand S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); 155de13d216SCornelia Huck 156e6505d53SDavid Hildenbrand fsc->inject_crw_mchk(fs); 15779afc36dSCornelia Huck } 15879afc36dSCornelia Huck 1598417f904SDavid Hildenbrand bool s390_cpu_has_mcck_int(S390CPU *cpu) 1608417f904SDavid Hildenbrand { 161*f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 1628417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env; 1638417f904SDavid Hildenbrand 1648417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_MCHECK)) { 1658417f904SDavid Hildenbrand return false; 1668417f904SDavid Hildenbrand } 1678417f904SDavid Hildenbrand 168520db63fSDavid Hildenbrand /* for now we only support channel report machine checks (floating) */ 169b194e447SDavid Hildenbrand if (qemu_s390_flic_has_crw_mchk(flic) && 170520db63fSDavid Hildenbrand (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) { 171520db63fSDavid Hildenbrand return true; 172520db63fSDavid Hildenbrand } 173520db63fSDavid Hildenbrand 174520db63fSDavid Hildenbrand return false; 1758417f904SDavid Hildenbrand } 1768417f904SDavid Hildenbrand 1778417f904SDavid Hildenbrand bool s390_cpu_has_ext_int(S390CPU *cpu) 1788417f904SDavid Hildenbrand { 179*f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 1808417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env; 1818417f904SDavid Hildenbrand 1828417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_EXT)) { 1838417f904SDavid Hildenbrand return false; 1848417f904SDavid Hildenbrand } 1858417f904SDavid Hildenbrand 1869dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) && 1879dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) { 1889dec2388SDavid Hildenbrand return true; 1899dec2388SDavid Hildenbrand } 1909dec2388SDavid Hildenbrand 1919dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 1929dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 1939dec2388SDavid Hildenbrand return true; 1949dec2388SDavid Hildenbrand } 1959dec2388SDavid Hildenbrand 1969dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) && 1979dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) { 1989dec2388SDavid Hildenbrand return true; 1999dec2388SDavid Hildenbrand } 2009dec2388SDavid Hildenbrand 2019dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) && 2029dec2388SDavid Hildenbrand (env->cregs[0] & CR0_CKC_SC)) { 2039dec2388SDavid Hildenbrand return true; 2049dec2388SDavid Hildenbrand } 2059dec2388SDavid Hildenbrand 2069dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) && 2079dec2388SDavid Hildenbrand (env->cregs[0] & CR0_CPU_TIMER_SC)) { 2089dec2388SDavid Hildenbrand return true; 2099dec2388SDavid Hildenbrand } 2109dec2388SDavid Hildenbrand 211b194e447SDavid Hildenbrand if (qemu_s390_flic_has_service(flic) && 2129dec2388SDavid Hildenbrand (env->cregs[0] & CR0_SERVICE_SC)) { 2139dec2388SDavid Hildenbrand return true; 2149dec2388SDavid Hildenbrand } 2159dec2388SDavid Hildenbrand 2169dec2388SDavid Hildenbrand return false; 2178417f904SDavid Hildenbrand } 2188417f904SDavid Hildenbrand 2198417f904SDavid Hildenbrand bool s390_cpu_has_io_int(S390CPU *cpu) 2208417f904SDavid Hildenbrand { 221*f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic()); 2228417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env; 2238417f904SDavid Hildenbrand 2248417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_IO)) { 2258417f904SDavid Hildenbrand return false; 2268417f904SDavid Hildenbrand } 2278417f904SDavid Hildenbrand 228b194e447SDavid Hildenbrand return qemu_s390_flic_has_io(flic, env->cregs[6]); 2298417f904SDavid Hildenbrand } 230b1ab5f60SDavid Hildenbrand 231b1ab5f60SDavid Hildenbrand bool s390_cpu_has_restart_int(S390CPU *cpu) 232b1ab5f60SDavid Hildenbrand { 233b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env; 234b1ab5f60SDavid Hildenbrand 235b1ab5f60SDavid Hildenbrand return env->pending_int & INTERRUPT_RESTART; 236b1ab5f60SDavid Hildenbrand } 237b1ab5f60SDavid Hildenbrand 238b1ab5f60SDavid Hildenbrand bool s390_cpu_has_stop_int(S390CPU *cpu) 239b1ab5f60SDavid Hildenbrand { 240b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env; 241b1ab5f60SDavid Hildenbrand 242b1ab5f60SDavid Hildenbrand return env->pending_int & INTERRUPT_STOP; 243b1ab5f60SDavid Hildenbrand } 244000a1a38SChristian Borntraeger #endif 2458417f904SDavid Hildenbrand 2468417f904SDavid Hildenbrand bool s390_cpu_has_int(S390CPU *cpu) 2478417f904SDavid Hildenbrand { 2488417f904SDavid Hildenbrand #ifndef CONFIG_USER_ONLY 2498417f904SDavid Hildenbrand if (!tcg_enabled()) { 2508417f904SDavid Hildenbrand return false; 2518417f904SDavid Hildenbrand } 2528417f904SDavid Hildenbrand return s390_cpu_has_mcck_int(cpu) || 2538417f904SDavid Hildenbrand s390_cpu_has_ext_int(cpu) || 254b1ab5f60SDavid Hildenbrand s390_cpu_has_io_int(cpu) || 255b1ab5f60SDavid Hildenbrand s390_cpu_has_restart_int(cpu) || 256b1ab5f60SDavid Hildenbrand s390_cpu_has_stop_int(cpu); 2578417f904SDavid Hildenbrand #else 2588417f904SDavid Hildenbrand return false; 2598417f904SDavid Hildenbrand #endif 2608417f904SDavid Hildenbrand } 261