diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/s390x/cpu.h | 13 | ||||
-rw-r--r-- | target/s390x/excp_helper.c | 63 | ||||
-rw-r--r-- | target/s390x/helper.c | 12 | ||||
-rw-r--r-- | target/s390x/internal.h | 2 | ||||
-rw-r--r-- | target/s390x/interrupt.c | 18 |
5 files changed, 61 insertions, 47 deletions
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 7e864c8..e32f87a 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -404,11 +404,14 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, #define EXCP_IO 7 /* I/O interrupt */ #define EXCP_MCHK 8 /* machine check */ -#define INTERRUPT_EXT (1 << 0) -#define INTERRUPT_TOD (1 << 1) -#define INTERRUPT_CPUTIMER (1 << 2) -#define INTERRUPT_IO (1 << 3) -#define INTERRUPT_MCHK (1 << 4) +#define INTERRUPT_IO (1 << 0) +#define INTERRUPT_MCHK (1 << 1) +#define INTERRUPT_EXT_SERVICE (1 << 2) +#define INTERRUPT_EXT_CPU_TIMER (1 << 3) +#define INTERRUPT_EXT_CLOCK_COMPARATOR (1 << 4) +#define INTERRUPT_EXT (INTERRUPT_EXT_SERVICE | \ + INTERRUPT_EXT_CPU_TIMER | \ + INTERRUPT_EXT_CLOCK_COMPARATOR) /* Program Status Word. */ #define S390_PSWM_REGNUM 0 diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 3e4349d..b58486b 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -247,29 +247,42 @@ static void do_ext_interrupt(CPUS390XState *env) cpu_abort(CPU(cpu), "Ext int w/o ext mask\n"); } - if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) { - cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index); - } - - q = &env->ext_queue[env->ext_index]; lowcore = cpu_map_lowcore(env); - lowcore->ext_int_code = cpu_to_be16(q->code); - lowcore->ext_params = cpu_to_be32(q->param); - lowcore->ext_params2 = cpu_to_be64(q->param64); - lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); - lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); + 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; + } else if (env->pending_int & INTERRUPT_EXT_CPU_TIMER) { + lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER); + lowcore->cpu_addr = 0; + env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER; + } else if (env->pending_int & INTERRUPT_EXT_SERVICE) { + g_assert(env->ext_index >= 0); + /* + * FIXME: floating IRQs should be considered by all CPUs and + * shuld not get cleared by CPU reset. + */ + q = &env->ext_queue[env->ext_index]; + lowcore->ext_int_code = cpu_to_be16(q->code); + lowcore->ext_params = cpu_to_be32(q->param); + lowcore->ext_params2 = cpu_to_be64(q->param64); + lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); + env->ext_index--; + if (env->ext_index == -1) { + env->pending_int &= ~INTERRUPT_EXT_SERVICE; + } + } else { + g_assert_not_reached(); + } + mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); + lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); cpu_unmap_lowcore(lowcore); - env->ext_index--; - if (env->ext_index == -1) { - env->pending_int &= ~INTERRUPT_EXT; - } - DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); @@ -422,21 +435,9 @@ void s390_cpu_do_interrupt(CPUState *cs) } /* handle external interrupts */ if ((env->psw.mask & PSW_MASK_EXT) && - cs->exception_index == -1) { - if (env->pending_int & INTERRUPT_EXT) { - /* code is already in env */ - cs->exception_index = EXCP_EXT; - } else if (env->pending_int & INTERRUPT_TOD) { - cpu_inject_ext(cpu, 0x1004, 0, 0); - cs->exception_index = EXCP_EXT; - env->pending_int &= ~INTERRUPT_EXT; - env->pending_int &= ~INTERRUPT_TOD; - } else if (env->pending_int & INTERRUPT_CPUTIMER) { - cpu_inject_ext(cpu, 0x1005, 0, 0); - cs->exception_index = EXCP_EXT; - env->pending_int &= ~INTERRUPT_EXT; - env->pending_int &= ~INTERRUPT_TOD; - } + cs->exception_index == -1 && + (env->pending_int & INTERRUPT_EXT)) { + cs->exception_index = EXCP_EXT; } /* handle I/O interrupts */ if ((env->psw.mask & PSW_MASK_IO) && diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 97adbcc..e22b932 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -51,20 +51,12 @@ #ifndef CONFIG_USER_ONLY void s390x_tod_timer(void *opaque) { - S390CPU *cpu = opaque; - CPUS390XState *env = &cpu->env; - - env->pending_int |= INTERRUPT_TOD; - cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + cpu_inject_clock_comparator((S390CPU *) opaque); } void s390x_cpu_timer(void *opaque) { - S390CPU *cpu = opaque; - CPUS390XState *env = &cpu->env; - - env->pending_int |= INTERRUPT_CPUTIMER; - cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + cpu_inject_cpu_timer((S390CPU *) opaque); } #endif diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 14bf3ea..4dda5cf 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -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_ext(S390CPU *cpu, uint32_t code, uint32_t param, uint64_t param64); +void cpu_inject_clock_comparator(S390CPU *cpu); +void cpu_inject_cpu_timer(S390CPU *cpu); /* ioinst.c */ diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index 058e219..b9c30f8 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -71,7 +71,23 @@ void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, env->ext_queue[env->ext_index].param = param; env->ext_queue[env->ext_index].param64 = param64; - env->pending_int |= INTERRUPT_EXT; + env->pending_int |= INTERRUPT_EXT_SERVICE; + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); +} + +void cpu_inject_clock_comparator(S390CPU *cpu) +{ + CPUS390XState *env = &cpu->env; + + env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); +} + +void cpu_inject_cpu_timer(S390CPU *cpu) +{ + CPUS390XState *env = &cpu->env; + + env->pending_int |= INTERRUPT_EXT_CPU_TIMER; cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } |