xref: /qemu/target/s390x/tcg/misc_helper.c (revision b4e2bd3563af75ba5b9fe809c8cf79d2d34aecf3)
110ec5117SAlexander Graf /*
2aea1e885SBlue Swirl  *  S/390 misc helper routines
310ec5117SAlexander Graf  *
4defb0e31SAlexander Graf  *  Copyright (c) 2009 Ulrich Hecht
510ec5117SAlexander Graf  *  Copyright (c) 2009 Alexander Graf
610ec5117SAlexander Graf  *
710ec5117SAlexander Graf  * This library is free software; you can redistribute it and/or
810ec5117SAlexander Graf  * modify it under the terms of the GNU Lesser General Public
910ec5117SAlexander Graf  * License as published by the Free Software Foundation; either
1010ec5117SAlexander Graf  * version 2 of the License, or (at your option) any later version.
1110ec5117SAlexander Graf  *
1210ec5117SAlexander Graf  * This library is distributed in the hope that it will be useful,
1310ec5117SAlexander Graf  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1410ec5117SAlexander Graf  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1510ec5117SAlexander Graf  * Lesser General Public License for more details.
1610ec5117SAlexander Graf  *
1710ec5117SAlexander Graf  * You should have received a copy of the GNU Lesser General Public
1870539e18SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1910ec5117SAlexander Graf  */
2010ec5117SAlexander Graf 
213e457172SBlue Swirl #include "cpu.h"
22022c62cbSPaolo Bonzini #include "exec/memory.h"
231de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
243208afbeSLluís Vilanova #include "helper.h"
25defb0e31SAlexander Graf #include <string.h>
269c17d615SPaolo Bonzini #include "sysemu/kvm.h"
271de7afc9SPaolo Bonzini #include "qemu/timer.h"
28af2be207SJan Kiszka #ifdef CONFIG_KVM
29af2be207SJan Kiszka #include <linux/kvm.h>
30af2be207SJan Kiszka #endif
3110ec5117SAlexander Graf 
321864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
33022c62cbSPaolo Bonzini #include "exec/softmmu_exec.h"
349c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3510ec5117SAlexander Graf #endif
36d5a43964SAlexander Graf 
37defb0e31SAlexander Graf /* #define DEBUG_HELPER */
38defb0e31SAlexander Graf #ifdef DEBUG_HELPER
39defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
40defb0e31SAlexander Graf #else
41defb0e31SAlexander Graf #define HELPER_LOG(x...)
42defb0e31SAlexander Graf #endif
43defb0e31SAlexander Graf 
44b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
45b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
46b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
47b4e2bd35SRichard Henderson {
48b4e2bd35SRichard Henderson     int t;
49b4e2bd35SRichard Henderson 
50b4e2bd35SRichard Henderson     env->exception_index = EXCP_PGM;
51b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
52b4e2bd35SRichard Henderson 
53b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
54b4e2bd35SRichard Henderson     cpu_restore_state(env, retaddr);
55b4e2bd35SRichard Henderson 
56b4e2bd35SRichard Henderson     /* Advance past the insn.  */
57b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
58b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
59b4e2bd35SRichard Henderson     env->psw.addr += 2 * t;
60b4e2bd35SRichard Henderson 
61b4e2bd35SRichard Henderson     cpu_loop_exit(env);
62b4e2bd35SRichard Henderson }
63b4e2bd35SRichard Henderson 
64d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
65089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
66defb0e31SAlexander Graf {
6771e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
68defb0e31SAlexander Graf     env->exception_index = excp;
691162c041SBlue Swirl     cpu_loop_exit(env);
70defb0e31SAlexander Graf }
71defb0e31SAlexander Graf 
72defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
73d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
74defb0e31SAlexander Graf {
750d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
760d404541SRichard Henderson                   env->psw.addr);
77defb0e31SAlexander Graf 
78defb0e31SAlexander Graf     if (kvm_enabled()) {
79af2be207SJan Kiszka #ifdef CONFIG_KVM
801bc22652SAndreas Färber         kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
81af2be207SJan Kiszka #endif
82defb0e31SAlexander Graf     } else {
83defb0e31SAlexander Graf         env->int_pgm_code = code;
84d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
85defb0e31SAlexander Graf         env->exception_index = EXCP_PGM;
861162c041SBlue Swirl         cpu_loop_exit(env);
87defb0e31SAlexander Graf     }
88defb0e31SAlexander Graf }
89defb0e31SAlexander Graf 
90defb0e31SAlexander Graf /* SCLP service call */
91089f5c06SBlue Swirl uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2)
92defb0e31SAlexander Graf {
939abf567dSChristian Borntraeger     int r;
94defb0e31SAlexander Graf 
95f6c98f92SHeinz Graalfs     r = sclp_service_call(r1, r2);
969abf567dSChristian Borntraeger     if (r < 0) {
979abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
98d5a43964SAlexander Graf         return 0;
99d5a43964SAlexander Graf     }
1009abf567dSChristian Borntraeger     return r;
1019abf567dSChristian Borntraeger }
102defb0e31SAlexander Graf 
103defb0e31SAlexander Graf /* DIAG */
104089f5c06SBlue Swirl uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
105089f5c06SBlue Swirl                       uint64_t code)
106defb0e31SAlexander Graf {
107defb0e31SAlexander Graf     uint64_t r;
108defb0e31SAlexander Graf 
109defb0e31SAlexander Graf     switch (num) {
110defb0e31SAlexander Graf     case 0x500:
111defb0e31SAlexander Graf         /* KVM hypercall */
112defb0e31SAlexander Graf         r = s390_virtio_hypercall(env, mem, code);
113defb0e31SAlexander Graf         break;
114defb0e31SAlexander Graf     case 0x44:
115defb0e31SAlexander Graf         /* yield */
116defb0e31SAlexander Graf         r = 0;
117defb0e31SAlexander Graf         break;
118defb0e31SAlexander Graf     case 0x308:
119defb0e31SAlexander Graf         /* ipl */
120defb0e31SAlexander Graf         r = 0;
121defb0e31SAlexander Graf         break;
122defb0e31SAlexander Graf     default:
123defb0e31SAlexander Graf         r = -1;
124defb0e31SAlexander Graf         break;
125defb0e31SAlexander Graf     }
126defb0e31SAlexander Graf 
127defb0e31SAlexander Graf     if (r) {
128d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
129defb0e31SAlexander Graf     }
130defb0e31SAlexander Graf 
131defb0e31SAlexander Graf     return r;
132defb0e31SAlexander Graf }
133defb0e31SAlexander Graf 
134defb0e31SAlexander Graf /* Store CPU ID */
135089f5c06SBlue Swirl void HELPER(stidp)(CPUS390XState *env, uint64_t a1)
136defb0e31SAlexander Graf {
137089f5c06SBlue Swirl     cpu_stq_data(env, a1, env->cpu_num);
138defb0e31SAlexander Graf }
139defb0e31SAlexander Graf 
140defb0e31SAlexander Graf /* Set Prefix */
141089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
142defb0e31SAlexander Graf {
143defb0e31SAlexander Graf     uint32_t prefix;
144defb0e31SAlexander Graf 
145089f5c06SBlue Swirl     prefix = cpu_ldl_data(env, a1);
146defb0e31SAlexander Graf     env->psa = prefix & 0xfffff000;
147defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
148defb0e31SAlexander Graf     tlb_flush_page(env, 0);
149defb0e31SAlexander Graf     tlb_flush_page(env, TARGET_PAGE_SIZE);
150defb0e31SAlexander Graf }
151defb0e31SAlexander Graf 
152defb0e31SAlexander Graf /* Set Clock */
153defb0e31SAlexander Graf uint32_t HELPER(sck)(uint64_t a1)
154defb0e31SAlexander Graf {
155defb0e31SAlexander Graf     /* XXX not implemented - is it necessary? */
156defb0e31SAlexander Graf 
157defb0e31SAlexander Graf     return 0;
158defb0e31SAlexander Graf }
159defb0e31SAlexander Graf 
160a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env)
161defb0e31SAlexander Graf {
162defb0e31SAlexander Graf     uint64_t time;
163defb0e31SAlexander Graf 
164defb0e31SAlexander Graf     time = env->tod_offset +
165defb0e31SAlexander Graf         time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
166defb0e31SAlexander Graf 
167defb0e31SAlexander Graf     return time;
168defb0e31SAlexander Graf }
169defb0e31SAlexander Graf 
170defb0e31SAlexander Graf /* Store Clock */
171089f5c06SBlue Swirl uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1)
172defb0e31SAlexander Graf {
173089f5c06SBlue Swirl     cpu_stq_data(env, a1, clock_value(env));
174defb0e31SAlexander Graf 
175defb0e31SAlexander Graf     return 0;
176defb0e31SAlexander Graf }
177defb0e31SAlexander Graf 
178defb0e31SAlexander Graf /* Store Clock Extended */
179089f5c06SBlue Swirl uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1)
180defb0e31SAlexander Graf {
181089f5c06SBlue Swirl     cpu_stb_data(env, a1, 0);
182defb0e31SAlexander Graf     /* basically the same value as stck */
183089f5c06SBlue Swirl     cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num);
184defb0e31SAlexander Graf     /* more fine grained than stck */
185089f5c06SBlue Swirl     cpu_stq_data(env, a1 + 9, 0);
186defb0e31SAlexander Graf     /* XXX programmable fields */
187089f5c06SBlue Swirl     cpu_stw_data(env, a1 + 17, 0);
188defb0e31SAlexander Graf 
189defb0e31SAlexander Graf     return 0;
190defb0e31SAlexander Graf }
191defb0e31SAlexander Graf 
192defb0e31SAlexander Graf /* Set Clock Comparator */
193089f5c06SBlue Swirl void HELPER(sckc)(CPUS390XState *env, uint64_t a1)
194defb0e31SAlexander Graf {
195089f5c06SBlue Swirl     uint64_t time = cpu_ldq_data(env, a1);
196defb0e31SAlexander Graf 
197defb0e31SAlexander Graf     if (time == -1ULL) {
198defb0e31SAlexander Graf         return;
199defb0e31SAlexander Graf     }
200defb0e31SAlexander Graf 
201defb0e31SAlexander Graf     /* difference between now and then */
202defb0e31SAlexander Graf     time -= clock_value(env);
203defb0e31SAlexander Graf     /* nanoseconds */
204defb0e31SAlexander Graf     time = (time * 125) >> 9;
205defb0e31SAlexander Graf 
206defb0e31SAlexander Graf     qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
207defb0e31SAlexander Graf }
208defb0e31SAlexander Graf 
209defb0e31SAlexander Graf /* Store Clock Comparator */
210089f5c06SBlue Swirl void HELPER(stckc)(CPUS390XState *env, uint64_t a1)
211defb0e31SAlexander Graf {
212defb0e31SAlexander Graf     /* XXX implement */
213089f5c06SBlue Swirl     cpu_stq_data(env, a1, 0);
214defb0e31SAlexander Graf }
215defb0e31SAlexander Graf 
216defb0e31SAlexander Graf /* Set CPU Timer */
217089f5c06SBlue Swirl void HELPER(spt)(CPUS390XState *env, uint64_t a1)
218defb0e31SAlexander Graf {
219089f5c06SBlue Swirl     uint64_t time = cpu_ldq_data(env, a1);
220defb0e31SAlexander Graf 
221defb0e31SAlexander Graf     if (time == -1ULL) {
222defb0e31SAlexander Graf         return;
223defb0e31SAlexander Graf     }
224defb0e31SAlexander Graf 
225defb0e31SAlexander Graf     /* nanoseconds */
226defb0e31SAlexander Graf     time = (time * 125) >> 9;
227defb0e31SAlexander Graf 
228defb0e31SAlexander Graf     qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
229defb0e31SAlexander Graf }
230defb0e31SAlexander Graf 
231defb0e31SAlexander Graf /* Store CPU Timer */
232089f5c06SBlue Swirl void HELPER(stpt)(CPUS390XState *env, uint64_t a1)
233defb0e31SAlexander Graf {
234defb0e31SAlexander Graf     /* XXX implement */
235089f5c06SBlue Swirl     cpu_stq_data(env, a1, 0);
236defb0e31SAlexander Graf }
237defb0e31SAlexander Graf 
238defb0e31SAlexander Graf /* Store System Information */
239089f5c06SBlue Swirl uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0,
240089f5c06SBlue Swirl                       uint32_t r1)
241defb0e31SAlexander Graf {
242defb0e31SAlexander Graf     int cc = 0;
243defb0e31SAlexander Graf     int sel1, sel2;
244defb0e31SAlexander Graf 
245defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
246defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
247defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
248defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
249defb0e31SAlexander Graf     }
250defb0e31SAlexander Graf 
251defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
252defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
253defb0e31SAlexander Graf 
254defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
255defb0e31SAlexander Graf 
256defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
257defb0e31SAlexander Graf     case STSI_LEVEL_1:
258defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
259defb0e31SAlexander Graf             /* Basic Machine Configuration */
260defb0e31SAlexander Graf             struct sysib_111 sysib;
261defb0e31SAlexander Graf 
262defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
263defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
264defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
265defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
266defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
267defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
268defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
269defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
270defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
271defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
272defb0e31SAlexander Graf             /* Basic Machine CPU */
273defb0e31SAlexander Graf             struct sysib_121 sysib;
274defb0e31SAlexander Graf 
275defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
276defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
277defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
278defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
279defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
280defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
281defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
282defb0e31SAlexander Graf             /* Basic Machine CPUs */
283defb0e31SAlexander Graf             struct sysib_122 sysib;
284defb0e31SAlexander Graf 
285defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
286defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
287defb0e31SAlexander Graf             /* XXX change when SMP comes */
288defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
289defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
290defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
291defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
292defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
293defb0e31SAlexander Graf         } else {
294defb0e31SAlexander Graf             cc = 3;
295defb0e31SAlexander Graf         }
296defb0e31SAlexander Graf         break;
297defb0e31SAlexander Graf     case STSI_LEVEL_2:
298defb0e31SAlexander Graf         {
299defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
300defb0e31SAlexander Graf                 /* LPAR CPU */
301defb0e31SAlexander Graf                 struct sysib_221 sysib;
302defb0e31SAlexander Graf 
303defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
304defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
305defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
306defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
307defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
308defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
309defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
310defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
311defb0e31SAlexander Graf                 /* LPAR CPUs */
312defb0e31SAlexander Graf                 struct sysib_222 sysib;
313defb0e31SAlexander Graf 
314defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
315defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
316defb0e31SAlexander Graf                 sysib.lcpuc = 0;
317defb0e31SAlexander Graf                 /* XXX change when SMP comes */
318defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
319defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
320defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
321defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
322defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
323defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
324defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
325defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
326defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
327defb0e31SAlexander Graf             } else {
328defb0e31SAlexander Graf                 cc = 3;
329defb0e31SAlexander Graf             }
330defb0e31SAlexander Graf             break;
331defb0e31SAlexander Graf         }
332defb0e31SAlexander Graf     case STSI_LEVEL_3:
333defb0e31SAlexander Graf         {
334defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
335defb0e31SAlexander Graf                 /* VM CPUs */
336defb0e31SAlexander Graf                 struct sysib_322 sysib;
337defb0e31SAlexander Graf 
338defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
339defb0e31SAlexander Graf                 sysib.count = 1;
340defb0e31SAlexander Graf                 /* XXX change when SMP comes */
341defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
342defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
343defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
344defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
345defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
346defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
347defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
348defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
349defb0e31SAlexander Graf             } else {
350defb0e31SAlexander Graf                 cc = 3;
351defb0e31SAlexander Graf             }
352defb0e31SAlexander Graf             break;
353defb0e31SAlexander Graf         }
354defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
355defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
356defb0e31SAlexander Graf         break;
357defb0e31SAlexander Graf     default:
358defb0e31SAlexander Graf         cc = 3;
359defb0e31SAlexander Graf         break;
360defb0e31SAlexander Graf     }
361defb0e31SAlexander Graf 
362defb0e31SAlexander Graf     return cc;
363defb0e31SAlexander Graf }
364defb0e31SAlexander Graf 
365089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
366089f5c06SBlue Swirl                       uint64_t cpu_addr)
367defb0e31SAlexander Graf {
368defb0e31SAlexander Graf     int cc = 0;
369defb0e31SAlexander Graf 
370defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
37171e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
372defb0e31SAlexander Graf 
373defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
374defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
375defb0e31SAlexander Graf 
376defb0e31SAlexander Graf     switch (order_code) {
377defb0e31SAlexander Graf     case SIGP_SET_ARCH:
378defb0e31SAlexander Graf         /* switch arch */
379defb0e31SAlexander Graf         break;
380defb0e31SAlexander Graf     case SIGP_SENSE:
381defb0e31SAlexander Graf         /* enumerate CPU status */
382defb0e31SAlexander Graf         if (cpu_addr) {
383defb0e31SAlexander Graf             /* XXX implement when SMP comes */
384defb0e31SAlexander Graf             return 3;
385defb0e31SAlexander Graf         }
386defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
387defb0e31SAlexander Graf         cc = 1;
388defb0e31SAlexander Graf         break;
3891864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
3901864b94aSAlexander Graf     case SIGP_RESTART:
3911864b94aSAlexander Graf         qemu_system_reset_request();
3921864b94aSAlexander Graf         cpu_loop_exit(env);
3931864b94aSAlexander Graf         break;
3941864b94aSAlexander Graf     case SIGP_STOP:
3951864b94aSAlexander Graf         qemu_system_shutdown_request();
3961864b94aSAlexander Graf         cpu_loop_exit(env);
3971864b94aSAlexander Graf         break;
3981864b94aSAlexander Graf #endif
399defb0e31SAlexander Graf     default:
400defb0e31SAlexander Graf         /* unknown sigp */
401defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
402defb0e31SAlexander Graf         cc = 3;
403defb0e31SAlexander Graf     }
404defb0e31SAlexander Graf 
405defb0e31SAlexander Graf     return cc;
406defb0e31SAlexander Graf }
407defb0e31SAlexander Graf #endif
408