Signed-off-by: Brian Cain <[email protected]>
---
target/hexagon/hex_mmu.h | 9 +++++----
target/hexagon/sys_macros.h | 4 ++--
target/hexagon/hex_mmu.c | 15 ++++++++-------
target/hexagon/op_helper.c | 15 ++++++++-------
target/hexagon/hex_common.py | 6 +++++-
5 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
index 56b2c4a89d0..4eaf15c4996 100644
--- a/target/hexagon/hex_mmu.h
+++ b/target/hexagon/hex_mmu.h
@@ -17,12 +17,13 @@ extern uint32_t hex_tlb_lookup(CPUHexagonState
*env, uint32_t ssr, uint32_t VA);
extern void hex_mmu_on(CPUHexagonState *env);
extern void hex_mmu_off(CPUHexagonState *env);
extern void hex_mmu_mode_change(CPUHexagonState *env);
-extern bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA,
- MMUAccessType access_type, hwaddr
*PA, int *prot,
- uint64_t *size, int32_t *excp, int
mmu_idx);
+extern bool hex_tlb_find_match(CPUHexagonState *env, target_ulong VA,
+ MMUAccessType access_type,
+ hwaddr *PA, int *prot, uint64_t *size,
+ int32_t *excp, int mmu_idx);
Why is this change included in this patch?
extern int hex_tlb_check_overlap(CPUHexagonState *env, uint64_t
entry,
uint64_t index);
-extern void hex_tlb_lock(CPUHexagonState *env);
+extern void hex_tlb_lock(CPUHexagonState *env, target_ulong PC);
extern void hex_tlb_unlock(CPUHexagonState *env);
void dump_mmu(MonitorHMP *hmp, CPUHexagonState *env);
#endif
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index a5b9b7f2592..72179d49ab3 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -145,10 +145,10 @@
#define fDCINVIDX(REG)
#define fDCINVA(REG) do { REG = REG; } while (0) /* Nothing to do
in qemu */
-#define fSET_TLB_LOCK() hex_tlb_lock(env);
+#define fSET_TLB_LOCK() hex_tlb_lock(env, PC);
#define fCLEAR_TLB_LOCK() hex_tlb_unlock(env);
-#define fSET_K0_LOCK() hex_k0_lock(env);
+#define fSET_K0_LOCK() hex_k0_lock(env, PC);
#define fCLEAR_K0_LOCK() hex_k0_unlock(env);
#define fTLB_IDXMASK(INDEX) \
diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
index d6ee7c40798..d7acaae5ac8 100644
--- a/target/hexagon/hex_mmu.c
+++ b/target/hexagon/hex_mmu.c
@@ -156,7 +156,7 @@ static inline void print_thread_states(const
char *str)
}
}
-void hex_tlb_lock(CPUHexagonState *env)
+void hex_tlb_lock(CPUHexagonState *env, target_ulong PC)
{
qemu_log_mask(CPU_LOG_MMU, "hex_tlb_lock: " TARGET_FMT_ld "\n",
env->threadId);
@@ -170,7 +170,6 @@ void hex_tlb_lock(CPUHexagonState *env)
uint8_t tlb_lock = GET_SYSCFG_FIELD(SYSCFG_TLBLOCK, syscfg);
if (tlb_lock) {
if (env->tlb_lock_state == HEX_LOCK_QUEUED) {
- env->next_PC += 4;
env->tlb_lock_count++;
env->tlb_lock_state = HEX_LOCK_OWNER;
SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1);
@@ -178,19 +177,21 @@ void hex_tlb_lock(CPUHexagonState *env)
}
if (env->tlb_lock_state == HEX_LOCK_OWNER) {
qemu_log_mask(CPU_LOG_MMU | LOG_GUEST_ERROR,
- "Double tlblock at PC: 0x%" PRIx32
- ", thread may hang\n",
- env->next_PC);
- env->next_PC += 4;
+ "Double tlblock at PC: 0x%x, thread may
hang\n", PC);
Don't use %x, use TARGET_FMT_lx.
CPUState *cs = env_cpu(env);
cpu_interrupt(cs, CPU_INTERRUPT_HALT);
return;
}
env->tlb_lock_state = HEX_LOCK_WAITING;
+ /*
+ * next_PC has already been advanced past this packet.
Rewind it
+ * so that the thread re-executes the tlblock when it is
woken by
+ * the thread that releases the lock.
+ */
+ env->next_PC = PC;
CPUState *cs = env_cpu(env);
cpu_interrupt(cs, CPU_INTERRUPT_HALT);
} else {
- env->next_PC += 4;
env->tlb_lock_count++;
env->tlb_lock_state = HEX_LOCK_OWNER;
SET_SYSCFG_FIELD(env, SYSCFG_TLBLOCK, 1);
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 0d08ac77361..07ba639449c 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1278,7 +1278,7 @@ void HELPER(modify_ssr)(CPUHexagonState
*env, uint32_t new, uint32_t old)
hexagon_modify_ssr(env, new, old);
}
-static void hex_k0_lock(CPUHexagonState *env)
+static void hex_k0_lock(CPUHexagonState *env, target_ulong PC)
{
HexagonCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
@@ -1292,7 +1292,6 @@ static void hex_k0_lock(CPUHexagonState *env)
env->threadId) : 0;
if (GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg)) {
if (env->k0_lock_state == HEX_LOCK_QUEUED) {
- env->next_PC += 4;
env->k0_lock_count++;
env->k0_lock_state = HEX_LOCK_OWNER;
SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
@@ -1300,19 +1299,21 @@ static void hex_k0_lock(CPUHexagonState *env)
}
if (env->k0_lock_state == HEX_LOCK_OWNER) {
qemu_log_mask(LOG_GUEST_ERROR,
- "Double k0lock at PC: 0x%" PRIx32
- ", thread may hang\n",
- env->next_PC);
- env->next_PC += 4;
+ "Double k0lock at PC: 0x%x, thread may
hang\n", PC);
Don't use %x, use TARGET_FMT_lx.
cpu_interrupt(cs, CPU_INTERRUPT_HALT);
cpu_loop_exit(cs);
return;
}
env->k0_lock_state = HEX_LOCK_WAITING;
+ /*
+ * next_PC has already been advanced past this packet.
Rewind it
+ * so that the thread re-executes the k0lock when it is
woken by
+ * the thread that releases the lock.
+ */
+ env->next_PC = PC;
cpu_interrupt(cs, CPU_INTERRUPT_HALT);
cpu_loop_exit(cs);
} else {
- env->next_PC += 4;
env->k0_lock_count++;
env->k0_lock_state = HEX_LOCK_OWNER;
SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
diff --git a/target/hexagon/hex_common.py
b/target/hexagon/hex_common.py
index c180c19b092..1bd31f76a4f 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -284,7 +284,11 @@ def need_ea(tag):
def need_PC(tag):
- return "A_IMPLICIT_READS_PC" in attribdict[tag]
+ return (
+ "A_IMPLICIT_READS_PC" in attribdict[tag]
+ or tag == "Y2_k0lock"
+ or tag == "Y2_tlblock"
+ )
This isn't needed. These 2 opcodes already have A_IMPLICIT_READS_PC set.
Look for fSET_K0_LOCK and fSET_TLB_LOCK in calculate_attribs in
hex_common.py.
Thanks,
Taylor