[sw] Move our memory operation functions into lib/base. This change also introduces read_32() and write_32(), for doing direct word manipulation without violating strict alising. These functions will be useful for DIF implementations. Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/lib/abort.c b/sw/device/lib/abort.c deleted file mode 100644 index 2185f8b..0000000 --- a/sw/device/lib/abort.c +++ /dev/null
@@ -1,11 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include "sw/device/lib/common.h" - -_Noreturn void abort(void) { - while (true) { - asm volatile("wfi;"); - } -}
diff --git a/sw/device/lib/base/memory.c b/sw/device/lib/base/memory.c new file mode 100644 index 0000000..d403989 --- /dev/null +++ b/sw/device/lib/base/memory.c
@@ -0,0 +1,32 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/lib/base/memory.h" + +extern uint32_t read_32(void *); +extern void write_32(uint32_t, void *); + +void *memcpy(void *restrict dest, const void *restrict src, size_t len) { + uint8_t *dest8 = (uint8_t *)dest; + uint8_t *src8 = (uint8_t *)src; + for (size_t i = 0; i < len; ++i) { + dest8[i] = src8[i]; + } + return dest; +} + +void *memset(void *dest, int value, size_t len) { + uint8_t *dest8 = (uint8_t *)dest; + uint8_t value8 = (uint8_t)value; + for (size_t i = 0; i < len; ++i) { + dest8[i] = value8; + } + return dest; +} + +noreturn void abort(void) { + while (true) { + asm volatile("wfi"); + } +}
diff --git a/sw/device/lib/base/memory.h b/sw/device/lib/base/memory.h new file mode 100644 index 0000000..bf1d280 --- /dev/null +++ b/sw/device/lib/base/memory.h
@@ -0,0 +1,107 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef SW_DEVICE_LIB_BASE_MEMORY_H_ +#define SW_DEVICE_LIB_BASE_MEMORY_H_ + +#include <stdalign.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdnoreturn.h> + +#include "sw/device/lib/base/stdasm.h" + +/** + * Load a word from memory directly, bypassing aliasing rules. + * + * ISO C forbids, in general, casting a pointer to non-character types and + * reading them, though it is frequently necessary to read exactly one word out + * of a |void *|. This function performs that action in a manner which is + * well-defined. + * + * Of course, |ptr| must point to word-aligned memory that is at least one word + * wide. To do otherwise is Undefined Behavior. It goes eithout saying that the + * memory this function intents to read must be initialized. + * + * This function has reordering properties as weak as a normal, non-atomic, + * non-volatile load. + * + * @param ptr a word-aligned pointer pointed to at least four bytes of memory. + * @return the word |ptr| points to. + */ +inline uint32_t read_32(void *ptr) { + // Both GCC and Clang optimize the code below into a single word-load on most + // platforms. It is necessary and sufficient to indicate to the compiler that + // the pointer points to four bytes of four-byte-aligned memory. + // + // Failing to get that particular codegen in either GCC or Clang with -O2 or + // -Os set shall be considred a bug in this function. The same applies to + // |write32()|. + ptr = __builtin_assume_aligned(ptr, alignof(uint32_t)); + uint32_t val; + __builtin_memcpy(&val, ptr, sizeof(uint32_t)); + return val; +} + +/** + * Store a word to memory directly, bypassing aliasing rules. + * + * ISO C forbids, in general, casting a pointer to non-character types and + * reading them, though it is frequently necessary to write exactly one word to + * a |void *|. This function performs that action in a manner which is + * well-defined. + * + * Of course, |ptr| must point to word-aligned memory that is at least one word + * wide. To do otherwise is Undefined Behavior. + * + * This function has reordering properties as weak as a normal, non-atomic, + * non-volatile load. + * + * @param value the value to store. + * @param ptr a word-aligned pointer pointed to at least four bytes of memory. + */ +inline void write_32(uint32_t value, void *ptr) { + // Both GCC and Clang optimize the code below into a single word-store on most + // platforms. See the comment in |read_32()| for more implementation-private + // information. + ptr = __builtin_assume_aligned(ptr, alignof(uint32_t)); + __builtin_memcpy(ptr, &value, sizeof(uint32_t)); +} + +/** + * Copy memory between non-overlapping regions. + * + * This function conforms to the semantics defined in ISO C11 S7.23.2.1. + * + * @param dest the region to copy to. + * @param src the region to copy from. + * @param len the number of bytes to copy. + * @return the value of |dest|. + */ +void *memcpy(void *restrict dest, const void *restrict src, size_t len); + +/** + * Set a region of memory to a particular byte value. + * + * This function conforms to the semantics defined in ISO C11 S7.23.6.1. + * + * @param dest the region to write to. + * @param value the value, converted to a byte, to write to each byte cell. + * @param len the number of bytes to write. + * #return the value of |dest|. + */ +void *memset(void *dest, int value, size_t len); + +// TODO: Find a better header for this function to live. See #1207. +/** + * Immediately halt program execution. + * + * This function conforms to the semantics defined in ISO C11 S7.22.4.1, except + * that it cannot be pre-empted by signal handlers (which do not exist in this + * environment). + */ +noreturn void abort(void); + +#endif // SW_DEVICE_LIB_BASE_MEMORY_H_
diff --git a/sw/device/lib/base/meson.build b/sw/device/lib/base/meson.build new file mode 100644 index 0000000..0beab29 --- /dev/null +++ b/sw/device/lib/base/meson.build
@@ -0,0 +1,13 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Memory Operations library (sw_lib_mem) +sw_lib_mem = declare_dependency( + link_with: static_library( + 'mem_ot', + sources: ['memory.c'], + c_args: ['-fno-builtin'], + ) +) +
diff --git a/sw/device/lib/common.h b/sw/device/lib/common.h index 1aa2b30..8ef1c51 100644 --- a/sw/device/lib/common.h +++ b/sw/device/lib/common.h
@@ -11,6 +11,7 @@ #include <stdnoreturn.h> #include "sw/device/lib/base/stdasm.h" +#include "sw/device/lib/base/memory.h" #ifdef SIMULATION #define CLK_FIXED_FREQ_HZ (500 * 1000) @@ -45,9 +46,4 @@ #define BITLENGTH(X) \ ((BITLENGTH_5(BITLENGTH_4(BITLENGTH_3(BITLENGTH_2(BITLENGTH_1(X)))))) & 0x7f) -void *memcpy(void *restrict dest, const void *restrict src, size_t n); -void *memset(void *dest, int val, size_t n); - -void abort(void); - #endif
diff --git a/sw/device/lib/memcpy.c b/sw/device/lib/memcpy.c deleted file mode 100644 index 8fd7401..0000000 --- a/sw/device/lib/memcpy.c +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include "sw/device/lib/common.h" - -void *memcpy(void *dest, const void *src, size_t n) { - char *dest_c = (char *)dest; - char *src_c = (char *)src; - - for (; n > 0; n--) { - *dest_c++ = *src_c++; - } - - return dest; -}
diff --git a/sw/device/lib/memset.c b/sw/device/lib/memset.c deleted file mode 100644 index 36150b0..0000000 --- a/sw/device/lib/memset.c +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -#include "sw/device/lib/common.h" - -void *memset(void *dest, int val, size_t n) { - char *dest_c = (char *)dest; - - for (; n > 0; n--) { - *dest_c++ = (char)val; - } - - return dest; -}
diff --git a/sw/device/lib/meson.build b/sw/device/lib/meson.build index 6c29b60..bd88345 100644 --- a/sw/device/lib/meson.build +++ b/sw/device/lib/meson.build
@@ -2,20 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -# Memory Operations library (sw_lib_mem) -sw_lib_mem = declare_dependency( - link_with: static_library( - 'mem_ot', - sources: [ - 'memcpy.c', - 'memset.c', - 'abort.c', - ], - c_args: [ - '-fno-builtin', - ], - ) -) +subdir('base') # UART library (sw_lib_uart) sw_lib_uart = declare_dependency(