xref: /qemu/target/s390x/tcg/misc_helper.c (revision d8b30c830243c5b7180befd9e1921383c9626bf0)
110ec5117SAlexander Graf /*
2aea1e885SBlue Swirl  *  S/390 misc helper routines
310ec5117SAlexander Graf  *
4defb0e31SAlexander Graf  *  Copyright (c) 2009 Ulrich Hecht
510ec5117SAlexander Graf  *  Copyright (c) 2009 Alexander Graf
610ec5117SAlexander Graf  *
710ec5117SAlexander Graf  * This library is free software; you can redistribute it and/or
810ec5117SAlexander Graf  * modify it under the terms of the GNU Lesser General Public
910ec5117SAlexander Graf  * License as published by the Free Software Foundation; either
1010ec5117SAlexander Graf  * version 2 of the License, or (at your option) any later version.
1110ec5117SAlexander Graf  *
1210ec5117SAlexander Graf  * This library is distributed in the hope that it will be useful,
1310ec5117SAlexander Graf  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1410ec5117SAlexander Graf  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1510ec5117SAlexander Graf  * Lesser General Public License for more details.
1610ec5117SAlexander Graf  *
1710ec5117SAlexander Graf  * You should have received a copy of the GNU Lesser General Public
1870539e18SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1910ec5117SAlexander Graf  */
2010ec5117SAlexander Graf 
213e457172SBlue Swirl #include "cpu.h"
22022c62cbSPaolo Bonzini #include "exec/memory.h"
231de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
243208afbeSLluís Vilanova #include "helper.h"
25defb0e31SAlexander Graf #include <string.h>
269c17d615SPaolo Bonzini #include "sysemu/kvm.h"
271de7afc9SPaolo Bonzini #include "qemu/timer.h"
28af2be207SJan Kiszka #ifdef CONFIG_KVM
29af2be207SJan Kiszka #include <linux/kvm.h>
30af2be207SJan Kiszka #endif
3110ec5117SAlexander Graf 
321864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
33022c62cbSPaolo Bonzini #include "exec/softmmu_exec.h"
34f0778475SChristian Borntraeger #include "sysemu/cpus.h"
359c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
3610ec5117SAlexander Graf #endif
37d5a43964SAlexander Graf 
38defb0e31SAlexander Graf /* #define DEBUG_HELPER */
39defb0e31SAlexander Graf #ifdef DEBUG_HELPER
40defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x)
41defb0e31SAlexander Graf #else
42defb0e31SAlexander Graf #define HELPER_LOG(x...)
43defb0e31SAlexander Graf #endif
44defb0e31SAlexander Graf 
45b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function.  */
46b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
47b4e2bd35SRichard Henderson                                      uintptr_t retaddr)
48b4e2bd35SRichard Henderson {
49b4e2bd35SRichard Henderson     int t;
50b4e2bd35SRichard Henderson 
51b4e2bd35SRichard Henderson     env->exception_index = EXCP_PGM;
52b4e2bd35SRichard Henderson     env->int_pgm_code = excp;
53b4e2bd35SRichard Henderson 
54b4e2bd35SRichard Henderson     /* Use the (ultimate) callers address to find the insn that trapped.  */
55b4e2bd35SRichard Henderson     cpu_restore_state(env, retaddr);
56b4e2bd35SRichard Henderson 
57b4e2bd35SRichard Henderson     /* Advance past the insn.  */
58b4e2bd35SRichard Henderson     t = cpu_ldub_code(env, env->psw.addr);
59b4e2bd35SRichard Henderson     env->int_pgm_ilen = t = get_ilen(t);
60b4e2bd35SRichard Henderson     env->psw.addr += 2 * t;
61b4e2bd35SRichard Henderson 
62b4e2bd35SRichard Henderson     cpu_loop_exit(env);
63b4e2bd35SRichard Henderson }
64b4e2bd35SRichard Henderson 
65d5a103cdSRichard Henderson /* Raise an exception statically from a TB.  */
66089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp)
67defb0e31SAlexander Graf {
6871e47088SBlue Swirl     HELPER_LOG("%s: exception %d\n", __func__, excp);
69defb0e31SAlexander Graf     env->exception_index = excp;
701162c041SBlue Swirl     cpu_loop_exit(env);
71defb0e31SAlexander Graf }
72defb0e31SAlexander Graf 
73defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY
74a158986dSStefan Weil 
75a158986dSStefan Weil /* EBCDIC handling */
76a158986dSStefan Weil static const uint8_t ebcdic2ascii[] = {
77a158986dSStefan Weil     0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
78a158986dSStefan Weil     0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
79a158986dSStefan Weil     0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
80a158986dSStefan Weil     0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
81a158986dSStefan Weil     0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
82a158986dSStefan Weil     0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
83a158986dSStefan Weil     0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
84a158986dSStefan Weil     0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
85a158986dSStefan Weil     0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
86a158986dSStefan Weil     0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
87a158986dSStefan Weil     0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
88a158986dSStefan Weil     0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
89a158986dSStefan Weil     0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
90a158986dSStefan Weil     0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
91a158986dSStefan Weil     0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
92a158986dSStefan Weil     0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
93a158986dSStefan Weil     0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94a158986dSStefan Weil     0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
95a158986dSStefan Weil     0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
96a158986dSStefan Weil     0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
97a158986dSStefan Weil     0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
98a158986dSStefan Weil     0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
99a158986dSStefan Weil     0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
100a158986dSStefan Weil     0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
101a158986dSStefan Weil     0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
102a158986dSStefan Weil     0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
103a158986dSStefan Weil     0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
104a158986dSStefan Weil     0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
105a158986dSStefan Weil     0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
106a158986dSStefan Weil     0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
107a158986dSStefan Weil     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
108a158986dSStefan Weil     0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
109a158986dSStefan Weil };
110a158986dSStefan Weil 
111a158986dSStefan Weil static const uint8_t ascii2ebcdic[] = {
112a158986dSStefan Weil     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
113a158986dSStefan Weil     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
114a158986dSStefan Weil     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
115a158986dSStefan Weil     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
116a158986dSStefan Weil     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
117a158986dSStefan Weil     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
118a158986dSStefan Weil     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
119a158986dSStefan Weil     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
120a158986dSStefan Weil     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
121a158986dSStefan Weil     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
122a158986dSStefan Weil     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
123a158986dSStefan Weil     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
124a158986dSStefan Weil     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
125a158986dSStefan Weil     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
126a158986dSStefan Weil     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
127a158986dSStefan Weil     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
128a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
129a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
130a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
131a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
132a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
133a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
134a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
135a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
136a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
137a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
138a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
139a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
140a158986dSStefan Weil     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
141a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
142a158986dSStefan Weil     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
143a158986dSStefan Weil     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
144a158986dSStefan Weil };
145a158986dSStefan Weil 
146a158986dSStefan Weil static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
147a158986dSStefan Weil {
148a158986dSStefan Weil     int i;
149a158986dSStefan Weil 
150a158986dSStefan Weil     for (i = 0; i < len; i++) {
151a158986dSStefan Weil         p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
152a158986dSStefan Weil     }
153a158986dSStefan Weil }
154a158986dSStefan Weil 
155d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
156defb0e31SAlexander Graf {
1570d404541SRichard Henderson     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
1580d404541SRichard Henderson                   env->psw.addr);
159defb0e31SAlexander Graf 
160defb0e31SAlexander Graf     if (kvm_enabled()) {
161af2be207SJan Kiszka #ifdef CONFIG_KVM
1621bc22652SAndreas Färber         kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
163af2be207SJan Kiszka #endif
164defb0e31SAlexander Graf     } else {
165defb0e31SAlexander Graf         env->int_pgm_code = code;
166d5a103cdSRichard Henderson         env->int_pgm_ilen = ilen;
167defb0e31SAlexander Graf         env->exception_index = EXCP_PGM;
1681162c041SBlue Swirl         cpu_loop_exit(env);
169defb0e31SAlexander Graf     }
170defb0e31SAlexander Graf }
171defb0e31SAlexander Graf 
172defb0e31SAlexander Graf /* SCLP service call */
173dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
174defb0e31SAlexander Graf {
175dc458df9SRichard Henderson     int r = sclp_service_call(r1, r2);
1769abf567dSChristian Borntraeger     if (r < 0) {
1779abf567dSChristian Borntraeger         program_interrupt(env, -r, 4);
178d5a43964SAlexander Graf         return 0;
179d5a43964SAlexander Graf     }
1809abf567dSChristian Borntraeger     return r;
1819abf567dSChristian Borntraeger }
182defb0e31SAlexander Graf 
183268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY
184f0778475SChristian Borntraeger static void cpu_reset_all(void)
185f0778475SChristian Borntraeger {
186bdc44640SAndreas Färber     CPUState *cs;
187f0778475SChristian Borntraeger     S390CPUClass *scc;
188f0778475SChristian Borntraeger 
189bdc44640SAndreas Färber     CPU_FOREACH(cs) {
190bdc44640SAndreas Färber         scc = S390_CPU_GET_CLASS(cs);
191bdc44640SAndreas Färber         scc->cpu_reset(cs);
192f0778475SChristian Borntraeger     }
193f0778475SChristian Borntraeger }
194f0778475SChristian Borntraeger 
195d8b30c83SChristian Borntraeger static void cpu_full_reset_all(void)
196d8b30c83SChristian Borntraeger {
197d8b30c83SChristian Borntraeger     CPUState *cpu;
198d8b30c83SChristian Borntraeger 
199d8b30c83SChristian Borntraeger     CPU_FOREACH(cpu) {
200d8b30c83SChristian Borntraeger         cpu_reset(cpu);
201d8b30c83SChristian Borntraeger     }
202d8b30c83SChristian Borntraeger }
203d8b30c83SChristian Borntraeger 
204d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu)
205d8b30c83SChristian Borntraeger {
206d8b30c83SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
207d8b30c83SChristian Borntraeger 
208d8b30c83SChristian Borntraeger     pause_all_vcpus();
209d8b30c83SChristian Borntraeger     cpu_synchronize_all_states();
210d8b30c83SChristian Borntraeger     cpu_full_reset_all();
211d8b30c83SChristian Borntraeger     io_subsystem_reset();
212d8b30c83SChristian Borntraeger     scc->load_normal(CPU(cpu));
213d8b30c83SChristian Borntraeger     cpu_synchronize_all_post_reset();
214d8b30c83SChristian Borntraeger     resume_all_vcpus();
215d8b30c83SChristian Borntraeger     return 0;
216d8b30c83SChristian Borntraeger }
217d8b30c83SChristian Borntraeger 
218f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu)
219f0778475SChristian Borntraeger {
220f0778475SChristian Borntraeger     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
221f0778475SChristian Borntraeger 
222f0778475SChristian Borntraeger     pause_all_vcpus();
223f0778475SChristian Borntraeger     cpu_synchronize_all_states();
224f0778475SChristian Borntraeger     cpu_reset_all();
225f0778475SChristian Borntraeger     io_subsystem_reset();
226f0778475SChristian Borntraeger     scc->initial_cpu_reset(CPU(cpu));
227f0778475SChristian Borntraeger     scc->load_normal(CPU(cpu));
228f0778475SChristian Borntraeger     cpu_synchronize_all_post_reset();
229f0778475SChristian Borntraeger     resume_all_vcpus();
230f0778475SChristian Borntraeger     return 0;
231f0778475SChristian Borntraeger }
232f0778475SChristian Borntraeger 
233268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF         0x0102
234268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID         0x0402
235268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
236268846baSEugene (jno) Dvurechenski {
237268846baSEugene (jno) Dvurechenski     uint64_t addr =  env->regs[r1];
238268846baSEugene (jno) Dvurechenski     uint64_t subcode = env->regs[r3];
239268846baSEugene (jno) Dvurechenski 
240268846baSEugene (jno) Dvurechenski     if (env->psw.mask & PSW_MASK_PSTATE) {
241268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
242268846baSEugene (jno) Dvurechenski         return;
243268846baSEugene (jno) Dvurechenski     }
244268846baSEugene (jno) Dvurechenski 
245268846baSEugene (jno) Dvurechenski     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
246268846baSEugene (jno) Dvurechenski         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
247268846baSEugene (jno) Dvurechenski         return;
248268846baSEugene (jno) Dvurechenski     }
249268846baSEugene (jno) Dvurechenski 
250268846baSEugene (jno) Dvurechenski     switch (subcode) {
251d8b30c83SChristian Borntraeger     case 0:
252d8b30c83SChristian Borntraeger         modified_clear_reset(s390_env_get_cpu(env));
253d8b30c83SChristian Borntraeger         break;
254f0778475SChristian Borntraeger     case 1:
255f0778475SChristian Borntraeger         load_normal_reset(s390_env_get_cpu(env));
256f0778475SChristian Borntraeger         break;
257268846baSEugene (jno) Dvurechenski     case 5:
258268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
259268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
260268846baSEugene (jno) Dvurechenski             return;
261268846baSEugene (jno) Dvurechenski         }
262268846baSEugene (jno) Dvurechenski         env->regs[r1+1] = DIAG_308_RC_INVALID;
263268846baSEugene (jno) Dvurechenski         return;
264268846baSEugene (jno) Dvurechenski     case 6:
265268846baSEugene (jno) Dvurechenski         if ((r1 & 1) || (addr & 0x0fffULL)) {
266268846baSEugene (jno) Dvurechenski             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
267268846baSEugene (jno) Dvurechenski             return;
268268846baSEugene (jno) Dvurechenski         }
269268846baSEugene (jno) Dvurechenski         env->regs[r1+1] = DIAG_308_RC_NO_CONF;
270268846baSEugene (jno) Dvurechenski         return;
271268846baSEugene (jno) Dvurechenski     default:
272268846baSEugene (jno) Dvurechenski         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
273268846baSEugene (jno) Dvurechenski         break;
274268846baSEugene (jno) Dvurechenski     }
275268846baSEugene (jno) Dvurechenski }
276268846baSEugene (jno) Dvurechenski #endif
277268846baSEugene (jno) Dvurechenski 
278defb0e31SAlexander Graf /* DIAG */
279089f5c06SBlue Swirl uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
280089f5c06SBlue Swirl                       uint64_t code)
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 */
295defb0e31SAlexander Graf         r = 0;
296defb0e31SAlexander Graf         break;
297defb0e31SAlexander Graf     default:
298defb0e31SAlexander Graf         r = -1;
299defb0e31SAlexander Graf         break;
300defb0e31SAlexander Graf     }
301defb0e31SAlexander Graf 
302defb0e31SAlexander Graf     if (r) {
303d5a103cdSRichard Henderson         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
304defb0e31SAlexander Graf     }
305defb0e31SAlexander Graf 
306defb0e31SAlexander Graf     return r;
307defb0e31SAlexander Graf }
308defb0e31SAlexander Graf 
309defb0e31SAlexander Graf /* Set Prefix */
310089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1)
311defb0e31SAlexander Graf {
312e805a0d3SRichard Henderson     uint32_t prefix = a1 & 0x7fffe000;
313e805a0d3SRichard Henderson     env->psa = prefix;
314defb0e31SAlexander Graf     qemu_log("prefix: %#x\n", prefix);
315defb0e31SAlexander Graf     tlb_flush_page(env, 0);
316defb0e31SAlexander Graf     tlb_flush_page(env, TARGET_PAGE_SIZE);
317defb0e31SAlexander Graf }
318defb0e31SAlexander Graf 
319a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env)
320defb0e31SAlexander Graf {
321defb0e31SAlexander Graf     uint64_t time;
322defb0e31SAlexander Graf 
323defb0e31SAlexander Graf     time = env->tod_offset +
324bc72ad67SAlex Bligh         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
325defb0e31SAlexander Graf 
326defb0e31SAlexander Graf     return time;
327defb0e31SAlexander Graf }
328defb0e31SAlexander Graf 
329defb0e31SAlexander Graf /* Store Clock */
330434c91a5SRichard Henderson uint64_t HELPER(stck)(CPUS390XState *env)
331defb0e31SAlexander Graf {
332434c91a5SRichard Henderson     return clock_value(env);
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 
342defb0e31SAlexander Graf     /* difference between now and then */
343defb0e31SAlexander Graf     time -= clock_value(env);
344defb0e31SAlexander Graf     /* nanoseconds */
345defb0e31SAlexander Graf     time = (time * 125) >> 9;
346defb0e31SAlexander Graf 
347bc72ad67SAlex Bligh     timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
348defb0e31SAlexander Graf }
349defb0e31SAlexander Graf 
350defb0e31SAlexander Graf /* Store Clock Comparator */
351dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env)
352defb0e31SAlexander Graf {
353defb0e31SAlexander Graf     /* XXX implement */
354dd3eb7b5SRichard Henderson     return 0;
355defb0e31SAlexander Graf }
356defb0e31SAlexander Graf 
357defb0e31SAlexander Graf /* Set CPU Timer */
358c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time)
359defb0e31SAlexander Graf {
360defb0e31SAlexander Graf     if (time == -1ULL) {
361defb0e31SAlexander Graf         return;
362defb0e31SAlexander Graf     }
363defb0e31SAlexander Graf 
364defb0e31SAlexander Graf     /* nanoseconds */
365defb0e31SAlexander Graf     time = (time * 125) >> 9;
366defb0e31SAlexander Graf 
367bc72ad67SAlex Bligh     timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
368defb0e31SAlexander Graf }
369defb0e31SAlexander Graf 
370defb0e31SAlexander Graf /* Store CPU Timer */
371c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env)
372defb0e31SAlexander Graf {
373defb0e31SAlexander Graf     /* XXX implement */
374c4f0a863SRichard Henderson     return 0;
375defb0e31SAlexander Graf }
376defb0e31SAlexander Graf 
377defb0e31SAlexander Graf /* Store System Information */
378d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
379d14b3e09SRichard Henderson                       uint64_t r0, uint64_t r1)
380defb0e31SAlexander Graf {
381defb0e31SAlexander Graf     int cc = 0;
382defb0e31SAlexander Graf     int sel1, sel2;
383defb0e31SAlexander Graf 
384defb0e31SAlexander Graf     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
385defb0e31SAlexander Graf         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
386defb0e31SAlexander Graf         /* valid function code, invalid reserved bits */
387defb0e31SAlexander Graf         program_interrupt(env, PGM_SPECIFICATION, 2);
388defb0e31SAlexander Graf     }
389defb0e31SAlexander Graf 
390defb0e31SAlexander Graf     sel1 = r0 & STSI_R0_SEL1_MASK;
391defb0e31SAlexander Graf     sel2 = r1 & STSI_R1_SEL2_MASK;
392defb0e31SAlexander Graf 
393defb0e31SAlexander Graf     /* XXX: spec exception if sysib is not 4k-aligned */
394defb0e31SAlexander Graf 
395defb0e31SAlexander Graf     switch (r0 & STSI_LEVEL_MASK) {
396defb0e31SAlexander Graf     case STSI_LEVEL_1:
397defb0e31SAlexander Graf         if ((sel1 == 1) && (sel2 == 1)) {
398defb0e31SAlexander Graf             /* Basic Machine Configuration */
399defb0e31SAlexander Graf             struct sysib_111 sysib;
400defb0e31SAlexander Graf 
401defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
402defb0e31SAlexander Graf             ebcdic_put(sysib.manuf, "QEMU            ", 16);
403defb0e31SAlexander Graf             /* same as machine type number in STORE CPU ID */
404defb0e31SAlexander Graf             ebcdic_put(sysib.type, "QEMU", 4);
405defb0e31SAlexander Graf             /* same as model number in STORE CPU ID */
406defb0e31SAlexander Graf             ebcdic_put(sysib.model, "QEMU            ", 16);
407defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMU            ", 16);
408defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
409defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
410defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 1)) {
411defb0e31SAlexander Graf             /* Basic Machine CPU */
412defb0e31SAlexander Graf             struct sysib_121 sysib;
413defb0e31SAlexander Graf 
414defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
415defb0e31SAlexander Graf             /* XXX make different for different CPUs? */
416defb0e31SAlexander Graf             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
417defb0e31SAlexander Graf             ebcdic_put(sysib.plant, "QEMU", 4);
418defb0e31SAlexander Graf             stw_p(&sysib.cpu_addr, env->cpu_num);
419defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
420defb0e31SAlexander Graf         } else if ((sel1 == 2) && (sel2 == 2)) {
421defb0e31SAlexander Graf             /* Basic Machine CPUs */
422defb0e31SAlexander Graf             struct sysib_122 sysib;
423defb0e31SAlexander Graf 
424defb0e31SAlexander Graf             memset(&sysib, 0, sizeof(sysib));
425defb0e31SAlexander Graf             stl_p(&sysib.capability, 0x443afc29);
426defb0e31SAlexander Graf             /* XXX change when SMP comes */
427defb0e31SAlexander Graf             stw_p(&sysib.total_cpus, 1);
428defb0e31SAlexander Graf             stw_p(&sysib.active_cpus, 1);
429defb0e31SAlexander Graf             stw_p(&sysib.standby_cpus, 0);
430defb0e31SAlexander Graf             stw_p(&sysib.reserved_cpus, 0);
431defb0e31SAlexander Graf             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
432defb0e31SAlexander Graf         } else {
433defb0e31SAlexander Graf             cc = 3;
434defb0e31SAlexander Graf         }
435defb0e31SAlexander Graf         break;
436defb0e31SAlexander Graf     case STSI_LEVEL_2:
437defb0e31SAlexander Graf         {
438defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 1)) {
439defb0e31SAlexander Graf                 /* LPAR CPU */
440defb0e31SAlexander Graf                 struct sysib_221 sysib;
441defb0e31SAlexander Graf 
442defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
443defb0e31SAlexander Graf                 /* XXX make different for different CPUs? */
444defb0e31SAlexander Graf                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
445defb0e31SAlexander Graf                 ebcdic_put(sysib.plant, "QEMU", 4);
446defb0e31SAlexander Graf                 stw_p(&sysib.cpu_addr, env->cpu_num);
447defb0e31SAlexander Graf                 stw_p(&sysib.cpu_id, 0);
448defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
449defb0e31SAlexander Graf             } else if ((sel1 == 2) && (sel2 == 2)) {
450defb0e31SAlexander Graf                 /* LPAR CPUs */
451defb0e31SAlexander Graf                 struct sysib_222 sysib;
452defb0e31SAlexander Graf 
453defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
454defb0e31SAlexander Graf                 stw_p(&sysib.lpar_num, 0);
455defb0e31SAlexander Graf                 sysib.lcpuc = 0;
456defb0e31SAlexander Graf                 /* XXX change when SMP comes */
457defb0e31SAlexander Graf                 stw_p(&sysib.total_cpus, 1);
458defb0e31SAlexander Graf                 stw_p(&sysib.conf_cpus, 1);
459defb0e31SAlexander Graf                 stw_p(&sysib.standby_cpus, 0);
460defb0e31SAlexander Graf                 stw_p(&sysib.reserved_cpus, 0);
461defb0e31SAlexander Graf                 ebcdic_put(sysib.name, "QEMU    ", 8);
462defb0e31SAlexander Graf                 stl_p(&sysib.caf, 1000);
463defb0e31SAlexander Graf                 stw_p(&sysib.dedicated_cpus, 0);
464defb0e31SAlexander Graf                 stw_p(&sysib.shared_cpus, 0);
465defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
466defb0e31SAlexander Graf             } else {
467defb0e31SAlexander Graf                 cc = 3;
468defb0e31SAlexander Graf             }
469defb0e31SAlexander Graf             break;
470defb0e31SAlexander Graf         }
471defb0e31SAlexander Graf     case STSI_LEVEL_3:
472defb0e31SAlexander Graf         {
473defb0e31SAlexander Graf             if ((sel1 == 2) && (sel2 == 2)) {
474defb0e31SAlexander Graf                 /* VM CPUs */
475defb0e31SAlexander Graf                 struct sysib_322 sysib;
476defb0e31SAlexander Graf 
477defb0e31SAlexander Graf                 memset(&sysib, 0, sizeof(sysib));
478defb0e31SAlexander Graf                 sysib.count = 1;
479defb0e31SAlexander Graf                 /* XXX change when SMP comes */
480defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].total_cpus, 1);
481defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].conf_cpus, 1);
482defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].standby_cpus, 0);
483defb0e31SAlexander Graf                 stw_p(&sysib.vm[0].reserved_cpus, 0);
484defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
485defb0e31SAlexander Graf                 stl_p(&sysib.vm[0].caf, 1000);
486defb0e31SAlexander Graf                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
487defb0e31SAlexander Graf                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
488defb0e31SAlexander Graf             } else {
489defb0e31SAlexander Graf                 cc = 3;
490defb0e31SAlexander Graf             }
491defb0e31SAlexander Graf             break;
492defb0e31SAlexander Graf         }
493defb0e31SAlexander Graf     case STSI_LEVEL_CURRENT:
494defb0e31SAlexander Graf         env->regs[0] = STSI_LEVEL_3;
495defb0e31SAlexander Graf         break;
496defb0e31SAlexander Graf     default:
497defb0e31SAlexander Graf         cc = 3;
498defb0e31SAlexander Graf         break;
499defb0e31SAlexander Graf     }
500defb0e31SAlexander Graf 
501defb0e31SAlexander Graf     return cc;
502defb0e31SAlexander Graf }
503defb0e31SAlexander Graf 
504089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
505089f5c06SBlue Swirl                       uint64_t cpu_addr)
506defb0e31SAlexander Graf {
507defb0e31SAlexander Graf     int cc = 0;
508defb0e31SAlexander Graf 
509defb0e31SAlexander Graf     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
51071e47088SBlue Swirl                __func__, order_code, r1, cpu_addr);
511defb0e31SAlexander Graf 
512defb0e31SAlexander Graf     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
513defb0e31SAlexander Graf        as parameter (input). Status (output) is always R1. */
514defb0e31SAlexander Graf 
515defb0e31SAlexander Graf     switch (order_code) {
516defb0e31SAlexander Graf     case SIGP_SET_ARCH:
517defb0e31SAlexander Graf         /* switch arch */
518defb0e31SAlexander Graf         break;
519defb0e31SAlexander Graf     case SIGP_SENSE:
520defb0e31SAlexander Graf         /* enumerate CPU status */
521defb0e31SAlexander Graf         if (cpu_addr) {
522defb0e31SAlexander Graf             /* XXX implement when SMP comes */
523defb0e31SAlexander Graf             return 3;
524defb0e31SAlexander Graf         }
525defb0e31SAlexander Graf         env->regs[r1] &= 0xffffffff00000000ULL;
526defb0e31SAlexander Graf         cc = 1;
527defb0e31SAlexander Graf         break;
5281864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY)
5291864b94aSAlexander Graf     case SIGP_RESTART:
5301864b94aSAlexander Graf         qemu_system_reset_request();
5311864b94aSAlexander Graf         cpu_loop_exit(env);
5321864b94aSAlexander Graf         break;
5331864b94aSAlexander Graf     case SIGP_STOP:
5341864b94aSAlexander Graf         qemu_system_shutdown_request();
5351864b94aSAlexander Graf         cpu_loop_exit(env);
5361864b94aSAlexander Graf         break;
5371864b94aSAlexander Graf #endif
538defb0e31SAlexander Graf     default:
539defb0e31SAlexander Graf         /* unknown sigp */
540defb0e31SAlexander Graf         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
541defb0e31SAlexander Graf         cc = 3;
542defb0e31SAlexander Graf     }
543defb0e31SAlexander Graf 
544defb0e31SAlexander Graf     return cc;
545defb0e31SAlexander Graf }
546defb0e31SAlexander Graf #endif
547