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/>.
22 #include "exec/memory.h"
23 #include "qemu/host-utils.h"
26 #include "sysemu/kvm.h"
27 #include "qemu/timer.h"
29 #include <linux/kvm.h>
32 #if !defined(CONFIG_USER_ONLY)
33 #include "exec/softmmu_exec.h"
34 #include "sysemu/cpus.h"
35 #include "sysemu/sysemu.h"
38 /* #define DEBUG_HELPER */
40 #define HELPER_LOG(x...) qemu_log(x)
42 #define HELPER_LOG(x...)
45 /* Raise an exception dynamically from a helper function. */
46 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
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;
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;
73 #ifndef CONFIG_USER_ONLY
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)
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",
162 kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
165 env->int_pgm_code = code;
166 env->int_pgm_ilen = ilen;
167 env->exception_index = EXCP_PGM;
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);
177 program_interrupt(env, -r, 4);
183 #ifndef CONFIG_USER_ONLY
184 static void cpu_reset_all(void)
190 scc = S390_CPU_GET_CLASS(cs);
195 static void cpu_full_reset_all(void)
204 static int modified_clear_reset(S390CPU *cpu)
206 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
209 cpu_synchronize_all_states();
210 cpu_full_reset_all();
211 io_subsystem_reset();
212 scc->load_normal(CPU(cpu));
213 cpu_synchronize_all_post_reset();
218 static int load_normal_reset(S390CPU *cpu)
220 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
223 cpu_synchronize_all_states();
225 io_subsystem_reset();
226 scc->initial_cpu_reset(CPU(cpu));
227 scc->load_normal(CPU(cpu));
228 cpu_synchronize_all_post_reset();
233 #define DIAG_308_RC_NO_CONF 0x0102
234 #define DIAG_308_RC_INVALID 0x0402
235 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
237 uint64_t addr = env->regs[r1];
238 uint64_t subcode = env->regs[r3];
240 if (env->psw.mask & PSW_MASK_PSTATE) {
241 program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
245 if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
246 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
252 modified_clear_reset(s390_env_get_cpu(env));
255 load_normal_reset(s390_env_get_cpu(env));
258 if ((r1 & 1) || (addr & 0x0fffULL)) {
259 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
262 env->regs[r1+1] = DIAG_308_RC_INVALID;
265 if ((r1 & 1) || (addr & 0x0fffULL)) {
266 program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
269 env->regs[r1+1] = DIAG_308_RC_NO_CONF;
272 hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
279 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
287 r = s390_virtio_hypercall(env);
303 program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
310 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
312 uint32_t prefix = a1 & 0x7fffe000;
314 qemu_log("prefix: %#x\n", prefix);
315 tlb_flush_page(env, 0);
316 tlb_flush_page(env, TARGET_PAGE_SIZE);
319 static inline uint64_t clock_value(CPUS390XState *env)
323 time = env->tod_offset +
324 time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
330 uint64_t HELPER(stck)(CPUS390XState *env)
332 return clock_value(env);
335 /* Set Clock Comparator */
336 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
342 /* difference between now and then */
343 time -= clock_value(env);
345 time = (time * 125) >> 9;
347 timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
350 /* Store Clock Comparator */
351 uint64_t HELPER(stckc)(CPUS390XState *env)
358 void HELPER(spt)(CPUS390XState *env, uint64_t time)
365 time = (time * 125) >> 9;
367 timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
370 /* Store CPU Timer */
371 uint64_t HELPER(stpt)(CPUS390XState *env)
377 /* Store System Information */
378 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
379 uint64_t r0, uint64_t r1)
384 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
385 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
386 /* valid function code, invalid reserved bits */
387 program_interrupt(env, PGM_SPECIFICATION, 2);
390 sel1 = r0 & STSI_R0_SEL1_MASK;
391 sel2 = r1 & STSI_R1_SEL2_MASK;
393 /* XXX: spec exception if sysib is not 4k-aligned */
395 switch (r0 & STSI_LEVEL_MASK) {
397 if ((sel1 == 1) && (sel2 == 1)) {
398 /* Basic Machine Configuration */
399 struct sysib_111 sysib;
401 memset(&sysib, 0, sizeof(sysib));
402 ebcdic_put(sysib.manuf, "QEMU ", 16);
403 /* same as machine type number in STORE CPU ID */
404 ebcdic_put(sysib.type, "QEMU", 4);
405 /* same as model number in STORE CPU ID */
406 ebcdic_put(sysib.model, "QEMU ", 16);
407 ebcdic_put(sysib.sequence, "QEMU ", 16);
408 ebcdic_put(sysib.plant, "QEMU", 4);
409 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
410 } else if ((sel1 == 2) && (sel2 == 1)) {
411 /* Basic Machine CPU */
412 struct sysib_121 sysib;
414 memset(&sysib, 0, sizeof(sysib));
415 /* XXX make different for different CPUs? */
416 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
417 ebcdic_put(sysib.plant, "QEMU", 4);
418 stw_p(&sysib.cpu_addr, env->cpu_num);
419 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
420 } else if ((sel1 == 2) && (sel2 == 2)) {
421 /* Basic Machine CPUs */
422 struct sysib_122 sysib;
424 memset(&sysib, 0, sizeof(sysib));
425 stl_p(&sysib.capability, 0x443afc29);
426 /* XXX change when SMP comes */
427 stw_p(&sysib.total_cpus, 1);
428 stw_p(&sysib.active_cpus, 1);
429 stw_p(&sysib.standby_cpus, 0);
430 stw_p(&sysib.reserved_cpus, 0);
431 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
438 if ((sel1 == 2) && (sel2 == 1)) {
440 struct sysib_221 sysib;
442 memset(&sysib, 0, sizeof(sysib));
443 /* XXX make different for different CPUs? */
444 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
445 ebcdic_put(sysib.plant, "QEMU", 4);
446 stw_p(&sysib.cpu_addr, env->cpu_num);
447 stw_p(&sysib.cpu_id, 0);
448 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
449 } else if ((sel1 == 2) && (sel2 == 2)) {
451 struct sysib_222 sysib;
453 memset(&sysib, 0, sizeof(sysib));
454 stw_p(&sysib.lpar_num, 0);
456 /* XXX change when SMP comes */
457 stw_p(&sysib.total_cpus, 1);
458 stw_p(&sysib.conf_cpus, 1);
459 stw_p(&sysib.standby_cpus, 0);
460 stw_p(&sysib.reserved_cpus, 0);
461 ebcdic_put(sysib.name, "QEMU ", 8);
462 stl_p(&sysib.caf, 1000);
463 stw_p(&sysib.dedicated_cpus, 0);
464 stw_p(&sysib.shared_cpus, 0);
465 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
473 if ((sel1 == 2) && (sel2 == 2)) {
475 struct sysib_322 sysib;
477 memset(&sysib, 0, sizeof(sysib));
479 /* XXX change when SMP comes */
480 stw_p(&sysib.vm[0].total_cpus, 1);
481 stw_p(&sysib.vm[0].conf_cpus, 1);
482 stw_p(&sysib.vm[0].standby_cpus, 0);
483 stw_p(&sysib.vm[0].reserved_cpus, 0);
484 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
485 stl_p(&sysib.vm[0].caf, 1000);
486 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
487 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
493 case STSI_LEVEL_CURRENT:
494 env->regs[0] = STSI_LEVEL_3;
504 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
509 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
510 __func__, order_code, r1, cpu_addr);
512 /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
513 as parameter (input). Status (output) is always R1. */
515 switch (order_code) {
520 /* enumerate CPU status */
522 /* XXX implement when SMP comes */
525 env->regs[r1] &= 0xffffffff00000000ULL;
528 #if !defined(CONFIG_USER_ONLY)
530 qemu_system_reset_request();
534 qemu_system_shutdown_request();
540 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);