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/sysemu.h"
37 /* #define DEBUG_HELPER */
39 #define HELPER_LOG(x...) qemu_log(x)
41 #define HELPER_LOG(x...)
44 /* Raise an exception dynamically from a helper function. */
45 void QEMU_NORETURN
runtime_exception(CPUS390XState
*env
, int excp
,
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
;
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
;
72 #ifndef CONFIG_USER_ONLY
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
)
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",
161 kvm_s390_interrupt(s390_env_get_cpu(env
), KVM_S390_PROGRAM_INT
, code
);
164 env
->int_pgm_code
= code
;
165 env
->int_pgm_ilen
= ilen
;
166 env
->exception_index
= EXCP_PGM
;
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
);
176 program_interrupt(env
, -r
, 4);
183 uint64_t HELPER(diag
)(CPUS390XState
*env
, uint32_t num
, uint64_t mem
,
191 r
= s390_virtio_hypercall(env
);
207 program_interrupt(env
, PGM_OPERATION
, ILEN_LATER_INC
);
214 void HELPER(spx
)(CPUS390XState
*env
, uint64_t a1
)
216 uint32_t prefix
= a1
& 0x7fffe000;
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
)
227 time
= env
->tod_offset
+
228 time2tod(qemu_get_clock_ns(vm_clock
) - env
->tod_basetime
);
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
)
246 /* difference between now and then */
247 time
-= clock_value(env
);
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
)
262 void HELPER(spt
)(CPUS390XState
*env
, uint64_t time
)
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
)
281 /* Store System Information */
282 uint32_t HELPER(stsi
)(CPUS390XState
*env
, uint64_t a0
,
283 uint64_t r0
, uint64_t r1
)
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
) {
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);
342 if ((sel1
== 2) && (sel2
== 1)) {
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)) {
355 struct sysib_222 sysib
;
357 memset(&sysib
, 0, sizeof(sysib
));
358 stw_p(&sysib
.lpar_num
, 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);
377 if ((sel1
== 2) && (sel2
== 2)) {
379 struct sysib_322 sysib
;
381 memset(&sysib
, 0, sizeof(sysib
));
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);
397 case STSI_LEVEL_CURRENT
:
398 env
->regs
[0] = STSI_LEVEL_3
;
408 uint32_t HELPER(sigp
)(CPUS390XState
*env
, uint64_t order_code
, uint32_t r1
,
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
) {
424 /* enumerate CPU status */
426 /* XXX implement when SMP comes */
429 env
->regs
[r1
] &= 0xffffffff00000000ULL
;
432 #if !defined(CONFIG_USER_ONLY)
434 qemu_system_reset_request();
438 qemu_system_shutdown_request();
444 fprintf(stderr
, "XXX unknown sigp: 0x%" PRIx64
"\n", order_code
);