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