aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/s390x/cpu.c8
-rw-r--r--target/s390x/excp_helper.c21
-rw-r--r--target/s390x/internal.h4
-rw-r--r--target/s390x/interrupt.c46
4 files changed, 62 insertions, 17 deletions
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 77d55c9e1e..b0517475fa 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -56,10 +56,12 @@ static void s390_cpu_set_pc(CPUState *cs, vaddr value)
static bool s390_cpu_has_work(CPUState *cs)
{
S390CPU *cpu = S390_CPU(cs);
- CPUS390XState *env = &cpu->env;
- return (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->psw.mask & PSW_MASK_EXT);
+ if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
+ return false;
+ }
+
+ return s390_cpu_has_int(cpu);
}
#if !defined(CONFIG_USER_ONLY)
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index 44e9b2c6a6..050d5a61f1 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -435,24 +435,16 @@ void s390_cpu_do_interrupt(CPUState *cs)
s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
/* handle machine checks */
- if ((env->psw.mask & PSW_MASK_MCHECK) &&
- (cs->exception_index == -1)) {
- if (env->pending_int & INTERRUPT_MCHK) {
- cs->exception_index = EXCP_MCHK;
- }
+ if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
+ cs->exception_index = EXCP_MCHK;
}
/* handle external interrupts */
- if ((env->psw.mask & PSW_MASK_EXT) &&
- cs->exception_index == -1 &&
- (env->pending_int & INTERRUPT_EXT)) {
+ if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
cs->exception_index = EXCP_EXT;
}
/* handle I/O interrupts */
- if ((env->psw.mask & PSW_MASK_IO) &&
- (cs->exception_index == -1)) {
- if (env->pending_int & INTERRUPT_IO) {
- cs->exception_index = EXCP_IO;
- }
+ if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
+ cs->exception_index = EXCP_IO;
}
switch (cs->exception_index) {
@@ -474,6 +466,7 @@ void s390_cpu_do_interrupt(CPUState *cs)
}
cs->exception_index = -1;
+ /* we might still have pending interrupts, but not deliverable */
if (!env->pending_int) {
cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
@@ -490,7 +483,7 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
the parent EXECUTE insn. */
return false;
}
- if (env->psw.mask & PSW_MASK_EXT) {
+ if (s390_cpu_has_int(cpu)) {
s390_cpu_do_interrupt(cs);
return true;
}
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index f67c2a1785..e41fb2e38e 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -364,6 +364,10 @@ void cpu_inject_clock_comparator(S390CPU *cpu);
void cpu_inject_cpu_timer(S390CPU *cpu);
void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr);
int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr);
+bool s390_cpu_has_io_int(S390CPU *cpu);
+bool s390_cpu_has_ext_int(S390CPU *cpu);
+bool s390_cpu_has_mcck_int(S390CPU *cpu);
+bool s390_cpu_has_int(S390CPU *cpu);
/* ioinst.c */
diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c
index bb7cc7f87f..0cb65a8c46 100644
--- a/target/s390x/interrupt.c
+++ b/target/s390x/interrupt.c
@@ -190,4 +190,50 @@ void s390_crw_mchk(void)
}
}
+bool s390_cpu_has_mcck_int(S390CPU *cpu)
+{
+ CPUS390XState *env = &cpu->env;
+
+ if (!(env->psw.mask & PSW_MASK_MCHECK)) {
+ return false;
+ }
+
+ return env->pending_int & INTERRUPT_MCHK;
+}
+
+bool s390_cpu_has_ext_int(S390CPU *cpu)
+{
+ CPUS390XState *env = &cpu->env;
+
+ if (!(env->psw.mask & PSW_MASK_EXT)) {
+ return false;
+ }
+
+ return env->pending_int & INTERRUPT_EXT;
+}
+
+bool s390_cpu_has_io_int(S390CPU *cpu)
+{
+ CPUS390XState *env = &cpu->env;
+
+ if (!(env->psw.mask & PSW_MASK_IO)) {
+ return false;
+ }
+
+ return env->pending_int & INTERRUPT_IO;
+}
#endif
+
+bool s390_cpu_has_int(S390CPU *cpu)
+{
+#ifndef CONFIG_USER_ONLY
+ if (!tcg_enabled()) {
+ return false;
+ }
+ return s390_cpu_has_mcck_int(cpu) ||
+ s390_cpu_has_ext_int(cpu) ||
+ s390_cpu_has_io_int(cpu);
+#else
+ return false;
+#endif
+}