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"
11000a1a38SChristian Borntraeger #include "cpu.h"
1267043607SCho, Yu-Chen #include "kvm/kvm_s390x.h"
13b6b47223SCho, Yu-Chen #include "s390x-internal.h"
1432cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
1532cad1ffSPhilippe Mathieu-Daudé #include "system/tcg.h"
16bd3f16acSPaolo Bonzini #include "hw/s390x/ioinst.h"
17c9274b6bSCho, Yu-Chen #include "tcg/tcg_s390x.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! */
trigger_pgm_exception(CPUS390XState * env,uint32_t code)235c58704bSRichard Henderson void trigger_pgm_exception(CPUS390XState *env, uint32_t code)
24e3cfd926SThomas Huth {
25dc79e928SRichard Henderson CPUState *cs = env_cpu(env);
26e3cfd926SThomas Huth
27e3cfd926SThomas Huth cs->exception_index = EXCP_PGM;
28e3cfd926SThomas Huth env->int_pgm_code = code;
295c58704bSRichard Henderson /* env->int_pgm_ilen is already set, or will be set during unwinding */
30c87ff4d1SRichard Henderson }
31e3cfd926SThomas Huth
32*f54c047eSPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
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
cpu_inject_clock_comparator(S390CPU * cpu)446482b0ffSDavid Hildenbrand void cpu_inject_clock_comparator(S390CPU *cpu)
456482b0ffSDavid Hildenbrand {
466482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env;
476482b0ffSDavid Hildenbrand
486482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR;
496482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
506482b0ffSDavid Hildenbrand }
516482b0ffSDavid Hildenbrand
cpu_inject_cpu_timer(S390CPU * cpu)526482b0ffSDavid Hildenbrand void cpu_inject_cpu_timer(S390CPU *cpu)
536482b0ffSDavid Hildenbrand {
546482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env;
556482b0ffSDavid Hildenbrand
566482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CPU_TIMER;
57bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
58bd3f16acSPaolo Bonzini }
59bd3f16acSPaolo Bonzini
cpu_inject_emergency_signal(S390CPU * cpu,uint16_t src_cpu_addr)6014ca122eSDavid Hildenbrand void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr)
6114ca122eSDavid Hildenbrand {
6214ca122eSDavid Hildenbrand CPUS390XState *env = &cpu->env;
6314ca122eSDavid Hildenbrand
6414ca122eSDavid Hildenbrand g_assert(src_cpu_addr < S390_MAX_CPUS);
6514ca122eSDavid Hildenbrand set_bit(src_cpu_addr, env->emergency_signals);
6614ca122eSDavid Hildenbrand
6714ca122eSDavid Hildenbrand env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL;
6814ca122eSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
6914ca122eSDavid Hildenbrand }
7014ca122eSDavid Hildenbrand
cpu_inject_external_call(S390CPU * cpu,uint16_t src_cpu_addr)7114ca122eSDavid Hildenbrand int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr)
7214ca122eSDavid Hildenbrand {
7314ca122eSDavid Hildenbrand CPUS390XState *env = &cpu->env;
7414ca122eSDavid Hildenbrand
7514ca122eSDavid Hildenbrand g_assert(src_cpu_addr < S390_MAX_CPUS);
7614ca122eSDavid Hildenbrand if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
7714ca122eSDavid Hildenbrand return -EBUSY;
7814ca122eSDavid Hildenbrand }
7914ca122eSDavid Hildenbrand env->external_call_addr = src_cpu_addr;
8014ca122eSDavid Hildenbrand
8114ca122eSDavid Hildenbrand env->pending_int |= INTERRUPT_EXTERNAL_CALL;
8214ca122eSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
8314ca122eSDavid Hildenbrand return 0;
8414ca122eSDavid Hildenbrand }
8514ca122eSDavid Hildenbrand
cpu_inject_restart(S390CPU * cpu)86eabcea18SDavid Hildenbrand void cpu_inject_restart(S390CPU *cpu)
87eabcea18SDavid Hildenbrand {
88b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env;
89b1ab5f60SDavid Hildenbrand
90eabcea18SDavid Hildenbrand if (kvm_enabled()) {
91eabcea18SDavid Hildenbrand kvm_s390_restart_interrupt(cpu);
92eabcea18SDavid Hildenbrand return;
93eabcea18SDavid Hildenbrand }
94b1ab5f60SDavid Hildenbrand
95b1ab5f60SDavid Hildenbrand env->pending_int |= INTERRUPT_RESTART;
96b1ab5f60SDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
97eabcea18SDavid Hildenbrand }
98eabcea18SDavid Hildenbrand
cpu_inject_stop(S390CPU * cpu)99eabcea18SDavid Hildenbrand void cpu_inject_stop(S390CPU *cpu)
100eabcea18SDavid Hildenbrand {
101b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env;
102b1ab5f60SDavid Hildenbrand
103eabcea18SDavid Hildenbrand if (kvm_enabled()) {
104eabcea18SDavid Hildenbrand kvm_s390_stop_interrupt(cpu);
105eabcea18SDavid Hildenbrand return;
106eabcea18SDavid Hildenbrand }
107b1ab5f60SDavid Hildenbrand
108b1ab5f60SDavid Hildenbrand env->pending_int |= INTERRUPT_STOP;
109b1ab5f60SDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
110eabcea18SDavid Hildenbrand }
111eabcea18SDavid Hildenbrand
11279afc36dSCornelia Huck /*
11379afc36dSCornelia Huck * All of the following interrupts are floating, i.e. not per-vcpu.
114de13d216SCornelia Huck * We just need a dummy cpustate in order to be able to inject in the
115de13d216SCornelia Huck * non-kvm case.
11679afc36dSCornelia Huck */
s390_sclp_extint(uint32_t parm)117000a1a38SChristian Borntraeger void s390_sclp_extint(uint32_t parm)
118000a1a38SChristian Borntraeger {
119e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic();
1206762808fSDavid Hildenbrand S390FLICStateClass *fsc = s390_get_flic_class(fs);
121000a1a38SChristian Borntraeger
122e6505d53SDavid Hildenbrand fsc->inject_service(fs, parm);
123000a1a38SChristian Borntraeger }
12479afc36dSCornelia Huck
s390_io_interrupt(uint16_t subchannel_id,uint16_t subchannel_nr,uint32_t io_int_parm,uint32_t io_int_word)125de13d216SCornelia Huck void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
126de13d216SCornelia Huck uint32_t io_int_parm, uint32_t io_int_word)
12779afc36dSCornelia Huck {
128e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic();
1296762808fSDavid Hildenbrand S390FLICStateClass *fsc = s390_get_flic_class(fs);
130de13d216SCornelia Huck
131e6505d53SDavid Hildenbrand fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word);
13279afc36dSCornelia Huck }
13379afc36dSCornelia Huck
s390_crw_mchk(void)134de13d216SCornelia Huck void s390_crw_mchk(void)
13579afc36dSCornelia Huck {
136e6505d53SDavid Hildenbrand S390FLICState *fs = s390_get_flic();
1376762808fSDavid Hildenbrand S390FLICStateClass *fsc = s390_get_flic_class(fs);
138de13d216SCornelia Huck
139e6505d53SDavid Hildenbrand fsc->inject_crw_mchk(fs);
14079afc36dSCornelia Huck }
14179afc36dSCornelia Huck
s390_cpu_has_mcck_int(S390CPU * cpu)1428417f904SDavid Hildenbrand bool s390_cpu_has_mcck_int(S390CPU *cpu)
1438417f904SDavid Hildenbrand {
144f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
1458417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env;
1468417f904SDavid Hildenbrand
1478417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_MCHECK)) {
1488417f904SDavid Hildenbrand return false;
1498417f904SDavid Hildenbrand }
1508417f904SDavid Hildenbrand
151520db63fSDavid Hildenbrand /* for now we only support channel report machine checks (floating) */
152b194e447SDavid Hildenbrand if (qemu_s390_flic_has_crw_mchk(flic) &&
153520db63fSDavid Hildenbrand (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) {
154520db63fSDavid Hildenbrand return true;
155520db63fSDavid Hildenbrand }
156520db63fSDavid Hildenbrand
157520db63fSDavid Hildenbrand return false;
1588417f904SDavid Hildenbrand }
1598417f904SDavid Hildenbrand
s390_cpu_has_ext_int(S390CPU * cpu)1608417f904SDavid Hildenbrand bool s390_cpu_has_ext_int(S390CPU *cpu)
1618417f904SDavid Hildenbrand {
162f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
1638417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env;
1648417f904SDavid Hildenbrand
1658417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_EXT)) {
1668417f904SDavid Hildenbrand return false;
1678417f904SDavid Hildenbrand }
1688417f904SDavid Hildenbrand
1699dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
1709dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
1719dec2388SDavid Hildenbrand return true;
1729dec2388SDavid Hildenbrand }
1739dec2388SDavid Hildenbrand
1749dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
1759dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
1769dec2388SDavid Hildenbrand return true;
1779dec2388SDavid Hildenbrand }
1789dec2388SDavid Hildenbrand
1799dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
1809dec2388SDavid Hildenbrand (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
1819dec2388SDavid Hildenbrand return true;
1829dec2388SDavid Hildenbrand }
1839dec2388SDavid Hildenbrand
1849dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
1859dec2388SDavid Hildenbrand (env->cregs[0] & CR0_CKC_SC)) {
1869dec2388SDavid Hildenbrand return true;
1879dec2388SDavid Hildenbrand }
1889dec2388SDavid Hildenbrand
1899dec2388SDavid Hildenbrand if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
1909dec2388SDavid Hildenbrand (env->cregs[0] & CR0_CPU_TIMER_SC)) {
1919dec2388SDavid Hildenbrand return true;
1929dec2388SDavid Hildenbrand }
1939dec2388SDavid Hildenbrand
194b194e447SDavid Hildenbrand if (qemu_s390_flic_has_service(flic) &&
1959dec2388SDavid Hildenbrand (env->cregs[0] & CR0_SERVICE_SC)) {
1969dec2388SDavid Hildenbrand return true;
1979dec2388SDavid Hildenbrand }
1989dec2388SDavid Hildenbrand
1999dec2388SDavid Hildenbrand return false;
2008417f904SDavid Hildenbrand }
2018417f904SDavid Hildenbrand
s390_cpu_has_io_int(S390CPU * cpu)2028417f904SDavid Hildenbrand bool s390_cpu_has_io_int(S390CPU *cpu)
2038417f904SDavid Hildenbrand {
204f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
2058417f904SDavid Hildenbrand CPUS390XState *env = &cpu->env;
2068417f904SDavid Hildenbrand
2078417f904SDavid Hildenbrand if (!(env->psw.mask & PSW_MASK_IO)) {
2088417f904SDavid Hildenbrand return false;
2098417f904SDavid Hildenbrand }
2108417f904SDavid Hildenbrand
211b194e447SDavid Hildenbrand return qemu_s390_flic_has_io(flic, env->cregs[6]);
2128417f904SDavid Hildenbrand }
213b1ab5f60SDavid Hildenbrand
s390_cpu_has_restart_int(S390CPU * cpu)214b1ab5f60SDavid Hildenbrand bool s390_cpu_has_restart_int(S390CPU *cpu)
215b1ab5f60SDavid Hildenbrand {
216b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env;
217b1ab5f60SDavid Hildenbrand
218b1ab5f60SDavid Hildenbrand return env->pending_int & INTERRUPT_RESTART;
219b1ab5f60SDavid Hildenbrand }
220b1ab5f60SDavid Hildenbrand
s390_cpu_has_stop_int(S390CPU * cpu)221b1ab5f60SDavid Hildenbrand bool s390_cpu_has_stop_int(S390CPU *cpu)
222b1ab5f60SDavid Hildenbrand {
223b1ab5f60SDavid Hildenbrand CPUS390XState *env = &cpu->env;
224b1ab5f60SDavid Hildenbrand
225b1ab5f60SDavid Hildenbrand return env->pending_int & INTERRUPT_STOP;
226b1ab5f60SDavid Hildenbrand }
2278417f904SDavid Hildenbrand
s390_cpu_has_int(S390CPU * cpu)2288417f904SDavid Hildenbrand bool s390_cpu_has_int(S390CPU *cpu)
2298417f904SDavid Hildenbrand {
2308417f904SDavid Hildenbrand if (!tcg_enabled()) {
2318417f904SDavid Hildenbrand return false;
2328417f904SDavid Hildenbrand }
2338417f904SDavid Hildenbrand return s390_cpu_has_mcck_int(cpu) ||
2348417f904SDavid Hildenbrand s390_cpu_has_ext_int(cpu) ||
235b1ab5f60SDavid Hildenbrand s390_cpu_has_io_int(cpu) ||
236b1ab5f60SDavid Hildenbrand s390_cpu_has_restart_int(cpu) ||
237b1ab5f60SDavid Hildenbrand s390_cpu_has_stop_int(cpu);
2388417f904SDavid Hildenbrand }
239*f54c047eSPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
240