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