When working on OpenRISC support for restartable sequences I noticed
and fixed these two issues with the riscv support bits.
1 The 'inc' argument to RSEQ_ASM_OP_R_DEREF_ADDV was being implicitly
passed to the macro. Fix this by adding 'inc' to the list of macro
arguments.
2 The inline asm input constraints for 'inc' and 'off' use "er", The
riscv gcc port does not have an "e" constraint, this looks to be
copied from the x86 port. Fix this by just using an "r" constraint.
I have compile tested this only for riscv. However, the same fixes I
use in the OpenRISC rseq selftests and everything passes with no issues.
Fixes: 171586a6ab
("selftests/rseq: riscv: Template memory ordering and percpu access mode")
Signed-off-by: Stafford Horne <shorne@gmail.com>
Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Shuah Khan <skhan@linuxfoundation.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20250114170721.3613280-1-shorne@gmail.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
410 lines
12 KiB
C
410 lines
12 KiB
C
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
|
|
|
#include "rseq-bits-template.h"
|
|
|
|
#if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
|
|
(defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev)(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[cmpfail]")
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(4)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
|
|
RSEQ_INJECT_ASM(5)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[v] "m" (*v),
|
|
[expect] "r" (expect),
|
|
[newv] "r" (newv)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort, cmpfail
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1, error2
|
|
#endif
|
|
);
|
|
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
cmpfail:
|
|
return 1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
error2:
|
|
rseq_bug("expected value comparison failed");
|
|
#endif
|
|
}
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load)(intptr_t *v, intptr_t expectnot,
|
|
off_t voffp, intptr_t *load, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[cmpfail]")
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
RSEQ_ASM_OP_CMPNE(v, expectnot, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(4)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
RSEQ_ASM_OP_CMPNE(v, expectnot, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_OP_R_LOAD(v)
|
|
RSEQ_ASM_OP_R_STORE(load)
|
|
RSEQ_ASM_OP_R_LOAD_OFF(voffp)
|
|
RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
|
|
RSEQ_INJECT_ASM(5)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[v] "m" (*v),
|
|
[expectnot] "r" (expectnot),
|
|
[load] "m" (*load),
|
|
[voffp] "r" (voffp)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort, cmpfail
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1, error2
|
|
#endif
|
|
);
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
cmpfail:
|
|
return 1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
error2:
|
|
rseq_bug("expected value comparison failed");
|
|
#endif
|
|
}
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv)(intptr_t *v, intptr_t count, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
#endif
|
|
RSEQ_ASM_OP_R_LOAD(v)
|
|
RSEQ_ASM_OP_R_ADD(count)
|
|
RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
|
|
RSEQ_INJECT_ASM(4)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[v] "m" (*v),
|
|
[count] "r" (count)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1
|
|
#endif
|
|
);
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
#endif
|
|
}
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev)(intptr_t *v, intptr_t expect,
|
|
intptr_t *v2, intptr_t expect2,
|
|
intptr_t newv, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[cmpfail]")
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error2]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error3]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(4)
|
|
RSEQ_ASM_OP_CMPEQ(v2, expect2, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(5)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[error2]")
|
|
RSEQ_ASM_OP_CMPEQ(v2, expect2, "%l[error3]")
|
|
#endif
|
|
RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
|
|
RSEQ_INJECT_ASM(6)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[v] "m" (*v),
|
|
[expect] "r" (expect),
|
|
[v2] "m" (*v2),
|
|
[expect2] "r" (expect2),
|
|
[newv] "r" (newv)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort, cmpfail
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1, error2, error3
|
|
#endif
|
|
);
|
|
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
cmpfail:
|
|
return 1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
error2:
|
|
rseq_bug("expected value comparison failed");
|
|
error3:
|
|
rseq_bug("2nd expected value comparison failed");
|
|
#endif
|
|
}
|
|
|
|
#define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
|
|
|
|
/*
|
|
* pval = *(ptr+off)
|
|
* *pval += inc;
|
|
*/
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_offset_deref_addv)(intptr_t *ptr, off_t off, intptr_t inc, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
#endif
|
|
RSEQ_ASM_OP_R_DEREF_ADDV(ptr, off, inc, 3)
|
|
RSEQ_INJECT_ASM(4)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[ptr] "r" (ptr),
|
|
[off] "r" (off),
|
|
[inc] "r" (inc)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1
|
|
#endif
|
|
);
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
#endif
|
|
}
|
|
|
|
#endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
|
|
(defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
|
|
|
|
#if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
|
|
(defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev)(intptr_t *v, intptr_t expect,
|
|
intptr_t *v2, intptr_t newv2,
|
|
intptr_t newv, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[cmpfail]")
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(4)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_OP_STORE(newv2, v2)
|
|
RSEQ_INJECT_ASM(5)
|
|
#ifdef RSEQ_TEMPLATE_MO_RELEASE
|
|
RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
|
|
#else
|
|
RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
|
|
#endif
|
|
RSEQ_INJECT_ASM(6)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[expect] "r" (expect),
|
|
[v] "m" (*v),
|
|
[newv] "r" (newv),
|
|
[v2] "m" (*v2),
|
|
[newv2] "r" (newv2)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort, cmpfail
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1, error2
|
|
#endif
|
|
);
|
|
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
cmpfail:
|
|
return 1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
error2:
|
|
rseq_bug("expected value comparison failed");
|
|
#endif
|
|
}
|
|
|
|
static inline __always_inline
|
|
int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev)(intptr_t *v, intptr_t expect,
|
|
void *dst, void *src, size_t len,
|
|
intptr_t newv, int cpu)
|
|
{
|
|
RSEQ_INJECT_C(9)
|
|
__asm__ __volatile__ goto(RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[cmpfail]")
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error1]")
|
|
RSEQ_ASM_DEFINE_EXIT_POINT(2f, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
|
|
RSEQ_INJECT_ASM(3)
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[cmpfail]")
|
|
RSEQ_INJECT_ASM(4)
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, "%l[error1]")
|
|
RSEQ_ASM_OP_CMPEQ(v, expect, "%l[error2]")
|
|
#endif
|
|
RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
|
|
RSEQ_INJECT_ASM(5)
|
|
#ifdef RSEQ_TEMPLATE_MO_RELEASE
|
|
RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
|
|
#else
|
|
RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
|
|
#endif
|
|
RSEQ_INJECT_ASM(6)
|
|
RSEQ_ASM_DEFINE_ABORT(4, abort)
|
|
: /* gcc asm goto does not allow outputs */
|
|
: [cpu_id] "r" (cpu),
|
|
[current_cpu_id] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD),
|
|
[rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
|
|
[expect] "r" (expect),
|
|
[v] "m" (*v),
|
|
[newv] "r" (newv),
|
|
[dst] "r" (dst),
|
|
[src] "r" (src),
|
|
[len] "r" (len)
|
|
RSEQ_INJECT_INPUT
|
|
: "memory", RSEQ_ASM_TMP_REG_1, RSEQ_ASM_TMP_REG_2,
|
|
RSEQ_ASM_TMP_REG_3, RSEQ_ASM_TMP_REG_4
|
|
RSEQ_INJECT_CLOBBER
|
|
: abort, cmpfail
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
, error1, error2
|
|
#endif
|
|
);
|
|
|
|
return 0;
|
|
abort:
|
|
RSEQ_INJECT_FAILED
|
|
return -1;
|
|
cmpfail:
|
|
return 1;
|
|
#ifdef RSEQ_COMPARE_TWICE
|
|
error1:
|
|
rseq_bug("cpu_id comparison failed");
|
|
error2:
|
|
rseq_bug("expected value comparison failed");
|
|
#endif
|
|
}
|
|
|
|
#endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
|
|
(defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
|
|
|
|
#include "rseq-bits-reset.h"
|