]> git.proxmox.com Git - mirror_qemu.git/blame - target/s390x/sigp.c
s390x/tcg: implement SIGP SENSE RUNNING STATUS
[mirror_qemu.git] / target / s390x / sigp.c
CommitLineData
74b4c74d
DH
1/*
2 * s390x SIGP instruction handling
3 *
4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
5 * Copyright IBM Corp. 2012
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
11#include "qemu/osdep.h"
12#include "qemu-common.h"
13#include "cpu.h"
14#include "internal.h"
15#include "sysemu/hw_accel.h"
16#include "exec/address-spaces.h"
17#include "sysemu/sysemu.h"
18#include "trace.h"
19
20QemuMutex qemu_sigp_mutex;
21
22typedef struct SigpInfo {
23 uint64_t param;
24 int cc;
25 uint64_t *status_reg;
26} SigpInfo;
27
28static void set_sigp_status(SigpInfo *si, uint64_t status)
29{
30 *si->status_reg &= 0xffffffff00000000ULL;
31 *si->status_reg |= status;
32 si->cc = SIGP_CC_STATUS_STORED;
33}
34
35static void sigp_start(CPUState *cs, run_on_cpu_data arg)
36{
37 S390CPU *cpu = S390_CPU(cs);
38 SigpInfo *si = arg.host_ptr;
39
40 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
41 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
42 return;
43 }
44
45 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
46 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
47}
48
49static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
50{
51 S390CPU *cpu = S390_CPU(cs);
52 SigpInfo *si = arg.host_ptr;
53
54 if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
55 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
56 return;
57 }
58
59 /* disabled wait - sleeping in user space */
60 if (cs->halted) {
61 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
62 } else {
63 /* execute the stop function */
64 cpu->env.sigp_order = SIGP_STOP;
65 cpu_inject_stop(cpu);
66 }
67 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
68}
69
70static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
71{
72 S390CPU *cpu = S390_CPU(cs);
73 SigpInfo *si = arg.host_ptr;
74
75 /* disabled wait - sleeping in user space */
76 if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) {
77 s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
78 }
79
80 switch (s390_cpu_get_state(cpu)) {
81 case CPU_STATE_OPERATING:
82 cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
83 cpu_inject_stop(cpu);
3047f8b5 84 /* store will be performed in do_stop_interrup() */
74b4c74d
DH
85 break;
86 case CPU_STATE_STOPPED:
87 /* already stopped, just store the status */
88 cpu_synchronize_state(cs);
89 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
90 break;
91 }
92 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
93}
94
95static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
96{
97 S390CPU *cpu = S390_CPU(cs);
98 SigpInfo *si = arg.host_ptr;
99 uint32_t address = si->param & 0x7ffffe00u;
100
101 /* cpu has to be stopped */
102 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
103 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
104 return;
105 }
106
107 cpu_synchronize_state(cs);
108
109 if (s390_store_status(cpu, address, false)) {
110 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
111 return;
112 }
113 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
114}
115
116#define ADTL_SAVE_LC_MASK 0xfUL
117static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
118{
119 S390CPU *cpu = S390_CPU(cs);
120 SigpInfo *si = arg.host_ptr;
121 uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
122 hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
123 hwaddr len = 1UL << (lc ? lc : 10);
124
125 if (!s390_has_feat(S390_FEAT_VECTOR) &&
126 !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
127 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
128 return;
129 }
130
131 /* cpu has to be stopped */
132 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
133 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
134 return;
135 }
136
137 /* address must be aligned to length */
138 if (addr & (len - 1)) {
139 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
140 return;
141 }
142
143 /* no GS: only lc == 0 is valid */
144 if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
145 lc != 0) {
146 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
147 return;
148 }
149
150 /* GS: 0, 10, 11, 12 are valid */
151 if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
152 lc != 0 &&
153 lc != 10 &&
154 lc != 11 &&
155 lc != 12) {
156 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
157 return;
158 }
159
160 cpu_synchronize_state(cs);
161
162 if (s390_store_adtl_status(cpu, addr, len)) {
163 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
164 return;
165 }
166 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
167}
168
169static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
170{
171 S390CPU *cpu = S390_CPU(cs);
172 SigpInfo *si = arg.host_ptr;
173
174 switch (s390_cpu_get_state(cpu)) {
175 case CPU_STATE_STOPPED:
176 /* the restart irq has to be delivered prior to any other pending irq */
177 cpu_synchronize_state(cs);
178 do_restart_interrupt(&cpu->env);
179 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
180 break;
181 case CPU_STATE_OPERATING:
182 cpu_inject_restart(cpu);
183 break;
184 }
185 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
186}
187
188static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
189{
190 S390CPU *cpu = S390_CPU(cs);
191 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
192 SigpInfo *si = arg.host_ptr;
193
194 cpu_synchronize_state(cs);
195 scc->initial_cpu_reset(cs);
196 cpu_synchronize_post_reset(cs);
197 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
198}
199
200static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
201{
202 S390CPU *cpu = S390_CPU(cs);
203 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
204 SigpInfo *si = arg.host_ptr;
205
206 cpu_synchronize_state(cs);
207 scc->cpu_reset(cs);
208 cpu_synchronize_post_reset(cs);
209 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
210}
211
212static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
213{
214 S390CPU *cpu = S390_CPU(cs);
215 SigpInfo *si = arg.host_ptr;
216 uint32_t addr = si->param & 0x7fffe000u;
217
218 cpu_synchronize_state(cs);
219
220 if (!address_space_access_valid(&address_space_memory, addr,
221 sizeof(struct LowCore), false)) {
222 set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
223 return;
224 }
225
226 /* cpu has to be stopped */
227 if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
228 set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
229 return;
230 }
231
232 cpu->env.psa = addr;
233 cpu_synchronize_post_init(cs);
234 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
235}
236
d1b468bc
DH
237static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
238{
239 if (!tcg_enabled()) {
240 /* handled in KVM */
241 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
242 return;
243 }
244
245 /* sensing without locks is racy, but it's the same for real hw */
246 if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
247 set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
248 return;
249 }
250
251 /* If halted (which includes also STOPPED), it is not running */
252 if (CPU(dst_cpu)->halted) {
253 si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
254 } else {
255 set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
256 }
257}
258
74b4c74d
DH
259static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order,
260 uint64_t param, uint64_t *status_reg)
261{
262 SigpInfo si = {
263 .param = param,
264 .status_reg = status_reg,
265 };
266
267 /* cpu available? */
268 if (dst_cpu == NULL) {
269 return SIGP_CC_NOT_OPERATIONAL;
270 }
271
272 /* only resets can break pending orders */
273 if (dst_cpu->env.sigp_order != 0 &&
274 order != SIGP_CPU_RESET &&
275 order != SIGP_INITIAL_CPU_RESET) {
276 return SIGP_CC_BUSY;
277 }
278
279 switch (order) {
280 case SIGP_START:
281 run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
282 break;
283 case SIGP_STOP:
284 run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
285 break;
286 case SIGP_RESTART:
287 run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
288 break;
289 case SIGP_STOP_STORE_STATUS:
290 run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
291 break;
292 case SIGP_STORE_STATUS_ADDR:
293 run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
294 break;
295 case SIGP_STORE_ADTL_STATUS:
296 run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
297 break;
298 case SIGP_SET_PREFIX:
299 run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
300 break;
301 case SIGP_INITIAL_CPU_RESET:
302 run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
303 break;
304 case SIGP_CPU_RESET:
305 run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
306 break;
d1b468bc
DH
307 case SIGP_SENSE_RUNNING:
308 sigp_sense_running(dst_cpu, &si);
309 break;
74b4c74d
DH
310 default:
311 set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
312 }
313
314 return si.cc;
315}
316
317static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
318 uint64_t *status_reg)
319{
320 CPUState *cur_cs;
321 S390CPU *cur_cpu;
322 bool all_stopped = true;
323
324 CPU_FOREACH(cur_cs) {
325 cur_cpu = S390_CPU(cur_cs);
326
327 if (cur_cpu == cpu) {
328 continue;
329 }
330 if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
331 all_stopped = false;
332 }
333 }
334
335 *status_reg &= 0xffffffff00000000ULL;
336
337 /* Reject set arch order, with czam we're always in z/Arch mode. */
338 *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
339 SIGP_STAT_INCORRECT_STATE);
340 return SIGP_CC_STATUS_STORED;
341}
342
343int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)
344{
345 uint64_t *status_reg = &env->regs[r1];
346 uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
347 S390CPU *cpu = s390_env_get_cpu(env);
348 S390CPU *dst_cpu = NULL;
349 int ret;
350
351 if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
352 ret = SIGP_CC_BUSY;
353 goto out;
354 }
355
356 switch (order) {
357 case SIGP_SET_ARCH:
358 ret = sigp_set_architecture(cpu, param, status_reg);
359 break;
360 default:
361 /* all other sigp orders target a single vcpu */
362 dst_cpu = s390_cpu_addr2state(env->regs[r3]);
363 ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
364 }
365 qemu_mutex_unlock(&qemu_sigp_mutex);
366
367out:
368 trace_sigp_finished(order, CPU(cpu)->cpu_index,
369 dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
370 g_assert(ret >= 0);
371
372 return ret;
373}
374
375int s390_cpu_restart(S390CPU *cpu)
376{
377 SigpInfo si = {};
378
379 if (tcg_enabled()) {
380 /* FIXME TCG */
381 return -ENOSYS;
382 }
383
384 run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
385 return 0;
386}
387
3047f8b5
DH
388void do_stop_interrupt(CPUS390XState *env)
389{
390 S390CPU *cpu = s390_env_get_cpu(env);
391
392 if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
393 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
394 }
395 if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
396 s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
397 }
398 env->sigp_order = 0;
399}
400
74b4c74d
DH
401void s390_init_sigp(void)
402{
403 qemu_mutex_init(&qemu_sigp_mutex);
404}