Pavona Software APIs
memory.h
Go to the documentation of this file.
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#ifndef OPENTITAN_SW_DEVICE_LIB_BASE_MEMORY_H_
6#define OPENTITAN_SW_DEVICE_LIB_BASE_MEMORY_H_
7
8/**
9 * @file
10 * @brief OpenTitan Device Memory Library
11 *
12 * This library provides memory functions for aligned word accesses, and some
13 * useful functions from the C library's <string.h>.
14 */
15
16#include <stdalign.h>
17#include <stddef.h>
18#include <stdint.h>
19
20#ifndef OT_PLATFORM_RV32
21#include <string.h>
22#endif
23
25
26// When compiling unit tests on the host machine, we must mangle the names of
27// OpenTitan's memory functions to disambiguate them from libc's variants.
28// Otherwise, the compiler could error when it encounters conflicting
29// declarations. For instance, OpenTitan's `memcpy()` could have a different
30// exception specifier than the one declared by the system header <string.h>.
31// (The <string.h> include is unavoidable because it's pulled in by GoogleTest.)
32//
33// Consumers of this header should almost always call the unmangled functions.
34// Device builds will naturally use OpenTitan's definitions and host builds will
35// use the system's definitions. However, nothing is stopping host builds from
36// calling the mangled function names; see :memory_unittest for an example.
37//
38// Separately, ASan segfaults during initialization when it calls our
39// user-defined memory functions. Prefixing the troublesome functions works
40// around this ASan bug, enabling us to run the unit tests with ASan enabled.
41// See https://github.com/lowRISC/opentitan/issues/13826.
42#ifdef OT_PLATFORM_RV32
43#define OT_PREFIX_IF_NOT_RV32(name) name
44#else
45#define OT_PREFIX_IF_NOT_RV32(name) ot_##name
46#endif
47
48#ifdef __cplusplus
49extern "C" {
50#endif // __cplusplus
51
52/**
53 * Computes how many bytes `addr` is ahead of the previous 32-bit word alignment
54 * boundary.
55 */
57inline ptrdiff_t misalignment32_of(uintptr_t addr) {
58 return addr % alignof(uint32_t);
59}
60
61/**
62 * Load a word from memory directly, bypassing aliasing rules.
63 *
64 * ISO C forbids, in general, casting a pointer to non-character types and
65 * reading them, though it is frequently necessary to read exactly one word out
66 * of a `void *`. This function performs that action in a manner which is
67 * well-defined.
68 *
69 * Of course, `ptr` must point to word-aligned memory that is at least one word
70 * wide. To do otherwise is Undefined Behavior. It goes without saying that the
71 * memory this function intents to read must be initialized.
72 *
73 * This function has reordering properties as weak as a normal, non-atomic,
74 * non-volatile load.
75 *
76 * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
77 * @return the word `ptr` points to.
78 */
80inline uint32_t read_32(const void *ptr) {
81 // Both GCC and Clang optimize the code below into a single word-load on most
82 // platforms. It is necessary and sufficient to indicate to the compiler that
83 // the pointer points to four bytes of four-byte-aligned memory.
84 //
85 // Failing to get that particular codegen in either GCC or Clang with -O2 or
86 // -Os set shall be considered a bug in this function. The same applies to
87 // `write32()`.
88 ptr = __builtin_assume_aligned(ptr, alignof(uint32_t));
89 uint32_t val;
90 __builtin_memcpy(&val, ptr, sizeof(uint32_t));
91 return val;
92}
93
94/**
95 * Load a 64-bit word from memory directly, bypassing aliasing rules.
96 *
97 * ISO C forbids, in general, casting a pointer to non-character types and
98 * reading them, though it is frequently necessary to read exactly one 64-bit
99 * word out of a `void *`. This function performs that action in a manner which
100 * is well-defined.
101 *
102 * Of course, `ptr` must point to word-aligned memory that is at least one
103 * 64-bit word wide. To do otherwise is Undefined Behavior. It goes without
104 * saying that the memory this function intents to read must be initialized.
105 *
106 * This function has reordering properties as weak as a normal, non-atomic,
107 * non-volatile load.
108 *
109 * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
110 * @return the word `ptr` points to.
111 */
113inline uint64_t read_64(const void *ptr) {
114 // Both GCC and Clang optimize the code below into a single word-load on most
115 // platforms. It is necessary and sufficient to indicate to the compiler that
116 // the pointer points to four bytes of four-byte-aligned memory.
117 //
118 // Failing to get that particular codegen in either GCC or Clang with -O2 or
119 // -Os set shall be considred a bug in this function. The same applies to
120 // `write32()`.
121 ptr = __builtin_assume_aligned(ptr, alignof(uint64_t));
122 uint64_t val;
123 __builtin_memcpy(&val, ptr, sizeof(uint64_t));
124 return val;
125}
126
127/**
128 * Store a word to memory directly, bypassing aliasing rules.
129 *
130 * ISO C forbids, in general, casting a pointer to non-character types and
131 * reading them, though it is frequently necessary to write exactly one word to
132 * a `void *`. This function performs that action in a manner which is
133 * well-defined.
134 *
135 * Of course, `ptr` must point to word-aligned memory that is at least one word
136 * wide. To do otherwise is Undefined Behavior.
137 *
138 * This function has reordering properties as weak as a normal, non-atomic,
139 * non-volatile load.
140 *
141 * @param value the value to store.
142 * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
143 */
144inline void write_32(uint32_t value, void *ptr) {
145 // Both GCC and Clang optimize the code below into a single word-store on most
146 // platforms. See the comment in `read_32()` for more implementation-private
147 // information.
148 ptr = __builtin_assume_aligned(ptr, alignof(uint32_t));
149 __builtin_memcpy(ptr, &value, sizeof(uint32_t));
150}
151
152/**
153 * Store a 64-bit word to memory directly, bypassing aliasing rules.
154 *
155 * ISO C forbids, in general, casting a pointer to non-character types and
156 * reading them, though it is frequently necessary to write exactly one 64-bit
157 * word to a `void *`. This function performs that action in a manner which is
158 * well-defined.
159 *
160 * Of course, `ptr` must point to word-aligned memory that is at least one
161 * 64-bit word wide. To do otherwise is Undefined Behavior.
162 *
163 * This function has reordering properties as weak as a normal, non-atomic,
164 * non-volatile load.
165 *
166 * @param value the value to store.
167 * @param ptr a word-aligned pointer pointed to at least four bytes of memory.
168 */
169
170inline void write_64(uint64_t value, void *ptr) {
171 // Both GCC and Clang optimize the code below into a single word-store on most
172 // platforms. See the comment in `read_64()` for more implementation-private
173 // information.
174 ptr = __builtin_assume_aligned(ptr, alignof(uint64_t));
175 __builtin_memcpy(ptr, &value, sizeof(uint64_t));
176}
177
178/**
179 * Copy memory between non-overlapping regions.
180 *
181 * This function conforms to the semantics defined in ISO C11 S7.23.2.1.
182 *
183 * This function will be provided by the platform's libc implementation for host
184 * builds.
185 *
186 * @param dest the region to copy to.
187 * @param src the region to copy from.
188 * @param len the number of bytes to copy.
189 * @return the value of `dest`.
190 */
192void *OT_PREFIX_IF_NOT_RV32(memcpy)(void *OT_RESTRICT dest,
193 const void *OT_RESTRICT src, size_t len);
194
195/**
196 * Set a region of memory to a particular byte value.
197 *
198 * This function conforms to the semantics defined in ISO C11 S7.23.6.1.
199 *
200 * This function will be provided by the platform's libc implementation for host
201 * builds.
202 *
203 * @param dest the region to write to.
204 * @param value the value, converted to a byte, to write to each byte cell.
205 * @param len the number of bytes to write.
206 * @return the value of `dest`.
207 */
209void *OT_PREFIX_IF_NOT_RV32(memset)(void *dest, int value, size_t len);
210
211/**
212 * Compare two (potentially overlapping) regions of memory for byte-wise
213 * lexicographic order.
214 *
215 * This function conforms to the semantics defined in ISO C11 S7.24.4.1.
216 *
217 * This function will be provided by the platform's libc implementation for host
218 * builds.
219 *
220 * @param lhs the left-hand-side of the comparison.
221 * @param rhs the right-hand-side of the comparison.
222 * @param len the length of both regions, in bytes.
223 * @return a zero, positive, or negative integer, corresponding to the
224 * contingencies of `lhs == rhs`, `lhs > rhs`, and `lhs < rhs` (as buffers, not
225 * pointers), respectively.
226 */
228int OT_PREFIX_IF_NOT_RV32(memcmp)(const void *lhs, const void *rhs, size_t len);
229
230/**
231 * Compare two (potentially overlapping) regions of memory for reverse
232 * byte-wise lexicographic order (i.e. the same as memcmp, but starting from
233 * the end of the memory regions).
234 *
235 * Can be used for arithmetic comparison of little-endian buffers.
236 *
237 * This function is provided by OpenTitan in host builds, not by the platform's
238 * libc implementation.
239 *
240 * @param lhs the left-hand-side of the comparison.
241 * @param rhs the right-hand-side of the comparison.
242 * @param len the length of both regions, in bytes.
243 * @return a zero, positive, or negative integer, corresponding to the
244 * contingencies of `lhs == rhs`, `lhs > rhs`, and `lhs < rhs` (as buffers, not
245 * pointers), respectively.
246 */
248int memrcmp(const void *lhs, const void *rhs, size_t len);
249
250/**
251 * Search a region of memory for the first occurrence of a particular byte
252 * value.
253 *
254 * This function conforms to the semantics defined in ISO C11 S7.24.5.1.
255 *
256 * Since libbase does not provide a `strlen()` function, this function can be
257 * used as an approximation: `memchr(my_str, 0, SIZE_MAX) - my_str`.
258 *
259 * This function will be provided by the platform's libc implementation for host
260 * builds.
261 *
262 * @param ptr the region to search.
263 * @param value the value, converted to a byte, to search for.
264 * @param len the length of the region, in bytes.
265 * @return a pointer to the found value, or NULL.
266 */
268void *OT_PREFIX_IF_NOT_RV32(memchr)(const void *ptr, int value, size_t len);
269
270/**
271 * Search a region of memory for the last occurrence of a particular byte value.
272 *
273 * This function is not specified by C11, but is named for a well-known glibc
274 * extension.
275 *
276 * @param ptr the region to search.
277 * @param value the value, converted to a byte, to search for.
278 * @param len the length of the region, in bytes.
279 * @return a pointer to the found value, or NULL.
280 */
282void *OT_PREFIX_IF_NOT_RV32(memrchr)(const void *ptr, int value, size_t len);
283
284#ifdef __cplusplus
285} // extern "C"
286#endif // __cplusplus
287
288#undef OT_PREFIX_IF_NOT_RV32
289
290#endif // OPENTITAN_SW_DEVICE_LIB_BASE_MEMORY_H_