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

Reply via email to