s390x/tcg: injection of emergency signals and external calls

Preparation for new TCG SIGP code. Especially also prepare for
indicating that another external call is already pending.

Take care of interrupt priority.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20170928203708.9376-4-david@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
David Hildenbrand 2017-09-28 22:36:41 +02:00 committed by Cornelia Huck
parent d516f74c99
commit 14ca122e75
4 changed files with 50 additions and 2 deletions

View file

@ -126,6 +126,8 @@ struct CPUS390XState {
int pending_int;
uint32_t service_param;
uint16_t external_call_addr;
DECLARE_BITMAP(emergency_signals, S390_MAX_CPUS);
int io_index[8];
int mchk_index;
@ -401,9 +403,13 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
#define INTERRUPT_EXT_SERVICE (1 << 2)
#define INTERRUPT_EXT_CPU_TIMER (1 << 3)
#define INTERRUPT_EXT_CLOCK_COMPARATOR (1 << 4)
#define INTERRUPT_EXTERNAL_CALL (1 << 5)
#define INTERRUPT_EMERGENCY_SIGNAL (1 << 6)
#define INTERRUPT_EXT (INTERRUPT_EXT_SERVICE | \
INTERRUPT_EXT_CPU_TIMER | \
INTERRUPT_EXT_CLOCK_COMPARATOR)
INTERRUPT_EXT_CLOCK_COMPARATOR | \
INTERRUPT_EXTERNAL_CALL | \
INTERRUPT_EMERGENCY_SIGNAL)
/* Program Status Word. */
#define S390_PSWM_REGNUM 0

View file

@ -240,6 +240,7 @@ static void do_ext_interrupt(CPUS390XState *env)
{
S390CPU *cpu = s390_env_get_cpu(env);
uint64_t mask, addr;
uint16_t cpu_addr;
LowCore *lowcore;
if (!(env->psw.mask & PSW_MASK_EXT)) {
@ -248,7 +249,20 @@ static void do_ext_interrupt(CPUS390XState *env)
lowcore = cpu_map_lowcore(env);
if (env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) {
if (env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) {
lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
g_assert(cpu_addr < S390_MAX_CPUS);
lowcore->cpu_addr = cpu_to_be16(cpu_addr);
clear_bit(cpu_addr, env->emergency_signals);
if (bitmap_empty(env->emergency_signals, max_cpus)) {
env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
}
} else if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
} else if (env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) {
lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
lowcore->cpu_addr = 0;
env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;

View file

@ -362,6 +362,8 @@ void cpu_unmap_lowcore(LowCore *lowcore);
void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen);
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);
/* ioinst.c */

View file

@ -81,6 +81,32 @@ void cpu_inject_cpu_timer(S390CPU *cpu)
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr)
{
CPUS390XState *env = &cpu->env;
g_assert(src_cpu_addr < S390_MAX_CPUS);
set_bit(src_cpu_addr, env->emergency_signals);
env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr)
{
CPUS390XState *env = &cpu->env;
g_assert(src_cpu_addr < S390_MAX_CPUS);
if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
return -EBUSY;
}
env->external_call_addr = src_cpu_addr;
env->pending_int |= INTERRUPT_EXTERNAL_CALL;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
return 0;
}
static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
uint16_t subchannel_number,
uint32_t io_int_parm, uint32_t io_int_word)