Skip to content

Commit 4fae60d

Browse files
committed
util: Add mmio helpers functions for riscv
Fix the issue where using intrinsics to generate atomic load/store instructions on RISC-V caused SEGFAULT when accessing MMIO regions, by adding a RISC-V specific implementation to resolve the problem. Signed-off-by: Zheng Zhang <[email protected]>
1 parent 7a04b9e commit 4fae60d

File tree

2 files changed

+251
-2
lines changed

2 files changed

+251
-2
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
From 6a3b608fb2e68b51f596ed6ff7d0b2f9e79d07ee Mon Sep 17 00:00:00 2001
2+
From: Zheng Zhang <[email protected]>
3+
Date: Fri, 29 Aug 2025 16:48:21 +0800
4+
Subject: [PATCH] util: Add mmio helpers functions for riscv
5+
6+
Fix the issue where using intrinsics to generate
7+
atomic load/store instructions on RISC-V caused
8+
SEGFAULT when accessing MMIO regions, by adding
9+
a RISC-V specific implementation to resolve the
10+
problem.
11+
12+
Signed-off-by: Zheng Zhang <[email protected]>
13+
---
14+
util/mmio.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++--
15+
1 file changed, 97 insertions(+), 2 deletions(-)
16+
17+
diff --git a/util/mmio.h b/util/mmio.h
18+
index 9af35099d..e0a6c1398 100644
19+
--- a/util/mmio.h
20+
+++ b/util/mmio.h
21+
@@ -124,7 +124,53 @@ static inline uint8_t mmio_read8(const void *addr)
22+
return res;
23+
}
24+
25+
-#else /* __s390x__ */
26+
+#elif defined(__riscv)
27+
+
28+
+#define MAKE_WRITE(_NAME_, _SZ_) \
29+
+ static inline void _NAME_##_be(void *addr, __be##_SZ_ val) \
30+
+ { \
31+
+ __atomic_thread_fence(__ATOMIC_RELEASE); \
32+
+ *(uint##_SZ_##_t *)addr = (uint##_SZ_##_t) val; \
33+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST); \
34+
+ } \
35+
+ static inline void _NAME_##_le(void *addr, __le##_SZ_ val) \
36+
+ { \
37+
+ __atomic_thread_fence(__ATOMIC_RELEASE); \
38+
+ *(uint##_SZ_##_t *)addr = (uint##_SZ_##_t) val; \
39+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST); \
40+
+ }
41+
+
42+
+#define MAKE_READ(_NAME_, _SZ_) \
43+
+ static inline __be##_SZ_ _NAME_##_be(const void *addr) \
44+
+ { \
45+
+ __atomic_thread_fence(__ATOMIC_RELEASE); \
46+
+ __be##_SZ_ val = *(uint##_SZ_##_t *)addr; \
47+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST); \
48+
+ return val; \
49+
+ } \
50+
+ static inline __le##_SZ_ _NAME_##_le(const void *addr) \
51+
+ { \
52+
+ __atomic_thread_fence(__ATOMIC_RELEASE); \
53+
+ __le##_SZ_ val = *(uint##_SZ_##_t *)addr; \
54+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST); \
55+
+ return val; \
56+
+ }
57+
+
58+
+static inline void mmio_write8(void *addr, uint8_t val)
59+
+{
60+
+ __atomic_thread_fence(__ATOMIC_RELEASE);
61+
+ *(uint8_t *)addr = val;
62+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST);
63+
+}
64+
+static inline uint8_t mmio_read8(const void *addr)
65+
+{
66+
+ __atomic_thread_fence(__ATOMIC_RELEASE);
67+
+ uint8_t val = *(uint8_t *)addr;
68+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST);
69+
+ return val;
70+
+}
71+
+
72+
+#else
73+
74+
#define MAKE_WRITE(_NAME_, _SZ_) \
75+
static inline void _NAME_##_be(void *addr, __be##_SZ_ value) \
76+
@@ -161,7 +207,7 @@ static inline uint8_t mmio_read8(const void *addr)
77+
return atomic_load_explicit((_Atomic(uint8_t) *)addr,
78+
memory_order_relaxed);
79+
}
80+
-#endif /* __s390x__ */
81+
+#endif
82+
83+
MAKE_WRITE(mmio_write16, 16)
84+
MAKE_WRITE(mmio_write32, 32)
85+
@@ -170,8 +216,10 @@ MAKE_READ(mmio_read16, 16)
86+
MAKE_READ(mmio_read32, 32)
87+
88+
#if SIZEOF_LONG == 8
89+
+
90+
MAKE_WRITE(mmio_write64, 64)
91+
MAKE_READ(mmio_read64, 64)
92+
+
93+
#else
94+
void mmio_write64_be(void *addr, __be64 val);
95+
static inline void mmio_write64_le(void *addr, __le64 val)
96+
@@ -234,6 +282,53 @@ static inline void _mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)
97+
})
98+
#elif defined(__s390x__)
99+
void mmio_memcpy_x64(void *dst, const void *src, size_t bytecnt);
100+
+#elif defined(__riscv)
101+
+static inline void _mmio_memcpy_x64_64b(void *dest, const void *src)
102+
+{
103+
+#if defined(__riscv_vector)
104+
+ const uint64_t *s = (const uint64_t *)src;
105+
+ uint64_t *d = (uint64_t *)dest;
106+
+ size_t n = 8;
107+
+
108+
+ while (n) {
109+
+ __atomic_thread_fence(__ATOMIC_RELEASE);
110+
+ size_t vl = vsetvl_e64m1(n);
111+
+ vuint64m1_t v = vle64_v_u64m1(s, vl);
112+
+ vse64_v_u64m1(d, v, vl);
113+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST);
114+
+ s += vl;
115+
+ d += vl;
116+
+ n -= vl;
117+
+ }
118+
+#else
119+
+ const uint64_t *s = (const uint64_t *)src;
120+
+ uint64_t *d = (uint64_t *)dest;
121+
+ __atomic_thread_fence(__ATOMIC_RELEASE);
122+
+ for (int i = 0; i < 8; i++)
123+
+ d[i] = s[i];
124+
+ __atomic_thread_fence(__ATOMIC_SEQ_CST);
125+
+#endif
126+
+}
127+
+
128+
+static inline void _mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)
129+
+{
130+
+ const char *s = (const char *)src;
131+
+ char *d = (char *)dest;
132+
+ do {
133+
+ _mmio_memcpy_x64_64b(d, s);
134+
+ bytecnt -= 64;
135+
+ s += 64;
136+
+ d += 64;
137+
+ } while (bytecnt > 0);
138+
+}
139+
+
140+
+#define mmio_memcpy_x64(dest, src, bytecount) \
141+
+ ({ \
142+
+ if (__builtin_constant_p((bytecount) == 64)) \
143+
+ _mmio_memcpy_x64_64b((dest), (src)); \
144+
+ else \
145+
+ _mmio_memcpy_x64((dest), (src), (bytecount)); \
146+
+ })
147+
#else
148+
/* Transfer is some multiple of 64 bytes */
149+
static inline void mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)
150+
--
151+
2.50.1
152+

