xref: /qemu/target/s390x/tcg/misc_helper.c (revision df75a4e2c607836eee044d7e6b0d94724d6ebf21)
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"
28df75a4e2SFan Zhang #include "exec/address-spaces.h"
29af2be207SJan Kiszka #ifdef CONFIG_KVM
30af2be207SJan Kiszka #include <linux/kvm.h>
31af2be207SJan Kiszka #endif
32f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
3310ec5117SAlexander Graf 
341864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
35f0778475SChristian Borntraeger #include "sysemu/cpus.h"
369c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3740fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h"
38df75a4e2SFan Zhang #include "hw/s390x/ipl.h"
3910ec5117SAlexander Graf #endif
40d5a43964SAlexander Graf 
41defb0e31SAlexander Graf /* #define DEBUG_HELPER */
42defb0e31SAlexander Graf #ifdef DEBUG_HELPER
43defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
44defb0e31SAlexander Graf #else
45defb0e31SAlexander Graf #define HELPER_LOG(x...)
46defb0e31SAlexander Graf #endif
47defb0e31SAlexander Graf 
48b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
49b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
50b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
51b4e2bd35SRichard Henderson {
5227103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
53b4e2bd35SRichard Henderson     int t;
54b4e2bd35SRichard Henderson 
5527103424SAndreas Färber     cs->exception_index = EXCP_PGM;
56b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
57b4e2bd35SRichard Henderson 
58b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
593f38f309SAndreas Färber     cpu_restore_state(cs, retaddr);
60b4e2bd35SRichard Henderson 
61b4e2bd35SRichard Henderson     /* Advance past the insn.  */
62b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
63b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
64b4e2bd35SRichard Henderson     env->psw.addr += 2 * t;
65b4e2bd35SRichard Henderson 
665638d180SAndreas Färber     cpu_loop_exit(cs);
67b4e2bd35SRichard Henderson }
68b4e2bd35SRichard Henderson 
69d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
70089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
71defb0e31SAlexander Graf {
7227103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
7327103424SAndreas Färber 
7471e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
7527103424SAndreas Färber     cs->exception_index = excp;
765638d180SAndreas Färber     cpu_loop_exit(cs);
77defb0e31SAlexander Graf }
78defb0e31SAlexander Graf 
79defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
80a158986dSStefan Weil 
81d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
82defb0e31SAlexander Graf {
8327103424SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
8427103424SAndreas Färber 
850d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
860d404541SRichard Henderson                   env->psw.addr);
87defb0e31SAlexander Graf 
88defb0e31SAlexander Graf     if (kvm_enabled()) {
89af2be207SJan Kiszka #ifdef CONFIG_KVM
90de13d216SCornelia Huck         struct kvm_s390_irq irq = {
91de13d216SCornelia Huck             .type = KVM_S390_PROGRAM_INT,
92de13d216SCornelia Huck             .u.pgm.code = code,
93de13d216SCornelia Huck         };
94de13d216SCornelia Huck 
95de13d216SCornelia Huck         kvm_s390_vcpu_interrupt(cpu, &irq);
96af2be207SJan Kiszka #endif
97defb0e31SAlexander Graf     } else {
9827103424SAndreas Färber         CPUState *cs = CPU(cpu);
9927103424SAndreas Färber 
100defb0e31SAlexander Graf         env->int_pgm_code = code;
101d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
10227103424SAndreas Färber         cs->exception_index = EXCP_PGM;
1035638d180SAndreas Färber         cpu_loop_exit(cs);
104defb0e31SAlexander Graf     }
105defb0e31SAlexander Graf }
106defb0e31SAlexander Graf 
107defb0e31SAlexander Graf /* SCLP service call */
108dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
109defb0e31SAlexander Graf {
1106e252802SThomas Huth     int r = sclp_service_call(env, r1, r2);
1119abf567dSChristian Borntraeger     if (r < 0) {
1129abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
113d5a43964SAlexander Graf         return 0;
114d5a43964SAlexander Graf     }
1159abf567dSChristian Borntraeger     return r;
1169abf567dSChristian Borntraeger }
117defb0e31SAlexander Graf 
118268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
119d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
120d8b30c83SChristian Borntraeger {
121d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
12285ca3371SDavid Hildenbrand     CPUState *t;
123d8b30c83SChristian Borntraeger 
124d8b30c83SChristian Borntraeger     pause_all_vcpus();
125d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
12685ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
12785ca3371SDavid Hildenbrand         run_on_cpu(t, s390_do_cpu_full_reset, t);
12885ca3371SDavid Hildenbrand     }
1294cb88c3cSDominik Dingel     cmma_reset(cpu);
130d8b30c83SChristian Borntraeger     io_subsystem_reset();
131d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
132d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
133d8b30c83SChristian Borntraeger     resume_all_vcpus();
134d8b30c83SChristian Borntraeger     return 0;
135d8b30c83SChristian Borntraeger }
136d8b30c83SChristian Borntraeger 
137f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
138f0778475SChristian Borntraeger {
139f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
14085ca3371SDavid Hildenbrand     CPUState *t;
141f0778475SChristian Borntraeger 
142f0778475SChristian Borntraeger     pause_all_vcpus();
143f0778475SChristian Borntraeger     cpu_synchronize_all_states();
14485ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
14585ca3371SDavid Hildenbrand         run_on_cpu(t, s390_do_cpu_reset, t);
14685ca3371SDavid Hildenbrand     }
1474cb88c3cSDominik Dingel     cmma_reset(cpu);
148f0778475SChristian Borntraeger     io_subsystem_reset();
149f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
150f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
151f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
152f0778475SChristian Borntraeger     resume_all_vcpus();
153f0778475SChristian Borntraeger     return 0;
154f0778475SChristian Borntraeger }
155f0778475SChristian Borntraeger 
156df75a4e2SFan Zhang #define DIAG_308_RC_OK              0x0001
157268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
158268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
159df75a4e2SFan Zhang 
160268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
161268846baSEugene (jno) Dvurechenski {
162268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
163268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
164df75a4e2SFan Zhang     IplParameterBlock *iplb;
165268846baSEugene (jno) Dvurechenski 
166268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
167268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
168268846baSEugene (jno) Dvurechenski         return;
169268846baSEugene (jno) Dvurechenski     }
170268846baSEugene (jno) Dvurechenski 
171268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
172268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
173268846baSEugene (jno) Dvurechenski         return;
174268846baSEugene (jno) Dvurechenski     }
175268846baSEugene (jno) Dvurechenski 
176268846baSEugene (jno) Dvurechenski     switch (subcode) {
177d8b30c83SChristian Borntraeger     case 0:
178d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
179d8b30c83SChristian Borntraeger         break;
180f0778475SChristian Borntraeger     case 1:
181f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
182f0778475SChristian Borntraeger         break;
183268846baSEugene (jno) Dvurechenski     case 5:
184268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
185268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
186268846baSEugene (jno) Dvurechenski             return;
187268846baSEugene (jno) Dvurechenski         }
188df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
189df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), false)) {
190df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
191df75a4e2SFan Zhang             return;
192df75a4e2SFan Zhang         }
193df75a4e2SFan Zhang         iplb = g_malloc0(sizeof(struct IplParameterBlock));
194df75a4e2SFan Zhang         cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock));
195df75a4e2SFan Zhang         if (!s390_ipl_update_diag308(iplb)) {
196df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
197df75a4e2SFan Zhang         } else {
198268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
199df75a4e2SFan Zhang         }
200df75a4e2SFan Zhang         g_free(iplb);
201268846baSEugene (jno) Dvurechenski         return;
202268846baSEugene (jno) Dvurechenski     case 6:
203268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
204268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
205268846baSEugene (jno) Dvurechenski             return;
206268846baSEugene (jno) Dvurechenski         }
207df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
208df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), true)) {
209df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
210df75a4e2SFan Zhang             return;
211df75a4e2SFan Zhang         }
212df75a4e2SFan Zhang         iplb = s390_ipl_get_iplb();
213df75a4e2SFan Zhang         if (iplb) {
214df75a4e2SFan Zhang             cpu_physical_memory_write(addr, iplb,
215df75a4e2SFan Zhang                                       sizeof(struct IplParameterBlock));
216df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
217df75a4e2SFan Zhang         } else {
218268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
219df75a4e2SFan Zhang         }
220268846baSEugene (jno) Dvurechenski         return;
221268846baSEugene (jno) Dvurechenski     default:
222268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
223268846baSEugene (jno) Dvurechenski         break;
224268846baSEugene (jno) Dvurechenski     }
225268846baSEugene (jno) Dvurechenski }
226268846baSEugene (jno) Dvurechenski #endif
227268846baSEugene (jno) Dvurechenski 
228defb0e31SAlexander Graf /* DIAG */
229089f5c06SBlue Swirl uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
230089f5c06SBlue Swirl                       uint64_t code)
231defb0e31SAlexander Graf {
232defb0e31SAlexander Graf     uint64_t r;
233defb0e31SAlexander Graf 
234defb0e31SAlexander Graf     switch (num) {
235defb0e31SAlexander Graf     case 0x500:
236defb0e31SAlexander Graf         /* KVM hypercall */
23728e942f8SCornelia Huck         r = s390_virtio_hypercall(env);
238defb0e31SAlexander Graf         break;
239defb0e31SAlexander Graf     case 0x44:
240defb0e31SAlexander Graf         /* yield */
241defb0e31SAlexander Graf         r = 0;
242defb0e31SAlexander Graf         break;
243defb0e31SAlexander Graf     case 0x308:
244defb0e31SAlexander Graf         /* ipl */
245defb0e31SAlexander Graf         r = 0;
246defb0e31SAlexander Graf         break;
247defb0e31SAlexander Graf     default:
248defb0e31SAlexander Graf         r = -1;
249defb0e31SAlexander Graf         break;
250defb0e31SAlexander Graf     }
251defb0e31SAlexander Graf 
252defb0e31SAlexander Graf     if (r) {
253d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
254defb0e31SAlexander Graf     }
255defb0e31SAlexander Graf 
256defb0e31SAlexander Graf     return r;
257defb0e31SAlexander Graf }
258defb0e31SAlexander Graf 
259defb0e31SAlexander Graf /* Set Prefix */
260089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
261defb0e31SAlexander Graf {
26231b030d4SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
263e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
26431b030d4SAndreas Färber 
265e805a0d3SRichard Henderson     env->psa = prefix;
266defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
26731b030d4SAndreas Färber     tlb_flush_page(cs, 0);
26831b030d4SAndreas Färber     tlb_flush_page(cs, TARGET_PAGE_SIZE);
269defb0e31SAlexander Graf }
270defb0e31SAlexander Graf 
271a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env)
272defb0e31SAlexander Graf {
273defb0e31SAlexander Graf     uint64_t time;
274defb0e31SAlexander Graf 
275defb0e31SAlexander Graf     time = env->tod_offset +
276bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
277defb0e31SAlexander Graf 
278defb0e31SAlexander Graf     return time;
279defb0e31SAlexander Graf }
280defb0e31SAlexander Graf 
281defb0e31SAlexander Graf /* Store Clock */
282434c91a5SRichard Henderson uint64_t HELPER(stck)(CPUS390XState *env)
283defb0e31SAlexander Graf {
284434c91a5SRichard Henderson     return clock_value(env);
285defb0e31SAlexander Graf }
286defb0e31SAlexander Graf 
287defb0e31SAlexander Graf /* Set Clock Comparator */
288dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
289defb0e31SAlexander Graf {
290defb0e31SAlexander Graf     if (time == -1ULL) {
291defb0e31SAlexander Graf         return;
292defb0e31SAlexander Graf     }
293defb0e31SAlexander Graf 
294defb0e31SAlexander Graf     /* difference between now and then */
295defb0e31SAlexander Graf     time -= clock_value(env);
296defb0e31SAlexander Graf     /* nanoseconds */
297defb0e31SAlexander Graf     time = (time * 125) >> 9;
298defb0e31SAlexander Graf 
299bc72ad67SAlex Bligh     timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
300defb0e31SAlexander Graf }
301defb0e31SAlexander Graf 
302defb0e31SAlexander Graf /* Store Clock Comparator */
303dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
304defb0e31SAlexander Graf {
305defb0e31SAlexander Graf     /* XXX implement */
306dd3eb7b5SRichard Henderson     return 0;
307defb0e31SAlexander Graf }
308defb0e31SAlexander Graf 
309defb0e31SAlexander Graf /* Set CPU Timer */
310c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
311defb0e31SAlexander Graf {
312defb0e31SAlexander Graf     if (time == -1ULL) {
313defb0e31SAlexander Graf         return;
314defb0e31SAlexander Graf     }
315defb0e31SAlexander Graf 
316defb0e31SAlexander Graf     /* nanoseconds */
317defb0e31SAlexander Graf     time = (time * 125) >> 9;
318defb0e31SAlexander Graf 
319bc72ad67SAlex Bligh     timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
320defb0e31SAlexander Graf }
321defb0e31SAlexander Graf 
322defb0e31SAlexander Graf /* Store CPU Timer */
323c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
324defb0e31SAlexander Graf {
325defb0e31SAlexander Graf     /* XXX implement */
326c4f0a863SRichard Henderson     return 0;
327defb0e31SAlexander Graf }
328defb0e31SAlexander Graf 
329defb0e31SAlexander Graf /* Store System Information */
330d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
331d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
332defb0e31SAlexander Graf {
333defb0e31SAlexander Graf     int cc = 0;
334defb0e31SAlexander Graf     int sel1, sel2;
335defb0e31SAlexander Graf 
336defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
337defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
338defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
339defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
340defb0e31SAlexander Graf     }
341defb0e31SAlexander Graf 
342defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
343defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
344defb0e31SAlexander Graf 
345defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
346defb0e31SAlexander Graf 
347defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
348defb0e31SAlexander Graf     case STSI_LEVEL_1:
349defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
350defb0e31SAlexander Graf             /* Basic Machine Configuration */
351defb0e31SAlexander Graf             struct sysib_111 sysib;
352defb0e31SAlexander Graf 
353defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
354defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
355defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
356defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
357defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
358defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
359defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
360defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
361eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
362defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
363defb0e31SAlexander Graf             /* Basic Machine CPU */
364defb0e31SAlexander Graf             struct sysib_121 sysib;
365defb0e31SAlexander Graf 
366defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
367defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
368defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
369defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
370defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
371eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
372defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
373defb0e31SAlexander Graf             /* Basic Machine CPUs */
374defb0e31SAlexander Graf             struct sysib_122 sysib;
375defb0e31SAlexander Graf 
376defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
377defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
378defb0e31SAlexander Graf             /* XXX change when SMP comes */
379defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
380defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
381defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
382defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
383eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
384defb0e31SAlexander Graf         } else {
385defb0e31SAlexander Graf             cc = 3;
386defb0e31SAlexander Graf         }
387defb0e31SAlexander Graf         break;
388defb0e31SAlexander Graf     case STSI_LEVEL_2:
389defb0e31SAlexander Graf         {
390defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
391defb0e31SAlexander Graf                 /* LPAR CPU */
392defb0e31SAlexander Graf                 struct sysib_221 sysib;
393defb0e31SAlexander Graf 
394defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
395defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
396defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
397defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
398defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
399defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
400eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
401defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
402defb0e31SAlexander Graf                 /* LPAR CPUs */
403defb0e31SAlexander Graf                 struct sysib_222 sysib;
404defb0e31SAlexander Graf 
405defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
406defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
407defb0e31SAlexander Graf                 sysib.lcpuc = 0;
408defb0e31SAlexander Graf                 /* XXX change when SMP comes */
409defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
410defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
411defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
412defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
413defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
414defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
415defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
416defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
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_3:
424defb0e31SAlexander Graf         {
425defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
426defb0e31SAlexander Graf                 /* VM CPUs */
427defb0e31SAlexander Graf                 struct sysib_322 sysib;
428defb0e31SAlexander Graf 
429defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
430defb0e31SAlexander Graf                 sysib.count = 1;
431defb0e31SAlexander Graf                 /* XXX change when SMP comes */
432defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
433defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
434defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
435defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
436defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
437defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
438defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
439eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
440defb0e31SAlexander Graf             } else {
441defb0e31SAlexander Graf                 cc = 3;
442defb0e31SAlexander Graf             }
443defb0e31SAlexander Graf             break;
444defb0e31SAlexander Graf         }
445defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
446defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
447defb0e31SAlexander Graf         break;
448defb0e31SAlexander Graf     default:
449defb0e31SAlexander Graf         cc = 3;
450defb0e31SAlexander Graf         break;
451defb0e31SAlexander Graf     }
452defb0e31SAlexander Graf 
453defb0e31SAlexander Graf     return cc;
454defb0e31SAlexander Graf }
455defb0e31SAlexander Graf 
456089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
457089f5c06SBlue Swirl                       uint64_t cpu_addr)
458defb0e31SAlexander Graf {
459defb0e31SAlexander Graf     int cc = 0;
460defb0e31SAlexander Graf 
461defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
46271e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
463defb0e31SAlexander Graf 
464defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
465defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
466defb0e31SAlexander Graf 
467defb0e31SAlexander Graf     switch (order_code) {
468defb0e31SAlexander Graf     case SIGP_SET_ARCH:
469defb0e31SAlexander Graf         /* switch arch */
470defb0e31SAlexander Graf         break;
471defb0e31SAlexander Graf     case SIGP_SENSE:
472defb0e31SAlexander Graf         /* enumerate CPU status */
473defb0e31SAlexander Graf         if (cpu_addr) {
474defb0e31SAlexander Graf             /* XXX implement when SMP comes */
475defb0e31SAlexander Graf             return 3;
476defb0e31SAlexander Graf         }
477defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
478defb0e31SAlexander Graf         cc = 1;
479defb0e31SAlexander Graf         break;
4801864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
4811864b94aSAlexander Graf     case SIGP_RESTART:
4821864b94aSAlexander Graf         qemu_system_reset_request();
4835638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4841864b94aSAlexander Graf         break;
4851864b94aSAlexander Graf     case SIGP_STOP:
4861864b94aSAlexander Graf         qemu_system_shutdown_request();
4875638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
4881864b94aSAlexander Graf         break;
4891864b94aSAlexander Graf #endif
490defb0e31SAlexander Graf     default:
491defb0e31SAlexander Graf         /* unknown sigp */
492defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
493defb0e31SAlexander Graf         cc = 3;
494defb0e31SAlexander Graf     }
495defb0e31SAlexander Graf 
496defb0e31SAlexander Graf     return cc;
497defb0e31SAlexander Graf }
498defb0e31SAlexander Graf #endif
499