From f5ef0e518d0331920cef0fb6f6c1141695ffab7b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Dec 2021 18:50:09 -0800 Subject: linux-user/nios2: Map a real kuser page The first word of page1 is data, so the whole thing can't be implemented with emulation of addresses. Use init_guest_commpage for the allocation. Hijack trap number 16 to implement cmpxchg. Signed-off-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20211221025012.1057923-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/nios2/cpu_loop.c | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'linux-user/nios2') diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c index 5c3d01d22d..de0fc63e21 100644 --- a/linux-user/nios2/cpu_loop.c +++ b/linux-user/nios2/cpu_loop.c @@ -76,6 +76,32 @@ void cpu_loop(CPUNios2State *env) force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->regs[R_PC]); break; + + case 16: /* QEMU specific, for __kuser_cmpxchg */ + { + abi_ptr g = env->regs[4]; + uint32_t *h, n, o; + + if (g & 0x3) { + force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, g); + break; + } + ret = page_get_flags(g); + if (!(ret & PAGE_VALID)) { + force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, g); + break; + } + if (!(ret & PAGE_READ) || !(ret & PAGE_WRITE)) { + force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_ACCERR, g); + break; + } + h = g2h(cs, g); + o = env->regs[5]; + n = env->regs[6]; + env->regs[2] = qatomic_cmpxchg(h, o, n) - o; + env->regs[R_PC] += 4; + } + break; } break; @@ -86,29 +112,7 @@ void cpu_loop(CPUNios2State *env) queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0xaa: - switch (env->regs[R_PC]) { - /*case 0x1000:*/ /* TODO:__kuser_helper_version */ - case 0x1004: /* __kuser_cmpxchg */ - start_exclusive(); - if (env->regs[4] & 0x3) { - goto kuser_fail; - } - ret = get_user_u32(env->regs[2], env->regs[4]); - if (ret) { - end_exclusive(); - goto kuser_fail; - } - env->regs[2] -= env->regs[5]; - if (env->regs[2] == 0) { - put_user_u32(env->regs[6], env->regs[4]); - } - end_exclusive(); - env->regs[R_PC] = env->regs[R_RA]; - break; - /*case 0x1040:*/ /* TODO:__kuser_sigtramp */ - default: - ; -kuser_fail: + { info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; /* TODO: check env->error_code */ -- cgit v1.2.3