target/hexagon: Add k0 {un,}lock
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Jun 22, 2026 at 15:28 UTC
1b8ec454840ea02df83b79316e5701eefa55fa06
3 files changed
+124
-2
target/hexagon/hex_mmu.c
+2
-2
@@ -206,8 +206,8 @@ void hex_tlb_unlock(CPUHexagonState *env)
206
(env->tlb_lock_state != HEX_LOCK_OWNER)) {
207
qemu_log_mask(LOG_GUEST_ERROR,
208
"thread %" PRIu32 " attempted to tlbunlock"
209
- " without having the lock, tlb_lock state = %d\n",
210
- env->threadId, env->tlb_lock_state);
209
+ " without having the lock, tlb_lock state = %u\n",
210
+ env->threadId, (unsigned)env->tlb_lock_state);
211
g_assert(env->tlb_lock_state != HEX_LOCK_WAITING);
212
return;
213
}
target/hexagon/op_helper.c
+119
@@ -37,6 +37,9 @@
37
#include "cpu_helper.h"
38
#include "translate.h"
39
#ifndef CONFIG_USER_ONLY
40
+#include "hw/hexagon/hexagon_globalreg.h"
41
+#include "hex_mmu.h"
42
+#include "hw/hexagon/hexagon_tlb.h"
43
#include "hex_interrupts.h"
44
#include "hexswi.h"
45
#endif
@@ -1233,6 +1236,122 @@ void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t new, uint32_t old)
1236
BQL_LOCK_GUARD();
1237
hexagon_modify_ssr(env, new, old);
1238
}
1239
+
1240
+static void hex_k0_lock(CPUHexagonState *env)
1241
+{
1242
+ HexagonCPU *cpu = env_archcpu(env);
1243
+ CPUState *cs = env_cpu(env);
1244
+ target_ulong syscfg;
1245
+
1246
+ BQL_LOCK_GUARD();
1247
+ g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1));
1248
+
1249
+ syscfg = cpu->globalregs ?
1250
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
1251
+ env->threadId) : 0;
1252
+ if (GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg)) {
1253
+ if (env->k0_lock_state == HEX_LOCK_QUEUED) {
1254
+ env->next_PC += 4;
1255
+ env->k0_lock_count++;
1256
+ env->k0_lock_state = HEX_LOCK_OWNER;
1257
+ SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
1258
+ return;
1259
+ }
1260
+ if (env->k0_lock_state == HEX_LOCK_OWNER) {
1261
+ qemu_log_mask(LOG_GUEST_ERROR,
1262
+ "Double k0lock at PC: 0x%" PRIx32
1263
+ ", thread may hang\n",
1264
+ env->next_PC);
1265
+ env->next_PC += 4;
1266
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
1267
+ cpu_loop_exit(cs);
1268
+ return;
1269
+ }
1270
+ env->k0_lock_state = HEX_LOCK_WAITING;
1271
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
1272
+ cpu_loop_exit(cs);
1273
+ } else {
1274
+ env->next_PC += 4;
1275
+ env->k0_lock_count++;
1276
+ env->k0_lock_state = HEX_LOCK_OWNER;
1277
+ SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 1);
1278
+ }
1279
+}
1280
+
1281
+static void hex_k0_unlock(CPUHexagonState *env)
1282
+{
1283
+ HexagonCPU *cpu = env_archcpu(env);
1284
+ unsigned int this_threadId = env->threadId;
1285
+ CPUHexagonState *unlock_thread = NULL;
1286
+ CPUState *cs;
1287
+ target_ulong syscfg;
1288
+
1289
+ BQL_LOCK_GUARD();
1290
+ g_assert((env->k0_lock_count == 0) || (env->k0_lock_count == 1));
1291
+
1292
+ /* Nothing to do if the k0 isn't locked by this thread */
1293
+ syscfg = cpu->globalregs ?
1294
+ hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SYSCFG,
1295
+ env->threadId) : 0;
1296
+ if ((GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg) == 0) ||
1297
+ (env->k0_lock_state != HEX_LOCK_OWNER)) {
1298
+ qemu_log_mask(LOG_GUEST_ERROR,
1299
+ "thread %" PRIu32 " attempted to unlock k0 without"
1300
+ " having the lock, k0_lock state = %u,"
1301
+ " syscfg:k0 = %" PRIu32 "\n",
1302
+ env->threadId, (unsigned)env->k0_lock_state,
1303
+ (uint32_t)GET_SYSCFG_FIELD(SYSCFG_K0LOCK, syscfg));
1304
+ g_assert(env->k0_lock_state != HEX_LOCK_WAITING);
1305
+ return;
1306
+ }
1307
+
1308
+ env->k0_lock_count--;
1309
+ env->k0_lock_state = HEX_LOCK_UNLOCKED;
1310
+ SET_SYSCFG_FIELD(env, SYSCFG_K0LOCK, 0);
1311
+
1312
+ /* Look for a thread to unlock */
1313
+ CPU_FOREACH(cs) {
1314
+ CPUHexagonState *thread = cpu_env(cs);
1315
+
1316
+ /*
1317
+ * The hardware implements round-robin fairness, so we look for threads
1318
+ * starting at env->threadId + 1 and incrementing modulo the number of
1319
+ * threads.
1320
+ *
1321
+ * To implement this, we check if thread is a earlier in the modulo
1322
+ * sequence than unlock_thread.
1323
+ * if unlock thread is higher than this thread
1324
+ * thread must be between this thread and unlock_thread
1325
+ * else
1326
+ * thread higher than this thread is ahead of unlock_thread
1327
+ * thread must be lower then unlock thread
1328
+ */
1329
+ if (thread->k0_lock_state == HEX_LOCK_WAITING) {
1330
+ if (!unlock_thread) {
1331
+ unlock_thread = thread;
1332
+ } else if (unlock_thread->threadId > this_threadId) {
1333
+ if (this_threadId < thread->threadId &&
1334
+ thread->threadId < unlock_thread->threadId) {
1335
+ unlock_thread = thread;
1336
+ }
1337
+ } else {
1338
+ if (thread->threadId > this_threadId) {
1339
+ unlock_thread = thread;
1340
+ }
1341
+ if (thread->threadId < unlock_thread->threadId) {
1342
+ unlock_thread = thread;
1343
+ }
1344
+ }
1345
+ }
1346
+ }
1347
+ if (unlock_thread) {
1348
+ cs = env_cpu(unlock_thread);
1349
+ unlock_thread->k0_lock_state = HEX_LOCK_QUEUED;
1350
+ SET_SYSCFG_FIELD(unlock_thread, SYSCFG_K0LOCK, 1);
1351
+ cpu_interrupt(cs, CPU_INTERRUPT_K0_UNLOCK);
1352
+ }
1353
+
1354
+}
1355
#endif
1356
1357
target/hexagon/sys_macros.h
+3
@@ -148,6 +148,9 @@
148
#define fSET_TLB_LOCK() hex_tlb_lock(env);
149
#define fCLEAR_TLB_LOCK() hex_tlb_unlock(env);
150
151
+#define fSET_K0_LOCK() hex_k0_lock(env);
152
+#define fCLEAR_K0_LOCK() hex_k0_unlock(env);
153
+
154
#define fTLB_IDXMASK(INDEX) \
155
((INDEX) & (fPOW2_ROUNDUP( \
156
fCAST4u(hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))) - 1))