xref: /qemu/target/s390x/tcg/misc_helper.c (revision 278f5e98c647f74e93636e8b6f9ba20a71765a44)
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"
22*278f5e98SAlex Bennée #include "qemu/main-loop.h"
233e457172SBlue Swirl #include "cpu.h"
24022c62cbSPaolo Bonzini #include "exec/memory.h"
251de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
262ef6175aSRichard Henderson #include "exec/helper-proto.h"
279c17d615SPaolo Bonzini #include "sysemu/kvm.h"
281de7afc9SPaolo Bonzini #include "qemu/timer.h"
298d04fb55SJan Kiszka #include "qemu/main-loop.h"
30df75a4e2SFan Zhang #include "exec/address-spaces.h"
31af2be207SJan Kiszka #ifdef CONFIG_KVM
32af2be207SJan Kiszka #include <linux/kvm.h>
33af2be207SJan Kiszka #endif
3463c91552SPaolo Bonzini #include "exec/exec-all.h"
35f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
3610ec5117SAlexander Graf 
371864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
38741da0d3SPaolo Bonzini #include "hw/watchdog/wdt_diag288.h"
39f0778475SChristian Borntraeger #include "sysemu/cpus.h"
409c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
4140fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h"
42df75a4e2SFan Zhang #include "hw/s390x/ipl.h"
4310ec5117SAlexander Graf #endif
44d5a43964SAlexander Graf 
45defb0e31SAlexander Graf /* #define DEBUG_HELPER */
46defb0e31SAlexander Graf #ifdef DEBUG_HELPER
47defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
48defb0e31SAlexander Graf #else
49defb0e31SAlexander Graf #define HELPER_LOG(x...)
50defb0e31SAlexander Graf #endif
51defb0e31SAlexander Graf 
52b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
53b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
54b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
55b4e2bd35SRichard Henderson {
5627103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
57b4e2bd35SRichard Henderson     int t;
58b4e2bd35SRichard Henderson 
5927103424SAndreas Färber     cs->exception_index = EXCP_PGM;
60b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
61b4e2bd35SRichard Henderson 
62b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
633f38f309SAndreas Färber     cpu_restore_state(cs, retaddr);
64b4e2bd35SRichard Henderson 
65b4e2bd35SRichard Henderson     /* Advance past the insn.  */
66b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
67b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
689bebf986SAurelien Jarno     env->psw.addr += t;
69b4e2bd35SRichard Henderson 
705638d180SAndreas Färber     cpu_loop_exit(cs);
71b4e2bd35SRichard Henderson }
72b4e2bd35SRichard Henderson 
73d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
74089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
75defb0e31SAlexander Graf {
7627103424SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
7727103424SAndreas Färber 
7871e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
7927103424SAndreas Färber     cs->exception_index = excp;
805638d180SAndreas Färber     cpu_loop_exit(cs);
81defb0e31SAlexander Graf }
82defb0e31SAlexander Graf 
83defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
84a158986dSStefan Weil 
85d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
86defb0e31SAlexander Graf {
8727103424SAndreas Färber     S390CPU *cpu = s390_env_get_cpu(env);
8827103424SAndreas Färber 
890d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
900d404541SRichard Henderson                   env->psw.addr);
91defb0e31SAlexander Graf 
92defb0e31SAlexander Graf     if (kvm_enabled()) {
93af2be207SJan Kiszka #ifdef CONFIG_KVM
94de13d216SCornelia Huck         struct kvm_s390_irq irq = {
95de13d216SCornelia Huck             .type = KVM_S390_PROGRAM_INT,
96de13d216SCornelia Huck             .u.pgm.code = code,
97de13d216SCornelia Huck         };
98de13d216SCornelia Huck 
99de13d216SCornelia Huck         kvm_s390_vcpu_interrupt(cpu, &irq);
100af2be207SJan Kiszka #endif
101defb0e31SAlexander Graf     } else {
10227103424SAndreas Färber         CPUState *cs = CPU(cpu);
10327103424SAndreas Färber 
104defb0e31SAlexander Graf         env->int_pgm_code = code;
105d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
10627103424SAndreas Färber         cs->exception_index = EXCP_PGM;
1075638d180SAndreas Färber         cpu_loop_exit(cs);
108defb0e31SAlexander Graf     }
109defb0e31SAlexander Graf }
110defb0e31SAlexander Graf 
111defb0e31SAlexander Graf /* SCLP service call */
112dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
113defb0e31SAlexander Graf {
1148d04fb55SJan Kiszka     qemu_mutex_lock_iothread();
1156e252802SThomas Huth     int r = sclp_service_call(env, r1, r2);
1169abf567dSChristian Borntraeger     if (r < 0) {
1179abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
1188d04fb55SJan Kiszka         r = 0;
119d5a43964SAlexander Graf     }
1208d04fb55SJan Kiszka     qemu_mutex_unlock_iothread();
1219abf567dSChristian Borntraeger     return r;
1229abf567dSChristian Borntraeger }
123defb0e31SAlexander Graf 
124268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
125d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
126d8b30c83SChristian Borntraeger {
127d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
12885ca3371SDavid Hildenbrand     CPUState *t;
129d8b30c83SChristian Borntraeger 
130d8b30c83SChristian Borntraeger     pause_all_vcpus();
131d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
13285ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
13314e6fe12SPaolo Bonzini         run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
13485ca3371SDavid Hildenbrand     }
1351cd4e0f6SDavid Hildenbrand     s390_cmma_reset();
136d9f090ecSDavid Hildenbrand     subsystem_reset();
1374ab72920SDavid Hildenbrand     s390_crypto_reset();
138d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
139d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
140d8b30c83SChristian Borntraeger     resume_all_vcpus();
141d8b30c83SChristian Borntraeger     return 0;
142d8b30c83SChristian Borntraeger }
143d8b30c83SChristian Borntraeger 
144f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
145f0778475SChristian Borntraeger {
146f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
14785ca3371SDavid Hildenbrand     CPUState *t;
148f0778475SChristian Borntraeger 
149f0778475SChristian Borntraeger     pause_all_vcpus();
150f0778475SChristian Borntraeger     cpu_synchronize_all_states();
15185ca3371SDavid Hildenbrand     CPU_FOREACH(t) {
15214e6fe12SPaolo Bonzini         run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
15385ca3371SDavid Hildenbrand     }
1541cd4e0f6SDavid Hildenbrand     s390_cmma_reset();
155d9f090ecSDavid Hildenbrand     subsystem_reset();
156f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
157f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
158f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
159f0778475SChristian Borntraeger     resume_all_vcpus();
160f0778475SChristian Borntraeger     return 0;
161f0778475SChristian Borntraeger }
162f0778475SChristian Borntraeger 
1638fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
1648fc639afSXu Wang {
1658fc639afSXu Wang     uint64_t func = env->regs[r1];
1668fc639afSXu Wang     uint64_t timeout = env->regs[r1 + 1];
1678fc639afSXu Wang     uint64_t action = env->regs[r3];
1688fc639afSXu Wang     Object *obj;
1698fc639afSXu Wang     DIAG288State *diag288;
1708fc639afSXu Wang     DIAG288Class *diag288_class;
1718fc639afSXu Wang 
1728fc639afSXu Wang     if (r1 % 2 || action != 0) {
1738fc639afSXu Wang         return -1;
1748fc639afSXu Wang     }
1758fc639afSXu Wang 
1768fc639afSXu Wang     /* Timeout must be more than 15 seconds except for timer deletion */
1778fc639afSXu Wang     if (func != WDT_DIAG288_CANCEL && timeout < 15) {
1788fc639afSXu Wang         return -1;
1798fc639afSXu Wang     }
1808fc639afSXu Wang 
1818fc639afSXu Wang     obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
1828fc639afSXu Wang     if (!obj) {
1838fc639afSXu Wang         return -1;
1848fc639afSXu Wang     }
1858fc639afSXu Wang 
1868fc639afSXu Wang     diag288 = DIAG288(obj);
1878fc639afSXu Wang     diag288_class = DIAG288_GET_CLASS(diag288);
1888fc639afSXu Wang     return diag288_class->handle_timer(diag288, func, timeout);
1898fc639afSXu Wang }
1908fc639afSXu Wang 
191df75a4e2SFan Zhang #define DIAG_308_RC_OK              0x0001
192268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
193268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
194df75a4e2SFan Zhang 
195268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
196268846baSEugene (jno) Dvurechenski {
197268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
198268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
199df75a4e2SFan Zhang     IplParameterBlock *iplb;
200268846baSEugene (jno) Dvurechenski 
201268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
202268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
203268846baSEugene (jno) Dvurechenski         return;
204268846baSEugene (jno) Dvurechenski     }
205268846baSEugene (jno) Dvurechenski 
206268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
207268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
208268846baSEugene (jno) Dvurechenski         return;
209268846baSEugene (jno) Dvurechenski     }
210268846baSEugene (jno) Dvurechenski 
211268846baSEugene (jno) Dvurechenski     switch (subcode) {
212d8b30c83SChristian Borntraeger     case 0:
213d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
2148df7eef3SAurelien Jarno         if (tcg_enabled()) {
2158df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2168df7eef3SAurelien Jarno         }
217d8b30c83SChristian Borntraeger         break;
218f0778475SChristian Borntraeger     case 1:
219f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
2208df7eef3SAurelien Jarno         if (tcg_enabled()) {
2218df7eef3SAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2228df7eef3SAurelien Jarno         }
223f0778475SChristian Borntraeger         break;
2242ecacb0bSAurelien Jarno     case 3:
2252ecacb0bSAurelien Jarno         s390_reipl_request();
2262ecacb0bSAurelien Jarno         if (tcg_enabled()) {
2272ecacb0bSAurelien Jarno             cpu_loop_exit(CPU(s390_env_get_cpu(env)));
2282ecacb0bSAurelien Jarno         }
2292ecacb0bSAurelien Jarno         break;
230268846baSEugene (jno) Dvurechenski     case 5:
231268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
232268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
233268846baSEugene (jno) Dvurechenski             return;
234268846baSEugene (jno) Dvurechenski         }
235df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
236df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), false)) {
237df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
238df75a4e2SFan Zhang             return;
239df75a4e2SFan Zhang         }
24004ca4b92SAlexander Yarygin         iplb = g_malloc0(sizeof(IplParameterBlock));
2419946a911SAlexander Yarygin         cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
2429946a911SAlexander Yarygin         if (!iplb_valid_len(iplb)) {
2439946a911SAlexander Yarygin             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
2449946a911SAlexander Yarygin             goto out;
2459946a911SAlexander Yarygin         }
2469946a911SAlexander Yarygin 
2479946a911SAlexander Yarygin         cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
2489946a911SAlexander Yarygin 
2499946a911SAlexander Yarygin         if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
2509946a911SAlexander Yarygin             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
2519946a911SAlexander Yarygin             goto out;
2529946a911SAlexander Yarygin         }
2539946a911SAlexander Yarygin 
254feacc6c2SDavid Hildenbrand         s390_ipl_update_diag308(iplb);
255df75a4e2SFan Zhang         env->regs[r1 + 1] = DIAG_308_RC_OK;
2569946a911SAlexander Yarygin out:
257df75a4e2SFan Zhang         g_free(iplb);
258268846baSEugene (jno) Dvurechenski         return;
259268846baSEugene (jno) Dvurechenski     case 6:
260268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
261268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
262268846baSEugene (jno) Dvurechenski             return;
263268846baSEugene (jno) Dvurechenski         }
264df75a4e2SFan Zhang         if (!address_space_access_valid(&address_space_memory, addr,
265df75a4e2SFan Zhang                                         sizeof(IplParameterBlock), true)) {
266df75a4e2SFan Zhang             program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
267df75a4e2SFan Zhang             return;
268df75a4e2SFan Zhang         }
269df75a4e2SFan Zhang         iplb = s390_ipl_get_iplb();
270df75a4e2SFan Zhang         if (iplb) {
2719946a911SAlexander Yarygin             cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
272df75a4e2SFan Zhang             env->regs[r1 + 1] = DIAG_308_RC_OK;
273df75a4e2SFan Zhang         } else {
274268846baSEugene (jno) Dvurechenski             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
275df75a4e2SFan Zhang         }
276268846baSEugene (jno) Dvurechenski         return;
277268846baSEugene (jno) Dvurechenski     default:
278268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
279268846baSEugene (jno) Dvurechenski         break;
280268846baSEugene (jno) Dvurechenski     }
281268846baSEugene (jno) Dvurechenski }
282268846baSEugene (jno) Dvurechenski #endif
283268846baSEugene (jno) Dvurechenski 
2848df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
285defb0e31SAlexander Graf {
286defb0e31SAlexander Graf     uint64_t r;
287defb0e31SAlexander Graf 
288defb0e31SAlexander Graf     switch (num) {
289defb0e31SAlexander Graf     case 0x500:
290defb0e31SAlexander Graf         /* KVM hypercall */
29128e942f8SCornelia Huck         r = s390_virtio_hypercall(env);
292defb0e31SAlexander Graf         break;
293defb0e31SAlexander Graf     case 0x44:
294defb0e31SAlexander Graf         /* yield */
295defb0e31SAlexander Graf         r = 0;
296defb0e31SAlexander Graf         break;
297defb0e31SAlexander Graf     case 0x308:
298defb0e31SAlexander Graf         /* ipl */
2998df7eef3SAurelien Jarno         handle_diag_308(env, r1, r3);
300defb0e31SAlexander Graf         r = 0;
301defb0e31SAlexander Graf         break;
302defb0e31SAlexander Graf     default:
303defb0e31SAlexander Graf         r = -1;
304defb0e31SAlexander Graf         break;
305defb0e31SAlexander Graf     }
306defb0e31SAlexander Graf 
307defb0e31SAlexander Graf     if (r) {
308d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
309defb0e31SAlexander Graf     }
310defb0e31SAlexander Graf }
311defb0e31SAlexander Graf 
312defb0e31SAlexander Graf /* Set Prefix */
313089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
314defb0e31SAlexander Graf {
31531b030d4SAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
316e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
31731b030d4SAndreas Färber 
318e805a0d3SRichard Henderson     env->psa = prefix;
319aafcf80eSPaolo Bonzini     HELPER_LOG("prefix: %#x\n", prefix);
32031b030d4SAndreas Färber     tlb_flush_page(cs, 0);
32131b030d4SAndreas Färber     tlb_flush_page(cs, TARGET_PAGE_SIZE);
322defb0e31SAlexander Graf }
323defb0e31SAlexander Graf 
324d9d55f11SAurelien Jarno /* Store Clock */
325d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env)
326defb0e31SAlexander Graf {
327defb0e31SAlexander Graf     uint64_t time;
328defb0e31SAlexander Graf 
329defb0e31SAlexander Graf     time = env->tod_offset +
330bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
331defb0e31SAlexander Graf 
332defb0e31SAlexander Graf     return time;
333defb0e31SAlexander Graf }
334defb0e31SAlexander Graf 
335defb0e31SAlexander Graf /* Set Clock Comparator */
336dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time)
337defb0e31SAlexander Graf {
338defb0e31SAlexander Graf     if (time == -1ULL) {
339defb0e31SAlexander Graf         return;
340defb0e31SAlexander Graf     }
341defb0e31SAlexander Graf 
342aa9e14e6SAurelien Jarno     env->ckc = time;
343aa9e14e6SAurelien Jarno 
344c941f074SAurelien Jarno     /* difference between origins */
345c941f074SAurelien Jarno     time -= env->tod_offset;
346c941f074SAurelien Jarno 
347defb0e31SAlexander Graf     /* nanoseconds */
3489cb32c44SAurelien Jarno     time = tod2time(time);
349defb0e31SAlexander Graf 
350c941f074SAurelien Jarno     timer_mod(env->tod_timer, env->tod_basetime + time);
351defb0e31SAlexander Graf }
352defb0e31SAlexander Graf 
353defb0e31SAlexander Graf /* Store Clock Comparator */
354dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
355defb0e31SAlexander Graf {
356aa9e14e6SAurelien Jarno     return env->ckc;
357defb0e31SAlexander Graf }
358defb0e31SAlexander Graf 
359defb0e31SAlexander Graf /* Set CPU Timer */
360c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
361defb0e31SAlexander Graf {
362defb0e31SAlexander Graf     if (time == -1ULL) {
363defb0e31SAlexander Graf         return;
364defb0e31SAlexander Graf     }
365defb0e31SAlexander Graf 
366defb0e31SAlexander Graf     /* nanoseconds */
3679cb32c44SAurelien Jarno     time = tod2time(time);
368defb0e31SAlexander Graf 
369b8ae94bdSAurelien Jarno     env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
370b8ae94bdSAurelien Jarno 
371b8ae94bdSAurelien Jarno     timer_mod(env->cpu_timer, env->cputm);
372defb0e31SAlexander Graf }
373defb0e31SAlexander Graf 
374defb0e31SAlexander Graf /* Store CPU Timer */
375c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
376defb0e31SAlexander Graf {
377b8ae94bdSAurelien Jarno     return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
378defb0e31SAlexander Graf }
379defb0e31SAlexander Graf 
380defb0e31SAlexander Graf /* Store System Information */
381d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
382d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
383defb0e31SAlexander Graf {
384defb0e31SAlexander Graf     int cc = 0;
385defb0e31SAlexander Graf     int sel1, sel2;
386defb0e31SAlexander Graf 
387defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
388defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
389defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
390defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
391defb0e31SAlexander Graf     }
392defb0e31SAlexander Graf 
393defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
394defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
395defb0e31SAlexander Graf 
396defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
397defb0e31SAlexander Graf 
398defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
399defb0e31SAlexander Graf     case STSI_LEVEL_1:
400defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
401defb0e31SAlexander Graf             /* Basic Machine Configuration */
402defb0e31SAlexander Graf             struct sysib_111 sysib;
403defb0e31SAlexander Graf 
404defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
405defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
406defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
407defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
408defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
409defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
410defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
411defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
412eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
413defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
414defb0e31SAlexander Graf             /* Basic Machine CPU */
415defb0e31SAlexander Graf             struct sysib_121 sysib;
416defb0e31SAlexander Graf 
417defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
418defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
419defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
420defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
421defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
422eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
423defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
424defb0e31SAlexander Graf             /* Basic Machine CPUs */
425defb0e31SAlexander Graf             struct sysib_122 sysib;
426defb0e31SAlexander Graf 
427defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
428defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
429defb0e31SAlexander Graf             /* XXX change when SMP comes */
430defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
431defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
432defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
433defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
434eb6282f2SStefan Weil             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
435defb0e31SAlexander Graf         } else {
436defb0e31SAlexander Graf             cc = 3;
437defb0e31SAlexander Graf         }
438defb0e31SAlexander Graf         break;
439defb0e31SAlexander Graf     case STSI_LEVEL_2:
440defb0e31SAlexander Graf         {
441defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
442defb0e31SAlexander Graf                 /* LPAR CPU */
443defb0e31SAlexander Graf                 struct sysib_221 sysib;
444defb0e31SAlexander Graf 
445defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
446defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
447defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
448defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
449defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
450defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
451eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
452defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
453defb0e31SAlexander Graf                 /* LPAR CPUs */
454defb0e31SAlexander Graf                 struct sysib_222 sysib;
455defb0e31SAlexander Graf 
456defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
457defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
458defb0e31SAlexander Graf                 sysib.lcpuc = 0;
459defb0e31SAlexander Graf                 /* XXX change when SMP comes */
460defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
461defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
462defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
463defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
464defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
465defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
466defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
467defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
468eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
469defb0e31SAlexander Graf             } else {
470defb0e31SAlexander Graf                 cc = 3;
471defb0e31SAlexander Graf             }
472defb0e31SAlexander Graf             break;
473defb0e31SAlexander Graf         }
474defb0e31SAlexander Graf     case STSI_LEVEL_3:
475defb0e31SAlexander Graf         {
476defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
477defb0e31SAlexander Graf                 /* VM CPUs */
478defb0e31SAlexander Graf                 struct sysib_322 sysib;
479defb0e31SAlexander Graf 
480defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
481defb0e31SAlexander Graf                 sysib.count = 1;
482defb0e31SAlexander Graf                 /* XXX change when SMP comes */
483defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
484defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
485defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
486defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
487defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
488defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
489defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
490eb6282f2SStefan Weil                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
491defb0e31SAlexander Graf             } else {
492defb0e31SAlexander Graf                 cc = 3;
493defb0e31SAlexander Graf             }
494defb0e31SAlexander Graf             break;
495defb0e31SAlexander Graf         }
496defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
497defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
498defb0e31SAlexander Graf         break;
499defb0e31SAlexander Graf     default:
500defb0e31SAlexander Graf         cc = 3;
501defb0e31SAlexander Graf         break;
502defb0e31SAlexander Graf     }
503defb0e31SAlexander Graf 
504defb0e31SAlexander Graf     return cc;
505defb0e31SAlexander Graf }
506defb0e31SAlexander Graf 
507089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
508089f5c06SBlue Swirl                       uint64_t cpu_addr)
509defb0e31SAlexander Graf {
5105172b780SDavid Hildenbrand     int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
511defb0e31SAlexander Graf 
512defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
51371e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
514defb0e31SAlexander Graf 
515defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
516defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
517defb0e31SAlexander Graf 
518defb0e31SAlexander Graf     switch (order_code) {
519defb0e31SAlexander Graf     case SIGP_SET_ARCH:
520defb0e31SAlexander Graf         /* switch arch */
521defb0e31SAlexander Graf         break;
522defb0e31SAlexander Graf     case SIGP_SENSE:
523defb0e31SAlexander Graf         /* enumerate CPU status */
524defb0e31SAlexander Graf         if (cpu_addr) {
525defb0e31SAlexander Graf             /* XXX implement when SMP comes */
526defb0e31SAlexander Graf             return 3;
527defb0e31SAlexander Graf         }
528defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
529defb0e31SAlexander Graf         cc = 1;
530defb0e31SAlexander Graf         break;
5311864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
5321864b94aSAlexander Graf     case SIGP_RESTART:
5331864b94aSAlexander Graf         qemu_system_reset_request();
5345638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5351864b94aSAlexander Graf         break;
5361864b94aSAlexander Graf     case SIGP_STOP:
5371864b94aSAlexander Graf         qemu_system_shutdown_request();
5385638d180SAndreas Färber         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
5391864b94aSAlexander Graf         break;
5401864b94aSAlexander Graf #endif
541defb0e31SAlexander Graf     default:
542defb0e31SAlexander Graf         /* unknown sigp */
543defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
5445172b780SDavid Hildenbrand         cc = SIGP_CC_NOT_OPERATIONAL;
545defb0e31SAlexander Graf     }
546defb0e31SAlexander Graf 
547defb0e31SAlexander Graf     return cc;
548defb0e31SAlexander Graf }
549defb0e31SAlexander Graf #endif
550ad8a4570SAlexander Graf 
551ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY
552ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
553ad8a4570SAlexander Graf {
554ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
555*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
556ad8a4570SAlexander Graf     ioinst_handle_xsch(cpu, r1);
557*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
558ad8a4570SAlexander Graf }
559ad8a4570SAlexander Graf 
560ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1)
561ad8a4570SAlexander Graf {
562ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
563*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
564ad8a4570SAlexander Graf     ioinst_handle_csch(cpu, r1);
565*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
566ad8a4570SAlexander Graf }
567ad8a4570SAlexander Graf 
568ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
569ad8a4570SAlexander Graf {
570ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
571*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
572ad8a4570SAlexander Graf     ioinst_handle_hsch(cpu, r1);
573*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
574ad8a4570SAlexander Graf }
575ad8a4570SAlexander Graf 
576ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
577ad8a4570SAlexander Graf {
578ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
579*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
580ad8a4570SAlexander Graf     ioinst_handle_msch(cpu, r1, inst >> 16);
581*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
582ad8a4570SAlexander Graf }
583ad8a4570SAlexander Graf 
584ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
585ad8a4570SAlexander Graf {
586ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
587*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
588ad8a4570SAlexander Graf     ioinst_handle_rchp(cpu, r1);
589*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
590ad8a4570SAlexander Graf }
591ad8a4570SAlexander Graf 
592ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
593ad8a4570SAlexander Graf {
594ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
595*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
596ad8a4570SAlexander Graf     ioinst_handle_rsch(cpu, r1);
597*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
598ad8a4570SAlexander Graf }
599ad8a4570SAlexander Graf 
600ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
601ad8a4570SAlexander Graf {
602ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
603*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
604ad8a4570SAlexander Graf     ioinst_handle_ssch(cpu, r1, inst >> 16);
605*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
606ad8a4570SAlexander Graf }
607ad8a4570SAlexander Graf 
608ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
609ad8a4570SAlexander Graf {
610ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
611*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
612ad8a4570SAlexander Graf     ioinst_handle_stsch(cpu, r1, inst >> 16);
613*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
614ad8a4570SAlexander Graf }
615ad8a4570SAlexander Graf 
616ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
617ad8a4570SAlexander Graf {
618ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
619*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
620ad8a4570SAlexander Graf     ioinst_handle_tsch(cpu, r1, inst >> 16);
621*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
622ad8a4570SAlexander Graf }
623ad8a4570SAlexander Graf 
624ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
625ad8a4570SAlexander Graf {
626ad8a4570SAlexander Graf     S390CPU *cpu = s390_env_get_cpu(env);
627*278f5e98SAlex Bennée     qemu_mutex_lock_iothread();
628ad8a4570SAlexander Graf     ioinst_handle_chsc(cpu, inst >> 16);
629*278f5e98SAlex Bennée     qemu_mutex_unlock_iothread();
630ad8a4570SAlexander Graf }
631ad8a4570SAlexander Graf #endif
632777c98c3SAurelien Jarno 
633777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY
634777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env)
635777c98c3SAurelien Jarno {
636777c98c3SAurelien Jarno     CPUState *cs = CPU(s390_env_get_cpu(env));
637777c98c3SAurelien Jarno 
638777c98c3SAurelien Jarno     if (env->per_perc_atmid) {
639777c98c3SAurelien Jarno         env->int_pgm_code = PGM_PER;
640777c98c3SAurelien Jarno         env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address));
641777c98c3SAurelien Jarno 
642777c98c3SAurelien Jarno         cs->exception_index = EXCP_PGM;
643777c98c3SAurelien Jarno         cpu_loop_exit(cs);
644777c98c3SAurelien Jarno     }
645777c98c3SAurelien Jarno }
6462c2275ebSAurelien Jarno 
6472c2275ebSAurelien Jarno void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
6482c2275ebSAurelien Jarno {
6492c2275ebSAurelien Jarno     if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
6502c2275ebSAurelien Jarno         if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
6512c2275ebSAurelien Jarno             || get_per_in_range(env, to)) {
6522c2275ebSAurelien Jarno             env->per_address = from;
6532c2275ebSAurelien Jarno             env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
6542c2275ebSAurelien Jarno         }
6552c2275ebSAurelien Jarno     }
6562c2275ebSAurelien Jarno }
657f0e0d817SAurelien Jarno 
658f0e0d817SAurelien Jarno void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
659f0e0d817SAurelien Jarno {
660f0e0d817SAurelien Jarno     if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
661f0e0d817SAurelien Jarno         env->per_address = addr;
662f0e0d817SAurelien Jarno         env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
66383bb1612SAurelien Jarno 
66483bb1612SAurelien Jarno         /* If the instruction has to be nullified, trigger the
66583bb1612SAurelien Jarno            exception immediately. */
66683bb1612SAurelien Jarno         if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
66783bb1612SAurelien Jarno             CPUState *cs = CPU(s390_env_get_cpu(env));
66883bb1612SAurelien Jarno 
66983bb1612SAurelien Jarno             env->int_pgm_code = PGM_PER;
67083bb1612SAurelien Jarno             env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
67183bb1612SAurelien Jarno 
67283bb1612SAurelien Jarno             cs->exception_index = EXCP_PGM;
67383bb1612SAurelien Jarno             cpu_loop_exit(cs);
67483bb1612SAurelien Jarno         }
675f0e0d817SAurelien Jarno     }
676f0e0d817SAurelien Jarno }
677777c98c3SAurelien Jarno #endif
678