Replace all setjmp()/longjmp() with sigsetjmp()/siglongjmp()
[qemu/pbrook.git] / target-s390x / misc_helper.c
blob09301d0a6f0ae34dd90741475ae751d3538d4f65
1 /*
2 * S/390 misc helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "cpu.h"
22 #include "exec/memory.h"
23 #include "qemu/host-utils.h"
24 #include "helper.h"
25 #include <string.h>
26 #include "sysemu/kvm.h"
27 #include "qemu/timer.h"
28 #ifdef CONFIG_KVM
29 #include <linux/kvm.h>
30 #endif
32 #if !defined(CONFIG_USER_ONLY)
33 #include "exec/softmmu_exec.h"
34 #include "sysemu/sysemu.h"
35 #endif
37 /* #define DEBUG_HELPER */
38 #ifdef DEBUG_HELPER
39 #define HELPER_LOG(x...) qemu_log(x)
40 #else
41 #define HELPER_LOG(x...)
42 #endif
44 /* Raise an exception dynamically from a helper function. */
45 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
46 uintptr_t retaddr)
48 int t;
50 env->exception_index = EXCP_PGM;
51 env->int_pgm_code = excp;
53 /* Use the (ultimate) callers address to find the insn that trapped. */
54 cpu_restore_state(env, retaddr);
56 /* Advance past the insn. */
57 t = cpu_ldub_code(env, env->psw.addr);
58 env->int_pgm_ilen = t = get_ilen(t);
59 env->psw.addr += 2 * t;
61 cpu_loop_exit(env);
64 /* Raise an exception statically from a TB. */
65 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
67 HELPER_LOG("%s: exception %d\n", __func__, excp);
68 env->exception_index = excp;
69 cpu_loop_exit(env);
72 #ifndef CONFIG_USER_ONLY
74 /* EBCDIC handling */
75 static const uint8_t ebcdic2ascii[] = {
76 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
77 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
78 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
79 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
80 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
81 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
82 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
83 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
84 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
85 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
86 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
87 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
88 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
89 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
90 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
91 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
92 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
93 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
94 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
95 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
96 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
97 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
98 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
99 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
100 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
101 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
102 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
103 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
104 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
105 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
106 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
107 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
110 static const uint8_t ascii2ebcdic[] = {
111 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
112 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
113 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
114 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
115 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
116 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
117 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
118 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
119 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
120 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
121 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
122 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
123 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
124 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
125 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
126 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
127 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
128 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
129 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
130 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
131 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
132 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
133 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
134 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
135 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
136 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
137 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
138 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
139 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
140 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
141 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
142 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
145 static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
147 int i;
149 for (i = 0; i < len; i++) {
150 p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
154 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
156 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
157 env->psw.addr);
159 if (kvm_enabled()) {
160 #ifdef CONFIG_KVM
161 kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
162 #endif
163 } else {
164 env->int_pgm_code = code;
165 env->int_pgm_ilen = ilen;
166 env->exception_index = EXCP_PGM;
167 cpu_loop_exit(env);
171 /* SCLP service call */
172 uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
174 int r = sclp_service_call(r1, r2);
175 if (r < 0) {
176 program_interrupt(env, -r, 4);
177 return 0;
179 return r;
182 /* DIAG */
183 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
184 uint64_t code)
186 uint64_t r;
188 switch (num) {
189 case 0x500:
190 /* KVM hypercall */
191 r = s390_virtio_hypercall(env);
192 break;
193 case 0x44:
194 /* yield */
195 r = 0;
196 break;
197 case 0x308:
198 /* ipl */
199 r = 0;
200 break;
201 default:
202 r = -1;
203 break;
206 if (r) {
207 program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
210 return r;
213 /* Set Prefix */
214 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
216 uint32_t prefix = a1 & 0x7fffe000;
217 env->psa = prefix;
218 qemu_log("prefix: %#x\n", prefix);
219 tlb_flush_page(env, 0);
220 tlb_flush_page(env, TARGET_PAGE_SIZE);
223 static inline uint64_t clock_value(CPUS390XState *env)
225 uint64_t time;
227 time = env->tod_offset +
228 time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
230 return time;
233 /* Store Clock */
234 uint64_t HELPER(stck)(CPUS390XState *env)
236 return clock_value(env);
239 /* Set Clock Comparator */
240 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
242 if (time == -1ULL) {
243 return;
246 /* difference between now and then */
247 time -= clock_value(env);
248 /* nanoseconds */
249 time = (time * 125) >> 9;
251 qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
254 /* Store Clock Comparator */
255 uint64_t HELPER(stckc)(CPUS390XState *env)
257 /* XXX implement */
258 return 0;
261 /* Set CPU Timer */
262 void HELPER(spt)(CPUS390XState *env, uint64_t time)
264 if (time == -1ULL) {
265 return;
268 /* nanoseconds */
269 time = (time * 125) >> 9;
271 qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
274 /* Store CPU Timer */
275 uint64_t HELPER(stpt)(CPUS390XState *env)
277 /* XXX implement */
278 return 0;
281 /* Store System Information */
282 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
283 uint64_t r0, uint64_t r1)
285 int cc = 0;
286 int sel1, sel2;
288 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
289 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
290 /* valid function code, invalid reserved bits */
291 program_interrupt(env, PGM_SPECIFICATION, 2);
294 sel1 = r0 & STSI_R0_SEL1_MASK;
295 sel2 = r1 & STSI_R1_SEL2_MASK;
297 /* XXX: spec exception if sysib is not 4k-aligned */
299 switch (r0 & STSI_LEVEL_MASK) {
300 case STSI_LEVEL_1:
301 if ((sel1 == 1) && (sel2 == 1)) {
302 /* Basic Machine Configuration */
303 struct sysib_111 sysib;
305 memset(&sysib, 0, sizeof(sysib));
306 ebcdic_put(sysib.manuf, "QEMU ", 16);
307 /* same as machine type number in STORE CPU ID */
308 ebcdic_put(sysib.type, "QEMU", 4);
309 /* same as model number in STORE CPU ID */
310 ebcdic_put(sysib.model, "QEMU ", 16);
311 ebcdic_put(sysib.sequence, "QEMU ", 16);
312 ebcdic_put(sysib.plant, "QEMU", 4);
313 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
314 } else if ((sel1 == 2) && (sel2 == 1)) {
315 /* Basic Machine CPU */
316 struct sysib_121 sysib;
318 memset(&sysib, 0, sizeof(sysib));
319 /* XXX make different for different CPUs? */
320 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
321 ebcdic_put(sysib.plant, "QEMU", 4);
322 stw_p(&sysib.cpu_addr, env->cpu_num);
323 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
324 } else if ((sel1 == 2) && (sel2 == 2)) {
325 /* Basic Machine CPUs */
326 struct sysib_122 sysib;
328 memset(&sysib, 0, sizeof(sysib));
329 stl_p(&sysib.capability, 0x443afc29);
330 /* XXX change when SMP comes */
331 stw_p(&sysib.total_cpus, 1);
332 stw_p(&sysib.active_cpus, 1);
333 stw_p(&sysib.standby_cpus, 0);
334 stw_p(&sysib.reserved_cpus, 0);
335 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
336 } else {
337 cc = 3;
339 break;
340 case STSI_LEVEL_2:
342 if ((sel1 == 2) && (sel2 == 1)) {
343 /* LPAR CPU */
344 struct sysib_221 sysib;
346 memset(&sysib, 0, sizeof(sysib));
347 /* XXX make different for different CPUs? */
348 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
349 ebcdic_put(sysib.plant, "QEMU", 4);
350 stw_p(&sysib.cpu_addr, env->cpu_num);
351 stw_p(&sysib.cpu_id, 0);
352 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
353 } else if ((sel1 == 2) && (sel2 == 2)) {
354 /* LPAR CPUs */
355 struct sysib_222 sysib;
357 memset(&sysib, 0, sizeof(sysib));
358 stw_p(&sysib.lpar_num, 0);
359 sysib.lcpuc = 0;
360 /* XXX change when SMP comes */
361 stw_p(&sysib.total_cpus, 1);
362 stw_p(&sysib.conf_cpus, 1);
363 stw_p(&sysib.standby_cpus, 0);
364 stw_p(&sysib.reserved_cpus, 0);
365 ebcdic_put(sysib.name, "QEMU ", 8);
366 stl_p(&sysib.caf, 1000);
367 stw_p(&sysib.dedicated_cpus, 0);
368 stw_p(&sysib.shared_cpus, 0);
369 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
370 } else {
371 cc = 3;
373 break;
375 case STSI_LEVEL_3:
377 if ((sel1 == 2) && (sel2 == 2)) {
378 /* VM CPUs */
379 struct sysib_322 sysib;
381 memset(&sysib, 0, sizeof(sysib));
382 sysib.count = 1;
383 /* XXX change when SMP comes */
384 stw_p(&sysib.vm[0].total_cpus, 1);
385 stw_p(&sysib.vm[0].conf_cpus, 1);
386 stw_p(&sysib.vm[0].standby_cpus, 0);
387 stw_p(&sysib.vm[0].reserved_cpus, 0);
388 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
389 stl_p(&sysib.vm[0].caf, 1000);
390 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
391 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
392 } else {
393 cc = 3;
395 break;
397 case STSI_LEVEL_CURRENT:
398 env->regs[0] = STSI_LEVEL_3;
399 break;
400 default:
401 cc = 3;
402 break;
405 return cc;
408 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
409 uint64_t cpu_addr)
411 int cc = 0;
413 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
414 __func__, order_code, r1, cpu_addr);
416 /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
417 as parameter (input). Status (output) is always R1. */
419 switch (order_code) {
420 case SIGP_SET_ARCH:
421 /* switch arch */
422 break;
423 case SIGP_SENSE:
424 /* enumerate CPU status */
425 if (cpu_addr) {
426 /* XXX implement when SMP comes */
427 return 3;
429 env->regs[r1] &= 0xffffffff00000000ULL;
430 cc = 1;
431 break;
432 #if !defined(CONFIG_USER_ONLY)
433 case SIGP_RESTART:
434 qemu_system_reset_request();
435 cpu_loop_exit(env);
436 break;
437 case SIGP_STOP:
438 qemu_system_shutdown_request();
439 cpu_loop_exit(env);
440 break;
441 #endif
442 default:
443 /* unknown sigp */
444 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
445 cc = 3;
448 return cc;
450 #endif