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