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 int load_normal_reset(S390CPU
*cpu
)
197 S390CPUClass
*scc
= S390_CPU_GET_CLASS(cpu
);
200 cpu_synchronize_all_states();
202 io_subsystem_reset();
203 scc
->initial_cpu_reset(CPU(cpu
));
204 scc
->load_normal(CPU(cpu
));
205 cpu_synchronize_all_post_reset();
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
);
222 if ((subcode
& ~0x0ffffULL
) || (subcode
> 6)) {
223 program_interrupt(env
, PGM_SPECIFICATION
, ILEN_LATER_INC
);
229 load_normal_reset(s390_env_get_cpu(env
));
232 if ((r1
& 1) || (addr
& 0x0fffULL
)) {
233 program_interrupt(env
, PGM_SPECIFICATION
, ILEN_LATER_INC
);
236 env
->regs
[r1
+1] = DIAG_308_RC_INVALID
;
239 if ((r1
& 1) || (addr
& 0x0fffULL
)) {
240 program_interrupt(env
, PGM_SPECIFICATION
, ILEN_LATER_INC
);
243 env
->regs
[r1
+1] = DIAG_308_RC_NO_CONF
;
246 hw_error("Unhandled diag308 subcode %" PRIx64
, subcode
);
253 uint64_t HELPER(diag
)(CPUS390XState
*env
, uint32_t num
, uint64_t mem
,
261 r
= s390_virtio_hypercall(env
);
277 program_interrupt(env
, PGM_OPERATION
, ILEN_LATER_INC
);
284 void HELPER(spx
)(CPUS390XState
*env
, uint64_t a1
)
286 uint32_t prefix
= a1
& 0x7fffe000;
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
)
297 time
= env
->tod_offset
+
298 time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - env
->tod_basetime
);
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
)
316 /* difference between now and then */
317 time
-= clock_value(env
);
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
)
332 void HELPER(spt
)(CPUS390XState
*env
, uint64_t time
)
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
)
351 /* Store System Information */
352 uint32_t HELPER(stsi
)(CPUS390XState
*env
, uint64_t a0
,
353 uint64_t r0
, uint64_t r1
)
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
) {
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);
412 if ((sel1
== 2) && (sel2
== 1)) {
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)) {
425 struct sysib_222 sysib
;
427 memset(&sysib
, 0, sizeof(sysib
));
428 stw_p(&sysib
.lpar_num
, 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);
447 if ((sel1
== 2) && (sel2
== 2)) {
449 struct sysib_322 sysib
;
451 memset(&sysib
, 0, sizeof(sysib
));
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);
467 case STSI_LEVEL_CURRENT
:
468 env
->regs
[0] = STSI_LEVEL_3
;
478 uint32_t HELPER(sigp
)(CPUS390XState
*env
, uint64_t order_code
, uint32_t r1
,
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
) {
494 /* enumerate CPU status */
496 /* XXX implement when SMP comes */
499 env
->regs
[r1
] &= 0xffffffff00000000ULL
;
502 #if !defined(CONFIG_USER_ONLY)
504 qemu_system_reset_request();
508 qemu_system_shutdown_request();
514 fprintf(stderr
, "XXX unknown sigp: 0x%" PRIx64
"\n", order_code
);