diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2017-10-11 13:19:11 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2018-01-30 10:08:18 -0800 |
commit | 1a19da0da44430581bf48b595d75ad6e9fc7e428 (patch) | |
tree | 5d46e77fe33e7e831d0408fc82d0eb3fc2a01647 /target | |
parent | f49b3537cb28b98284f6ce893ef7240a3cacded3 (diff) |
target/hppa: Fill in hppa_cpu_do_interrupt/hppa_cpu_exec_interrupt
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/hppa/Makefile.objs | 1 | ||||
-rw-r--r-- | target/hppa/cpu.c | 2 | ||||
-rw-r--r-- | target/hppa/helper.c | 63 | ||||
-rw-r--r-- | target/hppa/int_helper.c | 176 | ||||
-rw-r--r-- | target/hppa/translate.c | 16 |
5 files changed, 192 insertions, 66 deletions
diff --git a/target/hppa/Makefile.objs b/target/hppa/Makefile.objs index d89285307b..dcd60a6839 100644 --- a/target/hppa/Makefile.objs +++ b/target/hppa/Makefile.objs @@ -1 +1,2 @@ obj-y += translate.o helper.o cpu.o op_helper.o gdbstub.o mem_helper.o +obj-y += int_helper.o diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 9962ab71ee..ca619578dd 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -106,8 +106,10 @@ static void hppa_cpu_initfn(Object *obj) CPUHPPAState *env = &cpu->env; cs->env_ptr = env; + cs->exception_index = -1; cpu_hppa_loaded_fr0(env); set_snan_bit_is_one(true, &env->fp_status); + cpu_hppa_put_psw(env, PSW_W); } static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model) diff --git a/target/hppa/helper.c b/target/hppa/helper.c index 48ac80cb2d..6e8758f82c 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -67,69 +67,6 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) env->psw_cb = cb; } -void hppa_cpu_do_interrupt(CPUState *cs) -{ - HPPACPU *cpu = HPPA_CPU(cs); - CPUHPPAState *env = &cpu->env; - int i = cs->exception_index; - - if (qemu_loglevel_mask(CPU_LOG_INT)) { - static const char * const names[] = { - [EXCP_HPMC] = "high priority machine check", - [EXCP_POWER_FAIL] = "power fail interrupt", - [EXCP_RC] = "recovery counter trap", - [EXCP_EXT_INTERRUPT] = "external interrupt", - [EXCP_LPMC] = "low priority machine check", - [EXCP_ITLB_MISS] = "instruction tlb miss fault", - [EXCP_IMP] = "instruction memory protection trap", - [EXCP_ILL] = "illegal instruction trap", - [EXCP_BREAK] = "break instruction trap", - [EXCP_PRIV_OPR] = "privileged operation trap", - [EXCP_PRIV_REG] = "privileged register trap", - [EXCP_OVERFLOW] = "overflow trap", - [EXCP_COND] = "conditional trap", - [EXCP_ASSIST] = "assist exception trap", - [EXCP_DTLB_MISS] = "data tlb miss fault", - [EXCP_NA_ITLB_MISS] = "non-access instruction tlb miss", - [EXCP_NA_DTLB_MISS] = "non-access data tlb miss", - [EXCP_DMP] = "data memory protection trap", - [EXCP_DMB] = "data memory break trap", - [EXCP_TLB_DIRTY] = "tlb dirty bit trap", - [EXCP_PAGE_REF] = "page reference trap", - [EXCP_ASSIST_EMU] = "assist emulation trap", - [EXCP_HPT] = "high-privilege transfer trap", - [EXCP_LPT] = "low-privilege transfer trap", - [EXCP_TB] = "taken branch trap", - [EXCP_DMAR] = "data memory access rights trap", - [EXCP_DMPI] = "data memory protection id trap", - [EXCP_UNALIGN] = "unaligned data reference trap", - [EXCP_PER_INTERRUPT] = "performance monitor interrupt", - [EXCP_SYSCALL] = "syscall", - [EXCP_SYSCALL_LWS] = "syscall-lws", - }; - static int count; - const char *name = NULL; - - if (i >= 0 && i < ARRAY_SIZE(names)) { - name = names[i]; - } - if (name) { - qemu_log("INT %6d: %s ia_f=" TARGET_FMT_lx "\n", - ++count, name, env->iaoq_f); - } else { - qemu_log("INT %6d: unknown %d ia_f=" TARGET_FMT_lx "\n", - ++count, i, env->iaoq_f); - } - } - cs->exception_index = -1; -} - -bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - abort(); - return false; -} - void hppa_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags) { diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c new file mode 100644 index 0000000000..a59aae1189 --- /dev/null +++ b/target/hppa/int_helper.c @@ -0,0 +1,176 @@ +/* + * HPPA interrupt helper routines + * + * Copyright (c) 2017 Richard Henderson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "qom/cpu.h" + + +void hppa_cpu_do_interrupt(CPUState *cs) +{ + HPPACPU *cpu = HPPA_CPU(cs); + CPUHPPAState *env = &cpu->env; + int i = cs->exception_index; + target_ureg iaoq_f = env->iaoq_f; + target_ureg iaoq_b = env->iaoq_b; + +#ifndef CONFIG_USER_ONLY + target_ureg old_psw; + + /* As documented in pa2.0 -- interruption handling. */ + /* step 1 */ + env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env); + + /* step 2 -- note PSW_W == 0 for !HPPA64. */ + cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0)); + + /* step 3 */ + env->cr[CR_IIAOQ] = iaoq_f; + env->cr_back[1] = iaoq_b; + + if (old_psw & PSW_Q) { + /* step 5 */ + /* ISR and IOR will be set elsewhere. */ + switch (i) { + case EXCP_ILL: + case EXCP_BREAK: + case EXCP_PRIV_REG: + case EXCP_PRIV_OPR: + /* IIR set via translate.c. */ + break; + + case EXCP_OVERFLOW: + case EXCP_COND: + case EXCP_ASSIST: + case EXCP_DTLB_MISS: + case EXCP_NA_ITLB_MISS: + case EXCP_NA_DTLB_MISS: + case EXCP_DMAR: + case EXCP_DMPI: + case EXCP_UNALIGN: + case EXCP_DMP: + case EXCP_DMB: + case EXCP_TLB_DIRTY: + case EXCP_PAGE_REF: + case EXCP_ASSIST_EMU: + { + /* Avoid reading directly from the virtual address, lest we + raise another exception from some sort of TLB issue. */ + vaddr vaddr; + hwaddr paddr; + + paddr = vaddr = iaoq_f & -4; + env->cr[CR_IIR] = ldl_phys(cs->as, paddr); + } + break; + + default: + /* Other exceptions do not set IIR. */ + break; + } + + /* step 6 */ + env->shadow[0] = env->gr[1]; + env->shadow[1] = env->gr[8]; + env->shadow[2] = env->gr[9]; + env->shadow[3] = env->gr[16]; + env->shadow[4] = env->gr[17]; + env->shadow[5] = env->gr[24]; + env->shadow[6] = env->gr[25]; + } + + /* step 7 */ + env->iaoq_f = env->cr[CR_IVA] + 32 * i; + env->iaoq_b = env->iaoq_f + 4; +#endif + + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static const char * const names[] = { + [EXCP_HPMC] = "high priority machine check", + [EXCP_POWER_FAIL] = "power fail interrupt", + [EXCP_RC] = "recovery counter trap", + [EXCP_EXT_INTERRUPT] = "external interrupt", + [EXCP_LPMC] = "low priority machine check", + [EXCP_ITLB_MISS] = "instruction tlb miss fault", + [EXCP_IMP] = "instruction memory protection trap", + [EXCP_ILL] = "illegal instruction trap", + [EXCP_BREAK] = "break instruction trap", + [EXCP_PRIV_OPR] = "privileged operation trap", + [EXCP_PRIV_REG] = "privileged register trap", + [EXCP_OVERFLOW] = "overflow trap", + [EXCP_COND] = "conditional trap", + [EXCP_ASSIST] = "assist exception trap", + [EXCP_DTLB_MISS] = "data tlb miss fault", + [EXCP_NA_ITLB_MISS] = "non-access instruction tlb miss", + [EXCP_NA_DTLB_MISS] = "non-access data tlb miss", + [EXCP_DMP] = "data memory protection trap", + [EXCP_DMB] = "data memory break trap", + [EXCP_TLB_DIRTY] = "tlb dirty bit trap", + [EXCP_PAGE_REF] = "page reference trap", + [EXCP_ASSIST_EMU] = "assist emulation trap", + [EXCP_HPT] = "high-privilege transfer trap", + [EXCP_LPT] = "low-privilege transfer trap", + [EXCP_TB] = "taken branch trap", + [EXCP_DMAR] = "data memory access rights trap", + [EXCP_DMPI] = "data memory protection id trap", + [EXCP_UNALIGN] = "unaligned data reference trap", + [EXCP_PER_INTERRUPT] = "performance monitor interrupt", + [EXCP_SYSCALL] = "syscall", + [EXCP_SYSCALL_LWS] = "syscall-lws", + }; + static int count; + const char *name = NULL; + char unknown[16]; + + if (i >= 0 && i < ARRAY_SIZE(names)) { + name = names[i]; + } + if (!name) { + snprintf(unknown, sizeof(unknown), "unknown %d", i); + name = unknown; + } + qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx + " -> " TREG_FMT_lx " " TARGET_FMT_lx "\n", + ++count, name, + (target_ulong)iaoq_f, + (target_ulong)iaoq_b, + env->iaoq_f, + (target_ulong)env->cr[CR_IOR]); + } + cs->exception_index = -1; +} + +bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ +#ifndef CONFIG_USER_ONLY + HPPACPU *cpu = HPPA_CPU(cs); + CPUHPPAState *env = &cpu->env; + + /* If interrupts are requested and enabled, raise them. */ + if ((env->psw & PSW_I) && (interrupt_request & CPU_INTERRUPT_HARD)) { + cs->exception_index = EXCP_EXT_INTERRUPT; + hppa_cpu_do_interrupt(cs); + return true; + } +#endif + return false; +} diff --git a/target/hppa/translate.c b/target/hppa/translate.c index df0bb04907..34b999fb2c 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -282,6 +282,7 @@ typedef struct DisasContext { DisasCond null_cond; TCGLabel *null_lab; + uint32_t insn; int mmu_idx; int privilege; bool psw_n_nonzero; @@ -716,17 +717,25 @@ static DisasJumpType gen_excp(DisasContext *ctx, int exception) return DISAS_NORETURN; } +static DisasJumpType gen_excp_iir(DisasContext *ctx, int exc) +{ + TCGv_reg tmp = tcg_const_reg(ctx->insn); + tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[CR_IIR])); + tcg_temp_free(tmp); + return gen_excp(ctx, exc); +} + static DisasJumpType gen_illegal(DisasContext *ctx) { nullify_over(ctx); - return nullify_end(ctx, gen_excp(ctx, EXCP_ILL)); + return nullify_end(ctx, gen_excp_iir(ctx, EXCP_ILL)); } #define CHECK_MOST_PRIVILEGED(EXCP) \ do { \ if (ctx->privilege != 0) { \ nullify_over(ctx); \ - return nullify_end(ctx, gen_excp(ctx, EXCP)); \ + return nullify_end(ctx, gen_excp_iir(ctx, EXCP)); \ } \ } while (0) @@ -1893,7 +1902,7 @@ static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn, const DisasInsn *di) { nullify_over(ctx); - return nullify_end(ctx, gen_excp(ctx, EXCP_BREAK)); + return nullify_end(ctx, gen_excp_iir(ctx, EXCP_BREAK)); } static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn, @@ -4270,6 +4279,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ctx->null_cond.c = TCG_COND_NEVER; ret = DISAS_NEXT; } else { + ctx->insn = insn; ret = translate_one(ctx, insn); assert(ctx->null_lab == NULL); } |