2 * s390x exception / interrupt helpers
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2011 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.1 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/>.
21 #include "qemu/osdep.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 "sysemu/sysemu.h"
33 #include "hw/s390x/s390_flic.h"
36 void QEMU_NORETURN
tcg_s390_program_interrupt(CPUS390XState
*env
, uint32_t code
,
37 int ilen
, uintptr_t ra
)
39 CPUState
*cs
= CPU(s390_env_get_cpu(env
));
41 cpu_restore_state(cs
, ra
, true);
42 qemu_log_mask(CPU_LOG_INT
, "program interrupt at %#" PRIx64
"\n",
44 trigger_pgm_exception(env
, code
, ilen
);
48 void QEMU_NORETURN
tcg_s390_data_exception(CPUS390XState
*env
, uint32_t dxc
,
51 g_assert(dxc
<= 0xff);
52 #if !defined(CONFIG_USER_ONLY)
53 /* Store the DXC into the lowcore */
54 stl_phys(CPU(s390_env_get_cpu(env
))->as
,
55 env
->psa
+ offsetof(LowCore
, data_exc_code
), dxc
);
58 /* Store the DXC into the FPC if AFP is enabled */
59 if (env
->cregs
[0] & CR0_AFP
) {
60 env
->fpc
= deposit32(env
->fpc
, 8, 8, dxc
);
62 tcg_s390_program_interrupt(env
, PGM_DATA
, ILEN_AUTO
, ra
);
65 void HELPER(data_exception
)(CPUS390XState
*env
, uint32_t dxc
)
67 tcg_s390_data_exception(env
, dxc
, GETPC());
70 #if defined(CONFIG_USER_ONLY)
72 void s390_cpu_do_interrupt(CPUState
*cs
)
74 cs
->exception_index
= -1;
77 int s390_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
,
80 S390CPU
*cpu
= S390_CPU(cs
);
82 trigger_pgm_exception(&cpu
->env
, PGM_ADDRESSING
, ILEN_AUTO
);
83 /* On real machines this value is dropped into LowMem. Since this
84 is userland, simply put this someplace that cpu_loop can find it. */
85 cpu
->env
.__excp_addr
= address
;
89 #else /* !CONFIG_USER_ONLY */
91 static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx
)
95 return PSW_ASC_PRIMARY
;
96 case MMU_SECONDARY_IDX
:
97 return PSW_ASC_SECONDARY
;
105 int s390_cpu_handle_mmu_fault(CPUState
*cs
, vaddr orig_vaddr
, int size
,
108 S390CPU
*cpu
= S390_CPU(cs
);
109 CPUS390XState
*env
= &cpu
->env
;
110 target_ulong vaddr
, raddr
;
114 qemu_log_mask(CPU_LOG_MMU
, "%s: addr 0x%" VADDR_PRIx
" rw %d mmu_idx %d\n",
115 __func__
, orig_vaddr
, rw
, mmu_idx
);
119 if (mmu_idx
< MMU_REAL_IDX
) {
120 asc
= cpu_mmu_idx_to_asc(mmu_idx
);
122 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
125 if (mmu_translate(env
, vaddr
, rw
, asc
, &raddr
, &prot
, true)) {
128 } else if (mmu_idx
== MMU_REAL_IDX
) {
130 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
133 if (mmu_translate_real(env
, vaddr
, rw
, &raddr
, &prot
)) {
140 /* check out of RAM access */
141 if (!address_space_access_valid(&address_space_memory
, raddr
,
142 TARGET_PAGE_SIZE
, rw
,
143 MEMTXATTRS_UNSPECIFIED
)) {
144 qemu_log_mask(CPU_LOG_MMU
,
145 "%s: raddr %" PRIx64
" > ram_size %" PRIx64
"\n",
146 __func__
, (uint64_t)raddr
, (uint64_t)ram_size
);
147 trigger_pgm_exception(env
, PGM_ADDRESSING
, ILEN_AUTO
);
151 qemu_log_mask(CPU_LOG_MMU
, "%s: set tlb %" PRIx64
" -> %" PRIx64
" (%x)\n",
152 __func__
, (uint64_t)vaddr
, (uint64_t)raddr
, prot
);
154 tlb_set_page(cs
, orig_vaddr
& TARGET_PAGE_MASK
, raddr
, prot
,
155 mmu_idx
, TARGET_PAGE_SIZE
);
160 static void do_program_interrupt(CPUS390XState
*env
)
164 int ilen
= env
->int_pgm_ilen
;
166 if (ilen
== ILEN_AUTO
) {
167 ilen
= get_ilen(cpu_ldub_code(env
, env
->psw
.addr
));
169 assert(ilen
== 2 || ilen
== 4 || ilen
== 6);
171 switch (env
->int_pgm_code
) {
173 if (env
->per_perc_atmid
& PER_CODE_EVENT_NULLIFICATION
) {
182 case PGM_SPECIFICATION
:
184 case PGM_FIXPT_OVERFLOW
:
185 case PGM_FIXPT_DIVIDE
:
186 case PGM_DEC_OVERFLOW
:
188 case PGM_HFP_EXP_OVERFLOW
:
189 case PGM_HFP_EXP_UNDERFLOW
:
190 case PGM_HFP_SIGNIFICANCE
:
196 case PGM_PC_TRANS_SPEC
:
199 /* advance the PSW if our exception is not nullifying */
200 env
->psw
.addr
+= ilen
;
204 qemu_log_mask(CPU_LOG_INT
,
205 "%s: code=0x%x ilen=%d psw: %" PRIx64
" %" PRIx64
"\n",
206 __func__
, env
->int_pgm_code
, ilen
, env
->psw
.mask
,
209 lowcore
= cpu_map_lowcore(env
);
211 /* Signal PER events with the exception. */
212 if (env
->per_perc_atmid
) {
213 env
->int_pgm_code
|= PGM_PER
;
214 lowcore
->per_address
= cpu_to_be64(env
->per_address
);
215 lowcore
->per_perc_atmid
= cpu_to_be16(env
->per_perc_atmid
);
216 env
->per_perc_atmid
= 0;
219 lowcore
->pgm_ilen
= cpu_to_be16(ilen
);
220 lowcore
->pgm_code
= cpu_to_be16(env
->int_pgm_code
);
221 lowcore
->program_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
222 lowcore
->program_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
223 mask
= be64_to_cpu(lowcore
->program_new_psw
.mask
);
224 addr
= be64_to_cpu(lowcore
->program_new_psw
.addr
);
225 lowcore
->per_breaking_event_addr
= cpu_to_be64(env
->gbea
);
227 cpu_unmap_lowcore(lowcore
);
229 load_psw(env
, mask
, addr
);
232 static void do_svc_interrupt(CPUS390XState
*env
)
237 lowcore
= cpu_map_lowcore(env
);
239 lowcore
->svc_code
= cpu_to_be16(env
->int_svc_code
);
240 lowcore
->svc_ilen
= cpu_to_be16(env
->int_svc_ilen
);
241 lowcore
->svc_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
242 lowcore
->svc_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
+ env
->int_svc_ilen
);
243 mask
= be64_to_cpu(lowcore
->svc_new_psw
.mask
);
244 addr
= be64_to_cpu(lowcore
->svc_new_psw
.addr
);
246 cpu_unmap_lowcore(lowcore
);
248 load_psw(env
, mask
, addr
);
250 /* When a PER event is pending, the PER exception has to happen
251 immediately after the SERVICE CALL one. */
252 if (env
->per_perc_atmid
) {
253 env
->int_pgm_code
= PGM_PER
;
254 env
->int_pgm_ilen
= env
->int_svc_ilen
;
255 do_program_interrupt(env
);
259 #define VIRTIO_SUBCODE_64 0x0D00
261 static void do_ext_interrupt(CPUS390XState
*env
)
263 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
264 S390CPU
*cpu
= s390_env_get_cpu(env
);
269 if (!(env
->psw
.mask
& PSW_MASK_EXT
)) {
270 cpu_abort(CPU(cpu
), "Ext int w/o ext mask\n");
273 lowcore
= cpu_map_lowcore(env
);
275 if ((env
->pending_int
& INTERRUPT_EMERGENCY_SIGNAL
) &&
276 (env
->cregs
[0] & CR0_EMERGENCY_SIGNAL_SC
)) {
277 lowcore
->ext_int_code
= cpu_to_be16(EXT_EMERGENCY
);
278 cpu_addr
= find_first_bit(env
->emergency_signals
, S390_MAX_CPUS
);
279 g_assert(cpu_addr
< S390_MAX_CPUS
);
280 lowcore
->cpu_addr
= cpu_to_be16(cpu_addr
);
281 clear_bit(cpu_addr
, env
->emergency_signals
);
282 if (bitmap_empty(env
->emergency_signals
, max_cpus
)) {
283 env
->pending_int
&= ~INTERRUPT_EMERGENCY_SIGNAL
;
285 } else if ((env
->pending_int
& INTERRUPT_EXTERNAL_CALL
) &&
286 (env
->cregs
[0] & CR0_EXTERNAL_CALL_SC
)) {
287 lowcore
->ext_int_code
= cpu_to_be16(EXT_EXTERNAL_CALL
);
288 lowcore
->cpu_addr
= cpu_to_be16(env
->external_call_addr
);
289 env
->pending_int
&= ~INTERRUPT_EXTERNAL_CALL
;
290 } else if ((env
->pending_int
& INTERRUPT_EXT_CLOCK_COMPARATOR
) &&
291 (env
->cregs
[0] & CR0_CKC_SC
)) {
292 lowcore
->ext_int_code
= cpu_to_be16(EXT_CLOCK_COMP
);
293 lowcore
->cpu_addr
= 0;
294 env
->pending_int
&= ~INTERRUPT_EXT_CLOCK_COMPARATOR
;
295 } else if ((env
->pending_int
& INTERRUPT_EXT_CPU_TIMER
) &&
296 (env
->cregs
[0] & CR0_CPU_TIMER_SC
)) {
297 lowcore
->ext_int_code
= cpu_to_be16(EXT_CPU_TIMER
);
298 lowcore
->cpu_addr
= 0;
299 env
->pending_int
&= ~INTERRUPT_EXT_CPU_TIMER
;
300 } else if (qemu_s390_flic_has_service(flic
) &&
301 (env
->cregs
[0] & CR0_SERVICE_SC
)) {
304 param
= qemu_s390_flic_dequeue_service(flic
);
305 lowcore
->ext_int_code
= cpu_to_be16(EXT_SERVICE
);
306 lowcore
->ext_params
= cpu_to_be32(param
);
307 lowcore
->cpu_addr
= 0;
309 g_assert_not_reached();
312 mask
= be64_to_cpu(lowcore
->external_new_psw
.mask
);
313 addr
= be64_to_cpu(lowcore
->external_new_psw
.addr
);
314 lowcore
->external_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
315 lowcore
->external_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
317 cpu_unmap_lowcore(lowcore
);
319 load_psw(env
, mask
, addr
);
322 static void do_io_interrupt(CPUS390XState
*env
)
324 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
329 g_assert(env
->psw
.mask
& PSW_MASK_IO
);
330 io
= qemu_s390_flic_dequeue_io(flic
, env
->cregs
[6]);
333 lowcore
= cpu_map_lowcore(env
);
335 lowcore
->subchannel_id
= cpu_to_be16(io
->id
);
336 lowcore
->subchannel_nr
= cpu_to_be16(io
->nr
);
337 lowcore
->io_int_parm
= cpu_to_be32(io
->parm
);
338 lowcore
->io_int_word
= cpu_to_be32(io
->word
);
339 lowcore
->io_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
340 lowcore
->io_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
341 mask
= be64_to_cpu(lowcore
->io_new_psw
.mask
);
342 addr
= be64_to_cpu(lowcore
->io_new_psw
.addr
);
344 cpu_unmap_lowcore(lowcore
);
347 load_psw(env
, mask
, addr
);
350 typedef struct MchkExtSaveArea
{
351 uint64_t vregs
[32][2]; /* 0x0000 */
352 uint8_t pad_0x0200
[0x0400 - 0x0200]; /* 0x0200 */
354 QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea
) != 1024);
356 static int mchk_store_vregs(CPUS390XState
*env
, uint64_t mcesao
)
358 hwaddr len
= sizeof(MchkExtSaveArea
);
362 sa
= cpu_physical_memory_map(mcesao
, &len
, 1);
366 if (len
!= sizeof(MchkExtSaveArea
)) {
367 cpu_physical_memory_unmap(sa
, len
, 1, 0);
371 for (i
= 0; i
< 32; i
++) {
372 sa
->vregs
[i
][0] = cpu_to_be64(env
->vregs
[i
][0].ll
);
373 sa
->vregs
[i
][1] = cpu_to_be64(env
->vregs
[i
][1].ll
);
376 cpu_physical_memory_unmap(sa
, len
, 1, len
);
380 static void do_mchk_interrupt(CPUS390XState
*env
)
382 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
383 uint64_t mcic
= s390_build_validity_mcic() | MCIC_SC_CP
;
384 uint64_t mask
, addr
, mcesao
= 0;
388 /* for now we only support channel report machine checks (floating) */
389 g_assert(env
->psw
.mask
& PSW_MASK_MCHECK
);
390 g_assert(env
->cregs
[14] & CR14_CHANNEL_REPORT_SC
);
392 qemu_s390_flic_dequeue_crw_mchk(flic
);
394 lowcore
= cpu_map_lowcore(env
);
396 /* extended save area */
397 if (mcic
& MCIC_VB_VR
) {
398 /* length and alignment is 1024 bytes */
399 mcesao
= be64_to_cpu(lowcore
->mcesad
) & ~0x3ffull
;
402 /* try to store vector registers */
403 if (!mcesao
|| mchk_store_vregs(env
, mcesao
)) {
407 /* we are always in z/Architecture mode */
408 lowcore
->ar_access_id
= 1;
410 for (i
= 0; i
< 16; i
++) {
411 lowcore
->floating_pt_save_area
[i
] = cpu_to_be64(get_freg(env
, i
)->ll
);
412 lowcore
->gpregs_save_area
[i
] = cpu_to_be64(env
->regs
[i
]);
413 lowcore
->access_regs_save_area
[i
] = cpu_to_be32(env
->aregs
[i
]);
414 lowcore
->cregs_save_area
[i
] = cpu_to_be64(env
->cregs
[i
]);
416 lowcore
->prefixreg_save_area
= cpu_to_be32(env
->psa
);
417 lowcore
->fpt_creg_save_area
= cpu_to_be32(env
->fpc
);
418 lowcore
->tod_progreg_save_area
= cpu_to_be32(env
->todpr
);
419 lowcore
->cpu_timer_save_area
= cpu_to_be64(env
->cputm
);
420 lowcore
->clock_comp_save_area
= cpu_to_be64(env
->ckc
>> 8);
422 lowcore
->mcic
= cpu_to_be64(mcic
);
423 lowcore
->mcck_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
424 lowcore
->mcck_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
425 mask
= be64_to_cpu(lowcore
->mcck_new_psw
.mask
);
426 addr
= be64_to_cpu(lowcore
->mcck_new_psw
.addr
);
428 cpu_unmap_lowcore(lowcore
);
430 load_psw(env
, mask
, addr
);
433 void s390_cpu_do_interrupt(CPUState
*cs
)
435 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
436 S390CPU
*cpu
= S390_CPU(cs
);
437 CPUS390XState
*env
= &cpu
->env
;
438 bool stopped
= false;
440 qemu_log_mask(CPU_LOG_INT
, "%s: %d at psw=%" PRIx64
":%" PRIx64
"\n",
441 __func__
, cs
->exception_index
, env
->psw
.mask
, env
->psw
.addr
);
444 /* handle machine checks */
445 if (cs
->exception_index
== -1 && s390_cpu_has_mcck_int(cpu
)) {
446 cs
->exception_index
= EXCP_MCHK
;
448 /* handle external interrupts */
449 if (cs
->exception_index
== -1 && s390_cpu_has_ext_int(cpu
)) {
450 cs
->exception_index
= EXCP_EXT
;
452 /* handle I/O interrupts */
453 if (cs
->exception_index
== -1 && s390_cpu_has_io_int(cpu
)) {
454 cs
->exception_index
= EXCP_IO
;
456 /* RESTART interrupt */
457 if (cs
->exception_index
== -1 && s390_cpu_has_restart_int(cpu
)) {
458 cs
->exception_index
= EXCP_RESTART
;
460 /* STOP interrupt has least priority */
461 if (cs
->exception_index
== -1 && s390_cpu_has_stop_int(cpu
)) {
462 cs
->exception_index
= EXCP_STOP
;
465 switch (cs
->exception_index
) {
467 do_program_interrupt(env
);
470 do_svc_interrupt(env
);
473 do_ext_interrupt(env
);
476 do_io_interrupt(env
);
479 do_mchk_interrupt(env
);
482 do_restart_interrupt(env
);
485 do_stop_interrupt(env
);
490 if (cs
->exception_index
!= -1 && !stopped
) {
491 /* check if there are more pending interrupts to deliver */
492 cs
->exception_index
= -1;
495 cs
->exception_index
= -1;
497 /* we might still have pending interrupts, but not deliverable */
498 if (!env
->pending_int
&& !qemu_s390_flic_has_any(flic
)) {
499 cs
->interrupt_request
&= ~CPU_INTERRUPT_HARD
;
502 /* WAIT PSW during interrupt injection or STOP interrupt */
503 if ((env
->psw
.mask
& PSW_MASK_WAIT
) || stopped
) {
504 /* don't trigger a cpu_loop_exit(), use an interrupt instead */
505 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HALT
);
506 } else if (cs
->halted
) {
507 /* unhalt if we had a WAIT PSW somehwere in our injection chain */
508 s390_cpu_unhalt(cpu
);
512 bool s390_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
514 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
515 S390CPU
*cpu
= S390_CPU(cs
);
516 CPUS390XState
*env
= &cpu
->env
;
519 /* Execution of the target insn is indivisible from
520 the parent EXECUTE insn. */
523 if (s390_cpu_has_int(cpu
)) {
524 s390_cpu_do_interrupt(cs
);
527 if (env
->psw
.mask
& PSW_MASK_WAIT
) {
528 /* Woken up because of a floating interrupt but it has already
529 * been delivered. Go back to sleep. */
530 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HALT
);
536 void s390x_cpu_debug_excp_handler(CPUState
*cs
)
538 S390CPU
*cpu
= S390_CPU(cs
);
539 CPUS390XState
*env
= &cpu
->env
;
540 CPUWatchpoint
*wp_hit
= cs
->watchpoint_hit
;
542 if (wp_hit
&& wp_hit
->flags
& BP_CPU
) {
543 /* FIXME: When the storage-alteration-space control bit is set,
544 the exception should only be triggered if the memory access
545 is done using an address space with the storage-alteration-event
546 bit set. We have no way to detect that with the current
548 cs
->watchpoint_hit
= NULL
;
550 env
->per_address
= env
->psw
.addr
;
551 env
->per_perc_atmid
|= PER_CODE_EVENT_STORE
| get_per_atmid(env
);
552 /* FIXME: We currently no way to detect the address space used
553 to trigger the watchpoint. For now just consider it is the
554 current default ASC. This turn to be true except when MVCP
555 and MVCS instrutions are not used. */
556 env
->per_perc_atmid
|= env
->psw
.mask
& (PSW_MASK_ASC
) >> 46;
558 /* Remove all watchpoints to re-execute the code. A PER exception
559 will be triggered, it will call load_psw which will recompute
561 cpu_watchpoint_remove_all(cs
, BP_CPU
);
562 cpu_loop_exit_noexc(cs
);
566 /* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
567 this is only for the atomic operations, for which we want to raise a
568 specification exception. */
569 void s390x_cpu_do_unaligned_access(CPUState
*cs
, vaddr addr
,
570 MMUAccessType access_type
,
571 int mmu_idx
, uintptr_t retaddr
)
573 S390CPU
*cpu
= S390_CPU(cs
);
574 CPUS390XState
*env
= &cpu
->env
;
576 s390_program_interrupt(env
, PGM_SPECIFICATION
, ILEN_AUTO
, retaddr
);
579 #endif /* CONFIG_USER_ONLY */