xref: /qemu/target/s390x/tcg/misc_helper.c (revision 777c98c32ce577a9671b9267ff6e2802f69ebafd)
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"
338fc639afSXu Wang #include "hw/watchdog/wdt_diag288.h"
3410ec5117SAlexander Graf 
351864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
36f0778475SChristian Borntraeger #include "sysemu/cpus.h"
379c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3840fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h"
39df75a4e2SFan Zhang #include "hw/s390x/ipl.h"
4010ec5117SAlexander Graf #endif
41d5a43964SAlexander Graf 
42defb0e31SAlexander Graf /* #define DEBUG_HELPER */
43defb0e31SAlexander Graf #ifdef DEBUG_HELPER
44defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
45defb0e31SAlexander Graf #else
46defb0e31SAlexander Graf #define HELPER_LOG(x...)
47defb0e31SAlexander Graf #endif
48defb0e31SAlexander Graf 
49b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
50b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
51b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
52b4e2bd35SRichard Henderson {
5327103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
54b4e2bd35SRichard Henderson     int t;
55b4e2bd35SRichard Henderson 
5627103424SAndreas Färber     cs->exception_index = EXCP_PGM;
57b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
58b4e2bd35SRichard Henderson 
59b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
603f38f309SAndreas Färber     cpu_restore_state(cs, retaddr);
61b4e2bd35SRichard Henderson 
62b4e2bd35SRichard Henderson     /* Advance past the insn.  */
63b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
64b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
659bebf986SAurelien Jarno     env->psw.addr += t;
66b4e2bd35SRichard Henderson 
675638d180SAndreas Färber     cpu_loop_exit(cs);
68b4e2bd35SRichard Henderson }
69b4e2bd35SRichard Henderson 
70d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
71089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
72defb0e31SAlexander Graf {
7327103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
7427103424SAndreas Färber 
7571e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
7627103424SAndreas Färber     cs->exception_index = excp;
775638d180SAndreas Färber     cpu_loop_exit(cs);
78defb0e31SAlexander Graf }
79defb0e31SAlexander Graf 
80defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
81a158986dSStefan Weil 
82d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
83defb0e31SAlexander Graf {
8427103424SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
8527103424SAndreas Färber 
860d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
870d404541SRichard Henderson                   env->psw.addr);
88defb0e31SAlexander Graf 
89defb0e31SAlexander Graf     if (kvm_enabled()) {
90af2be207SJan Kiszka #ifdef CONFIG_KVM
91de13d216SCornelia Huck         struct kvm_s390_irq irq = {
92de13d216SCornelia Huck             .type = KVM_S390_PROGRAM_INT,
93de13d216SCornelia Huck             .u.pgm.code = code,
94de13d216SCornelia Huck         };
95de13d216SCornelia Huck 
96de13d216SCornelia Huck         kvm_s390_vcpu_interrupt(cpu, &irq);
97af2be207SJan Kiszka #endif
98defb0e31SAlexander Graf     } else {
9927103424SAndreas Färber         CPUState *cs = CPU(cpu);
10027103424SAndreas Färber 
101defb0e31SAlexander Graf         env->int_pgm_code = code;
102d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
10327103424SAndreas Färber         cs->exception_index = EXCP_PGM;
1045638d180SAndreas Färber         cpu_loop_exit(cs);
105defb0e31SAlexander Graf     }
106defb0e31SAlexander Graf }
107defb0e31SAlexander Graf 
108defb0e31SAlexander Graf /* SCLP service call */
109dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
110defb0e31SAlexander Graf {
1116e252802SThomas Huth     int r = sclp_service_call(env, r1, r2);
1129abf567dSChristian Borntraeger     if (r < 0) {
1139abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
114d5a43964SAlexander Graf         return 0;
115d5a43964SAlexander Graf     }
1169abf567dSChristian Borntraeger     return r;
1179abf567dSChristian Borntraeger }
118defb0e31SAlexander Graf 
119268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
120d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
121d8b30c83SChristian Borntraeger {
122d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
12385ca3371SDavid Hildenbrand     CPUState *t;
124d8b30c83SChristian Borntraeger 
125d8b30c83SChristian Borntraeger     pause_all_vcpus();
126d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
12785ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
12885ca3371SDavid Hildenbrand         run_on_cpu(t, s390_do_cpu_full_reset, t);
12985ca3371SDavid Hildenbrand     }
1304cb88c3cSDominik Dingel     cmma_reset(cpu);
131d8b30c83SChristian Borntraeger     io_subsystem_reset();
132d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
133d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
134d8b30c83SChristian Borntraeger     resume_all_vcpus();
135d8b30c83SChristian Borntraeger     return 0;
136d8b30c83SChristian Borntraeger }
137d8b30c83SChristian Borntraeger 
138f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
139f0778475SChristian Borntraeger {
140f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
14185ca3371SDavid Hildenbrand     CPUState *t;
142f0778475SChristian Borntraeger 
143f0778475SChristian Borntraeger     pause_all_vcpus();
144f0778475SChristian Borntraeger     cpu_synchronize_all_states();
14585ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
14685ca3371SDavid Hildenbrand         run_on_cpu(t, s390_do_cpu_reset, t);
14785ca3371SDavid Hildenbrand     }
1484cb88c3cSDominik Dingel     cmma_reset(cpu);
149f0778475SChristian Borntraeger     io_subsystem_reset();
150f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
151f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
152f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
153f0778475SChristian Borntraeger     resume_all_vcpus();
154f0778475SChristian Borntraeger     return 0;
155f0778475SChristian Borntraeger }
156f0778475SChristian Borntraeger 
1578fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
1588fc639afSXu Wang {
1598fc639afSXu Wang     uint64_t func = env->regs[r1];
1608fc639afSXu Wang     uint64_t timeout = env->regs[r1 + 1];
1618fc639afSXu Wang     uint64_t action = env->regs[r3];
1628fc639afSXu Wang     Object *obj;
1638fc639afSXu Wang     DIAG288State *diag288;
1648fc639afSXu Wang     DIAG288Class *diag288_class;
1658fc639afSXu Wang 
1668fc639afSXu Wang     if (r1 % 2 || action != 0) {
1678fc639afSXu Wang         return -1;
1688fc639afSXu Wang     }
1698fc639afSXu Wang 
1708fc639afSXu Wang     /* Timeout must be more than 15 seconds except for timer deletion */
1718fc639afSXu Wang     if (func != WDT_DIAG288_CANCEL && timeout < 15) {
1728fc639afSXu Wang         return -1;
1738fc639afSXu Wang     }
1748fc639afSXu Wang 
1758fc639afSXu Wang     obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
1768fc639afSXu Wang     if (!obj) {
1778fc639afSXu Wang         return -1;
1788fc639afSXu Wang     }
1798fc639afSXu Wang 
1808fc639afSXu Wang     diag288 = DIAG288(obj);
1818fc639afSXu Wang     diag288_class = DIAG288_GET_CLASS(diag288);
1828fc639afSXu Wang     return diag288_class->handle_timer(diag288, func, timeout);
1838fc639afSXu Wang }
1848fc639afSXu Wang 
185df75a4e2SFan Zhang #define DIAG_308_RC_OK              0x0001
186268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
187268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
188df75a4e2SFan Zhang 
189268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
190268846baSEugene (jno) Dvurechenski {
191268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
192268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
193df75a4e2SFan Zhang     IplParameterBlock *iplb;
194268846baSEugene (jno) Dvurechenski 
195268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
196268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
197268846baSEugene (jno) Dvurechenski         return;
198268846baSEugene (jno) Dvurechenski     }
199268846baSEugene (jno) Dvurechenski 
200268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
201268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
202268846baSEugene (jno) Dvurechenski         return;
203268846baSEugene (jno) Dvurechenski     }
204268846baSEugene (jno) Dvurechenski 
205268846baSEugene (jno) Dvurechenski     switch (subcode) {
206d8b30c83SChristian Borntraeger     case 0:
207d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
2088df7eef3SAurelien Jarno         if (tcg_enabled()) {
2098df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2108df7eef3SAurelien Jarno         }
211d8b30c83SChristian Borntraeger         break;
212f0778475SChristian Borntraeger     case 1:
213f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
2148df7eef3SAurelien Jarno         if (tcg_enabled()) {
2158df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2168df7eef3SAurelien Jarno         }
217f0778475SChristian Borntraeger         break;
2182ecacb0bSAurelien Jarno     case 3:
2192ecacb0bSAurelien Jarno         s390_reipl_request();
2202ecacb0bSAurelien Jarno         if (tcg_enabled()) {
2212ecacb0bSAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2222ecacb0bSAurelien Jarno         }
2232ecacb0bSAurelien Jarno         break;
224268846baSEugene (jno) Dvurechenski     case 5:
225268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
226268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
227268846baSEugene (jno) Dvurechenski             return;
228268846baSEugene (jno) Dvurechenski         }
229df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
230df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), false)) {
231df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
232df75a4e2SFan Zhang             return;
233df75a4e2SFan Zhang         }
234df75a4e2SFan Zhang         iplb = g_malloc0(sizeof(struct IplParameterBlock));
235df75a4e2SFan Zhang         cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock));
236df75a4e2SFan Zhang         if (!s390_ipl_update_diag308(iplb)) {
237df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
238df75a4e2SFan Zhang         } else {
239268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
240df75a4e2SFan Zhang         }
241df75a4e2SFan Zhang         g_free(iplb);
242268846baSEugene (jno) Dvurechenski         return;
243268846baSEugene (jno) Dvurechenski     case 6:
244268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
245268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
246268846baSEugene (jno) Dvurechenski             return;
247268846baSEugene (jno) Dvurechenski         }
248df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
249df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), true)) {
250df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
251df75a4e2SFan Zhang             return;
252df75a4e2SFan Zhang         }
253df75a4e2SFan Zhang         iplb = s390_ipl_get_iplb();
254df75a4e2SFan Zhang         if (iplb) {
255df75a4e2SFan Zhang             cpu_physical_memory_write(addr, iplb,
256df75a4e2SFan Zhang                                       sizeof(struct IplParameterBlock));
257df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
258df75a4e2SFan Zhang         } else {
259268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
260df75a4e2SFan Zhang         }
261268846baSEugene (jno) Dvurechenski         return;
262268846baSEugene (jno) Dvurechenski     default:
263268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
264268846baSEugene (jno) Dvurechenski         break;
265268846baSEugene (jno) Dvurechenski     }
266268846baSEugene (jno) Dvurechenski }
267268846baSEugene (jno) Dvurechenski #endif
268268846baSEugene (jno) Dvurechenski 
2698df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
270defb0e31SAlexander Graf {
271defb0e31SAlexander Graf     uint64_t r;
272defb0e31SAlexander Graf 
273defb0e31SAlexander Graf     switch (num) {
274defb0e31SAlexander Graf     case 0x500:
275defb0e31SAlexander Graf         /* KVM hypercall */
27628e942f8SCornelia Huck         r = s390_virtio_hypercall(env);
277defb0e31SAlexander Graf         break;
278defb0e31SAlexander Graf     case 0x44:
279defb0e31SAlexander Graf         /* yield */
280defb0e31SAlexander Graf         r = 0;
281defb0e31SAlexander Graf         break;
282defb0e31SAlexander Graf     case 0x308:
283defb0e31SAlexander Graf         /* ipl */
2848df7eef3SAurelien Jarno         handle_diag_308(env, r1, r3);
285defb0e31SAlexander Graf         r = 0;
286defb0e31SAlexander Graf         break;
287defb0e31SAlexander Graf     default:
288defb0e31SAlexander Graf         r = -1;
289defb0e31SAlexander Graf         break;
290defb0e31SAlexander Graf     }
291defb0e31SAlexander Graf 
292defb0e31SAlexander Graf     if (r) {
293d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
294defb0e31SAlexander Graf     }
295defb0e31SAlexander Graf }
296defb0e31SAlexander Graf 
297defb0e31SAlexander Graf /* Set Prefix */
298089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
299defb0e31SAlexander Graf {
30031b030d4SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
301e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
30231b030d4SAndreas Färber 
303e805a0d3SRichard Henderson     env->psa = prefix;
304defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
30531b030d4SAndreas Färber     tlb_flush_page(cs, 0);
30631b030d4SAndreas Färber     tlb_flush_page(cs, TARGET_PAGE_SIZE);
307defb0e31SAlexander Graf }
308defb0e31SAlexander Graf 
309d9d55f11SAurelien Jarno /* Store Clock */
310d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env)
311defb0e31SAlexander Graf {
312defb0e31SAlexander Graf     uint64_t time;
313defb0e31SAlexander Graf 
314defb0e31SAlexander Graf     time = env->tod_offset +
315bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
316defb0e31SAlexander Graf 
317defb0e31SAlexander Graf     return time;
318defb0e31SAlexander Graf }
319defb0e31SAlexander Graf 
320defb0e31SAlexander Graf /* Set Clock Comparator */
321dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
322defb0e31SAlexander Graf {
323defb0e31SAlexander Graf     if (time == -1ULL) {
324defb0e31SAlexander Graf         return;
325defb0e31SAlexander Graf     }
326defb0e31SAlexander Graf 
327aa9e14e6SAurelien Jarno     env->ckc = time;
328aa9e14e6SAurelien Jarno 
329c941f074SAurelien Jarno     /* difference between origins */
330c941f074SAurelien Jarno     time -= env->tod_offset;
331c941f074SAurelien Jarno 
332defb0e31SAlexander Graf     /* nanoseconds */
3339cb32c44SAurelien Jarno     time = tod2time(time);
334defb0e31SAlexander Graf 
335c941f074SAurelien Jarno     timer_mod(env->tod_timer, env->tod_basetime + time);
336defb0e31SAlexander Graf }
337defb0e31SAlexander Graf 
338defb0e31SAlexander Graf /* Store Clock Comparator */
339dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
340defb0e31SAlexander Graf {
341aa9e14e6SAurelien Jarno     return env->ckc;
342defb0e31SAlexander Graf }
343defb0e31SAlexander Graf 
344defb0e31SAlexander Graf /* Set CPU Timer */
345c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
346defb0e31SAlexander Graf {
347defb0e31SAlexander Graf     if (time == -1ULL) {
348defb0e31SAlexander Graf         return;
349defb0e31SAlexander Graf     }
350defb0e31SAlexander Graf 
351defb0e31SAlexander Graf     /* nanoseconds */
3529cb32c44SAurelien Jarno     time = tod2time(time);
353defb0e31SAlexander Graf 
354b8ae94bdSAurelien Jarno     env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
355b8ae94bdSAurelien Jarno 
356b8ae94bdSAurelien Jarno     timer_mod(env->cpu_timer, env->cputm);
357defb0e31SAlexander Graf }
358defb0e31SAlexander Graf 
359defb0e31SAlexander Graf /* Store CPU Timer */
360c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
361defb0e31SAlexander Graf {
362b8ae94bdSAurelien Jarno     return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
363defb0e31SAlexander Graf }
364defb0e31SAlexander Graf 
365defb0e31SAlexander Graf /* Store System Information */
366d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
367d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
368defb0e31SAlexander Graf {
369defb0e31SAlexander Graf     int cc = 0;
370defb0e31SAlexander Graf     int sel1, sel2;
371defb0e31SAlexander Graf 
372defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
373defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
374defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
375defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
376defb0e31SAlexander Graf     }
377defb0e31SAlexander Graf 
378defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
379defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
380defb0e31SAlexander Graf 
381defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
382defb0e31SAlexander Graf 
383defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
384defb0e31SAlexander Graf     case STSI_LEVEL_1:
385defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
386defb0e31SAlexander Graf             /* Basic Machine Configuration */
387defb0e31SAlexander Graf             struct sysib_111 sysib;
388defb0e31SAlexander Graf 
389defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
390defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
391defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
392defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
393defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
394defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
395defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
396defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
397eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
398defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
399defb0e31SAlexander Graf             /* Basic Machine CPU */
400defb0e31SAlexander Graf             struct sysib_121 sysib;
401defb0e31SAlexander Graf 
402defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
403defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
404defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
405defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
406defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
407eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
408defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
409defb0e31SAlexander Graf             /* Basic Machine CPUs */
410defb0e31SAlexander Graf             struct sysib_122 sysib;
411defb0e31SAlexander Graf 
412defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
413defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
414defb0e31SAlexander Graf             /* XXX change when SMP comes */
415defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
416defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
417defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
418defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
419eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
420defb0e31SAlexander Graf         } else {
421defb0e31SAlexander Graf             cc = 3;
422defb0e31SAlexander Graf         }
423defb0e31SAlexander Graf         break;
424defb0e31SAlexander Graf     case STSI_LEVEL_2:
425defb0e31SAlexander Graf         {
426defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
427defb0e31SAlexander Graf                 /* LPAR CPU */
428defb0e31SAlexander Graf                 struct sysib_221 sysib;
429defb0e31SAlexander Graf 
430defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
431defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
432defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
433defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
434defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
435defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
436eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
437defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
438defb0e31SAlexander Graf                 /* LPAR CPUs */
439defb0e31SAlexander Graf                 struct sysib_222 sysib;
440defb0e31SAlexander Graf 
441defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
442defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
443defb0e31SAlexander Graf                 sysib.lcpuc = 0;
444defb0e31SAlexander Graf                 /* XXX change when SMP comes */
445defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
446defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
447defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
448defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
449defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
450defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
451defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
452defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
453eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
454defb0e31SAlexander Graf             } else {
455defb0e31SAlexander Graf                 cc = 3;
456defb0e31SAlexander Graf             }
457defb0e31SAlexander Graf             break;
458defb0e31SAlexander Graf         }
459defb0e31SAlexander Graf     case STSI_LEVEL_3:
460defb0e31SAlexander Graf         {
461defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
462defb0e31SAlexander Graf                 /* VM CPUs */
463defb0e31SAlexander Graf                 struct sysib_322 sysib;
464defb0e31SAlexander Graf 
465defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
466defb0e31SAlexander Graf                 sysib.count = 1;
467defb0e31SAlexander Graf                 /* XXX change when SMP comes */
468defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
469defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
470defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
471defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
472defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
473defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
474defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
475eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
476defb0e31SAlexander Graf             } else {
477defb0e31SAlexander Graf                 cc = 3;
478defb0e31SAlexander Graf             }
479defb0e31SAlexander Graf             break;
480defb0e31SAlexander Graf         }
481defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
482defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
483defb0e31SAlexander Graf         break;
484defb0e31SAlexander Graf     default:
485defb0e31SAlexander Graf         cc = 3;
486defb0e31SAlexander Graf         break;
487defb0e31SAlexander Graf     }
488defb0e31SAlexander Graf 
489defb0e31SAlexander Graf     return cc;
490defb0e31SAlexander Graf }
491defb0e31SAlexander Graf 
492089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
493089f5c06SBlue Swirl                       uint64_t cpu_addr)
494defb0e31SAlexander Graf {
4955172b780SDavid Hildenbrand     int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
496defb0e31SAlexander Graf 
497defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
49871e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
499defb0e31SAlexander Graf 
500defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
501defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
502defb0e31SAlexander Graf 
503defb0e31SAlexander Graf     switch (order_code) {
504defb0e31SAlexander Graf     case SIGP_SET_ARCH:
505defb0e31SAlexander Graf         /* switch arch */
506defb0e31SAlexander Graf         break;
507defb0e31SAlexander Graf     case SIGP_SENSE:
508defb0e31SAlexander Graf         /* enumerate CPU status */
509defb0e31SAlexander Graf         if (cpu_addr) {
510defb0e31SAlexander Graf             /* XXX implement when SMP comes */
511defb0e31SAlexander Graf             return 3;
512defb0e31SAlexander Graf         }
513defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
514defb0e31SAlexander Graf         cc = 1;
515defb0e31SAlexander Graf         break;
5161864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
5171864b94aSAlexander Graf     case SIGP_RESTART:
5181864b94aSAlexander Graf         qemu_system_reset_request();
5195638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5201864b94aSAlexander Graf         break;
5211864b94aSAlexander Graf     case SIGP_STOP:
5221864b94aSAlexander Graf         qemu_system_shutdown_request();
5235638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5241864b94aSAlexander Graf         break;
5251864b94aSAlexander Graf #endif
526defb0e31SAlexander Graf     default:
527defb0e31SAlexander Graf         /* unknown sigp */
528defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
5295172b780SDavid Hildenbrand         cc = SIGP_CC_NOT_OPERATIONAL;
530defb0e31SAlexander Graf     }
531defb0e31SAlexander Graf 
532defb0e31SAlexander Graf     return cc;
533defb0e31SAlexander Graf }
534defb0e31SAlexander Graf #endif
535ad8a4570SAlexander Graf 
536ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY
537ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
538ad8a4570SAlexander Graf {
539ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
540ad8a4570SAlexander Graf     ioinst_handle_xsch(cpu, r1);
541ad8a4570SAlexander Graf }
542ad8a4570SAlexander Graf 
543ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1)
544ad8a4570SAlexander Graf {
545ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
546ad8a4570SAlexander Graf     ioinst_handle_csch(cpu, r1);
547ad8a4570SAlexander Graf }
548ad8a4570SAlexander Graf 
549ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
550ad8a4570SAlexander Graf {
551ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
552ad8a4570SAlexander Graf     ioinst_handle_hsch(cpu, r1);
553ad8a4570SAlexander Graf }
554ad8a4570SAlexander Graf 
555ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
556ad8a4570SAlexander Graf {
557ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
558ad8a4570SAlexander Graf     ioinst_handle_msch(cpu, r1, inst >> 16);
559ad8a4570SAlexander Graf }
560ad8a4570SAlexander Graf 
561ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
562ad8a4570SAlexander Graf {
563ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
564ad8a4570SAlexander Graf     ioinst_handle_rchp(cpu, r1);
565ad8a4570SAlexander Graf }
566ad8a4570SAlexander Graf 
567ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
568ad8a4570SAlexander Graf {
569ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
570ad8a4570SAlexander Graf     ioinst_handle_rsch(cpu, r1);
571ad8a4570SAlexander Graf }
572ad8a4570SAlexander Graf 
573ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
574ad8a4570SAlexander Graf {
575ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
576ad8a4570SAlexander Graf     ioinst_handle_ssch(cpu, r1, inst >> 16);
577ad8a4570SAlexander Graf }
578ad8a4570SAlexander Graf 
579ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
580ad8a4570SAlexander Graf {
581ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
582ad8a4570SAlexander Graf     ioinst_handle_stsch(cpu, r1, inst >> 16);
583ad8a4570SAlexander Graf }
584ad8a4570SAlexander Graf 
585ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
586ad8a4570SAlexander Graf {
587ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
588ad8a4570SAlexander Graf     ioinst_handle_tsch(cpu, r1, inst >> 16);
589ad8a4570SAlexander Graf }
590ad8a4570SAlexander Graf 
591ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
592ad8a4570SAlexander Graf {
593ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
594ad8a4570SAlexander Graf     ioinst_handle_chsc(cpu, inst >> 16);
595ad8a4570SAlexander Graf }
596ad8a4570SAlexander Graf #endif
597777c98c3SAurelien Jarno 
598777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY
599777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env)
600777c98c3SAurelien Jarno {
601777c98c3SAurelien Jarno     CPUState *cs = CPU(s390_env_get_cpu(env));
602777c98c3SAurelien Jarno 
603777c98c3SAurelien Jarno     if (env->per_perc_atmid) {
604777c98c3SAurelien Jarno         env->int_pgm_code = PGM_PER;
605777c98c3SAurelien Jarno         env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address));
606777c98c3SAurelien Jarno 
607777c98c3SAurelien Jarno         cs->exception_index = EXCP_PGM;
608777c98c3SAurelien Jarno         cpu_loop_exit(cs);
609777c98c3SAurelien Jarno     }
610777c98c3SAurelien Jarno }
611777c98c3SAurelien Jarno #endif
612