1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
31
32#if !defined(CONFIG_USER_ONLY)
33#include "exec/softmmu_exec.h"
34#include "sysemu/sysemu.h"
35#endif
36
37
38#ifdef DEBUG_HELPER
39#define HELPER_LOG(x...) qemu_log(x)
40#else
41#define HELPER_LOG(x...)
42#endif
43
44
45void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
46 uintptr_t retaddr)
47{
48 int t;
49
50 env->exception_index = EXCP_PGM;
51 env->int_pgm_code = excp;
52
53
54 cpu_restore_state(env, retaddr);
55
56
57 t = cpu_ldub_code(env, env->psw.addr);
58 env->int_pgm_ilen = t = get_ilen(t);
59 env->psw.addr += 2 * t;
60
61 cpu_loop_exit(env);
62}
63
64
65void HELPER(exception)(CPUS390XState *env, uint32_t excp)
66{
67 HELPER_LOG("%s: exception %d\n", __func__, excp);
68 env->exception_index = excp;
69 cpu_loop_exit(env);
70}
71
72#ifndef CONFIG_USER_ONLY
73
74
75static 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,
108};
109
110static 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
143};
144
145static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
146{
147 int i;
148
149 for (i = 0; i < len; i++) {
150 p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
151 }
152}
153
154void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
155{
156 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
157 env->psw.addr);
158
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);
168 }
169}
170
171
172uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
173{
174 int r = sclp_service_call(r1, r2);
175 if (r < 0) {
176 program_interrupt(env, -r, 4);
177 return 0;
178 }
179 return r;
180}
181
182
183uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
184 uint64_t code)
185{
186 uint64_t r;
187
188 switch (num) {
189 case 0x500:
190
191 r = s390_virtio_hypercall(env);
192 break;
193 case 0x44:
194
195 r = 0;
196 break;
197 case 0x308:
198
199 r = 0;
200 break;
201 default:
202 r = -1;
203 break;
204 }
205
206 if (r) {
207 program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
208 }
209
210 return r;
211}
212
213
214void HELPER(spx)(CPUS390XState *env, uint64_t a1)
215{
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);
221}
222
223static inline uint64_t clock_value(CPUS390XState *env)
224{
225 uint64_t time;
226
227 time = env->tod_offset +
228 time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
229
230 return time;
231}
232
233
234uint64_t HELPER(stck)(CPUS390XState *env)
235{
236 return clock_value(env);
237}
238
239
240void HELPER(sckc)(CPUS390XState *env, uint64_t time)
241{
242 if (time == -1ULL) {
243 return;
244 }
245
246
247 time -= clock_value(env);
248
249 time = (time * 125) >> 9;
250
251 qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
252}
253
254
255uint64_t HELPER(stckc)(CPUS390XState *env)
256{
257
258 return 0;
259}
260
261
262void HELPER(spt)(CPUS390XState *env, uint64_t time)
263{
264 if (time == -1ULL) {
265 return;
266 }
267
268
269 time = (time * 125) >> 9;
270
271 qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
272}
273
274
275uint64_t HELPER(stpt)(CPUS390XState *env)
276{
277
278 return 0;
279}
280
281
282uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
283 uint64_t r0, uint64_t r1)
284{
285 int cc = 0;
286 int sel1, sel2;
287
288 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
289 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
290
291 program_interrupt(env, PGM_SPECIFICATION, 2);
292 }
293
294 sel1 = r0 & STSI_R0_SEL1_MASK;
295 sel2 = r1 & STSI_R1_SEL2_MASK;
296
297
298
299 switch (r0 & STSI_LEVEL_MASK) {
300 case STSI_LEVEL_1:
301 if ((sel1 == 1) && (sel2 == 1)) {
302
303 struct sysib_111 sysib;
304
305 memset(&sysib, 0, sizeof(sysib));
306 ebcdic_put(sysib.manuf, "QEMU ", 16);
307
308 ebcdic_put(sysib.type, "QEMU", 4);
309
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
316 struct sysib_121 sysib;
317
318 memset(&sysib, 0, sizeof(sysib));
319
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
326 struct sysib_122 sysib;
327
328 memset(&sysib, 0, sizeof(sysib));
329 stl_p(&sysib.capability, 0x443afc29);
330
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;
338 }
339 break;
340 case STSI_LEVEL_2:
341 {
342 if ((sel1 == 2) && (sel2 == 1)) {
343
344 struct sysib_221 sysib;
345
346 memset(&sysib, 0, sizeof(sysib));
347
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
355 struct sysib_222 sysib;
356
357 memset(&sysib, 0, sizeof(sysib));
358 stw_p(&sysib.lpar_num, 0);
359 sysib.lcpuc = 0;
360
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;
372 }
373 break;
374 }
375 case STSI_LEVEL_3:
376 {
377 if ((sel1 == 2) && (sel2 == 2)) {
378
379 struct sysib_322 sysib;
380
381 memset(&sysib, 0, sizeof(sysib));
382 sysib.count = 1;
383
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;
394 }
395 break;
396 }
397 case STSI_LEVEL_CURRENT:
398 env->regs[0] = STSI_LEVEL_3;
399 break;
400 default:
401 cc = 3;
402 break;
403 }
404
405 return cc;
406}
407
408uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
409 uint64_t cpu_addr)
410{
411 int cc = 0;
412
413 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
414 __func__, order_code, r1, cpu_addr);
415
416
417
418
419 switch (order_code) {
420 case SIGP_SET_ARCH:
421
422 break;
423 case SIGP_SENSE:
424
425 if (cpu_addr) {
426
427 return 3;
428 }
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
444 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
445 cc = 3;
446 }
447
448 return cc;
449}
450#endif
451