1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "qemu/log.h"
23#include "cpu.h"
24#include "s390x-internal.h"
25#include "exec/helper-proto.h"
26#include "qemu/timer.h"
27#include "exec/exec-all.h"
28#include "exec/cpu_ldst.h"
29#include "hw/s390x/ioinst.h"
30#include "exec/address-spaces.h"
31#include "tcg_s390x.h"
32#ifndef CONFIG_USER_ONLY
33#include "hw/s390x/s390_flic.h"
34#include "hw/boards.h"
35#endif
36
37G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env,
38 uint32_t code, uintptr_t ra)
39{
40 CPUState *cs = env_cpu(env);
41
42 cpu_restore_state(cs, ra, true);
43 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
44 env->psw.addr);
45 trigger_pgm_exception(env, code);
46 cpu_loop_exit(cs);
47}
48
49G_NORETURN void tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
50 uintptr_t ra)
51{
52 g_assert(dxc <= 0xff);
53#if !defined(CONFIG_USER_ONLY)
54
55 stl_phys(env_cpu(env)->as,
56 env->psa + offsetof(LowCore, data_exc_code), dxc);
57#endif
58
59
60 if (env->cregs[0] & CR0_AFP) {
61 env->fpc = deposit32(env->fpc, 8, 8, dxc);
62 }
63 tcg_s390_program_interrupt(env, PGM_DATA, ra);
64}
65
66G_NORETURN void tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
67 uintptr_t ra)
68{
69 g_assert(vxc <= 0xff);
70#if !defined(CONFIG_USER_ONLY)
71
72 stl_phys(env_cpu(env)->as,
73 env->psa + offsetof(LowCore, data_exc_code), vxc);
74#endif
75
76
77 env->fpc = deposit32(env->fpc, 8, 8, vxc);
78 tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
79}
80
81void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
82{
83 tcg_s390_data_exception(env, dxc, GETPC());
84}
85
86
87
88
89
90
91static G_NORETURN
92void do_unaligned_access(CPUState *cs, uintptr_t retaddr)
93{
94 S390CPU *cpu = S390_CPU(cs);
95 CPUS390XState *env = &cpu->env;
96
97 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
98}
99
100#if defined(CONFIG_USER_ONLY)
101
102void s390_cpu_do_interrupt(CPUState *cs)
103{
104 cs->exception_index = -1;
105}
106
107void s390_cpu_record_sigsegv(CPUState *cs, vaddr address,
108 MMUAccessType access_type,
109 bool maperr, uintptr_t retaddr)
110{
111 S390CPU *cpu = S390_CPU(cs);
112
113 trigger_pgm_exception(&cpu->env, maperr ? PGM_ADDRESSING : PGM_PROTECTION);
114
115
116
117
118
119
120 cpu->env.__excp_addr = address & TARGET_PAGE_MASK;
121 cpu_loop_exit_restore(cs, retaddr);
122}
123
124void s390_cpu_record_sigbus(CPUState *cs, vaddr address,
125 MMUAccessType access_type, uintptr_t retaddr)
126{
127 do_unaligned_access(cs, retaddr);
128}
129
130#else
131
132static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
133{
134 switch (mmu_idx) {
135 case MMU_PRIMARY_IDX:
136 return PSW_ASC_PRIMARY;
137 case MMU_SECONDARY_IDX:
138 return PSW_ASC_SECONDARY;
139 case MMU_HOME_IDX:
140 return PSW_ASC_HOME;
141 default:
142 abort();
143 }
144}
145
146bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
147 MMUAccessType access_type, int mmu_idx,
148 bool probe, uintptr_t retaddr)
149{
150 S390CPU *cpu = S390_CPU(cs);
151 CPUS390XState *env = &cpu->env;
152 target_ulong vaddr, raddr;
153 uint64_t asc, tec;
154 int prot, excp;
155
156 qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
157 __func__, address, access_type, mmu_idx);
158
159 vaddr = address;
160
161 if (mmu_idx < MMU_REAL_IDX) {
162 asc = cpu_mmu_idx_to_asc(mmu_idx);
163
164 if (!(env->psw.mask & PSW_MASK_64)) {
165 vaddr &= 0x7fffffff;
166 }
167 excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
168 } else if (mmu_idx == MMU_REAL_IDX) {
169
170 if (!(env->psw.mask & PSW_MASK_64)) {
171 vaddr &= 0x7fffffff;
172 }
173 excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
174 } else {
175 g_assert_not_reached();
176 }
177
178 env->tlb_fill_exc = excp;
179 env->tlb_fill_tec = tec;
180
181 if (!excp) {
182 qemu_log_mask(CPU_LOG_MMU,
183 "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
184 __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
185 tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
186 mmu_idx, TARGET_PAGE_SIZE);
187 return true;
188 }
189 if (probe) {
190 return false;
191 }
192
193 if (excp != PGM_ADDRESSING) {
194 stq_phys(env_cpu(env)->as,
195 env->psa + offsetof(LowCore, trans_exc_code), tec);
196 }
197
198
199
200
201
202
203
204 env->int_pgm_ilen = 2;
205 trigger_pgm_exception(env, excp);
206 cpu_loop_exit_restore(cs, retaddr);
207}
208
209static void do_program_interrupt(CPUS390XState *env)
210{
211 uint64_t mask, addr;
212 LowCore *lowcore;
213 int ilen = env->int_pgm_ilen;
214
215 assert(ilen == 2 || ilen == 4 || ilen == 6);
216
217 switch (env->int_pgm_code) {
218 case PGM_PER:
219 if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
220 break;
221 }
222
223 case PGM_OPERATION:
224 case PGM_PRIVILEGED:
225 case PGM_EXECUTE:
226 case PGM_PROTECTION:
227 case PGM_ADDRESSING:
228 case PGM_SPECIFICATION:
229 case PGM_DATA:
230 case PGM_FIXPT_OVERFLOW:
231 case PGM_FIXPT_DIVIDE:
232 case PGM_DEC_OVERFLOW:
233 case PGM_DEC_DIVIDE:
234 case PGM_HFP_EXP_OVERFLOW:
235 case PGM_HFP_EXP_UNDERFLOW:
236 case PGM_HFP_SIGNIFICANCE:
237 case PGM_HFP_DIVIDE:
238 case PGM_TRANS_SPEC:
239 case PGM_SPECIAL_OP:
240 case PGM_OPERAND:
241 case PGM_HFP_SQRT:
242 case PGM_PC_TRANS_SPEC:
243 case PGM_ALET_SPEC:
244 case PGM_MONITOR:
245
246 env->psw.addr += ilen;
247 break;
248 }
249
250 qemu_log_mask(CPU_LOG_INT,
251 "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
252 __func__, env->int_pgm_code, ilen, env->psw.mask,
253 env->psw.addr);
254
255 lowcore = cpu_map_lowcore(env);
256
257
258 if (env->per_perc_atmid) {
259 env->int_pgm_code |= PGM_PER;
260 lowcore->per_address = cpu_to_be64(env->per_address);
261 lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
262 env->per_perc_atmid = 0;
263 }
264
265 lowcore->pgm_ilen = cpu_to_be16(ilen);
266 lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
267 lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
268 lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
269 mask = be64_to_cpu(lowcore->program_new_psw.mask);
270 addr = be64_to_cpu(lowcore->program_new_psw.addr);
271 lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
272
273 cpu_unmap_lowcore(lowcore);
274
275 s390_cpu_set_psw(env, mask, addr);
276}
277
278static void do_svc_interrupt(CPUS390XState *env)
279{
280 uint64_t mask, addr;
281 LowCore *lowcore;
282
283 lowcore = cpu_map_lowcore(env);
284
285 lowcore->svc_code = cpu_to_be16(env->int_svc_code);
286 lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
287 lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
288 lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
289 mask = be64_to_cpu(lowcore->svc_new_psw.mask);
290 addr = be64_to_cpu(lowcore->svc_new_psw.addr);
291
292 cpu_unmap_lowcore(lowcore);
293
294 s390_cpu_set_psw(env, mask, addr);
295
296
297
298 if (env->per_perc_atmid) {
299 env->int_pgm_code = PGM_PER;
300 env->int_pgm_ilen = env->int_svc_ilen;
301 do_program_interrupt(env);
302 }
303}
304
305#define VIRTIO_SUBCODE_64 0x0D00
306
307static void do_ext_interrupt(CPUS390XState *env)
308{
309 QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
310 S390CPU *cpu = env_archcpu(env);
311 uint64_t mask, addr;
312 uint16_t cpu_addr;
313 LowCore *lowcore;
314
315 if (!(env->psw.mask & PSW_MASK_EXT)) {
316 cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
317 }
318
319 lowcore = cpu_map_lowcore(env);
320
321 if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
322 (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
323 MachineState *ms = MACHINE(qdev_get_machine());
324 unsigned int max_cpus = ms->smp.max_cpus;
325
326 lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
327 cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
328 g_assert(cpu_addr < S390_MAX_CPUS);
329 lowcore->cpu_addr = cpu_to_be16(cpu_addr);
330 clear_bit(cpu_addr, env->emergency_signals);
331 if (bitmap_empty(env->emergency_signals, max_cpus)) {
332 env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
333 }
334 } else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
335 (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
336 lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
337 lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
338 env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
339 } else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
340 (env->cregs[0] & CR0_CKC_SC)) {
341 lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
342 lowcore->cpu_addr = 0;
343 env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
344 } else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
345 (env->cregs[0] & CR0_CPU_TIMER_SC)) {
346 lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
347 lowcore->cpu_addr = 0;
348 env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
349 } else if (qemu_s390_flic_has_service(flic) &&
350 (env->cregs[0] & CR0_SERVICE_SC)) {
351 uint32_t param;
352
353 param = qemu_s390_flic_dequeue_service(flic);
354 lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
355 lowcore->ext_params = cpu_to_be32(param);
356 lowcore->cpu_addr = 0;
357 } else {
358 g_assert_not_reached();
359 }
360
361 mask = be64_to_cpu(lowcore->external_new_psw.mask);
362 addr = be64_to_cpu(lowcore->external_new_psw.addr);
363 lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
364 lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
365
366 cpu_unmap_lowcore(lowcore);
367
368 s390_cpu_set_psw(env, mask, addr);
369}
370
371static void do_io_interrupt(CPUS390XState *env)
372{
373 QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
374 uint64_t mask, addr;
375 QEMUS390FlicIO *io;
376 LowCore *lowcore;
377
378 g_assert(env->psw.mask & PSW_MASK_IO);
379 io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
380 g_assert(io);
381
382 lowcore = cpu_map_lowcore(env);
383
384 lowcore->subchannel_id = cpu_to_be16(io->id);
385 lowcore->subchannel_nr = cpu_to_be16(io->nr);
386 lowcore->io_int_parm = cpu_to_be32(io->parm);
387 lowcore->io_int_word = cpu_to_be32(io->word);
388 lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
389 lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
390 mask = be64_to_cpu(lowcore->io_new_psw.mask);
391 addr = be64_to_cpu(lowcore->io_new_psw.addr);
392
393 cpu_unmap_lowcore(lowcore);
394 g_free(io);
395
396 s390_cpu_set_psw(env, mask, addr);
397}
398
399typedef struct MchkExtSaveArea {
400 uint64_t vregs[32][2];
401 uint8_t pad_0x0200[0x0400 - 0x0200];
402} MchkExtSaveArea;
403QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
404
405static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
406{
407 hwaddr len = sizeof(MchkExtSaveArea);
408 MchkExtSaveArea *sa;
409 int i;
410
411 sa = cpu_physical_memory_map(mcesao, &len, true);
412 if (!sa) {
413 return -EFAULT;
414 }
415 if (len != sizeof(MchkExtSaveArea)) {
416 cpu_physical_memory_unmap(sa, len, 1, 0);
417 return -EFAULT;
418 }
419
420 for (i = 0; i < 32; i++) {
421 sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
422 sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
423 }
424
425 cpu_physical_memory_unmap(sa, len, 1, len);
426 return 0;
427}
428
429static void do_mchk_interrupt(CPUS390XState *env)
430{
431 QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
432 uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
433 uint64_t mask, addr, mcesao = 0;
434 LowCore *lowcore;
435 int i;
436
437
438 g_assert(env->psw.mask & PSW_MASK_MCHECK);
439 g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
440
441 qemu_s390_flic_dequeue_crw_mchk(flic);
442
443 lowcore = cpu_map_lowcore(env);
444
445
446 if (mcic & MCIC_VB_VR) {
447
448 mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
449 }
450
451
452 if (!mcesao || mchk_store_vregs(env, mcesao)) {
453 mcic &= ~MCIC_VB_VR;
454 }
455
456
457 lowcore->ar_access_id = 1;
458
459 for (i = 0; i < 16; i++) {
460 lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
461 lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
462 lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
463 lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
464 }
465 lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
466 lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
467 lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
468 lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
469 lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
470
471 lowcore->mcic = cpu_to_be64(mcic);
472 lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
473 lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
474 mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
475 addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
476
477 cpu_unmap_lowcore(lowcore);
478
479 s390_cpu_set_psw(env, mask, addr);
480}
481
482void s390_cpu_do_interrupt(CPUState *cs)
483{
484 QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
485 S390CPU *cpu = S390_CPU(cs);
486 CPUS390XState *env = &cpu->env;
487 bool stopped = false;
488
489 qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
490 __func__, cs->exception_index, env->psw.mask, env->psw.addr);
491
492try_deliver:
493
494 if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
495 cs->exception_index = EXCP_MCHK;
496 }
497
498 if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
499 cs->exception_index = EXCP_EXT;
500 }
501
502 if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
503 cs->exception_index = EXCP_IO;
504 }
505
506 if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
507 cs->exception_index = EXCP_RESTART;
508 }
509
510 if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
511 cs->exception_index = EXCP_STOP;
512 }
513
514 switch (cs->exception_index) {
515 case EXCP_PGM:
516 do_program_interrupt(env);
517 break;
518 case EXCP_SVC:
519 do_svc_interrupt(env);
520 break;
521 case EXCP_EXT:
522 do_ext_interrupt(env);
523 break;
524 case EXCP_IO:
525 do_io_interrupt(env);
526 break;
527 case EXCP_MCHK:
528 do_mchk_interrupt(env);
529 break;
530 case EXCP_RESTART:
531 do_restart_interrupt(env);
532 break;
533 case EXCP_STOP:
534 do_stop_interrupt(env);
535 stopped = true;
536 break;
537 }
538
539 if (cs->exception_index != -1 && !stopped) {
540
541 cs->exception_index = -1;
542 goto try_deliver;
543 }
544 cs->exception_index = -1;
545
546
547 if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
548 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
549 }
550
551
552 if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
553
554 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
555 } else if (cs->halted) {
556
557 s390_cpu_unhalt(cpu);
558 }
559}
560
561bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
562{
563 if (interrupt_request & CPU_INTERRUPT_HARD) {
564 S390CPU *cpu = S390_CPU(cs);
565 CPUS390XState *env = &cpu->env;
566
567 if (env->ex_value) {
568
569
570 return false;
571 }
572 if (s390_cpu_has_int(cpu)) {
573 s390_cpu_do_interrupt(cs);
574 return true;
575 }
576 if (env->psw.mask & PSW_MASK_WAIT) {
577
578
579 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
580 }
581 }
582 return false;
583}
584
585void s390x_cpu_debug_excp_handler(CPUState *cs)
586{
587 S390CPU *cpu = S390_CPU(cs);
588 CPUS390XState *env = &cpu->env;
589 CPUWatchpoint *wp_hit = cs->watchpoint_hit;
590
591 if (wp_hit && wp_hit->flags & BP_CPU) {
592
593
594
595
596
597 cs->watchpoint_hit = NULL;
598
599 env->per_address = env->psw.addr;
600 env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
601
602
603
604
605 env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
606
607
608
609
610
611
612 cpu_watchpoint_remove_all(cs, BP_CPU);
613 cpu_loop_exit_noexc(cs);
614 }
615}
616
617void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
618 MMUAccessType access_type,
619 int mmu_idx, uintptr_t retaddr)
620{
621 do_unaligned_access(cs, retaddr);
622}
623
624static G_NORETURN
625void monitor_event(CPUS390XState *env,
626 uint64_t monitor_code,
627 uint8_t monitor_class, uintptr_t ra)
628{
629
630 stq_phys(env_cpu(env)->as,
631 env->psa + offsetof(LowCore, monitor_code), monitor_code);
632 stw_phys(env_cpu(env)->as,
633 env->psa + offsetof(LowCore, mon_class_num), monitor_class);
634
635 tcg_s390_program_interrupt(env, PGM_MONITOR, ra);
636}
637
638void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
639 uint32_t monitor_class)
640{
641 g_assert(monitor_class <= 0xff);
642
643 if (env->cregs[8] & (0x8000 >> monitor_class)) {
644 monitor_event(env, monitor_code, monitor_class, GETPC());
645 }
646}
647
648#endif
649