x86: Introduce RSEQ_ASM_U32
[librseq.git] / include / rseq / arch / riscv.h
CommitLineData
90702366 1/* SPDX-License-Identifier: MIT */
f2d7b530 2/* SPDX-FileCopyrightText: 2022 Vincent Chen <vincent.chen@sifive.com> */
c4f3965f
MD
3/* SPDX-FileCopyrightText: 2024 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> */
4
5/*
6 * rseq-riscv.h
7 */
8
9/*
10 * RSEQ_ASM_*() macro helpers are internal to the librseq headers. Those
11 * are not part of the public API.
12 */
f2d7b530 13
44ec21eb
MJ
14#ifndef _RSEQ_RSEQ_H
15#error "Never use <rseq/arch/riscv.h> directly; include <rseq/rseq.h> instead."
16#endif
17
074b1077
MJ
18/*
19 * Select the instruction "csrw mhartid, x0" as the RSEQ_SIG. Unlike
20 * other architectures, the ebreak instruction has no immediate field for
21 * distinguishing purposes. Hence, ebreak is not suitable as RSEQ_SIG.
22 * "csrw mhartid, x0" can also satisfy the RSEQ requirement because it
23 * is an uncommon instruction and will raise an illegal instruction
24 * exception when executed in all modes.
25 */
26#include <endian.h>
27
28#if defined(__BYTE_ORDER) ? (__BYTE_ORDER == __LITTLE_ENDIAN) : defined(__LITTLE_ENDIAN)
29#define RSEQ_SIG 0xf1401073 /* csrr mhartid, x0 */
30#else
31#error "Currently, RSEQ only supports Little-Endian version"
32#endif
33
c4f3965f
MD
34/*
35 * Instruction selection between 32-bit/64-bit. Used internally in the
36 * rseq headers.
37 */
074b1077 38#if __riscv_xlen == 64
ad5902d4 39#define __RSEQ_ASM_REG_SEL(a, b) a
074b1077 40#elif __riscv_xlen == 32
ad5902d4 41#define __RSEQ_ASM_REG_SEL(a, b) b
074b1077
MJ
42#endif
43
ad5902d4
MD
44#define RSEQ_ASM_REG_L __RSEQ_ASM_REG_SEL("ld ", "lw ")
45#define RSEQ_ASM_REG_S __RSEQ_ASM_REG_SEL("sd ", "sw ")
074b1077 46
c4f3965f
MD
47/*
48 * Refer to the Linux kernel memory model (LKMM) for documentation of
49 * the memory barriers.
50 */
51
52/* Only used internally in rseq headers. */
ad5902d4 53#define RSEQ_ASM_RISCV_FENCE(p, s) \
074b1077 54 __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
c4f3965f 55/* CPU memory barrier. */
ad5902d4 56#define rseq_smp_mb() RSEQ_ASM_RISCV_FENCE(rw, rw)
c4f3965f 57/* CPU read memory barrier */
ad5902d4 58#define rseq_smp_rmb() RSEQ_ASM_RISCV_FENCE(r, r)
c4f3965f 59/* CPU write memory barrier */
ad5902d4 60#define rseq_smp_wmb() RSEQ_ASM_RISCV_FENCE(w, w)
074b1077 61
c4f3965f 62/* Acquire: One-way permeable barrier. */
074b1077
MJ
63#define rseq_smp_load_acquire(p) \
64__extension__ ({ \
3664a718 65 rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
ad5902d4 66 RSEQ_ASM_RISCV_FENCE(r, rw); \
074b1077
MJ
67 ____p1; \
68})
69
c4f3965f 70/* Acquire barrier after control dependency. */
074b1077
MJ
71#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
72
c4f3965f 73/* Release: One-way permeable barrier. */
074b1077
MJ
74#define rseq_smp_store_release(p, v) \
75do { \
ad5902d4 76 RSEQ_ASM_RISCV_FENCE(rw, w); \
826417f6 77 RSEQ_WRITE_ONCE(*(p), v); \
074b1077
MJ
78} while (0)
79
9dc22f84
MD
80#define RSEQ_ASM_U64_PTR(x) ".quad " x
81#define RSEQ_ASM_U32(x) ".long " x
82
c4f3965f
MD
83/* Temporary registers. */
84#define RSEQ_ASM_TMP_REG_1 "t6"
85#define RSEQ_ASM_TMP_REG_2 "t5"
86#define RSEQ_ASM_TMP_REG_3 "t4"
87#define RSEQ_ASM_TMP_REG_4 "t3"
88
89/* Only used in RSEQ_ASM_DEFINE_TABLE. */
074b1077
MJ
90#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
91 post_commit_offset, abort_ip) \
92 ".pushsection __rseq_cs, \"aw\"\n" \
93 ".balign 32\n" \
94 __rseq_str(label) ":\n" \
9dc22f84
MD
95 RSEQ_ASM_U32(__rseq_str(version)) "\n" \
96 RSEQ_ASM_U32(__rseq_str(flags)) "\n" \
97 RSEQ_ASM_U64_PTR(__rseq_str(start_ip)) "\n" \
98 RSEQ_ASM_U64_PTR(__rseq_str(post_commit_offset)) "\n" \
99 RSEQ_ASM_U64_PTR(__rseq_str(abort_ip)) "\n" \
074b1077
MJ
100 ".popsection\n\t" \
101 ".pushsection __rseq_cs_ptr_array, \"aw\"\n" \
9dc22f84 102 RSEQ_ASM_U64_PTR(__rseq_str(label) "b") "\n" \
074b1077
MJ
103 ".popsection\n"
104
c4f3965f
MD
105/*
106 * Define an rseq critical section structure of version 0 with no flags.
107 *
108 * @label:
109 * Local label for the beginning of the critical section descriptor
110 * structure.
111 * @start_ip:
112 * Pointer to the first instruction of the sequence of consecutive assembly
113 * instructions.
114 * @post_commit_ip:
115 * Pointer to the instruction after the last instruction of the sequence of
116 * consecutive assembly instructions.
117 * @abort_ip:
118 * Pointer to the instruction where to move the execution flow in case of
119 * abort of the sequence of consecutive assembly instructions.
120 */
074b1077
MJ
121#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
122 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
d15481d2 123 (post_commit_ip) - (start_ip), abort_ip)
074b1077
MJ
124
125/*
c4f3965f
MD
126 * Define the @exit_ip pointer as an exit point for the sequence of consecutive
127 * assembly instructions at @start_ip.
128 *
129 * @start_ip:
130 * Pointer to the first instruction of the sequence of consecutive assembly
131 * instructions.
132 * @exit_ip:
133 * Pointer to an exit point instruction.
134 *
074b1077
MJ
135 * Exit points of a rseq critical section consist of all instructions outside
136 * of the critical section where a critical section can either branch to or
137 * reach through the normal course of its execution. The abort IP and the
138 * post-commit IP are already part of the __rseq_cs section and should not be
139 * explicitly defined as additional exit points. Knowing all exit points is
140 * useful to assist debuggers stepping over the critical section.
141 */
142#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
143 ".pushsection __rseq_exit_point_array, \"aw\"\n" \
9dc22f84
MD
144 RSEQ_ASM_U64_PTR(__rseq_str(start_ip)) "\n" \
145 RSEQ_ASM_U64_PTR(__rseq_str(exit_ip)) "\n" \
074b1077
MJ
146 ".popsection\n"
147
c4f3965f
MD
148/*
149 * Define a critical section abort handler.
150 *
151 * @label:
152 * Local label to the abort handler.
153 * @teardown:
154 * Sequence of instructions to run on abort.
155 * @abort_label:
156 * C label to jump to at the end of the sequence.
157 */
ebd27573 158#define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
074b1077
MJ
159 "j 222f\n" \
160 ".balign 4\n" \
9dc22f84 161 RSEQ_ASM_U32(__rseq_str(RSEQ_SIG)) "\n" \
074b1077 162 __rseq_str(label) ":\n" \
ebd27573 163 teardown \
074b1077
MJ
164 "j %l[" __rseq_str(abort_label) "]\n" \
165 "222:\n"
166
c4f3965f
MD
167/* Jump to local label @label when @cpu_id != @current_cpu_id. */
168#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
169 RSEQ_INJECT_ASM(1) \
170 "la " RSEQ_ASM_TMP_REG_1 ", " __rseq_str(cs_label) "\n" \
171 RSEQ_ASM_REG_S RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(rseq_cs) "]\n" \
172 __rseq_str(label) ":\n"
173
174/* Store @value to address @var. */
074b1077 175#define RSEQ_ASM_OP_STORE(value, var) \
ad5902d4 176 RSEQ_ASM_REG_S "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
074b1077 177
c4f3965f 178/* Jump to local label @label when @var != @expect. */
769ec9a5 179#define RSEQ_ASM_OP_CBNE(var, expect, label) \
ad5902d4 180 RSEQ_ASM_REG_L RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n" \
074b1077
MJ
181 "bne " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ," \
182 __rseq_str(label) "\n"
183
c4f3965f
MD
184/*
185 * Jump to local label @label when @var != @expect (32-bit register
186 * comparison).
187 */
769ec9a5 188#define RSEQ_ASM_OP_CBNE32(var, expect, label) \
074b1077
MJ
189 "lw " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n" \
190 "bne " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ," \
191 __rseq_str(label) "\n"
192
c4f3965f 193/* Jump to local label @label when @var == @expect. */
769ec9a5 194#define RSEQ_ASM_OP_CBEQ(var, expect, label) \
ad5902d4 195 RSEQ_ASM_REG_L RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n" \
074b1077
MJ
196 "beq " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(expect) "] ," \
197 __rseq_str(label) "\n"
198
c4f3965f 199/* Jump to local label @label when @cpu_id != @current_cpu_id. */
769ec9a5 200#define RSEQ_ASM_CBNE_CPU_ID(cpu_id, current_cpu_id, label) \
074b1077 201 RSEQ_INJECT_ASM(2) \
769ec9a5 202 RSEQ_ASM_OP_CBNE32(current_cpu_id, cpu_id, label)
074b1077 203
c4f3965f 204/* Load @var into temporary register. */
074b1077 205#define RSEQ_ASM_OP_R_LOAD(var) \
ad5902d4 206 RSEQ_ASM_REG_L RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"
074b1077 207
c4f3965f 208/* Store from temporary register into @var. */
074b1077 209#define RSEQ_ASM_OP_R_STORE(var) \
ad5902d4 210 RSEQ_ASM_REG_S RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n"
074b1077 211
c4f3965f 212/* Load from address in temporary register+@offset into temporary register. */
074b1077
MJ
213#define RSEQ_ASM_OP_R_LOAD_OFF(offset) \
214 "add " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(offset) "], " \
215 RSEQ_ASM_TMP_REG_1 "\n" \
ad5902d4 216 RSEQ_ASM_REG_L RSEQ_ASM_TMP_REG_1 ", (" RSEQ_ASM_TMP_REG_1 ")\n"
074b1077 217
c4f3965f 218/* Add @count to temporary register. */
074b1077
MJ
219#define RSEQ_ASM_OP_R_ADD(count) \
220 "add " RSEQ_ASM_TMP_REG_1 ", " RSEQ_ASM_TMP_REG_1 \
221 ", %[" __rseq_str(count) "]\n"
222
c4f3965f
MD
223/*
224 * End-of-sequence store of @value to address @var. Emit
225 * @post_commit_label label after the store instruction.
226 */
074b1077
MJ
227#define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
228 RSEQ_ASM_OP_STORE(value, var) \
229 __rseq_str(post_commit_label) ":\n"
230
c4f3965f
MD
231/*
232 * End-of-sequence store-release of @value to address @var. Emit
233 * @post_commit_label label after the store instruction.
234 */
074b1077
MJ
235#define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label) \
236 "fence rw, w\n" \
237 RSEQ_ASM_OP_STORE(value, var) \
238 __rseq_str(post_commit_label) ":\n"
239
c4f3965f
MD
240/*
241 * End-of-sequence store of temporary register to address @var. Emit
242 * @post_commit_label label after the store instruction.
243 */
074b1077 244#define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
ad5902d4 245 RSEQ_ASM_REG_S RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(var) "]\n" \
074b1077
MJ
246 __rseq_str(post_commit_label) ":\n"
247
c4f3965f
MD
248/*
249 * Copy @len bytes from @src to @dst. This is an inefficient bytewise
250 * copy and could be improved in the future.
251 */
28880e72 252#define RSEQ_ASM_OP_R_BYTEWISE_MEMCPY(dst, src, len) \
074b1077
MJ
253 "beqz %[" __rseq_str(len) "], 333f\n" \
254 "mv " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(len) "]\n" \
255 "mv " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(src) "]\n" \
256 "mv " RSEQ_ASM_TMP_REG_3 ", %[" __rseq_str(dst) "]\n" \
257 "222:\n" \
258 "lb " RSEQ_ASM_TMP_REG_4 ", 0(" RSEQ_ASM_TMP_REG_2 ")\n" \
259 "sb " RSEQ_ASM_TMP_REG_4 ", 0(" RSEQ_ASM_TMP_REG_3 ")\n" \
260 "addi " RSEQ_ASM_TMP_REG_1 ", " RSEQ_ASM_TMP_REG_1 ", -1\n" \
261 "addi " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", 1\n" \
262 "addi " RSEQ_ASM_TMP_REG_3 ", " RSEQ_ASM_TMP_REG_3 ", 1\n" \
263 "bnez " RSEQ_ASM_TMP_REG_1 ", 222b\n" \
264 "333:\n"
265
c4f3965f
MD
266/*
267 * Load pointer address from @ptr. Add @off to offset from this pointer.
268 * Add @inc to the resulting address as an end-of-sequence store.
269 */
bbf6c31a 270#define RSEQ_ASM_OP_R_DEREF_ADDV(ptr, off, inc, post_commit_label) \
074b1077
MJ
271 "mv " RSEQ_ASM_TMP_REG_1 ", %[" __rseq_str(ptr) "]\n" \
272 RSEQ_ASM_OP_R_ADD(off) \
ad5902d4 273 RSEQ_ASM_REG_L RSEQ_ASM_TMP_REG_1 ", 0(" RSEQ_ASM_TMP_REG_1 ")\n" \
074b1077
MJ
274 RSEQ_ASM_OP_R_ADD(inc) \
275 __rseq_str(post_commit_label) ":\n"
276
154b6bde 277/* Per-cpu-id indexing. */
074b1077 278
abf9e855 279#define RSEQ_TEMPLATE_INDEX_CPU_ID
154b6bde 280#define RSEQ_TEMPLATE_MO_RELAXED
44ec21eb 281#include "rseq/arch/riscv/bits.h"
154b6bde 282#undef RSEQ_TEMPLATE_MO_RELAXED
074b1077 283
154b6bde 284#define RSEQ_TEMPLATE_MO_RELEASE
44ec21eb 285#include "rseq/arch/riscv/bits.h"
154b6bde 286#undef RSEQ_TEMPLATE_MO_RELEASE
abf9e855 287#undef RSEQ_TEMPLATE_INDEX_CPU_ID
074b1077 288
154b6bde 289/* Per-mm-cid indexing. */
074b1077 290
abf9e855 291#define RSEQ_TEMPLATE_INDEX_MM_CID
154b6bde 292#define RSEQ_TEMPLATE_MO_RELAXED
44ec21eb 293#include "rseq/arch/riscv/bits.h"
154b6bde
MD
294#undef RSEQ_TEMPLATE_MO_RELAXED
295
296#define RSEQ_TEMPLATE_MO_RELEASE
44ec21eb 297#include "rseq/arch/riscv/bits.h"
154b6bde 298#undef RSEQ_TEMPLATE_MO_RELEASE
abf9e855 299#undef RSEQ_TEMPLATE_INDEX_MM_CID
154b6bde 300
abf9e855 301/* APIs which are not indexed. */
154b6bde 302
abf9e855 303#define RSEQ_TEMPLATE_INDEX_NONE
154b6bde 304#define RSEQ_TEMPLATE_MO_RELAXED
44ec21eb 305#include "rseq/arch/riscv/bits.h"
154b6bde 306#undef RSEQ_TEMPLATE_MO_RELAXED
abf9e855 307#undef RSEQ_TEMPLATE_INDEX_NONE
This page took 0.053862 seconds and 4 git commands to generate.