In system mode, route accesses to the qtimer-backed global
TIMERLO/TIMERHI so guest reads see a live, monotonically increasing
timer.

In user mode we derive it from QEMU_CLOCK_VIRTUAL.

Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/helper.h     |  4 ++++
 target/hexagon/genptr.c     | 29 +++++++++++++++++++++++++++++
 target/hexagon/op_helper.c  | 21 +++++++++++++++++++++
 tests/tcg/hexagon/reg_mut.c | 11 ++++++++---
 4 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 78dc28ca9e5..e39afd623b5 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -113,6 +113,10 @@ DEF_HELPER_FLAGS_4(gvec_sabsdiff_w, TCG_CALL_NO_RWG, void, 
ptr, ptr, ptr, i32)
 DEF_HELPER_FLAGS_4(gvec_uabsdiff_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
 DEF_HELPER_FLAGS_4(gvec_uabsdiff_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
 
+#if defined(CONFIG_USER_ONLY)
+DEF_HELPER_FLAGS_0(utimer, TCG_CALL_NO_RWG, i64)
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32)
 DEF_HELPER_2(swi, void, env, i32)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 2a98b13b714..282a697d190 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -411,6 +411,23 @@ static inline void gen_read_ctrl_reg(DisasContext *ctx, 
const int reg_num,
     } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
                         ctx->num_hvx_insns);
+#ifndef CONFIG_USER_ONLY
+    } else if (reg_num == HEX_REG_UTIMERLO) {
+        gen_helper_sreg_read(dest, tcg_env,
+                             tcg_constant_i32(HEX_SREG_TIMERLO));
+    } else if (reg_num == HEX_REG_UTIMERHI) {
+        gen_helper_sreg_read(dest, tcg_env,
+                             tcg_constant_i32(HEX_SREG_TIMERHI));
+#else
+    } else if (reg_num == HEX_REG_UTIMERLO) {
+        TCGv_i64 utimer = tcg_temp_new_i64();
+        gen_helper_utimer(utimer);
+        tcg_gen_extrl_i64_i32(dest, utimer);
+    } else if (reg_num == HEX_REG_UTIMERHI) {
+        TCGv_i64 utimer = tcg_temp_new_i64();
+        gen_helper_utimer(utimer);
+        tcg_gen_extrh_i64_i32(dest, utimer);
+#endif
     } else {
         tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
     }
@@ -439,6 +456,18 @@ static inline void gen_read_ctrl_reg_pair(DisasContext 
*ctx, const int reg_num,
         tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
                         ctx->num_hvx_insns);
         tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
+#ifndef CONFIG_USER_ONLY
+    } else if (reg_num == HEX_REG_UTIMERLO) {
+        TCGv lo = tcg_temp_new();
+        TCGv hi = tcg_temp_new();
+        gen_helper_sreg_read(lo, tcg_env, tcg_constant_i32(HEX_SREG_TIMERLO));
+        gen_helper_sreg_read(hi, tcg_env, tcg_constant_i32(HEX_SREG_TIMERHI));
+        tcg_gen_concat_i32_i64(dest, lo, hi);
+#else
+    } else if (reg_num == HEX_REG_UTIMERLO) {
+        /* One helper call, so the pair is a coherent 64-bit snapshot. */
+        gen_helper_utimer(dest);
+#endif
     } else {
         tcg_gen_concat_i32_i64(dest,
             hex_gpr[reg_num],
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 2cea1927263..df31ed2488a 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -37,6 +37,9 @@
 #include "cpu_helper.h"
 #include "tcg/tcg-gvec-desc.h"
 #include "translate.h"
+#ifdef CONFIG_USER_ONLY
+#include "qemu/timer.h"
+#endif
 #ifndef CONFIG_USER_ONLY
 #include "hw/hexagon/hexagon_globalreg.h"
 #include "hex_mmu.h"
@@ -46,6 +49,24 @@
 #include "hexswi.h"
 #endif
 
+#ifdef CONFIG_USER_ONLY
+/*
+ * User mode has no qtimer device backing TIMERLO/TIMERHI, so derive the
+ * user timer directly from the virtual clock -- the same clock the qtimer
+ * counts -- at the qtimer's default 19.2MHz tick rate, masked to the
+ * qtimer's counter width.
+ */
+#define HEX_UTIMER_FREQ_HZ  19200000ULL
+#define HEX_UTIMER_CNT_MASK 0x00ffffffffffffffULL
+
+uint64_t HELPER(utimer)(void)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+                    HEX_UTIMER_FREQ_HZ, NANOSECONDS_PER_SECOND) &
+           HEX_UTIMER_CNT_MASK;
+}
+#endif
+
 #define SF_BIAS        127
 #define SF_MANTBITS    23
 
diff --git a/tests/tcg/hexagon/reg_mut.c b/tests/tcg/hexagon/reg_mut.c
index c5a39e55100..9ce18f3ebe5 100644
--- a/tests/tcg/hexagon/reg_mut.c
+++ b/tests/tcg/hexagon/reg_mut.c
@@ -77,10 +77,10 @@ static inline void write_control_registers(void)
     check32(result, 0x00000000);
 
     WRITE_REG_NOCLOBBER(result, "utimerlo", 0xffffffff);
-    check32(result, 0x00000000);
+    check32_ne(result, 0xffffffff);
 
     WRITE_REG_NOCLOBBER(result, "utimerhi", 0xffffffff);
-    check32(result, 0x00000000);
+    check32_ne(result, 0xffffffff);
 
     /*
      * PC is special.  Setting it to these values
@@ -106,8 +106,13 @@ static inline void write_control_register_pairs(void)
     WRITE_REG_NOCLOBBER(result, "c15:14", 0xffffffffffffffff);
     check64(result, 0x0000000000000000);
 
+    /*
+     * c31:30 is UTIMERHI:UTIMERLO, a read-only free-running counter.  The
+     * write must be discarded; the read-back is whatever the timer says,
+     * so only check that the written value did not stick.
+     */
     WRITE_REG_NOCLOBBER(result, "c31:30", 0xffffffffffffffff);
-    check64(result, 0x0000000000000000);
+    check64_ne(result, 0xffffffffffffffff);
 
     WRITE_REG_PAIR_ENCODED(result, "c9:8", (uint64_t) 0x0000000000000000,
                            C9_8_EQ_R1_0);
-- 
2.34.1

Reply via email to