Implement them like KVM implements/handles them. Both can only be
triggered via SIGP instructions. RESET has (almost) the lowest priority if
the CPU is running, and the highest if the CPU is STOPPED. This is handled
in SIGP code already. On delivery, we only have to care about the
"CPU running" scenario.
STOP is defined to be delivered after all other interrupts have been
delivered. Therefore it has the actual lowest priority.
As both can wake up a CPU if sleeping, indicate them correctly to
external code (e.g. cpu_has_work()).
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <
20170928203708.9376-25-david@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
#define EXCP_EXT 1 /* external interrupt */
#define EXCP_SVC 2 /* supervisor call (syscall) */
#define EXCP_PGM 3 /* program interruption */
+#define EXCP_RESTART 4 /* restart interrupt */
+#define EXCP_STOP 5 /* stop interrupt */
#define EXCP_IO 7 /* I/O interrupt */
#define EXCP_MCHK 8 /* machine check */
#define INTERRUPT_EXT_CLOCK_COMPARATOR (1 << 4)
#define INTERRUPT_EXTERNAL_CALL (1 << 5)
#define INTERRUPT_EMERGENCY_SIGNAL (1 << 6)
+#define INTERRUPT_RESTART (1 << 7)
+#define INTERRUPT_STOP (1 << 8)
/* Program Status Word. */
#define S390_PSWM_REGNUM 0
if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
cs->exception_index = EXCP_IO;
}
+ /* RESTART interrupt */
+ if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
+ cs->exception_index = EXCP_RESTART;
+ }
+ /* STOP interrupt has least priority */
+ if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
+ cs->exception_index = EXCP_STOP;
+ }
switch (cs->exception_index) {
case EXCP_PGM:
case EXCP_MCHK:
do_mchk_interrupt(env);
break;
+ case EXCP_RESTART:
+ do_restart_interrupt(env);
+ break;
+ case EXCP_STOP:
+ do_stop_interrupt(env);
+ break;
}
- /* WAIT PSW during interrupt injection */
+ /* WAIT PSW during interrupt injection or STOP interrupt */
if (cs->exception_index == EXCP_HLT) {
/* don't trigger a cpu_loop_exit(), use an interrupt instead */
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
addr = be64_to_cpu(lowcore->restart_new_psw.addr);
cpu_unmap_lowcore(lowcore);
+ env->pending_int &= ~INTERRUPT_RESTART;
load_psw(env, mask, addr);
}
bool s390_cpu_has_ext_int(S390CPU *cpu);
bool s390_cpu_has_mcck_int(S390CPU *cpu);
bool s390_cpu_has_int(S390CPU *cpu);
+bool s390_cpu_has_restart_int(S390CPU *cpu);
+bool s390_cpu_has_stop_int(S390CPU *cpu);
void cpu_inject_restart(S390CPU *cpu);
void cpu_inject_stop(S390CPU *cpu);
void cpu_inject_restart(S390CPU *cpu)
{
+ CPUS390XState *env = &cpu->env;
+
if (kvm_enabled()) {
kvm_s390_restart_interrupt(cpu);
return;
}
- /* FIXME TCG */
- g_assert_not_reached();
+
+ env->pending_int |= INTERRUPT_RESTART;
+ cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
void cpu_inject_stop(S390CPU *cpu)
{
+ CPUS390XState *env = &cpu->env;
+
if (kvm_enabled()) {
kvm_s390_stop_interrupt(cpu);
return;
}
- /* FIXME TCG */
- g_assert_not_reached();
+
+ env->pending_int |= INTERRUPT_STOP;
+ cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
return env->pending_int & INTERRUPT_IO;
}
+
+bool s390_cpu_has_restart_int(S390CPU *cpu)
+{
+ CPUS390XState *env = &cpu->env;
+
+ return env->pending_int & INTERRUPT_RESTART;
+}
+
+bool s390_cpu_has_stop_int(S390CPU *cpu)
+{
+ CPUS390XState *env = &cpu->env;
+
+ return env->pending_int & INTERRUPT_STOP;
+}
#endif
bool s390_cpu_has_int(S390CPU *cpu)
}
return s390_cpu_has_mcck_int(cpu) ||
s390_cpu_has_ext_int(cpu) ||
- s390_cpu_has_io_int(cpu);
+ s390_cpu_has_io_int(cpu) ||
+ s390_cpu_has_restart_int(cpu) ||
+ s390_cpu_has_stop_int(cpu);
#else
return false;
#endif
#include "internal.h"
#include "sysemu/hw_accel.h"
#include "exec/address-spaces.h"
+#include "exec/exec-all.h"
#include "sysemu/sysemu.h"
#include "trace.h"
s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
}
env->sigp_order = 0;
+ env->pending_int &= ~INTERRUPT_STOP;
}
void s390_init_sigp(void)