util/mmio.h

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,55 @@ static inline uint8_t mmio_read8(const void *addr)
124124
return res;
125125
}
126126

127-
#else /* __s390x__ */
127+
#elif defined(__riscv)
128+
#define __MMIO_LE_TYPE(sz) __le##sz
129+
#define __MMIO_BE_TYPE(sz) __be##sz
130+
131+
#define MAKE_WRITE(_NAME_, _SZ_) \
132+
static inline void _NAME_##_be(void *addr, __MMIO_BE_TYPE(_SZ_) val) \
133+
{ \
134+
__atomic_thread_fence(__ATOMIC_RELEASE); \
135+
*(volatile uint##_SZ_##_t *)addr = (uint##_SZ_##_t) val; \
136+
__atomic_thread_fence(__ATOMIC_SEQ_CST); \
137+
} \
138+
static inline void _NAME_##_le(void *addr, __MMIO_LE_TYPE(_SZ_) val) \
139+
{ \
140+
__atomic_thread_fence(__ATOMIC_RELEASE); \
141+
*(volatile uint##_SZ_##_t *)addr = (uint##_SZ_##_t) val; \
142+
__atomic_thread_fence(__ATOMIC_SEQ_CST); \
143+
}
144+
145+
#define MAKE_READ(_NAME_, _SZ_) \
146+
static inline __MMIO_BE_TYPE(_SZ_) _NAME_##_be(const void *addr) \
147+
{ \
148+
__atomic_thread_fence(__ATOMIC_RELEASE); \
149+
__MMIO_BE_TYPE(_SZ_) val = *(const uint##_SZ_##_t *)addr; \
150+
__atomic_thread_fence(__ATOMIC_SEQ_CST); \
151+
return val; \
152+
} \
153+
static inline __MMIO_LE_TYPE(_SZ_) _NAME_##_le(const void *addr) \
154+
{ \
155+
__atomic_thread_fence(__ATOMIC_RELEASE); \
156+
__MMIO_LE_TYPE(_SZ_) val = *(const uint##_SZ_##_t *)addr; \
157+
__atomic_thread_fence(__ATOMIC_SEQ_CST); \
158+
return val; \
159+
}
160+
161+
static inline void mmio_write8(void *addr, uint8_t val)
162+
{
163+
__atomic_thread_fence(__ATOMIC_RELEASE);
164+
*(uint8_t *)addr = val;
165+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
166+
}
167+
static inline uint8_t mmio_read8(const void *addr)
168+
{
169+
__atomic_thread_fence(__ATOMIC_RELEASE);
170+
uint8_t val = *(uint8_t *)addr;
171+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
172+
return val;
173+
}
174+
175+
#else
128176

129177
#define MAKE_WRITE(_NAME_, _SZ_) \
130178
static inline void _NAME_##_be(void *addr, __be##_SZ_ value) \
@@ -161,7 +209,7 @@ static inline uint8_t mmio_read8(const void *addr)
161209
return atomic_load_explicit((_Atomic(uint8_t) *)addr,
162210
memory_order_relaxed);
163211
}
164-
#endif /* __s390x__ */
212+
#endif
165213

166214
MAKE_WRITE(mmio_write16, 16)
167215
MAKE_WRITE(mmio_write32, 32)
@@ -170,8 +218,10 @@ MAKE_READ(mmio_read16, 16)
170218
MAKE_READ(mmio_read32, 32)
171219

172220
#if SIZEOF_LONG == 8
221+
173222
MAKE_WRITE(mmio_write64, 64)
174223
MAKE_READ(mmio_read64, 64)
224+
175225
#else
176226
void mmio_write64_be(void *addr, __be64 val);
177227
static inline void mmio_write64_le(void *addr, __le64 val)
@@ -234,6 +284,53 @@ static inline void _mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)
234284
})
235285
#elif defined(__s390x__)
236286
void mmio_memcpy_x64(void *dst, const void *src, size_t bytecnt);
287+
#elif defined(__riscv)
288+
static inline void _mmio_memcpy_x64_64b(void *dest, const void *src)
289+
{
290+
#if defined(__riscv_vector)
291+
const uint64_t *s = (const uint64_t *)src;
292+
volatile uint64_t *d = (uint64_t *)dest;
293+
size_t n = 8;
294+
295+
while (n) {
296+
__atomic_thread_fence(__ATOMIC_RELEASE);
297+
size_t vl = vsetvl_e64m1(n);
298+
vuint64m1_t v = vle64_v_u64m1(s, vl);
299+
vse64_v_u64m1(d, v, vl);
300+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
301+
s += vl;
302+
d += vl;
303+
n -= vl;
304+
}
305+
#else
306+
const uint64_t *s = (const uint64_t *)src;
307+
volatile uint64_t *d = (uint64_t *)dest;
308+
__atomic_thread_fence(__ATOMIC_RELEASE);
309+
for (int i = 0; i < 8; i++)
310+
d[i] = s[i];
311+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
312+
#endif
313+
}
314+
315+
static inline void _mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)
316+
{
317+
const char *s = (const char *)src;
318+
char *d = (char *)dest;
319+
do {
320+
_mmio_memcpy_x64_64b(d, s);
321+
bytecnt -= 64;
322+
s += 64;
323+
d += 64;
324+
} while (bytecnt > 0);
325+
}
326+
327+
#define mmio_memcpy_x64(dest, src, bytecount) \
328+
({ \
329+
if (__builtin_constant_p((bytecount) == 64)) \
330+
_mmio_memcpy_x64_64b((dest), (src)); \
331+
else \
332+
_mmio_memcpy_x64((dest), (src), (bytecount)); \
333+
})
237334
#else
238335
/* Transfer is some multiple of 64 bytes */
239336
static inline void mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt)

0 commit comments

Comments
 (0)