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