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
49 extern "C" {
50 #endif // __cplusplus
51 
52 /**
53  * Computes how many bytes `addr` is ahead of the previous 32-bit word alignment
54  * boundary.
55  */
57 inline 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  */
80 inline 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  */
113 inline 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  */
144 inline 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 
170 inline 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  */
191 void *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  */
207 void *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  */
225 int 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  */
244 int 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  */
263 void *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  */
276 void *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_