xref: /qemu/target/s390x/tcg/misc_helper.c (revision 14e6fe12a705c065fecdfd2a97199728123d4d9a)
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 
219615495aSPeter Maydell #include "qemu/osdep.h"
223e457172SBlue Swirl #include "cpu.h"
23022c62cbSPaolo Bonzini #include "exec/memory.h"
241de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
252ef6175aSRichard Henderson #include "exec/helper-proto.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
3263c91552SPaolo Bonzini #include "exec/exec-all.h"
33f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
3410ec5117SAlexander Graf 
351864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
36741da0d3SPaolo Bonzini #include "hw/watchdog/wdt_diag288.h"
37f0778475SChristian Borntraeger #include "sysemu/cpus.h"
389c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3940fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h"
40df75a4e2SFan Zhang #include "hw/s390x/ipl.h"
4110ec5117SAlexander Graf #endif
42d5a43964SAlexander Graf 
43defb0e31SAlexander Graf /* #define DEBUG_HELPER */
44defb0e31SAlexander Graf #ifdef DEBUG_HELPER
45defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
46defb0e31SAlexander Graf #else
47defb0e31SAlexander Graf #define HELPER_LOG(x...)
48defb0e31SAlexander Graf #endif
49defb0e31SAlexander Graf 
50b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
51b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
52b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
53b4e2bd35SRichard Henderson {
5427103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
55b4e2bd35SRichard Henderson     int t;
56b4e2bd35SRichard Henderson 
5727103424SAndreas Färber     cs->exception_index = EXCP_PGM;
58b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
59b4e2bd35SRichard Henderson 
60b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
613f38f309SAndreas Färber     cpu_restore_state(cs, retaddr);
62b4e2bd35SRichard Henderson 
63b4e2bd35SRichard Henderson     /* Advance past the insn.  */
64b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
65b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
669bebf986SAurelien Jarno     env->psw.addr += t;
67b4e2bd35SRichard Henderson 
685638d180SAndreas Färber     cpu_loop_exit(cs);
69b4e2bd35SRichard Henderson }
70b4e2bd35SRichard Henderson 
71d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
72089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
73defb0e31SAlexander Graf {
7427103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
7527103424SAndreas Färber 
7671e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
7727103424SAndreas Färber     cs->exception_index = excp;
785638d180SAndreas Färber     cpu_loop_exit(cs);
79defb0e31SAlexander Graf }
80defb0e31SAlexander Graf 
81defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
82a158986dSStefan Weil 
83d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
84defb0e31SAlexander Graf {
8527103424SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
8627103424SAndreas Färber 
870d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
880d404541SRichard Henderson                   env->psw.addr);
89defb0e31SAlexander Graf 
90defb0e31SAlexander Graf     if (kvm_enabled()) {
91af2be207SJan Kiszka #ifdef CONFIG_KVM
92de13d216SCornelia Huck         struct kvm_s390_irq irq = {
93de13d216SCornelia Huck             .type = KVM_S390_PROGRAM_INT,
94de13d216SCornelia Huck             .u.pgm.code = code,
95de13d216SCornelia Huck         };
96de13d216SCornelia Huck 
97de13d216SCornelia Huck         kvm_s390_vcpu_interrupt(cpu, &irq);
98af2be207SJan Kiszka #endif
99defb0e31SAlexander Graf     } else {
10027103424SAndreas Färber         CPUState *cs = CPU(cpu);
10127103424SAndreas Färber 
102defb0e31SAlexander Graf         env->int_pgm_code = code;
103d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
10427103424SAndreas Färber         cs->exception_index = EXCP_PGM;
1055638d180SAndreas Färber         cpu_loop_exit(cs);
106defb0e31SAlexander Graf     }
107defb0e31SAlexander Graf }
108defb0e31SAlexander Graf 
109defb0e31SAlexander Graf /* SCLP service call */
110dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
111defb0e31SAlexander Graf {
1126e252802SThomas Huth     int r = sclp_service_call(env, r1, r2);
1139abf567dSChristian Borntraeger     if (r < 0) {
1149abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
115d5a43964SAlexander Graf         return 0;
116d5a43964SAlexander Graf     }
1179abf567dSChristian Borntraeger     return r;
1189abf567dSChristian Borntraeger }
119defb0e31SAlexander Graf 
120268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
121d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
122d8b30c83SChristian Borntraeger {
123d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
12485ca3371SDavid Hildenbrand     CPUState *t;
125d8b30c83SChristian Borntraeger 
126d8b30c83SChristian Borntraeger     pause_all_vcpus();
127d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
12885ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
12914e6fe12SPaolo Bonzini         run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
13085ca3371SDavid Hildenbrand     }
1311cd4e0f6SDavid Hildenbrand     s390_cmma_reset();
132d9f090ecSDavid Hildenbrand     subsystem_reset();
1334ab72920SDavid Hildenbrand     s390_crypto_reset();
134d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
135d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
136d8b30c83SChristian Borntraeger     resume_all_vcpus();
137d8b30c83SChristian Borntraeger     return 0;
138d8b30c83SChristian Borntraeger }
139d8b30c83SChristian Borntraeger 
140f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
141f0778475SChristian Borntraeger {
142f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
14385ca3371SDavid Hildenbrand     CPUState *t;
144f0778475SChristian Borntraeger 
145f0778475SChristian Borntraeger     pause_all_vcpus();
146f0778475SChristian Borntraeger     cpu_synchronize_all_states();
14785ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
14814e6fe12SPaolo Bonzini         run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
14985ca3371SDavid Hildenbrand     }
1501cd4e0f6SDavid Hildenbrand     s390_cmma_reset();
151d9f090ecSDavid Hildenbrand     subsystem_reset();
152f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
153f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
154f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
155f0778475SChristian Borntraeger     resume_all_vcpus();
156f0778475SChristian Borntraeger     return 0;
157f0778475SChristian Borntraeger }
158f0778475SChristian Borntraeger 
1598fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
1608fc639afSXu Wang {
1618fc639afSXu Wang     uint64_t func = env->regs[r1];
1628fc639afSXu Wang     uint64_t timeout = env->regs[r1 + 1];
1638fc639afSXu Wang     uint64_t action = env->regs[r3];
1648fc639afSXu Wang     Object *obj;
1658fc639afSXu Wang     DIAG288State *diag288;
1668fc639afSXu Wang     DIAG288Class *diag288_class;
1678fc639afSXu Wang 
1688fc639afSXu Wang     if (r1 % 2 || action != 0) {
1698fc639afSXu Wang         return -1;
1708fc639afSXu Wang     }
1718fc639afSXu Wang 
1728fc639afSXu Wang     /* Timeout must be more than 15 seconds except for timer deletion */
1738fc639afSXu Wang     if (func != WDT_DIAG288_CANCEL && timeout < 15) {
1748fc639afSXu Wang         return -1;
1758fc639afSXu Wang     }
1768fc639afSXu Wang 
1778fc639afSXu Wang     obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
1788fc639afSXu Wang     if (!obj) {
1798fc639afSXu Wang         return -1;
1808fc639afSXu Wang     }
1818fc639afSXu Wang 
1828fc639afSXu Wang     diag288 = DIAG288(obj);
1838fc639afSXu Wang     diag288_class = DIAG288_GET_CLASS(diag288);
1848fc639afSXu Wang     return diag288_class->handle_timer(diag288, func, timeout);
1858fc639afSXu Wang }
1868fc639afSXu Wang 
187df75a4e2SFan Zhang #define DIAG_308_RC_OK              0x0001
188268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
189268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
190df75a4e2SFan Zhang 
191268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
192268846baSEugene (jno) Dvurechenski {
193268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
194268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
195df75a4e2SFan Zhang     IplParameterBlock *iplb;
196268846baSEugene (jno) Dvurechenski 
197268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
198268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
199268846baSEugene (jno) Dvurechenski         return;
200268846baSEugene (jno) Dvurechenski     }
201268846baSEugene (jno) Dvurechenski 
202268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
203268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
204268846baSEugene (jno) Dvurechenski         return;
205268846baSEugene (jno) Dvurechenski     }
206268846baSEugene (jno) Dvurechenski 
207268846baSEugene (jno) Dvurechenski     switch (subcode) {
208d8b30c83SChristian Borntraeger     case 0:
209d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
2108df7eef3SAurelien Jarno         if (tcg_enabled()) {
2118df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2128df7eef3SAurelien Jarno         }
213d8b30c83SChristian Borntraeger         break;
214f0778475SChristian Borntraeger     case 1:
215f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
2168df7eef3SAurelien Jarno         if (tcg_enabled()) {
2178df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2188df7eef3SAurelien Jarno         }
219f0778475SChristian Borntraeger         break;
2202ecacb0bSAurelien Jarno     case 3:
2212ecacb0bSAurelien Jarno         s390_reipl_request();
2222ecacb0bSAurelien Jarno         if (tcg_enabled()) {
2232ecacb0bSAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2242ecacb0bSAurelien Jarno         }
2252ecacb0bSAurelien Jarno         break;
226268846baSEugene (jno) Dvurechenski     case 5:
227268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
228268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
229268846baSEugene (jno) Dvurechenski             return;
230268846baSEugene (jno) Dvurechenski         }
231df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
232df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), false)) {
233df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
234df75a4e2SFan Zhang             return;
235df75a4e2SFan Zhang         }
23604ca4b92SAlexander Yarygin         iplb = g_malloc0(sizeof(IplParameterBlock));
2379946a911SAlexander Yarygin         cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
2389946a911SAlexander Yarygin         if (!iplb_valid_len(iplb)) {
2399946a911SAlexander Yarygin             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
2409946a911SAlexander Yarygin             goto out;
2419946a911SAlexander Yarygin         }
2429946a911SAlexander Yarygin 
2439946a911SAlexander Yarygin         cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
2449946a911SAlexander Yarygin 
2459946a911SAlexander Yarygin         if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
2469946a911SAlexander Yarygin             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
2479946a911SAlexander Yarygin             goto out;
2489946a911SAlexander Yarygin         }
2499946a911SAlexander Yarygin 
250feacc6c2SDavid Hildenbrand         s390_ipl_update_diag308(iplb);
251df75a4e2SFan Zhang         env->regs[r1 + 1] = DIAG_308_RC_OK;
2529946a911SAlexander Yarygin out:
253df75a4e2SFan Zhang         g_free(iplb);
254268846baSEugene (jno) Dvurechenski         return;
255268846baSEugene (jno) Dvurechenski     case 6:
256268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
257268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
258268846baSEugene (jno) Dvurechenski             return;
259268846baSEugene (jno) Dvurechenski         }
260df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
261df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), true)) {
262df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
263df75a4e2SFan Zhang             return;
264df75a4e2SFan Zhang         }
265df75a4e2SFan Zhang         iplb = s390_ipl_get_iplb();
266df75a4e2SFan Zhang         if (iplb) {
2679946a911SAlexander Yarygin             cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
268df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
269df75a4e2SFan Zhang         } else {
270268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
271df75a4e2SFan Zhang         }
272268846baSEugene (jno) Dvurechenski         return;
273268846baSEugene (jno) Dvurechenski     default:
274268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
275268846baSEugene (jno) Dvurechenski         break;
276268846baSEugene (jno) Dvurechenski     }
277268846baSEugene (jno) Dvurechenski }
278268846baSEugene (jno) Dvurechenski #endif
279268846baSEugene (jno) Dvurechenski 
2808df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
281defb0e31SAlexander Graf {
282defb0e31SAlexander Graf     uint64_t r;
283defb0e31SAlexander Graf 
284defb0e31SAlexander Graf     switch (num) {
285defb0e31SAlexander Graf     case 0x500:
286defb0e31SAlexander Graf         /* KVM hypercall */
28728e942f8SCornelia Huck         r = s390_virtio_hypercall(env);
288defb0e31SAlexander Graf         break;
289defb0e31SAlexander Graf     case 0x44:
290defb0e31SAlexander Graf         /* yield */
291defb0e31SAlexander Graf         r = 0;
292defb0e31SAlexander Graf         break;
293defb0e31SAlexander Graf     case 0x308:
294defb0e31SAlexander Graf         /* ipl */
2958df7eef3SAurelien Jarno         handle_diag_308(env, r1, r3);
296defb0e31SAlexander Graf         r = 0;
297defb0e31SAlexander Graf         break;
298defb0e31SAlexander Graf     default:
299defb0e31SAlexander Graf         r = -1;
300defb0e31SAlexander Graf         break;
301defb0e31SAlexander Graf     }
302defb0e31SAlexander Graf 
303defb0e31SAlexander Graf     if (r) {
304d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
305defb0e31SAlexander Graf     }
306defb0e31SAlexander Graf }
307defb0e31SAlexander Graf 
308defb0e31SAlexander Graf /* Set Prefix */
309089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
310defb0e31SAlexander Graf {
31131b030d4SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
312e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
31331b030d4SAndreas Färber 
314e805a0d3SRichard Henderson     env->psa = prefix;
315aafcf80eSPaolo Bonzini     HELPER_LOG("prefix: %#x\n", prefix);
31631b030d4SAndreas Färber     tlb_flush_page(cs, 0);
31731b030d4SAndreas Färber     tlb_flush_page(cs, TARGET_PAGE_SIZE);
318defb0e31SAlexander Graf }
319defb0e31SAlexander Graf 
320d9d55f11SAurelien Jarno /* Store Clock */
321d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env)
322defb0e31SAlexander Graf {
323defb0e31SAlexander Graf     uint64_t time;
324defb0e31SAlexander Graf 
325defb0e31SAlexander Graf     time = env->tod_offset +
326bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
327defb0e31SAlexander Graf 
328defb0e31SAlexander Graf     return time;
329defb0e31SAlexander Graf }
330defb0e31SAlexander Graf 
331defb0e31SAlexander Graf /* Set Clock Comparator */
332dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
333defb0e31SAlexander Graf {
334defb0e31SAlexander Graf     if (time == -1ULL) {
335defb0e31SAlexander Graf         return;
336defb0e31SAlexander Graf     }
337defb0e31SAlexander Graf 
338aa9e14e6SAurelien Jarno     env->ckc = time;
339aa9e14e6SAurelien Jarno 
340c941f074SAurelien Jarno     /* difference between origins */
341c941f074SAurelien Jarno     time -= env->tod_offset;
342c941f074SAurelien Jarno 
343defb0e31SAlexander Graf     /* nanoseconds */
3449cb32c44SAurelien Jarno     time = tod2time(time);
345defb0e31SAlexander Graf 
346c941f074SAurelien Jarno     timer_mod(env->tod_timer, env->tod_basetime + time);
347defb0e31SAlexander Graf }
348defb0e31SAlexander Graf 
349defb0e31SAlexander Graf /* Store Clock Comparator */
350dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
351defb0e31SAlexander Graf {
352aa9e14e6SAurelien Jarno     return env->ckc;
353defb0e31SAlexander Graf }
354defb0e31SAlexander Graf 
355defb0e31SAlexander Graf /* Set CPU Timer */
356c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
357defb0e31SAlexander Graf {
358defb0e31SAlexander Graf     if (time == -1ULL) {
359defb0e31SAlexander Graf         return;
360defb0e31SAlexander Graf     }
361defb0e31SAlexander Graf 
362defb0e31SAlexander Graf     /* nanoseconds */
3639cb32c44SAurelien Jarno     time = tod2time(time);
364defb0e31SAlexander Graf 
365b8ae94bdSAurelien Jarno     env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
366b8ae94bdSAurelien Jarno 
367b8ae94bdSAurelien Jarno     timer_mod(env->cpu_timer, env->cputm);
368defb0e31SAlexander Graf }
369defb0e31SAlexander Graf 
370defb0e31SAlexander Graf /* Store CPU Timer */
371c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
372defb0e31SAlexander Graf {
373b8ae94bdSAurelien Jarno     return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
374defb0e31SAlexander Graf }
375defb0e31SAlexander Graf 
376defb0e31SAlexander Graf /* Store System Information */
377d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
378d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
379defb0e31SAlexander Graf {
380defb0e31SAlexander Graf     int cc = 0;
381defb0e31SAlexander Graf     int sel1, sel2;
382defb0e31SAlexander Graf 
383defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
384defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
385defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
386defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
387defb0e31SAlexander Graf     }
388defb0e31SAlexander Graf 
389defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
390defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
391defb0e31SAlexander Graf 
392defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
393defb0e31SAlexander Graf 
394defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
395defb0e31SAlexander Graf     case STSI_LEVEL_1:
396defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
397defb0e31SAlexander Graf             /* Basic Machine Configuration */
398defb0e31SAlexander Graf             struct sysib_111 sysib;
399defb0e31SAlexander Graf 
400defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
401defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
402defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
403defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
404defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
405defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
406defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
407defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
408eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
409defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
410defb0e31SAlexander Graf             /* Basic Machine CPU */
411defb0e31SAlexander Graf             struct sysib_121 sysib;
412defb0e31SAlexander Graf 
413defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
414defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
415defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
416defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
417defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
418eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
419defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
420defb0e31SAlexander Graf             /* Basic Machine CPUs */
421defb0e31SAlexander Graf             struct sysib_122 sysib;
422defb0e31SAlexander Graf 
423defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
424defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
425defb0e31SAlexander Graf             /* XXX change when SMP comes */
426defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
427defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
428defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
429defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
430eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
431defb0e31SAlexander Graf         } else {
432defb0e31SAlexander Graf             cc = 3;
433defb0e31SAlexander Graf         }
434defb0e31SAlexander Graf         break;
435defb0e31SAlexander Graf     case STSI_LEVEL_2:
436defb0e31SAlexander Graf         {
437defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
438defb0e31SAlexander Graf                 /* LPAR CPU */
439defb0e31SAlexander Graf                 struct sysib_221 sysib;
440defb0e31SAlexander Graf 
441defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
442defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
443defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
444defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
445defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
446defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
447eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
448defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
449defb0e31SAlexander Graf                 /* LPAR CPUs */
450defb0e31SAlexander Graf                 struct sysib_222 sysib;
451defb0e31SAlexander Graf 
452defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
453defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
454defb0e31SAlexander Graf                 sysib.lcpuc = 0;
455defb0e31SAlexander Graf                 /* XXX change when SMP comes */
456defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
457defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
458defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
459defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
460defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
461defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
462defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
463defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
464eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
465defb0e31SAlexander Graf             } else {
466defb0e31SAlexander Graf                 cc = 3;
467defb0e31SAlexander Graf             }
468defb0e31SAlexander Graf             break;
469defb0e31SAlexander Graf         }
470defb0e31SAlexander Graf     case STSI_LEVEL_3:
471defb0e31SAlexander Graf         {
472defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
473defb0e31SAlexander Graf                 /* VM CPUs */
474defb0e31SAlexander Graf                 struct sysib_322 sysib;
475defb0e31SAlexander Graf 
476defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
477defb0e31SAlexander Graf                 sysib.count = 1;
478defb0e31SAlexander Graf                 /* XXX change when SMP comes */
479defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
480defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
481defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
482defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
483defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
484defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
485defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
486eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
487defb0e31SAlexander Graf             } else {
488defb0e31SAlexander Graf                 cc = 3;
489defb0e31SAlexander Graf             }
490defb0e31SAlexander Graf             break;
491defb0e31SAlexander Graf         }
492defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
493defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
494defb0e31SAlexander Graf         break;
495defb0e31SAlexander Graf     default:
496defb0e31SAlexander Graf         cc = 3;
497defb0e31SAlexander Graf         break;
498defb0e31SAlexander Graf     }
499defb0e31SAlexander Graf 
500defb0e31SAlexander Graf     return cc;
501defb0e31SAlexander Graf }
502defb0e31SAlexander Graf 
503089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
504089f5c06SBlue Swirl                       uint64_t cpu_addr)
505defb0e31SAlexander Graf {
5065172b780SDavid Hildenbrand     int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
507defb0e31SAlexander Graf 
508defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
50971e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
510defb0e31SAlexander Graf 
511defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
512defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
513defb0e31SAlexander Graf 
514defb0e31SAlexander Graf     switch (order_code) {
515defb0e31SAlexander Graf     case SIGP_SET_ARCH:
516defb0e31SAlexander Graf         /* switch arch */
517defb0e31SAlexander Graf         break;
518defb0e31SAlexander Graf     case SIGP_SENSE:
519defb0e31SAlexander Graf         /* enumerate CPU status */
520defb0e31SAlexander Graf         if (cpu_addr) {
521defb0e31SAlexander Graf             /* XXX implement when SMP comes */
522defb0e31SAlexander Graf             return 3;
523defb0e31SAlexander Graf         }
524defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
525defb0e31SAlexander Graf         cc = 1;
526defb0e31SAlexander Graf         break;
5271864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
5281864b94aSAlexander Graf     case SIGP_RESTART:
5291864b94aSAlexander Graf         qemu_system_reset_request();
5305638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5311864b94aSAlexander Graf         break;
5321864b94aSAlexander Graf     case SIGP_STOP:
5331864b94aSAlexander Graf         qemu_system_shutdown_request();
5345638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5351864b94aSAlexander Graf         break;
5361864b94aSAlexander Graf #endif
537defb0e31SAlexander Graf     default:
538defb0e31SAlexander Graf         /* unknown sigp */
539defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
5405172b780SDavid Hildenbrand         cc = SIGP_CC_NOT_OPERATIONAL;
541defb0e31SAlexander Graf     }
542defb0e31SAlexander Graf 
543defb0e31SAlexander Graf     return cc;
544defb0e31SAlexander Graf }
545defb0e31SAlexander Graf #endif
546ad8a4570SAlexander Graf 
547ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY
548ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
549ad8a4570SAlexander Graf {
550ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
551ad8a4570SAlexander Graf     ioinst_handle_xsch(cpu, r1);
552ad8a4570SAlexander Graf }
553ad8a4570SAlexander Graf 
554ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1)
555ad8a4570SAlexander Graf {
556ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
557ad8a4570SAlexander Graf     ioinst_handle_csch(cpu, r1);
558ad8a4570SAlexander Graf }
559ad8a4570SAlexander Graf 
560ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
561ad8a4570SAlexander Graf {
562ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
563ad8a4570SAlexander Graf     ioinst_handle_hsch(cpu, r1);
564ad8a4570SAlexander Graf }
565ad8a4570SAlexander Graf 
566ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
567ad8a4570SAlexander Graf {
568ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
569ad8a4570SAlexander Graf     ioinst_handle_msch(cpu, r1, inst >> 16);
570ad8a4570SAlexander Graf }
571ad8a4570SAlexander Graf 
572ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
573ad8a4570SAlexander Graf {
574ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
575ad8a4570SAlexander Graf     ioinst_handle_rchp(cpu, r1);
576ad8a4570SAlexander Graf }
577ad8a4570SAlexander Graf 
578ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
579ad8a4570SAlexander Graf {
580ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
581ad8a4570SAlexander Graf     ioinst_handle_rsch(cpu, r1);
582ad8a4570SAlexander Graf }
583ad8a4570SAlexander Graf 
584ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
585ad8a4570SAlexander Graf {
586ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
587ad8a4570SAlexander Graf     ioinst_handle_ssch(cpu, r1, inst >> 16);
588ad8a4570SAlexander Graf }
589ad8a4570SAlexander Graf 
590ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
591ad8a4570SAlexander Graf {
592ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
593ad8a4570SAlexander Graf     ioinst_handle_stsch(cpu, r1, inst >> 16);
594ad8a4570SAlexander Graf }
595ad8a4570SAlexander Graf 
596ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
597ad8a4570SAlexander Graf {
598ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
599ad8a4570SAlexander Graf     ioinst_handle_tsch(cpu, r1, inst >> 16);
600ad8a4570SAlexander Graf }
601ad8a4570SAlexander Graf 
602ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
603ad8a4570SAlexander Graf {
604ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
605ad8a4570SAlexander Graf     ioinst_handle_chsc(cpu, inst >> 16);
606ad8a4570SAlexander Graf }
607ad8a4570SAlexander Graf #endif
608777c98c3SAurelien Jarno 
609777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY
610777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env)
611777c98c3SAurelien Jarno {
612777c98c3SAurelien Jarno     CPUState *cs = CPU(s390_env_get_cpu(env));
613777c98c3SAurelien Jarno 
614777c98c3SAurelien Jarno     if (env->per_perc_atmid) {
615777c98c3SAurelien Jarno         env->int_pgm_code = PGM_PER;
616777c98c3SAurelien Jarno         env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address));
617777c98c3SAurelien Jarno 
618777c98c3SAurelien Jarno         cs->exception_index = EXCP_PGM;
619777c98c3SAurelien Jarno         cpu_loop_exit(cs);
620777c98c3SAurelien Jarno     }
621777c98c3SAurelien Jarno }
6222c2275ebSAurelien Jarno 
6232c2275ebSAurelien Jarno void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
6242c2275ebSAurelien Jarno {
6252c2275ebSAurelien Jarno     if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
6262c2275ebSAurelien Jarno         if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
6272c2275ebSAurelien Jarno             || get_per_in_range(env, to)) {
6282c2275ebSAurelien Jarno             env->per_address = from;
6292c2275ebSAurelien Jarno             env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
6302c2275ebSAurelien Jarno         }
6312c2275ebSAurelien Jarno     }
6322c2275ebSAurelien Jarno }
633f0e0d817SAurelien Jarno 
634f0e0d817SAurelien Jarno void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
635f0e0d817SAurelien Jarno {
636f0e0d817SAurelien Jarno     if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
637f0e0d817SAurelien Jarno         env->per_address = addr;
638f0e0d817SAurelien Jarno         env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
63983bb1612SAurelien Jarno 
64083bb1612SAurelien Jarno         /* If the instruction has to be nullified, trigger the
64183bb1612SAurelien Jarno            exception immediately. */
64283bb1612SAurelien Jarno         if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
64383bb1612SAurelien Jarno             CPUState *cs = CPU(s390_env_get_cpu(env));
64483bb1612SAurelien Jarno 
64583bb1612SAurelien Jarno             env->int_pgm_code = PGM_PER;
64683bb1612SAurelien Jarno             env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
64783bb1612SAurelien Jarno 
64883bb1612SAurelien Jarno             cs->exception_index = EXCP_PGM;
64983bb1612SAurelien Jarno             cpu_loop_exit(cs);
65083bb1612SAurelien Jarno         }
651f0e0d817SAurelien Jarno     }
652f0e0d817SAurelien Jarno }
653777c98c3SAurelien Jarno #endif
654