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 */
191void *OT_PREFIX_IF_NOT_RV32(memcpy)(void *OT_RESTRICT dest,
192 const void *OT_RESTRICT src, size_t len);
193
194/**
195 * Set a region of memory to a particular byte value.
196 *
197 * This function conforms to the semantics defined in ISO C11 S7.23.6.1.
198 *
199 * This function will be provided by the platform's libc implementation for host
200 * builds.
201 *
202 * @param dest the region to write to.
203 * @param value the value, converted to a byte, to write to each byte cell.
204 * @param len the number of bytes to write.
205 * @return the value of `dest`.
206 */
207void *OT_PREFIX_IF_NOT_RV32(memset)(void *dest, int value, size_t len);
208
209/**
210 * Compare two (potentially overlapping) regions of memory for byte-wise
211 * lexicographic order.
212 *
213 * This function conforms to the semantics defined in ISO C11 S7.24.4.1.
214 *
215 * This function will be provided by the platform's libc implementation for host
216 * builds.
217 *
218 * @param lhs the left-hand-side of the comparison.
219 * @param rhs the right-hand-side of the comparison.
220 * @param len the length of both regions, in bytes.
221 * @return a zero, positive, or negative integer, corresponding to the
222 * contingencies of `lhs == rhs`, `lhs > rhs`, and `lhs < rhs` (as buffers, not
223 * pointers), respectively.
224 */
225int OT_PREFIX_IF_NOT_RV32(memcmp)(const void *lhs, const void *rhs, size_t len);
226
227/**
228 * Compare two (potentially overlapping) regions of memory for reverse
229 * byte-wise lexicographic order (i.e. the same as memcmp, but starting from
230 * the end of the memory regions).
231 *
232 * Can be used for arithmetic comparison of little-endian buffers.
233 *
234 * This function is provided by OpenTitan in host builds, not by the platform's
235 * libc implementation.
236 *
237 * @param lhs the left-hand-side of the comparison.
238 * @param rhs the right-hand-side of the comparison.
239 * @param len the length of both regions, in bytes.
240 * @return a zero, positive, or negative integer, corresponding to the
241 * contingencies of `lhs == rhs`, `lhs > rhs`, and `lhs < rhs` (as buffers, not
242 * pointers), respectively.
243 */
244int memrcmp(const void *lhs, const void *rhs, size_t len);
245
246/**
247 * Search a region of memory for the first occurrence of a particular byte
248 * value.
249 *
250 * This function conforms to the semantics defined in ISO C11 S7.24.5.1.
251 *
252 * Since libbase does not provide a `strlen()` function, this function can be
253 * used as an approximation: `memchr(my_str, 0, SIZE_MAX) - my_str`.
254 *
255 * This function will be provided by the platform's libc implementation for host
256 * builds.
257 *
258 * @param ptr the region to search.
259 * @param value the value, converted to a byte, to search for.
260 * @param len the length of the region, in bytes.
261 * @return a pointer to the found value, or NULL.
262 */
263void *OT_PREFIX_IF_NOT_RV32(memchr)(const void *ptr, int value, size_t len);
264
265/**
266 * Search a region of memory for the last occurrence of a particular byte value.
267 *
268 * This function is not specified by C11, but is named for a well-known glibc
269 * extension.
270 *
271 * @param ptr the region to search.
272 * @param value the value, converted to a byte, to search for.
273 * @param len the length of the region, in bytes.
274 * @return a pointer to the found value, or NULL.
275 */
276void *OT_PREFIX_IF_NOT_RV32(memrchr)(const void *ptr, int value, size_t len);
277
278#ifdef __cplusplus
279} // extern "C"
280#endif // __cplusplus
281
282#undef OT_PREFIX_IF_NOT_RV32
283
284#endif // OPENTITAN_SW_DEVICE_LIB_BASE_MEMORY_H_