xref: /qemu/target/s390x/tcg/misc_helper.c (revision f08b617018e424134a0a012b08253d567c62f7ee)
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"
242ef6175aSRichard Henderson #include "exec/helper-proto.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
31f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
3210ec5117SAlexander Graf 
331864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
34f0778475SChristian Borntraeger #include "sysemu/cpus.h"
359c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3640fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h"
3710ec5117SAlexander Graf #endif
38d5a43964SAlexander Graf 
39defb0e31SAlexander Graf /* #define DEBUG_HELPER */
40defb0e31SAlexander Graf #ifdef DEBUG_HELPER
41defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
42defb0e31SAlexander Graf #else
43defb0e31SAlexander Graf #define HELPER_LOG(x...)
44defb0e31SAlexander Graf #endif
45defb0e31SAlexander Graf 
46b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
47b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
48b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
49b4e2bd35SRichard Henderson {
5027103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
51b4e2bd35SRichard Henderson     int t;
52b4e2bd35SRichard Henderson 
5327103424SAndreas Färber     cs->exception_index = EXCP_PGM;
54b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
55b4e2bd35SRichard Henderson 
56b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
573f38f309SAndreas Färber     cpu_restore_state(cs, retaddr);
58b4e2bd35SRichard Henderson 
59b4e2bd35SRichard Henderson     /* Advance past the insn.  */
60b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
61b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
62b4e2bd35SRichard Henderson     env->psw.addr += 2 * t;
63b4e2bd35SRichard Henderson 
645638d180SAndreas Färber     cpu_loop_exit(cs);
65b4e2bd35SRichard Henderson }
66b4e2bd35SRichard Henderson 
67d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
68089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
69defb0e31SAlexander Graf {
7027103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
7127103424SAndreas Färber 
7271e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
7327103424SAndreas Färber     cs->exception_index = excp;
745638d180SAndreas Färber     cpu_loop_exit(cs);
75defb0e31SAlexander Graf }
76defb0e31SAlexander Graf 
77defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
78a158986dSStefan Weil 
79d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
80defb0e31SAlexander Graf {
8127103424SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
8227103424SAndreas Färber 
830d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
840d404541SRichard Henderson                   env->psw.addr);
85defb0e31SAlexander Graf 
86defb0e31SAlexander Graf     if (kvm_enabled()) {
87af2be207SJan Kiszka #ifdef CONFIG_KVM
8827103424SAndreas Färber         kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code);
89af2be207SJan Kiszka #endif
90defb0e31SAlexander Graf     } else {
9127103424SAndreas Färber         CPUState *cs = CPU(cpu);
9227103424SAndreas Färber 
93defb0e31SAlexander Graf         env->int_pgm_code = code;
94d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
9527103424SAndreas Färber         cs->exception_index = EXCP_PGM;
965638d180SAndreas Färber         cpu_loop_exit(cs);
97defb0e31SAlexander Graf     }
98defb0e31SAlexander Graf }
99defb0e31SAlexander Graf 
100defb0e31SAlexander Graf /* SCLP service call */
101dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
102defb0e31SAlexander Graf {
1036e252802SThomas Huth     int r = sclp_service_call(env, r1, r2);
1049abf567dSChristian Borntraeger     if (r < 0) {
1059abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
106d5a43964SAlexander Graf         return 0;
107d5a43964SAlexander Graf     }
1089abf567dSChristian Borntraeger     return r;
1099abf567dSChristian Borntraeger }
110defb0e31SAlexander Graf 
111268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
112f0778475SChristian Borntraeger static void cpu_reset_all(void)
113f0778475SChristian Borntraeger {
114bdc44640SAndreas Färber     CPUState *cs;
115f0778475SChristian Borntraeger     S390CPUClass *scc;
116f0778475SChristian Borntraeger 
117bdc44640SAndreas Färber     CPU_FOREACH(cs) {
118bdc44640SAndreas Färber         scc = S390_CPU_GET_CLASS(cs);
119bdc44640SAndreas Färber         scc->cpu_reset(cs);
120f0778475SChristian Borntraeger     }
121f0778475SChristian Borntraeger }
122f0778475SChristian Borntraeger 
123d8b30c83SChristian Borntraeger static void cpu_full_reset_all(void)
124d8b30c83SChristian Borntraeger {
125d8b30c83SChristian Borntraeger     CPUState *cpu;
126d8b30c83SChristian Borntraeger 
127d8b30c83SChristian Borntraeger     CPU_FOREACH(cpu) {
128d8b30c83SChristian Borntraeger         cpu_reset(cpu);
129d8b30c83SChristian Borntraeger     }
130d8b30c83SChristian Borntraeger }
131d8b30c83SChristian Borntraeger 
132d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
133d8b30c83SChristian Borntraeger {
134d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
135d8b30c83SChristian Borntraeger 
136d8b30c83SChristian Borntraeger     pause_all_vcpus();
137d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
138d8b30c83SChristian Borntraeger     cpu_full_reset_all();
139d8b30c83SChristian Borntraeger     io_subsystem_reset();
140d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
141d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
142d8b30c83SChristian Borntraeger     resume_all_vcpus();
143d8b30c83SChristian Borntraeger     return 0;
144d8b30c83SChristian Borntraeger }
145d8b30c83SChristian Borntraeger 
146f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
147f0778475SChristian Borntraeger {
148f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
149f0778475SChristian Borntraeger 
150f0778475SChristian Borntraeger     pause_all_vcpus();
151f0778475SChristian Borntraeger     cpu_synchronize_all_states();
152f0778475SChristian Borntraeger     cpu_reset_all();
153f0778475SChristian Borntraeger     io_subsystem_reset();
154f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
155f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
156f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
157f0778475SChristian Borntraeger     resume_all_vcpus();
158f0778475SChristian Borntraeger     return 0;
159f0778475SChristian Borntraeger }
160f0778475SChristian Borntraeger 
161268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
162268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
163268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
164268846baSEugene (jno) Dvurechenski {
165268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
166268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
167268846baSEugene (jno) Dvurechenski 
168268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
169268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
170268846baSEugene (jno) Dvurechenski         return;
171268846baSEugene (jno) Dvurechenski     }
172268846baSEugene (jno) Dvurechenski 
173268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
174268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
175268846baSEugene (jno) Dvurechenski         return;
176268846baSEugene (jno) Dvurechenski     }
177268846baSEugene (jno) Dvurechenski 
178268846baSEugene (jno) Dvurechenski     switch (subcode) {
179d8b30c83SChristian Borntraeger     case 0:
180d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
181d8b30c83SChristian Borntraeger         break;
182f0778475SChristian Borntraeger     case 1:
183f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
184f0778475SChristian Borntraeger         break;
185268846baSEugene (jno) Dvurechenski     case 5:
186268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
187268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
188268846baSEugene (jno) Dvurechenski             return;
189268846baSEugene (jno) Dvurechenski         }
190268846baSEugene (jno) Dvurechenski         env->regs[r1+1] = DIAG_308_RC_INVALID;
191268846baSEugene (jno) Dvurechenski         return;
192268846baSEugene (jno) Dvurechenski     case 6:
193268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
194268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
195268846baSEugene (jno) Dvurechenski             return;
196268846baSEugene (jno) Dvurechenski         }
197268846baSEugene (jno) Dvurechenski         env->regs[r1+1] = DIAG_308_RC_NO_CONF;
198268846baSEugene (jno) Dvurechenski         return;
199268846baSEugene (jno) Dvurechenski     default:
200268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
201268846baSEugene (jno) Dvurechenski         break;
202268846baSEugene (jno) Dvurechenski     }
203268846baSEugene (jno) Dvurechenski }
204268846baSEugene (jno) Dvurechenski #endif
205268846baSEugene (jno) Dvurechenski 
206defb0e31SAlexander Graf /* DIAG */
207089f5c06SBlue Swirl uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
208089f5c06SBlue Swirl                       uint64_t code)
209defb0e31SAlexander Graf {
210defb0e31SAlexander Graf     uint64_t r;
211defb0e31SAlexander Graf 
212defb0e31SAlexander Graf     switch (num) {
213defb0e31SAlexander Graf     case 0x500:
214defb0e31SAlexander Graf         /* KVM hypercall */
21528e942f8SCornelia Huck         r = s390_virtio_hypercall(env);
216defb0e31SAlexander Graf         break;
217defb0e31SAlexander Graf     case 0x44:
218defb0e31SAlexander Graf         /* yield */
219defb0e31SAlexander Graf         r = 0;
220defb0e31SAlexander Graf         break;
221defb0e31SAlexander Graf     case 0x308:
222defb0e31SAlexander Graf         /* ipl */
223defb0e31SAlexander Graf         r = 0;
224defb0e31SAlexander Graf         break;
225defb0e31SAlexander Graf     default:
226defb0e31SAlexander Graf         r = -1;
227defb0e31SAlexander Graf         break;
228defb0e31SAlexander Graf     }
229defb0e31SAlexander Graf 
230defb0e31SAlexander Graf     if (r) {
231d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
232defb0e31SAlexander Graf     }
233defb0e31SAlexander Graf 
234defb0e31SAlexander Graf     return r;
235defb0e31SAlexander Graf }
236defb0e31SAlexander Graf 
237defb0e31SAlexander Graf /* Set Prefix */
238089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
239defb0e31SAlexander Graf {
24031b030d4SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
241e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
24231b030d4SAndreas Färber 
243e805a0d3SRichard Henderson     env->psa = prefix;
244defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
24531b030d4SAndreas Färber     tlb_flush_page(cs, 0);
24631b030d4SAndreas Färber     tlb_flush_page(cs, TARGET_PAGE_SIZE);
247defb0e31SAlexander Graf }
248defb0e31SAlexander Graf 
249a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env)
250defb0e31SAlexander Graf {
251defb0e31SAlexander Graf     uint64_t time;
252defb0e31SAlexander Graf 
253defb0e31SAlexander Graf     time = env->tod_offset +
254bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
255defb0e31SAlexander Graf 
256defb0e31SAlexander Graf     return time;
257defb0e31SAlexander Graf }
258defb0e31SAlexander Graf 
259defb0e31SAlexander Graf /* Store Clock */
260434c91a5SRichard Henderson uint64_t HELPER(stck)(CPUS390XState *env)
261defb0e31SAlexander Graf {
262434c91a5SRichard Henderson     return clock_value(env);
263defb0e31SAlexander Graf }
264defb0e31SAlexander Graf 
265defb0e31SAlexander Graf /* Set Clock Comparator */
266dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
267defb0e31SAlexander Graf {
268defb0e31SAlexander Graf     if (time == -1ULL) {
269defb0e31SAlexander Graf         return;
270defb0e31SAlexander Graf     }
271defb0e31SAlexander Graf 
272defb0e31SAlexander Graf     /* difference between now and then */
273defb0e31SAlexander Graf     time -= clock_value(env);
274defb0e31SAlexander Graf     /* nanoseconds */
275defb0e31SAlexander Graf     time = (time * 125) >> 9;
276defb0e31SAlexander Graf 
277bc72ad67SAlex Bligh     timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
278defb0e31SAlexander Graf }
279defb0e31SAlexander Graf 
280defb0e31SAlexander Graf /* Store Clock Comparator */
281dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
282defb0e31SAlexander Graf {
283defb0e31SAlexander Graf     /* XXX implement */
284dd3eb7b5SRichard Henderson     return 0;
285defb0e31SAlexander Graf }
286defb0e31SAlexander Graf 
287defb0e31SAlexander Graf /* Set CPU Timer */
288c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
289defb0e31SAlexander Graf {
290defb0e31SAlexander Graf     if (time == -1ULL) {
291defb0e31SAlexander Graf         return;
292defb0e31SAlexander Graf     }
293defb0e31SAlexander Graf 
294defb0e31SAlexander Graf     /* nanoseconds */
295defb0e31SAlexander Graf     time = (time * 125) >> 9;
296defb0e31SAlexander Graf 
297bc72ad67SAlex Bligh     timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
298defb0e31SAlexander Graf }
299defb0e31SAlexander Graf 
300defb0e31SAlexander Graf /* Store CPU Timer */
301c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
302defb0e31SAlexander Graf {
303defb0e31SAlexander Graf     /* XXX implement */
304c4f0a863SRichard Henderson     return 0;
305defb0e31SAlexander Graf }
306defb0e31SAlexander Graf 
307defb0e31SAlexander Graf /* Store System Information */
308d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
309d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
310defb0e31SAlexander Graf {
311defb0e31SAlexander Graf     int cc = 0;
312defb0e31SAlexander Graf     int sel1, sel2;
313defb0e31SAlexander Graf 
314defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
315defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
316defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
317defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
318defb0e31SAlexander Graf     }
319defb0e31SAlexander Graf 
320defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
321defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
322defb0e31SAlexander Graf 
323defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
324defb0e31SAlexander Graf 
325defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
326defb0e31SAlexander Graf     case STSI_LEVEL_1:
327defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
328defb0e31SAlexander Graf             /* Basic Machine Configuration */
329defb0e31SAlexander Graf             struct sysib_111 sysib;
330defb0e31SAlexander Graf 
331defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
332defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
333defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
334defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
335defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
336defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
337defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
338defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
339eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
340defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
341defb0e31SAlexander Graf             /* Basic Machine CPU */
342defb0e31SAlexander Graf             struct sysib_121 sysib;
343defb0e31SAlexander Graf 
344defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
345defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
346defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
347defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
348defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
349eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
350defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
351defb0e31SAlexander Graf             /* Basic Machine CPUs */
352defb0e31SAlexander Graf             struct sysib_122 sysib;
353defb0e31SAlexander Graf 
354defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
355defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
356defb0e31SAlexander Graf             /* XXX change when SMP comes */
357defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
358defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
359defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
360defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
361eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
362defb0e31SAlexander Graf         } else {
363defb0e31SAlexander Graf             cc = 3;
364defb0e31SAlexander Graf         }
365defb0e31SAlexander Graf         break;
366defb0e31SAlexander Graf     case STSI_LEVEL_2:
367defb0e31SAlexander Graf         {
368defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
369defb0e31SAlexander Graf                 /* LPAR CPU */
370defb0e31SAlexander Graf                 struct sysib_221 sysib;
371defb0e31SAlexander Graf 
372defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
373defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
374defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
375defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
376defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
377defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
378eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
379defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
380defb0e31SAlexander Graf                 /* LPAR CPUs */
381defb0e31SAlexander Graf                 struct sysib_222 sysib;
382defb0e31SAlexander Graf 
383defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
384defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
385defb0e31SAlexander Graf                 sysib.lcpuc = 0;
386defb0e31SAlexander Graf                 /* XXX change when SMP comes */
387defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
388defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
389defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
390defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
391defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
392defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
393defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
394defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
395eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
396defb0e31SAlexander Graf             } else {
397defb0e31SAlexander Graf                 cc = 3;
398defb0e31SAlexander Graf             }
399defb0e31SAlexander Graf             break;
400defb0e31SAlexander Graf         }
401defb0e31SAlexander Graf     case STSI_LEVEL_3:
402defb0e31SAlexander Graf         {
403defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
404defb0e31SAlexander Graf                 /* VM CPUs */
405defb0e31SAlexander Graf                 struct sysib_322 sysib;
406defb0e31SAlexander Graf 
407defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
408defb0e31SAlexander Graf                 sysib.count = 1;
409defb0e31SAlexander Graf                 /* XXX change when SMP comes */
410defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
411defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
412defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
413defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
414defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
415defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
416defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
417eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
418defb0e31SAlexander Graf             } else {
419defb0e31SAlexander Graf                 cc = 3;
420defb0e31SAlexander Graf             }
421defb0e31SAlexander Graf             break;
422defb0e31SAlexander Graf         }
423defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
424defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
425defb0e31SAlexander Graf         break;
426defb0e31SAlexander Graf     default:
427defb0e31SAlexander Graf         cc = 3;
428defb0e31SAlexander Graf         break;
429defb0e31SAlexander Graf     }
430defb0e31SAlexander Graf 
431defb0e31SAlexander Graf     return cc;
432defb0e31SAlexander Graf }
433defb0e31SAlexander Graf 
434089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
435089f5c06SBlue Swirl                       uint64_t cpu_addr)
436defb0e31SAlexander Graf {
437defb0e31SAlexander Graf     int cc = 0;
438defb0e31SAlexander Graf 
439defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
44071e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
441defb0e31SAlexander Graf 
442defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
443defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
444defb0e31SAlexander Graf 
445defb0e31SAlexander Graf     switch (order_code) {
446defb0e31SAlexander Graf     case SIGP_SET_ARCH:
447defb0e31SAlexander Graf         /* switch arch */
448defb0e31SAlexander Graf         break;
449defb0e31SAlexander Graf     case SIGP_SENSE:
450defb0e31SAlexander Graf         /* enumerate CPU status */
451defb0e31SAlexander Graf         if (cpu_addr) {
452defb0e31SAlexander Graf             /* XXX implement when SMP comes */
453defb0e31SAlexander Graf             return 3;
454defb0e31SAlexander Graf         }
455defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
456defb0e31SAlexander Graf         cc = 1;
457defb0e31SAlexander Graf         break;
4581864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
4591864b94aSAlexander Graf     case SIGP_RESTART:
4601864b94aSAlexander Graf         qemu_system_reset_request();
4615638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4621864b94aSAlexander Graf         break;
4631864b94aSAlexander Graf     case SIGP_STOP:
4641864b94aSAlexander Graf         qemu_system_shutdown_request();
4655638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4661864b94aSAlexander Graf         break;
4671864b94aSAlexander Graf #endif
468defb0e31SAlexander Graf     default:
469defb0e31SAlexander Graf         /* unknown sigp */
470defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
471defb0e31SAlexander Graf         cc = 3;
472defb0e31SAlexander Graf     }
473defb0e31SAlexander Graf 
474defb0e31SAlexander Graf     return cc;
475defb0e31SAlexander Graf }
476defb0e31SAlexander Graf #endif
477