xref: /qemu/target/s390x/tcg/misc_helper.c (revision 3f38f309b22d9a30b5b427501eb3d522c439482e)
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"
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 {
240e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
241e805a0d3SRichard Henderson     env->psa = prefix;
242defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
243defb0e31SAlexander Graf     tlb_flush_page(env, 0);
244defb0e31SAlexander Graf     tlb_flush_page(env, TARGET_PAGE_SIZE);
245defb0e31SAlexander Graf }
246defb0e31SAlexander Graf 
247a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env)
248defb0e31SAlexander Graf {
249defb0e31SAlexander Graf     uint64_t time;
250defb0e31SAlexander Graf 
251defb0e31SAlexander Graf     time = env->tod_offset +
252bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
253defb0e31SAlexander Graf 
254defb0e31SAlexander Graf     return time;
255defb0e31SAlexander Graf }
256defb0e31SAlexander Graf 
257defb0e31SAlexander Graf /* Store Clock */
258434c91a5SRichard Henderson uint64_t HELPER(stck)(CPUS390XState *env)
259defb0e31SAlexander Graf {
260434c91a5SRichard Henderson     return clock_value(env);
261defb0e31SAlexander Graf }
262defb0e31SAlexander Graf 
263defb0e31SAlexander Graf /* Set Clock Comparator */
264dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
265defb0e31SAlexander Graf {
266defb0e31SAlexander Graf     if (time == -1ULL) {
267defb0e31SAlexander Graf         return;
268defb0e31SAlexander Graf     }
269defb0e31SAlexander Graf 
270defb0e31SAlexander Graf     /* difference between now and then */
271defb0e31SAlexander Graf     time -= clock_value(env);
272defb0e31SAlexander Graf     /* nanoseconds */
273defb0e31SAlexander Graf     time = (time * 125) >> 9;
274defb0e31SAlexander Graf 
275bc72ad67SAlex Bligh     timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
276defb0e31SAlexander Graf }
277defb0e31SAlexander Graf 
278defb0e31SAlexander Graf /* Store Clock Comparator */
279dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
280defb0e31SAlexander Graf {
281defb0e31SAlexander Graf     /* XXX implement */
282dd3eb7b5SRichard Henderson     return 0;
283defb0e31SAlexander Graf }
284defb0e31SAlexander Graf 
285defb0e31SAlexander Graf /* Set CPU Timer */
286c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
287defb0e31SAlexander Graf {
288defb0e31SAlexander Graf     if (time == -1ULL) {
289defb0e31SAlexander Graf         return;
290defb0e31SAlexander Graf     }
291defb0e31SAlexander Graf 
292defb0e31SAlexander Graf     /* nanoseconds */
293defb0e31SAlexander Graf     time = (time * 125) >> 9;
294defb0e31SAlexander Graf 
295bc72ad67SAlex Bligh     timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
296defb0e31SAlexander Graf }
297defb0e31SAlexander Graf 
298defb0e31SAlexander Graf /* Store CPU Timer */
299c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
300defb0e31SAlexander Graf {
301defb0e31SAlexander Graf     /* XXX implement */
302c4f0a863SRichard Henderson     return 0;
303defb0e31SAlexander Graf }
304defb0e31SAlexander Graf 
305defb0e31SAlexander Graf /* Store System Information */
306d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
307d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
308defb0e31SAlexander Graf {
309defb0e31SAlexander Graf     int cc = 0;
310defb0e31SAlexander Graf     int sel1, sel2;
311defb0e31SAlexander Graf 
312defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
313defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
314defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
315defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
316defb0e31SAlexander Graf     }
317defb0e31SAlexander Graf 
318defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
319defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
320defb0e31SAlexander Graf 
321defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
322defb0e31SAlexander Graf 
323defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
324defb0e31SAlexander Graf     case STSI_LEVEL_1:
325defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
326defb0e31SAlexander Graf             /* Basic Machine Configuration */
327defb0e31SAlexander Graf             struct sysib_111 sysib;
328defb0e31SAlexander Graf 
329defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
330defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
331defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
332defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
333defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
334defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
335defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
336defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
337defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
338defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
339defb0e31SAlexander Graf             /* Basic Machine CPU */
340defb0e31SAlexander Graf             struct sysib_121 sysib;
341defb0e31SAlexander Graf 
342defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
343defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
344defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
345defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
346defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
347defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
348defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
349defb0e31SAlexander Graf             /* Basic Machine CPUs */
350defb0e31SAlexander Graf             struct sysib_122 sysib;
351defb0e31SAlexander Graf 
352defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
353defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
354defb0e31SAlexander Graf             /* XXX change when SMP comes */
355defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
356defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
357defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
358defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
359defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
360defb0e31SAlexander Graf         } else {
361defb0e31SAlexander Graf             cc = 3;
362defb0e31SAlexander Graf         }
363defb0e31SAlexander Graf         break;
364defb0e31SAlexander Graf     case STSI_LEVEL_2:
365defb0e31SAlexander Graf         {
366defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
367defb0e31SAlexander Graf                 /* LPAR CPU */
368defb0e31SAlexander Graf                 struct sysib_221 sysib;
369defb0e31SAlexander Graf 
370defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
371defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
372defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
373defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
374defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
375defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
376defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
377defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
378defb0e31SAlexander Graf                 /* LPAR CPUs */
379defb0e31SAlexander Graf                 struct sysib_222 sysib;
380defb0e31SAlexander Graf 
381defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
382defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
383defb0e31SAlexander Graf                 sysib.lcpuc = 0;
384defb0e31SAlexander Graf                 /* XXX change when SMP comes */
385defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
386defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
387defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
388defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
389defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
390defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
391defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
392defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
393defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
394defb0e31SAlexander Graf             } else {
395defb0e31SAlexander Graf                 cc = 3;
396defb0e31SAlexander Graf             }
397defb0e31SAlexander Graf             break;
398defb0e31SAlexander Graf         }
399defb0e31SAlexander Graf     case STSI_LEVEL_3:
400defb0e31SAlexander Graf         {
401defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
402defb0e31SAlexander Graf                 /* VM CPUs */
403defb0e31SAlexander Graf                 struct sysib_322 sysib;
404defb0e31SAlexander Graf 
405defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
406defb0e31SAlexander Graf                 sysib.count = 1;
407defb0e31SAlexander Graf                 /* XXX change when SMP comes */
408defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
409defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
410defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
411defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
412defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
413defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
414defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
415defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
416defb0e31SAlexander Graf             } else {
417defb0e31SAlexander Graf                 cc = 3;
418defb0e31SAlexander Graf             }
419defb0e31SAlexander Graf             break;
420defb0e31SAlexander Graf         }
421defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
422defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
423defb0e31SAlexander Graf         break;
424defb0e31SAlexander Graf     default:
425defb0e31SAlexander Graf         cc = 3;
426defb0e31SAlexander Graf         break;
427defb0e31SAlexander Graf     }
428defb0e31SAlexander Graf 
429defb0e31SAlexander Graf     return cc;
430defb0e31SAlexander Graf }
431defb0e31SAlexander Graf 
432089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
433089f5c06SBlue Swirl                       uint64_t cpu_addr)
434defb0e31SAlexander Graf {
435defb0e31SAlexander Graf     int cc = 0;
436defb0e31SAlexander Graf 
437defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
43871e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
439defb0e31SAlexander Graf 
440defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
441defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
442defb0e31SAlexander Graf 
443defb0e31SAlexander Graf     switch (order_code) {
444defb0e31SAlexander Graf     case SIGP_SET_ARCH:
445defb0e31SAlexander Graf         /* switch arch */
446defb0e31SAlexander Graf         break;
447defb0e31SAlexander Graf     case SIGP_SENSE:
448defb0e31SAlexander Graf         /* enumerate CPU status */
449defb0e31SAlexander Graf         if (cpu_addr) {
450defb0e31SAlexander Graf             /* XXX implement when SMP comes */
451defb0e31SAlexander Graf             return 3;
452defb0e31SAlexander Graf         }
453defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
454defb0e31SAlexander Graf         cc = 1;
455defb0e31SAlexander Graf         break;
4561864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
4571864b94aSAlexander Graf     case SIGP_RESTART:
4581864b94aSAlexander Graf         qemu_system_reset_request();
4595638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4601864b94aSAlexander Graf         break;
4611864b94aSAlexander Graf     case SIGP_STOP:
4621864b94aSAlexander Graf         qemu_system_shutdown_request();
4635638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4641864b94aSAlexander Graf         break;
4651864b94aSAlexander Graf #endif
466defb0e31SAlexander Graf     default:
467defb0e31SAlexander Graf         /* unknown sigp */
468defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
469defb0e31SAlexander Graf         cc = 3;
470defb0e31SAlexander Graf     }
471defb0e31SAlexander Graf 
472defb0e31SAlexander Graf     return cc;
473defb0e31SAlexander Graf }
474defb0e31SAlexander Graf #endif
475