Implement guest event entry: trap0 when CCR.GTE is set, and precise errors, fp traps and debug events when CCR.GEE is set.
Now that it's implemented, remove ASSERT_DIRECT_TO_GUEST_UNSET. Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/hexswi.h | 5 ++ target/hexagon/sys_macros.h | 24 ---------- target/hexagon/cpu_helper.c | 1 - target/hexagon/hex_interrupts.c | 7 +-- target/hexagon/hexswi.c | 85 ++++++++++++++++++++++++++++++++- target/hexagon/op_helper.c | 2 - 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/target/hexagon/hexswi.h b/target/hexagon/hexswi.h index 48c1ae6e4c1..587f790414c 100644 --- a/target/hexagon/hexswi.h +++ b/target/hexagon/hexswi.h @@ -14,4 +14,9 @@ void hexagon_cpu_do_interrupt(CPUState *cpu); void register_trap_exception(CPUHexagonState *env, int type, int imm, uint32_t PC); +#define HEX_GEVB_HW_ERROR (HEX_EVENT_PRECISE << 2) +#define HEX_GEVB_HW_TRAP0 (HEX_EVENT_TRAP0 << 2) +#define HEX_GEVB_HW_FPTRAP (HEX_EVENT_FPTRAP << 2) +#define HEX_GEVB_HW_DEBUG (HEX_EVENT_DEBUG << 2) + #endif /* HEXSWI_H */ diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h index 2e4cda29e61..b896ee1c81b 100644 --- a/target/hexagon/sys_macros.h +++ b/target/hexagon/sys_macros.h @@ -52,28 +52,6 @@ #define CCR_FIELD_SET(ENV, FIELD) \ (!!GET_FIELD(FIELD, (ENV)->t_sreg[HEX_SREG_CCR])) -/* - * Direct-to-guest is not implemented yet, continuing would cause unexpected - * behavior, so we abort. - */ -#define ASSERT_DIRECT_TO_GUEST_UNSET(ENV, EXCP) \ - do { \ - switch (EXCP) { \ - case HEX_EVENT_TRAP0: \ - g_assert(!CCR_FIELD_SET(ENV, CCR_GTE)); \ - break; \ - case HEX_EVENT_IMPRECISE: \ - case HEX_EVENT_PRECISE: \ - case HEX_EVENT_FPTRAP: \ - g_assert(!CCR_FIELD_SET(ENV, CCR_GEE)); \ - break; \ - default: \ - if ((EXCP) >= HEX_EVENT_INT0) { \ - g_assert(!CCR_FIELD_SET(ENV, CCR_GIE)); \ - } \ - break; \ - } \ - } while (0) #endif #define fREAD_ELR() (env->t_sreg[HEX_SREG_ELR]) @@ -247,8 +225,6 @@ } while (0) #endif -#else -#define ASSERT_DIRECT_TO_GUEST_UNSET(ENV, EXCP) do { } while (0) #endif #define NUM_TLB_REGS(x) (hexagon_tlb_get_num_entries(env_archcpu(env)->tlb)) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index baffe6bbaa9..5b68539f1e5 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -97,7 +97,6 @@ static void hexagon_resume_thread(CPUHexagonState *env) CPUState *cs = env_cpu(env); clear_wait_mode(env); cs = env_cpu(env); - ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); cpu_reset_interrupt(cs, CPU_INTERRUPT_HALT); cs->halted = false; cs->exception_index = HEX_EVENT_NONE; diff --git a/target/hexagon/hex_interrupts.c b/target/hexagon/hex_interrupts.c index b5a872db989..26a574f76f2 100644 --- a/target/hexagon/hex_interrupts.c +++ b/target/hexagon/hex_interrupts.c @@ -305,8 +305,8 @@ static bool int_should_dtg(CPUHexagonState *env, int int_num) return GET_FIELD(CCR_GIE, ccr); } -static void guest_interrupt_entry(CPUHexagonState *env, uint32_t cause, - uint32_t event_pc) +static void guest_interrupt_entry(CPUHexagonState *env, int int_num, + uint32_t cause, uint32_t event_pc) { uint32_t old_ssr = env->t_sreg[HEX_SREG_SSR]; uint32_t new_ssr = old_ssr; @@ -328,6 +328,7 @@ static void guest_interrupt_entry(CPUHexagonState *env, uint32_t cause, fSET_FIELD(new_ssr, SSR_SS, 0); fSET_FIELD(new_ssr, SSR_GM, 1); + fSET_FIELD(new_ssr, SSR_CAUSE, HEX_CAUSE_INT0 | int_num); env->t_sreg[HEX_SREG_SSR] = new_ssr; hexagon_modify_ssr(env, new_ssr, old_ssr); @@ -367,7 +368,7 @@ static void hex_accept_int(CPUHexagonState *env, int int_num) uint32_t vid = extract32(vid_packed, (vic_group & 1) ? 16 : 0, 16); - guest_interrupt_entry(env, vid, elr); + guest_interrupt_entry(env, int_num, vid, elr); } else { uint32_t evb = hexagon_globalreg_read(cpu->globalregs, HEX_SREG_EVB, diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c index fb46c05360c..9d94eef96a7 100644 --- a/target/hexagon/hexswi.c +++ b/target/hexagon/hexswi.c @@ -761,6 +761,66 @@ static void set_addresses(CPUHexagonState *env, uint32_t pc_offset, env->gpr[HEX_REG_PC] = evb | (exception_index << 2); } +static bool event_to_guest(CPUHexagonState *env, unsigned enable_field) +{ + return get_cpu_mode(env) != HEX_CPU_MODE_MONITOR && + GET_FIELD(enable_field, env->t_sreg[HEX_SREG_CCR]); +} + +#define HEX_CAUSE_INSN_FAULT_FIRST 0x10 +#define HEX_CAUSE_DATA_FAULT_FIRST 0x20 +#define HEX_CAUSE_DATA_FAULT_LAST 0x2f +#define HEX_CAUSE_TLB_MISS_FIRST 0x72 +#define HEX_CAUSE_TLB_MISS_LAST 0x75 +#define HEX_CAUSE_TLB_MISS_EXTRA 0x79 + +static bool cause_goes_to_guest(uint32_t cause) +{ + return (cause >= HEX_CAUSE_INSN_FAULT_FIRST && + cause <= HEX_CAUSE_DATA_FAULT_LAST) || + (cause >= HEX_CAUSE_TLB_MISS_FIRST && + cause <= HEX_CAUSE_TLB_MISS_LAST) || + cause == HEX_CAUSE_TLB_MISS_EXTRA; +} + +static bool cause_sets_gbadva(uint32_t cause) +{ + return cause >= HEX_CAUSE_DATA_FAULT_FIRST && cause_goes_to_guest(cause); +} + +/* Take an event from guest user mode in the guest kernel. */ +static void guest_event_entry(CPUHexagonState *env, uint32_t cause, + uint32_t event_pc, uint32_t vec_offset, + bool set_gbadva) +{ + uint32_t old_ssr = env->t_sreg[HEX_SREG_SSR]; + uint32_t gsr = 0; + uint32_t gevb = env->t_sreg[HEX_SREG_GEVB]; + + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause); + gsr = deposit32(gsr, reg_field_info[GSR_CAUSE].offset, + reg_field_info[GSR_CAUSE].width, cause); + gsr = deposit32(gsr, reg_field_info[GSR_SS].offset, + reg_field_info[GSR_SS].width, + GET_FIELD(SSR_SS, old_ssr)); + gsr = deposit32(gsr, reg_field_info[GSR_UM].offset, + reg_field_info[GSR_UM].width, + !GET_FIELD(SSR_GM, old_ssr)); + gsr = deposit32(gsr, reg_field_info[GSR_IE].offset, + reg_field_info[GSR_IE].width, + GET_FIELD(CCR_GIE, env->t_sreg[HEX_SREG_CCR])); + env->greg[HEX_GREG_GSR] = gsr; + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_SS, 0); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_GM, 1); + hexagon_modify_ssr(env, env->t_sreg[HEX_SREG_SSR], old_ssr); + SET_SYSTEM_FIELD(env, HEX_SREG_CCR, CCR_GIE, 0); + env->greg[HEX_GREG_GELR] = event_pc; + if (set_gbadva) { + env->greg[HEX_GREG_GBADVA] = env->t_sreg[HEX_SREG_BADVA]; + } + env->gpr[HEX_REG_PC] = gevb + vec_offset; +} + void hexagon_cpu_do_interrupt(CPUState *cs) { @@ -800,6 +860,12 @@ void hexagon_cpu_do_interrupt(CPUState *cs) switch (cs->exception_index) { case HEX_EVENT_TRAP0: + if (event_to_guest(env, CCR_GTE)) { + guest_event_entry(env, env->cause_code, + env->gpr[HEX_REG_PC] + 4, + HEX_GEVB_HW_TRAP0, false); + break; + } if (env->cause_code == 0) { sim_handle_trap0(env); } @@ -880,16 +946,33 @@ void hexagon_cpu_do_interrupt(CPUState *cs) break; case HEX_EVENT_FPTRAP: + if (event_to_guest(env, CCR_GEE)) { + guest_event_entry(env, env->cause_code, env->gpr[HEX_REG_PC], + HEX_GEVB_HW_FPTRAP, false); + break; + } hexagon_ssr_set_cause(env, env->cause_code); set_addresses(env, 0, cs->exception_index); break; case HEX_EVENT_DEBUG: + if (event_to_guest(env, CCR_GEE)) { + guest_event_entry(env, env->cause_code, env->gpr[HEX_REG_PC], + HEX_GEVB_HW_DEBUG, false); + break; + } hexagon_ssr_set_cause(env, env->cause_code); set_addresses(env, 0, cs->exception_index); break; case HEX_EVENT_PRECISE: + if (event_to_guest(env, CCR_GEE) && + cause_goes_to_guest(env->cause_code)) { + guest_event_entry(env, env->cause_code, + env->gpr[HEX_REG_PC], HEX_GEVB_HW_ERROR, + cause_sets_gbadva(env->cause_code)); + break; + } switch (env->cause_code) { case HEX_CAUSE_FETCH_NO_XPAGE: case HEX_CAUSE_FETCH_NO_UPAGE: @@ -1018,8 +1101,6 @@ void register_trap_exception(CPUHexagonState *env, int traptype, int imm, default: g_assert_not_reached(); } - ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); - env->cause_code = imm; env->gpr[HEX_REG_PC] = PC; cpu_loop_exit(cs); diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6076a5f29fd..6f9df299f9a 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -79,7 +79,6 @@ void do_raise_exception(CPUHexagonState *env, uint32_t exception, CPUState *cs = env_cpu(env); qemu_log_mask(CPU_LOG_INT, "%s: 0x%08" PRIx32 ", @ %08" PRIx32 "\n", __func__, exception, PC); - ASSERT_DIRECT_TO_GUEST_UNSET(env, exception); env->gpr[HEX_REG_PC] = PC; cs->exception_index = exception; @@ -1665,7 +1664,6 @@ void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot, cs = env_cpu(env); cs->exception_index = HEX_EVENT_PRECISE; env->cause_code = HEX_CAUSE_STACK_LIMIT; - ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); if (slot == 0) { env->t_sreg[HEX_SREG_BADVA0] = badva; -- 2.34.1
