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 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 "qemu/timer.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
27 #include "hw/s390x/ioinst.h"
28 #include "exec/address-spaces.h"
29 #ifndef CONFIG_USER_ONLY
30 #include "sysemu/sysemu.h"
31 #include "hw/s390x/s390_flic.h"
34 /* #define DEBUG_S390 */
35 /* #define DEBUG_S390_STDOUT */
38 #ifdef DEBUG_S390_STDOUT
39 #define DPRINTF(fmt, ...) \
40 do { fprintf(stderr, fmt, ## __VA_ARGS__); \
41 if (qemu_log_separate()) { qemu_log(fmt, ##__VA_ARGS__); } } while (0)
43 #define DPRINTF(fmt, ...) \
44 do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
47 #define DPRINTF(fmt, ...) \
51 #if defined(CONFIG_USER_ONLY)
53 void s390_cpu_do_interrupt(CPUState
*cs
)
55 cs
->exception_index
= -1;
58 int s390_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
,
61 S390CPU
*cpu
= S390_CPU(cs
);
63 trigger_pgm_exception(&cpu
->env
, PGM_ADDRESSING
, ILEN_AUTO
);
64 /* On real machines this value is dropped into LowMem. Since this
65 is userland, simply put this someplace that cpu_loop can find it. */
66 cpu
->env
.__excp_addr
= address
;
70 #else /* !CONFIG_USER_ONLY */
72 static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx
)
76 return PSW_ASC_PRIMARY
;
77 case MMU_SECONDARY_IDX
:
78 return PSW_ASC_SECONDARY
;
86 int s390_cpu_handle_mmu_fault(CPUState
*cs
, vaddr orig_vaddr
, int size
,
89 S390CPU
*cpu
= S390_CPU(cs
);
90 CPUS390XState
*env
= &cpu
->env
;
91 target_ulong vaddr
, raddr
;
95 DPRINTF("%s: address 0x%" VADDR_PRIx
" rw %d mmu_idx %d\n",
96 __func__
, orig_vaddr
, rw
, mmu_idx
);
100 if (mmu_idx
< MMU_REAL_IDX
) {
101 asc
= cpu_mmu_idx_to_asc(mmu_idx
);
103 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
106 if (mmu_translate(env
, vaddr
, rw
, asc
, &raddr
, &prot
, true)) {
109 } else if (mmu_idx
== MMU_REAL_IDX
) {
111 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
114 if (mmu_translate_real(env
, vaddr
, rw
, &raddr
, &prot
)) {
121 /* check out of RAM access */
122 if (!address_space_access_valid(&address_space_memory
, raddr
,
123 TARGET_PAGE_SIZE
, rw
,
124 MEMTXATTRS_UNSPECIFIED
)) {
125 DPRINTF("%s: raddr %" PRIx64
" > ram_size %" PRIx64
"\n", __func__
,
126 (uint64_t)raddr
, (uint64_t)ram_size
);
127 trigger_pgm_exception(env
, PGM_ADDRESSING
, ILEN_AUTO
);
131 qemu_log_mask(CPU_LOG_MMU
, "%s: set tlb %" PRIx64
" -> %" PRIx64
" (%x)\n",
132 __func__
, (uint64_t)vaddr
, (uint64_t)raddr
, prot
);
134 tlb_set_page(cs
, orig_vaddr
& TARGET_PAGE_MASK
, raddr
, prot
,
135 mmu_idx
, TARGET_PAGE_SIZE
);
140 static void do_program_interrupt(CPUS390XState
*env
)
144 int ilen
= env
->int_pgm_ilen
;
146 if (ilen
== ILEN_AUTO
) {
147 ilen
= get_ilen(cpu_ldub_code(env
, env
->psw
.addr
));
149 assert(ilen
== 2 || ilen
== 4 || ilen
== 6);
151 switch (env
->int_pgm_code
) {
153 if (env
->per_perc_atmid
& PER_CODE_EVENT_NULLIFICATION
) {
162 case PGM_SPECIFICATION
:
164 case PGM_FIXPT_OVERFLOW
:
165 case PGM_FIXPT_DIVIDE
:
166 case PGM_DEC_OVERFLOW
:
168 case PGM_HFP_EXP_OVERFLOW
:
169 case PGM_HFP_EXP_UNDERFLOW
:
170 case PGM_HFP_SIGNIFICANCE
:
176 case PGM_PC_TRANS_SPEC
:
179 /* advance the PSW if our exception is not nullifying */
180 env
->psw
.addr
+= ilen
;
184 qemu_log_mask(CPU_LOG_INT
, "%s: code=0x%x ilen=%d\n",
185 __func__
, env
->int_pgm_code
, ilen
);
187 lowcore
= cpu_map_lowcore(env
);
189 /* Signal PER events with the exception. */
190 if (env
->per_perc_atmid
) {
191 env
->int_pgm_code
|= PGM_PER
;
192 lowcore
->per_address
= cpu_to_be64(env
->per_address
);
193 lowcore
->per_perc_atmid
= cpu_to_be16(env
->per_perc_atmid
);
194 env
->per_perc_atmid
= 0;
197 lowcore
->pgm_ilen
= cpu_to_be16(ilen
);
198 lowcore
->pgm_code
= cpu_to_be16(env
->int_pgm_code
);
199 lowcore
->program_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
200 lowcore
->program_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
201 mask
= be64_to_cpu(lowcore
->program_new_psw
.mask
);
202 addr
= be64_to_cpu(lowcore
->program_new_psw
.addr
);
203 lowcore
->per_breaking_event_addr
= cpu_to_be64(env
->gbea
);
205 cpu_unmap_lowcore(lowcore
);
207 DPRINTF("%s: %x %x %" PRIx64
" %" PRIx64
"\n", __func__
,
208 env
->int_pgm_code
, ilen
, env
->psw
.mask
,
211 load_psw(env
, mask
, addr
);
214 static void do_svc_interrupt(CPUS390XState
*env
)
219 lowcore
= cpu_map_lowcore(env
);
221 lowcore
->svc_code
= cpu_to_be16(env
->int_svc_code
);
222 lowcore
->svc_ilen
= cpu_to_be16(env
->int_svc_ilen
);
223 lowcore
->svc_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
224 lowcore
->svc_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
+ env
->int_svc_ilen
);
225 mask
= be64_to_cpu(lowcore
->svc_new_psw
.mask
);
226 addr
= be64_to_cpu(lowcore
->svc_new_psw
.addr
);
228 cpu_unmap_lowcore(lowcore
);
230 load_psw(env
, mask
, addr
);
232 /* When a PER event is pending, the PER exception has to happen
233 immediately after the SERVICE CALL one. */
234 if (env
->per_perc_atmid
) {
235 env
->int_pgm_code
= PGM_PER
;
236 env
->int_pgm_ilen
= env
->int_svc_ilen
;
237 do_program_interrupt(env
);
241 #define VIRTIO_SUBCODE_64 0x0D00
243 static void do_ext_interrupt(CPUS390XState
*env
)
245 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
246 S390CPU
*cpu
= s390_env_get_cpu(env
);
251 if (!(env
->psw
.mask
& PSW_MASK_EXT
)) {
252 cpu_abort(CPU(cpu
), "Ext int w/o ext mask\n");
255 lowcore
= cpu_map_lowcore(env
);
257 if ((env
->pending_int
& INTERRUPT_EMERGENCY_SIGNAL
) &&
258 (env
->cregs
[0] & CR0_EMERGENCY_SIGNAL_SC
)) {
259 lowcore
->ext_int_code
= cpu_to_be16(EXT_EMERGENCY
);
260 cpu_addr
= find_first_bit(env
->emergency_signals
, S390_MAX_CPUS
);
261 g_assert(cpu_addr
< S390_MAX_CPUS
);
262 lowcore
->cpu_addr
= cpu_to_be16(cpu_addr
);
263 clear_bit(cpu_addr
, env
->emergency_signals
);
264 if (bitmap_empty(env
->emergency_signals
, max_cpus
)) {
265 env
->pending_int
&= ~INTERRUPT_EMERGENCY_SIGNAL
;
267 } else if ((env
->pending_int
& INTERRUPT_EXTERNAL_CALL
) &&
268 (env
->cregs
[0] & CR0_EXTERNAL_CALL_SC
)) {
269 lowcore
->ext_int_code
= cpu_to_be16(EXT_EXTERNAL_CALL
);
270 lowcore
->cpu_addr
= cpu_to_be16(env
->external_call_addr
);
271 env
->pending_int
&= ~INTERRUPT_EXTERNAL_CALL
;
272 } else if ((env
->pending_int
& INTERRUPT_EXT_CLOCK_COMPARATOR
) &&
273 (env
->cregs
[0] & CR0_CKC_SC
)) {
274 lowcore
->ext_int_code
= cpu_to_be16(EXT_CLOCK_COMP
);
275 lowcore
->cpu_addr
= 0;
276 env
->pending_int
&= ~INTERRUPT_EXT_CLOCK_COMPARATOR
;
277 } else if ((env
->pending_int
& INTERRUPT_EXT_CPU_TIMER
) &&
278 (env
->cregs
[0] & CR0_CPU_TIMER_SC
)) {
279 lowcore
->ext_int_code
= cpu_to_be16(EXT_CPU_TIMER
);
280 lowcore
->cpu_addr
= 0;
281 env
->pending_int
&= ~INTERRUPT_EXT_CPU_TIMER
;
282 } else if (qemu_s390_flic_has_service(flic
) &&
283 (env
->cregs
[0] & CR0_SERVICE_SC
)) {
286 param
= qemu_s390_flic_dequeue_service(flic
);
287 lowcore
->ext_int_code
= cpu_to_be16(EXT_SERVICE
);
288 lowcore
->ext_params
= cpu_to_be32(param
);
289 lowcore
->cpu_addr
= 0;
291 g_assert_not_reached();
294 mask
= be64_to_cpu(lowcore
->external_new_psw
.mask
);
295 addr
= be64_to_cpu(lowcore
->external_new_psw
.addr
);
296 lowcore
->external_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
297 lowcore
->external_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
299 cpu_unmap_lowcore(lowcore
);
301 DPRINTF("%s: %" PRIx64
" %" PRIx64
"\n", __func__
,
302 env
->psw
.mask
, env
->psw
.addr
);
304 load_psw(env
, mask
, addr
);
307 static void do_io_interrupt(CPUS390XState
*env
)
309 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
314 g_assert(env
->psw
.mask
& PSW_MASK_IO
);
315 io
= qemu_s390_flic_dequeue_io(flic
, env
->cregs
[6]);
318 lowcore
= cpu_map_lowcore(env
);
320 lowcore
->subchannel_id
= cpu_to_be16(io
->id
);
321 lowcore
->subchannel_nr
= cpu_to_be16(io
->nr
);
322 lowcore
->io_int_parm
= cpu_to_be32(io
->parm
);
323 lowcore
->io_int_word
= cpu_to_be32(io
->word
);
324 lowcore
->io_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
325 lowcore
->io_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
326 mask
= be64_to_cpu(lowcore
->io_new_psw
.mask
);
327 addr
= be64_to_cpu(lowcore
->io_new_psw
.addr
);
329 cpu_unmap_lowcore(lowcore
);
332 DPRINTF("%s: %" PRIx64
" %" PRIx64
"\n", __func__
, env
->psw
.mask
,
334 load_psw(env
, mask
, addr
);
337 static void do_mchk_interrupt(CPUS390XState
*env
)
339 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
344 /* for now we only support channel report machine checks (floating) */
345 g_assert(env
->psw
.mask
& PSW_MASK_MCHECK
);
346 g_assert(env
->cregs
[14] & CR14_CHANNEL_REPORT_SC
);
348 qemu_s390_flic_dequeue_crw_mchk(flic
);
350 lowcore
= cpu_map_lowcore(env
);
352 /* we are always in z/Architecture mode */
353 lowcore
->ar_access_id
= 1;
355 for (i
= 0; i
< 16; i
++) {
356 lowcore
->floating_pt_save_area
[i
] = cpu_to_be64(get_freg(env
, i
)->ll
);
357 lowcore
->gpregs_save_area
[i
] = cpu_to_be64(env
->regs
[i
]);
358 lowcore
->access_regs_save_area
[i
] = cpu_to_be32(env
->aregs
[i
]);
359 lowcore
->cregs_save_area
[i
] = cpu_to_be64(env
->cregs
[i
]);
361 lowcore
->prefixreg_save_area
= cpu_to_be32(env
->psa
);
362 lowcore
->fpt_creg_save_area
= cpu_to_be32(env
->fpc
);
363 lowcore
->tod_progreg_save_area
= cpu_to_be32(env
->todpr
);
364 lowcore
->cpu_timer_save_area
= cpu_to_be64(env
->cputm
);
365 lowcore
->clock_comp_save_area
= cpu_to_be64(env
->ckc
>> 8);
367 lowcore
->mcic
= cpu_to_be64(s390_build_validity_mcic() | MCIC_SC_CP
);
368 lowcore
->mcck_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
369 lowcore
->mcck_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
370 mask
= be64_to_cpu(lowcore
->mcck_new_psw
.mask
);
371 addr
= be64_to_cpu(lowcore
->mcck_new_psw
.addr
);
373 cpu_unmap_lowcore(lowcore
);
375 DPRINTF("%s: %" PRIx64
" %" PRIx64
"\n", __func__
,
376 env
->psw
.mask
, env
->psw
.addr
);
378 load_psw(env
, mask
, addr
);
381 void s390_cpu_do_interrupt(CPUState
*cs
)
383 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(s390_get_flic());
384 S390CPU
*cpu
= S390_CPU(cs
);
385 CPUS390XState
*env
= &cpu
->env
;
386 bool stopped
= false;
388 qemu_log_mask(CPU_LOG_INT
, "%s: %d at pc=%" PRIx64
"\n",
389 __func__
, cs
->exception_index
, env
->psw
.addr
);
392 /* handle machine checks */
393 if (cs
->exception_index
== -1 && s390_cpu_has_mcck_int(cpu
)) {
394 cs
->exception_index
= EXCP_MCHK
;
396 /* handle external interrupts */
397 if (cs
->exception_index
== -1 && s390_cpu_has_ext_int(cpu
)) {
398 cs
->exception_index
= EXCP_EXT
;
400 /* handle I/O interrupts */
401 if (cs
->exception_index
== -1 && s390_cpu_has_io_int(cpu
)) {
402 cs
->exception_index
= EXCP_IO
;
404 /* RESTART interrupt */
405 if (cs
->exception_index
== -1 && s390_cpu_has_restart_int(cpu
)) {
406 cs
->exception_index
= EXCP_RESTART
;
408 /* STOP interrupt has least priority */
409 if (cs
->exception_index
== -1 && s390_cpu_has_stop_int(cpu
)) {
410 cs
->exception_index
= EXCP_STOP
;
413 switch (cs
->exception_index
) {
415 do_program_interrupt(env
);
418 do_svc_interrupt(env
);
421 do_ext_interrupt(env
);
424 do_io_interrupt(env
);
427 do_mchk_interrupt(env
);
430 do_restart_interrupt(env
);
433 do_stop_interrupt(env
);
438 if (cs
->exception_index
!= -1 && !stopped
) {
439 /* check if there are more pending interrupts to deliver */
440 cs
->exception_index
= -1;
443 cs
->exception_index
= -1;
445 /* we might still have pending interrupts, but not deliverable */
446 if (!env
->pending_int
&& !qemu_s390_flic_has_any(flic
)) {
447 cs
->interrupt_request
&= ~CPU_INTERRUPT_HARD
;
450 /* WAIT PSW during interrupt injection or STOP interrupt */
451 if ((env
->psw
.mask
& PSW_MASK_WAIT
) || stopped
) {
452 /* don't trigger a cpu_loop_exit(), use an interrupt instead */
453 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HALT
);
454 } else if (cs
->halted
) {
455 /* unhalt if we had a WAIT PSW somehwere in our injection chain */
456 s390_cpu_unhalt(cpu
);
460 bool s390_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
462 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
463 S390CPU
*cpu
= S390_CPU(cs
);
464 CPUS390XState
*env
= &cpu
->env
;
467 /* Execution of the target insn is indivisible from
468 the parent EXECUTE insn. */
471 if (s390_cpu_has_int(cpu
)) {
472 s390_cpu_do_interrupt(cs
);
475 if (env
->psw
.mask
& PSW_MASK_WAIT
) {
476 /* Woken up because of a floating interrupt but it has already
477 * been delivered. Go back to sleep. */
478 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HALT
);
484 void s390x_cpu_debug_excp_handler(CPUState
*cs
)
486 S390CPU
*cpu
= S390_CPU(cs
);
487 CPUS390XState
*env
= &cpu
->env
;
488 CPUWatchpoint
*wp_hit
= cs
->watchpoint_hit
;
490 if (wp_hit
&& wp_hit
->flags
& BP_CPU
) {
491 /* FIXME: When the storage-alteration-space control bit is set,
492 the exception should only be triggered if the memory access
493 is done using an address space with the storage-alteration-event
494 bit set. We have no way to detect that with the current
496 cs
->watchpoint_hit
= NULL
;
498 env
->per_address
= env
->psw
.addr
;
499 env
->per_perc_atmid
|= PER_CODE_EVENT_STORE
| get_per_atmid(env
);
500 /* FIXME: We currently no way to detect the address space used
501 to trigger the watchpoint. For now just consider it is the
502 current default ASC. This turn to be true except when MVCP
503 and MVCS instrutions are not used. */
504 env
->per_perc_atmid
|= env
->psw
.mask
& (PSW_MASK_ASC
) >> 46;
506 /* Remove all watchpoints to re-execute the code. A PER exception
507 will be triggered, it will call load_psw which will recompute
509 cpu_watchpoint_remove_all(cs
, BP_CPU
);
510 cpu_loop_exit_noexc(cs
);
514 /* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
515 this is only for the atomic operations, for which we want to raise a
516 specification exception. */
517 void s390x_cpu_do_unaligned_access(CPUState
*cs
, vaddr addr
,
518 MMUAccessType access_type
,
519 int mmu_idx
, uintptr_t retaddr
)
521 S390CPU
*cpu
= S390_CPU(cs
);
522 CPUS390XState
*env
= &cpu
->env
;
524 s390_program_interrupt(env
, PGM_SPECIFICATION
, ILEN_AUTO
, retaddr
);
527 #endif /* CONFIG_USER_ONLY */