xref: /openbmc/qemu/target/s390x/interrupt.c (revision 57e28d34c0cb04abf7683ac6a12c87ede447c320)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  * QEMU S/390 Interrupt support
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  * Copyright IBM Corp. 2012, 2014
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
7fcf5ef2aSThomas Huth  * option) any later version.  See the COPYING file in the top-level directory.
8fcf5ef2aSThomas Huth  */
9fcf5ef2aSThomas Huth 
10fcf5ef2aSThomas Huth #include "qemu/osdep.h"
11fcf5ef2aSThomas Huth #include "cpu.h"
12*67043607SCho, Yu-Chen #include "kvm/kvm_s390x.h"
13b6b47223SCho, Yu-Chen #include "s390x-internal.h"
14e3cfd926SThomas Huth #include "exec/exec-all.h"
15fcf5ef2aSThomas Huth #include "sysemu/kvm.h"
1614a48c1dSMarkus Armbruster #include "sysemu/tcg.h"
17fcf5ef2aSThomas Huth #include "hw/s390x/ioinst.h"
18c9274b6bSCho, Yu-Chen #include "tcg/tcg_s390x.h"
19e6505d53SDavid Hildenbrand #if !defined(CONFIG_USER_ONLY)
20e6505d53SDavid Hildenbrand #include "hw/s390x/s390_flic.h"
21e6505d53SDavid Hildenbrand #endif
22fcf5ef2aSThomas Huth 
23e3cfd926SThomas Huth /* Ensure to exit the TB after this call! */
trigger_pgm_exception(CPUS390XState * env,uint32_t code)245c58704bSRichard Henderson void trigger_pgm_exception(CPUS390XState *env, uint32_t code)
25e3cfd926SThomas Huth {
26dc79e928SRichard Henderson     CPUState *cs = env_cpu(env);
27e3cfd926SThomas Huth 
28e3cfd926SThomas Huth     cs->exception_index = EXCP_PGM;
29e3cfd926SThomas Huth     env->int_pgm_code = code;
305c58704bSRichard Henderson     /* env->int_pgm_ilen is already set, or will be set during unwinding */
31c87ff4d1SRichard Henderson }
32e3cfd926SThomas Huth 
s390_program_interrupt(CPUS390XState * env,uint32_t code,uintptr_t ra)3377b703f8SRichard Henderson void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra)
34e3cfd926SThomas Huth {
35e3cfd926SThomas Huth     if (kvm_enabled()) {
36dc79e928SRichard Henderson         kvm_s390_program_interrupt(env_archcpu(env), code);
37e3cfd926SThomas Huth     } else if (tcg_enabled()) {
383e201858SRichard Henderson         tcg_s390_program_interrupt(env, code, ra);
39e3cfd926SThomas Huth     } else {
40e3cfd926SThomas Huth         g_assert_not_reached();
41e3cfd926SThomas Huth     }
42e3cfd926SThomas Huth }
43e3cfd926SThomas Huth 
44fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
cpu_inject_clock_comparator(S390CPU * cpu)456482b0ffSDavid Hildenbrand void cpu_inject_clock_comparator(S390CPU *cpu)
466482b0ffSDavid Hildenbrand {
476482b0ffSDavid Hildenbrand     CPUS390XState *env = &cpu->env;
486482b0ffSDavid Hildenbrand 
496482b0ffSDavid Hildenbrand     env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR;
506482b0ffSDavid Hildenbrand     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
516482b0ffSDavid Hildenbrand }
526482b0ffSDavid Hildenbrand 
cpu_inject_cpu_timer(S390CPU * cpu)536482b0ffSDavid Hildenbrand void cpu_inject_cpu_timer(S390CPU *cpu)
546482b0ffSDavid Hildenbrand {
556482b0ffSDavid Hildenbrand     CPUS390XState *env = &cpu->env;
566482b0ffSDavid Hildenbrand 
576482b0ffSDavid Hildenbrand     env->pending_int |= INTERRUPT_EXT_CPU_TIMER;
58fcf5ef2aSThomas Huth     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
59fcf5ef2aSThomas Huth }
60fcf5ef2aSThomas Huth 
cpu_inject_emergency_signal(S390CPU * cpu,uint16_t src_cpu_addr)6114ca122eSDavid Hildenbrand void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr)
6214ca122eSDavid Hildenbrand {
6314ca122eSDavid Hildenbrand     CPUS390XState *env = &cpu->env;
6414ca122eSDavid Hildenbrand 
6514ca122eSDavid Hildenbrand     g_assert(src_cpu_addr < S390_MAX_CPUS);
6614ca122eSDavid Hildenbrand     set_bit(src_cpu_addr, env->emergency_signals);
6714ca122eSDavid Hildenbrand 
6814ca122eSDavid Hildenbrand     env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL;
6914ca122eSDavid Hildenbrand     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
7014ca122eSDavid Hildenbrand }
7114ca122eSDavid Hildenbrand 
cpu_inject_external_call(S390CPU * cpu,uint16_t src_cpu_addr)7214ca122eSDavid Hildenbrand int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr)
7314ca122eSDavid Hildenbrand {
7414ca122eSDavid Hildenbrand     CPUS390XState *env = &cpu->env;
7514ca122eSDavid Hildenbrand 
7614ca122eSDavid Hildenbrand     g_assert(src_cpu_addr < S390_MAX_CPUS);
7714ca122eSDavid Hildenbrand     if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
7814ca122eSDavid Hildenbrand         return -EBUSY;
7914ca122eSDavid Hildenbrand     }
8014ca122eSDavid Hildenbrand     env->external_call_addr = src_cpu_addr;
8114ca122eSDavid Hildenbrand 
8214ca122eSDavid Hildenbrand     env->pending_int |= INTERRUPT_EXTERNAL_CALL;
8314ca122eSDavid Hildenbrand     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
8414ca122eSDavid Hildenbrand     return 0;
8514ca122eSDavid Hildenbrand }
8614ca122eSDavid Hildenbrand 
cpu_inject_restart(S390CPU * cpu)87eabcea18SDavid Hildenbrand void cpu_inject_restart(S390CPU *cpu)
88eabcea18SDavid Hildenbrand {
89b1ab5f60SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
90b1ab5f60SDavid Hildenbrand 
91eabcea18SDavid Hildenbrand     if (kvm_enabled()) {
92eabcea18SDavid Hildenbrand         kvm_s390_restart_interrupt(cpu);
93eabcea18SDavid Hildenbrand         return;
94eabcea18SDavid Hildenbrand     }
95b1ab5f60SDavid Hildenbrand 
96b1ab5f60SDavid Hildenbrand     env->pending_int |= INTERRUPT_RESTART;
97b1ab5f60SDavid Hildenbrand     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
98eabcea18SDavid Hildenbrand }
99eabcea18SDavid Hildenbrand 
cpu_inject_stop(S390CPU * cpu)100eabcea18SDavid Hildenbrand void cpu_inject_stop(S390CPU *cpu)
101eabcea18SDavid Hildenbrand {
102b1ab5f60SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
103b1ab5f60SDavid Hildenbrand 
104eabcea18SDavid Hildenbrand     if (kvm_enabled()) {
105eabcea18SDavid Hildenbrand         kvm_s390_stop_interrupt(cpu);
106eabcea18SDavid Hildenbrand         return;
107eabcea18SDavid Hildenbrand     }
108b1ab5f60SDavid Hildenbrand 
109b1ab5f60SDavid Hildenbrand     env->pending_int |= INTERRUPT_STOP;
110b1ab5f60SDavid Hildenbrand     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
111eabcea18SDavid Hildenbrand }
112eabcea18SDavid Hildenbrand 
113fcf5ef2aSThomas Huth /*
114fcf5ef2aSThomas Huth  * All of the following interrupts are floating, i.e. not per-vcpu.
115fcf5ef2aSThomas Huth  * We just need a dummy cpustate in order to be able to inject in the
116fcf5ef2aSThomas Huth  * non-kvm case.
117fcf5ef2aSThomas Huth  */
s390_sclp_extint(uint32_t parm)118fcf5ef2aSThomas Huth void s390_sclp_extint(uint32_t parm)
119fcf5ef2aSThomas Huth {
120e6505d53SDavid Hildenbrand     S390FLICState *fs = s390_get_flic();
1216762808fSDavid Hildenbrand     S390FLICStateClass *fsc = s390_get_flic_class(fs);
122fcf5ef2aSThomas Huth 
123e6505d53SDavid Hildenbrand     fsc->inject_service(fs, parm);
124fcf5ef2aSThomas Huth }
125fcf5ef2aSThomas Huth 
s390_io_interrupt(uint16_t subchannel_id,uint16_t subchannel_nr,uint32_t io_int_parm,uint32_t io_int_word)126fcf5ef2aSThomas Huth void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
127fcf5ef2aSThomas Huth                        uint32_t io_int_parm, uint32_t io_int_word)
128fcf5ef2aSThomas Huth {
129e6505d53SDavid Hildenbrand     S390FLICState *fs = s390_get_flic();
1306762808fSDavid Hildenbrand     S390FLICStateClass *fsc = s390_get_flic_class(fs);
131fcf5ef2aSThomas Huth 
132e6505d53SDavid Hildenbrand     fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word);
133fcf5ef2aSThomas Huth }
134fcf5ef2aSThomas Huth 
s390_crw_mchk(void)135fcf5ef2aSThomas Huth void s390_crw_mchk(void)
136fcf5ef2aSThomas Huth {
137e6505d53SDavid Hildenbrand     S390FLICState *fs = s390_get_flic();
1386762808fSDavid Hildenbrand     S390FLICStateClass *fsc = s390_get_flic_class(fs);
139fcf5ef2aSThomas Huth 
140e6505d53SDavid Hildenbrand     fsc->inject_crw_mchk(fs);
141fcf5ef2aSThomas Huth }
142fcf5ef2aSThomas Huth 
s390_cpu_has_mcck_int(S390CPU * cpu)1438417f904SDavid Hildenbrand bool s390_cpu_has_mcck_int(S390CPU *cpu)
1448417f904SDavid Hildenbrand {
145f68ecdd4SDavid Hildenbrand     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
1468417f904SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
1478417f904SDavid Hildenbrand 
1488417f904SDavid Hildenbrand     if (!(env->psw.mask & PSW_MASK_MCHECK)) {
1498417f904SDavid Hildenbrand         return false;
1508417f904SDavid Hildenbrand     }
1518417f904SDavid Hildenbrand 
152520db63fSDavid Hildenbrand     /* for now we only support channel report machine checks (floating) */
153b194e447SDavid Hildenbrand     if (qemu_s390_flic_has_crw_mchk(flic) &&
154520db63fSDavid Hildenbrand         (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) {
155520db63fSDavid Hildenbrand         return true;
156520db63fSDavid Hildenbrand     }
157520db63fSDavid Hildenbrand 
158520db63fSDavid Hildenbrand     return false;
1598417f904SDavid Hildenbrand }
1608417f904SDavid Hildenbrand 
s390_cpu_has_ext_int(S390CPU * cpu)1618417f904SDavid Hildenbrand bool s390_cpu_has_ext_int(S390CPU *cpu)
1628417f904SDavid Hildenbrand {
163f68ecdd4SDavid Hildenbrand     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
1648417f904SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
1658417f904SDavid Hildenbrand 
1668417f904SDavid Hildenbrand     if (!(env->psw.mask & PSW_MASK_EXT)) {
1678417f904SDavid Hildenbrand         return false;
1688417f904SDavid Hildenbrand     }
1698417f904SDavid Hildenbrand 
1709dec2388SDavid Hildenbrand     if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
1719dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
1729dec2388SDavid Hildenbrand         return true;
1739dec2388SDavid Hildenbrand     }
1749dec2388SDavid Hildenbrand 
1759dec2388SDavid Hildenbrand     if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
1769dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
1779dec2388SDavid Hildenbrand         return true;
1789dec2388SDavid Hildenbrand     }
1799dec2388SDavid Hildenbrand 
1809dec2388SDavid Hildenbrand     if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
1819dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
1829dec2388SDavid Hildenbrand         return true;
1839dec2388SDavid Hildenbrand     }
1849dec2388SDavid Hildenbrand 
1859dec2388SDavid Hildenbrand     if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
1869dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_CKC_SC)) {
1879dec2388SDavid Hildenbrand         return true;
1889dec2388SDavid Hildenbrand     }
1899dec2388SDavid Hildenbrand 
1909dec2388SDavid Hildenbrand     if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
1919dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_CPU_TIMER_SC)) {
1929dec2388SDavid Hildenbrand         return true;
1939dec2388SDavid Hildenbrand     }
1949dec2388SDavid Hildenbrand 
195b194e447SDavid Hildenbrand     if (qemu_s390_flic_has_service(flic) &&
1969dec2388SDavid Hildenbrand         (env->cregs[0] & CR0_SERVICE_SC)) {
1979dec2388SDavid Hildenbrand         return true;
1989dec2388SDavid Hildenbrand     }
1999dec2388SDavid Hildenbrand 
2009dec2388SDavid Hildenbrand     return false;
2018417f904SDavid Hildenbrand }
2028417f904SDavid Hildenbrand 
s390_cpu_has_io_int(S390CPU * cpu)2038417f904SDavid Hildenbrand bool s390_cpu_has_io_int(S390CPU *cpu)
2048417f904SDavid Hildenbrand {
205f68ecdd4SDavid Hildenbrand     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
2068417f904SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
2078417f904SDavid Hildenbrand 
2088417f904SDavid Hildenbrand     if (!(env->psw.mask & PSW_MASK_IO)) {
2098417f904SDavid Hildenbrand         return false;
2108417f904SDavid Hildenbrand     }
2118417f904SDavid Hildenbrand 
212b194e447SDavid Hildenbrand     return qemu_s390_flic_has_io(flic, env->cregs[6]);
2138417f904SDavid Hildenbrand }
214b1ab5f60SDavid Hildenbrand 
s390_cpu_has_restart_int(S390CPU * cpu)215b1ab5f60SDavid Hildenbrand bool s390_cpu_has_restart_int(S390CPU *cpu)
216b1ab5f60SDavid Hildenbrand {
217b1ab5f60SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
218b1ab5f60SDavid Hildenbrand 
219b1ab5f60SDavid Hildenbrand     return env->pending_int & INTERRUPT_RESTART;
220b1ab5f60SDavid Hildenbrand }
221b1ab5f60SDavid Hildenbrand 
s390_cpu_has_stop_int(S390CPU * cpu)222b1ab5f60SDavid Hildenbrand bool s390_cpu_has_stop_int(S390CPU *cpu)
223b1ab5f60SDavid Hildenbrand {
224b1ab5f60SDavid Hildenbrand     CPUS390XState *env = &cpu->env;
225b1ab5f60SDavid Hildenbrand 
226b1ab5f60SDavid Hildenbrand     return env->pending_int & INTERRUPT_STOP;
227b1ab5f60SDavid Hildenbrand }
228fcf5ef2aSThomas Huth #endif
2298417f904SDavid Hildenbrand 
s390_cpu_has_int(S390CPU * cpu)2308417f904SDavid Hildenbrand bool s390_cpu_has_int(S390CPU *cpu)
2318417f904SDavid Hildenbrand {
2328417f904SDavid Hildenbrand #ifndef CONFIG_USER_ONLY
2338417f904SDavid Hildenbrand     if (!tcg_enabled()) {
2348417f904SDavid Hildenbrand         return false;
2358417f904SDavid Hildenbrand     }
2368417f904SDavid Hildenbrand     return s390_cpu_has_mcck_int(cpu) ||
2378417f904SDavid Hildenbrand            s390_cpu_has_ext_int(cpu) ||
238b1ab5f60SDavid Hildenbrand            s390_cpu_has_io_int(cpu) ||
239b1ab5f60SDavid Hildenbrand            s390_cpu_has_restart_int(cpu) ||
240b1ab5f60SDavid Hildenbrand            s390_cpu_has_stop_int(cpu);
2418417f904SDavid Hildenbrand #else
2428417f904SDavid Hildenbrand     return false;
2438417f904SDavid Hildenbrand #endif
2448417f904SDavid Hildenbrand }
245