pseries: Add H_SET_MODE hcall to change guest exception endianness
[qemu/kevin.git] / target-s390x / misc_helper.c
blob4afd7dab1c2a81f31f67ffecddb5fd0888ce5b47
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/cpus.h"
35 #include "sysemu/sysemu.h"
36 #endif
38 /* #define DEBUG_HELPER */
39 #ifdef DEBUG_HELPER
40 #define HELPER_LOG(x...) qemu_log(x)
41 #else
42 #define HELPER_LOG(x...)
43 #endif
45 /* Raise an exception dynamically from a helper function. */
46 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
47 uintptr_t retaddr)
49 int t;
51 env->exception_index = EXCP_PGM;
52 env->int_pgm_code = excp;
54 /* Use the (ultimate) callers address to find the insn that trapped. */
55 cpu_restore_state(env, retaddr);
57 /* Advance past the insn. */
58 t = cpu_ldub_code(env, env->psw.addr);
59 env->int_pgm_ilen = t = get_ilen(t);
60 env->psw.addr += 2 * t;
62 cpu_loop_exit(env);
65 /* Raise an exception statically from a TB. */
66 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
68 HELPER_LOG("%s: exception %d\n", __func__, excp);
69 env->exception_index = excp;
70 cpu_loop_exit(env);
73 #ifndef CONFIG_USER_ONLY
75 /* EBCDIC handling */
76 static const uint8_t ebcdic2ascii[] = {
77 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
78 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
79 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
80 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
81 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
82 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
83 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
84 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
85 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
86 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
87 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
88 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
89 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
90 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
91 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
92 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
93 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
95 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
96 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
97 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
98 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
99 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
100 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
101 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
102 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
103 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
104 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
105 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
106 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
107 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
108 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
111 static const uint8_t ascii2ebcdic[] = {
112 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
113 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
114 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
115 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
116 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
117 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
118 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
119 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
120 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
121 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
122 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
123 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
124 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
125 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
126 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
127 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
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, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
140 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
141 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
142 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
143 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
146 static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
148 int i;
150 for (i = 0; i < len; i++) {
151 p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
155 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
157 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
158 env->psw.addr);
160 if (kvm_enabled()) {
161 #ifdef CONFIG_KVM
162 kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
163 #endif
164 } else {
165 env->int_pgm_code = code;
166 env->int_pgm_ilen = ilen;
167 env->exception_index = EXCP_PGM;
168 cpu_loop_exit(env);
172 /* SCLP service call */
173 uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
175 int r = sclp_service_call(r1, r2);
176 if (r < 0) {
177 program_interrupt(env, -r, 4);
178 return 0;
180 return r;
183 #ifndef CONFIG_USER_ONLY
184 static void cpu_reset_all(void)
186 CPUState *cpu;
187 S390CPUClass *scc;
189 for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
190 scc = S390_CPU_GET_CLASS(CPU(cpu));
191 scc->cpu_reset(CPU(cpu));
195 static int load_normal_reset(S390CPU *cpu)
197 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
199 pause_all_vcpus();
200 cpu_synchronize_all_states();
201 cpu_reset_all();
202 io_subsystem_reset();
203 scc->initial_cpu_reset(CPU(cpu));
204 scc->load_normal(CPU(cpu));
205 cpu_synchronize_all_post_reset();
206 resume_all_vcpus();
207 return 0;
210 #define DIAG_308_RC_NO_CONF 0x0102
211 #define DIAG_308_RC_INVALID 0x0402
212 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
214 uint64_t addr = env->regs[r1];
215 uint64_t subcode = env->regs[r3];
217 if (env->psw.mask & PSW_MASK_PSTATE) {
218 program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
219 return;
222 if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
223 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
224 return;
227 switch (subcode) {
228 case 1:
229 load_normal_reset(s390_env_get_cpu(env));
230 break;
231 case 5:
232 if ((r1 & 1) || (addr & 0x0fffULL)) {
233 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
234 return;
236 env->regs[r1+1] = DIAG_308_RC_INVALID;
237 return;
238 case 6:
239 if ((r1 & 1) || (addr & 0x0fffULL)) {
240 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
241 return;
243 env->regs[r1+1] = DIAG_308_RC_NO_CONF;
244 return;
245 default:
246 hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
247 break;
250 #endif
252 /* DIAG */
253 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
254 uint64_t code)
256 uint64_t r;
258 switch (num) {
259 case 0x500:
260 /* KVM hypercall */
261 r = s390_virtio_hypercall(env);
262 break;
263 case 0x44:
264 /* yield */
265 r = 0;
266 break;
267 case 0x308:
268 /* ipl */
269 r = 0;
270 break;
271 default:
272 r = -1;
273 break;
276 if (r) {
277 program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
280 return r;
283 /* Set Prefix */
284 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
286 uint32_t prefix = a1 & 0x7fffe000;
287 env->psa = prefix;
288 qemu_log("prefix: %#x\n", prefix);
289 tlb_flush_page(env, 0);
290 tlb_flush_page(env, TARGET_PAGE_SIZE);
293 static inline uint64_t clock_value(CPUS390XState *env)
295 uint64_t time;
297 time = env->tod_offset +
298 time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
300 return time;
303 /* Store Clock */
304 uint64_t HELPER(stck)(CPUS390XState *env)
306 return clock_value(env);
309 /* Set Clock Comparator */
310 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
312 if (time == -1ULL) {
313 return;
316 /* difference between now and then */
317 time -= clock_value(env);
318 /* nanoseconds */
319 time = (time * 125) >> 9;
321 timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
324 /* Store Clock Comparator */
325 uint64_t HELPER(stckc)(CPUS390XState *env)
327 /* XXX implement */
328 return 0;
331 /* Set CPU Timer */
332 void HELPER(spt)(CPUS390XState *env, uint64_t time)
334 if (time == -1ULL) {
335 return;
338 /* nanoseconds */
339 time = (time * 125) >> 9;
341 timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
344 /* Store CPU Timer */
345 uint64_t HELPER(stpt)(CPUS390XState *env)
347 /* XXX implement */
348 return 0;
351 /* Store System Information */
352 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
353 uint64_t r0, uint64_t r1)
355 int cc = 0;
356 int sel1, sel2;
358 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
359 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
360 /* valid function code, invalid reserved bits */
361 program_interrupt(env, PGM_SPECIFICATION, 2);
364 sel1 = r0 & STSI_R0_SEL1_MASK;
365 sel2 = r1 & STSI_R1_SEL2_MASK;
367 /* XXX: spec exception if sysib is not 4k-aligned */
369 switch (r0 & STSI_LEVEL_MASK) {
370 case STSI_LEVEL_1:
371 if ((sel1 == 1) && (sel2 == 1)) {
372 /* Basic Machine Configuration */
373 struct sysib_111 sysib;
375 memset(&sysib, 0, sizeof(sysib));
376 ebcdic_put(sysib.manuf, "QEMU ", 16);
377 /* same as machine type number in STORE CPU ID */
378 ebcdic_put(sysib.type, "QEMU", 4);
379 /* same as model number in STORE CPU ID */
380 ebcdic_put(sysib.model, "QEMU ", 16);
381 ebcdic_put(sysib.sequence, "QEMU ", 16);
382 ebcdic_put(sysib.plant, "QEMU", 4);
383 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
384 } else if ((sel1 == 2) && (sel2 == 1)) {
385 /* Basic Machine CPU */
386 struct sysib_121 sysib;
388 memset(&sysib, 0, sizeof(sysib));
389 /* XXX make different for different CPUs? */
390 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
391 ebcdic_put(sysib.plant, "QEMU", 4);
392 stw_p(&sysib.cpu_addr, env->cpu_num);
393 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
394 } else if ((sel1 == 2) && (sel2 == 2)) {
395 /* Basic Machine CPUs */
396 struct sysib_122 sysib;
398 memset(&sysib, 0, sizeof(sysib));
399 stl_p(&sysib.capability, 0x443afc29);
400 /* XXX change when SMP comes */
401 stw_p(&sysib.total_cpus, 1);
402 stw_p(&sysib.active_cpus, 1);
403 stw_p(&sysib.standby_cpus, 0);
404 stw_p(&sysib.reserved_cpus, 0);
405 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
406 } else {
407 cc = 3;
409 break;
410 case STSI_LEVEL_2:
412 if ((sel1 == 2) && (sel2 == 1)) {
413 /* LPAR CPU */
414 struct sysib_221 sysib;
416 memset(&sysib, 0, sizeof(sysib));
417 /* XXX make different for different CPUs? */
418 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
419 ebcdic_put(sysib.plant, "QEMU", 4);
420 stw_p(&sysib.cpu_addr, env->cpu_num);
421 stw_p(&sysib.cpu_id, 0);
422 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
423 } else if ((sel1 == 2) && (sel2 == 2)) {
424 /* LPAR CPUs */
425 struct sysib_222 sysib;
427 memset(&sysib, 0, sizeof(sysib));
428 stw_p(&sysib.lpar_num, 0);
429 sysib.lcpuc = 0;
430 /* XXX change when SMP comes */
431 stw_p(&sysib.total_cpus, 1);
432 stw_p(&sysib.conf_cpus, 1);
433 stw_p(&sysib.standby_cpus, 0);
434 stw_p(&sysib.reserved_cpus, 0);
435 ebcdic_put(sysib.name, "QEMU ", 8);
436 stl_p(&sysib.caf, 1000);
437 stw_p(&sysib.dedicated_cpus, 0);
438 stw_p(&sysib.shared_cpus, 0);
439 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
440 } else {
441 cc = 3;
443 break;
445 case STSI_LEVEL_3:
447 if ((sel1 == 2) && (sel2 == 2)) {
448 /* VM CPUs */
449 struct sysib_322 sysib;
451 memset(&sysib, 0, sizeof(sysib));
452 sysib.count = 1;
453 /* XXX change when SMP comes */
454 stw_p(&sysib.vm[0].total_cpus, 1);
455 stw_p(&sysib.vm[0].conf_cpus, 1);
456 stw_p(&sysib.vm[0].standby_cpus, 0);
457 stw_p(&sysib.vm[0].reserved_cpus, 0);
458 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
459 stl_p(&sysib.vm[0].caf, 1000);
460 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
461 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
462 } else {
463 cc = 3;
465 break;
467 case STSI_LEVEL_CURRENT:
468 env->regs[0] = STSI_LEVEL_3;
469 break;
470 default:
471 cc = 3;
472 break;
475 return cc;
478 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
479 uint64_t cpu_addr)
481 int cc = 0;
483 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
484 __func__, order_code, r1, cpu_addr);
486 /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
487 as parameter (input). Status (output) is always R1. */
489 switch (order_code) {
490 case SIGP_SET_ARCH:
491 /* switch arch */
492 break;
493 case SIGP_SENSE:
494 /* enumerate CPU status */
495 if (cpu_addr) {
496 /* XXX implement when SMP comes */
497 return 3;
499 env->regs[r1] &= 0xffffffff00000000ULL;
500 cc = 1;
501 break;
502 #if !defined(CONFIG_USER_ONLY)
503 case SIGP_RESTART:
504 qemu_system_reset_request();
505 cpu_loop_exit(env);
506 break;
507 case SIGP_STOP:
508 qemu_system_shutdown_request();
509 cpu_loop_exit(env);
510 break;
511 #endif
512 default:
513 /* unknown sigp */
514 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
515 cc = 3;
518 return cc;
520 #endif