| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| #ifndef OPENTITAN_SW_DEVICE_LIB_BASE_MACROS_H_ | |
| #define OPENTITAN_SW_DEVICE_LIB_BASE_MACROS_H_ | |
| // This file may be used in .S files, in which case standard library includes | |
| // should be elided. | |
| #if !defined(__ASSEMBLER__) && !defined(NOSTDINC) | |
| #include <assert.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #endif | |
| /** | |
| * @file | |
| * @brief Generic preprocessor macros that don't really fit anywhere else. | |
| */ | |
| /** | |
| * Computes the number of elements in the given array. | |
| * | |
| * Note that this can only determine the length of *fixed-size* arrays. Due to | |
| * limitations of C, it will incorrectly compute the size of an array passed as | |
| * a function argument, because those automatically decay into pointers. This | |
| * function can only be used correctly with: | |
| * - Arrays declared as stack variables. | |
| * - Arrays declared at global scope. | |
| * - Arrays that are members of a struct or union. | |
| * | |
| * @param array The array expression to measure. | |
| * @return The number of elements in the array, as a `size_t`. | |
| */ | |
| // This is a sufficiently well-known macro that we don't really need to bother | |
| // with a prefix like the others, and a rename will cause churn. | |
| #define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0])) | |
| /** | |
| * An annotation that a switch/case fallthrough is the intended behavior. | |
| */ | |
| #define OT_FALLTHROUGH_INTENDED __attribute__((fallthrough)) | |
| /** | |
| * A directive to force the compiler to inline a function. | |
| */ | |
| #define OT_ALWAYS_INLINE __attribute__((always_inline)) inline | |
| /** | |
| * The `restrict` keyword is C specific, so we provide a C++-portable wrapper | |
| * that uses the GCC name. | |
| * | |
| * It only needs to be used in headers; .c files can use `restrict` directly. | |
| */ | |
| #define OT_RESTRICT __restrict__ | |
| /** | |
| * An argument stringification macro. | |
| */ | |
| #define OT_STRINGIFY(a) OT_STRINGIFY_(a) | |
| #define OT_STRINGIFY_(a) #a | |
| /** | |
| * A variable-argument macro that expands to the number of arguments passed into | |
| * it, between 0 and 31 arguments. | |
| * | |
| * This macro is based off of a well-known preprocessor trick. This | |
| * StackOverflow post expains the trick in detail: | |
| * https://stackoverflow.com/questions/2308243/macro-returning-the-number-of-arguments-it-is-given-in-c | |
| * TODO #2026: a dummy token is required for this to work correctly. | |
| * | |
| * @param dummy a dummy token that is required to be passed for the calculation | |
| * to work correctly. | |
| * @param ... the variable args list. | |
| */ | |
| #define OT_VA_ARGS_COUNT(dummy, ...) \ | |
| OT_SHIFT_N_VARIABLE_ARGS_(dummy, ##__VA_ARGS__, 31, 30, 29, 28, 27, 26, 25, \ | |
| 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, \ | |
| 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) | |
| // Implementation details for `OT_VA_ARGS_COUNT()`. | |
| #define OT_SHIFT_N_VARIABLE_ARGS_(...) OT_GET_NTH_VARIABLE_ARG_(__VA_ARGS__) | |
| #define OT_GET_NTH_VARIABLE_ARG_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, \ | |
| x11, x12, x13, x14, x15, x16, x17, x18, x19, \ | |
| x20, x21, x22, x23, x24, x25, x26, x27, x28, \ | |
| x29, x30, x31, n, ...) \ | |
| n | |
| /** | |
| * An argument concatenation macro. | |
| * | |
| * Because the `##` operator inhibits expansion, we use a level of indirection | |
| * to create a macro which concatenates without inhibition. | |
| */ | |
| #define OT_CAT(a, ...) OT_PRIMITIVE_CAT(a, __VA_ARGS__) | |
| #define OT_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ | |
| /** | |
| * A macro which gets the nth arg from a __VA_LIST__ | |
| */ | |
| #define OT_GET_ARG(n, ...) OT_CAT(OT_CAT(OT_GET_ARG_, n), _)(__VA_ARGS__) | |
| /** | |
| * A macro which gets the last arg from a __VA_LIST__ | |
| * | |
| * Note: we leave out the dummy argument because we want count to | |
| * give us the number of args minus one so that the created | |
| * OT_GET_ARG_n token will contain the correct integer. | |
| */ | |
| #define OT_GET_LAST_ARG(...) \ | |
| OT_GET_ARG(OT_VA_ARGS_COUNT(__VA_ARGS__), ##__VA_ARGS__) | |
| /** | |
| * The following collection of `OT_GET_ARG` macros are used to construct the | |
| * generic "get nth arg" macro. | |
| */ | |
| #define OT_GET_ARG_0_(x0, ...) x0 | |
| #define OT_GET_ARG_1_(x1, x0, ...) x0 | |
| #define OT_GET_ARG_2_(x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_3_(x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_4_(x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_5_(x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_6_(x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_7_(x7, x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_8_(x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_9_(x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_10_(x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_11_(x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) x0 | |
| #define OT_GET_ARG_12_(x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, \ | |
| ...) \ | |
| x0 | |
| #define OT_GET_ARG_13_(x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, \ | |
| x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_14_(x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, \ | |
| x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_15_(x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, \ | |
| x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_16_(x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, \ | |
| x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_17_(x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, \ | |
| x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_18_(x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, \ | |
| x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_19_(x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, \ | |
| x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_20_(x20, x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, \ | |
| x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_21_(x21, x20, x19, x18, x17, x16, x15, x14, x13, x12, x11, \ | |
| x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_22_(x22, x21, x20, x19, x18, x17, x16, x15, x14, x13, x12, \ | |
| x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_23_(x23, x22, x21, x20, x19, x18, x17, x16, x15, x14, x13, \ | |
| x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, \ | |
| ...) \ | |
| x0 | |
| #define OT_GET_ARG_24_(x24, x23, x22, x21, x20, x19, x18, x17, x16, x15, x14, \ | |
| x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, \ | |
| x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_25_(x25, x24, x23, x22, x21, x20, x19, x18, x17, x16, x15, \ | |
| x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, x3, \ | |
| x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_26_(x26, x25, x24, x23, x22, x21, x20, x19, x18, x17, x16, \ | |
| x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, x4, \ | |
| x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_27_(x27, x26, x25, x24, x23, x22, x21, x20, x19, x18, x17, \ | |
| x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, x5, \ | |
| x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_28_(x28, x27, x26, x25, x24, x23, x22, x21, x20, x19, x18, \ | |
| x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, x7, x6, \ | |
| x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_29_(x29, x28, x27, x26, x25, x24, x23, x22, x21, x20, x19, \ | |
| x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, x8, \ | |
| x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_30_(x30, x29, x28, x27, x26, x25, x24, x23, x22, x21, x20, \ | |
| x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, x9, \ | |
| x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| #define OT_GET_ARG_31_(x31, x30, x29, x28, x27, x26, x25, x24, x23, x22, x21, \ | |
| x20, x19, x18, x17, x16, x15, x14, x13, x12, x11, x10, \ | |
| x9, x8, x7, x6, x5, x4, x3, x2, x1, x0, ...) \ | |
| x0 | |
| /** | |
| * A macro that expands to an assertion for the offset of a struct member. | |
| * | |
| * @param type A struct type. | |
| * @param member A member of the struct. | |
| * @param offset Expected offset of the member. | |
| */ | |
| #define OT_ASSERT_MEMBER_OFFSET(type, member, offset) \ | |
| static_assert(offsetof(type, member) == UINT32_C(offset), \ | |
| "Unexpected offset for " #type "." #member) | |
| /** | |
| * A macro that expands to an assertion for the size of a struct member. | |
| * | |
| * @param type A struct type. | |
| * @param member A member of the struct. | |
| * @param size Expected size of the type. | |
| */ | |
| #define OT_ASSERT_MEMBER_SIZE(type, member, size) \ | |
| static_assert(sizeof(((type){0}).member) == UINT32_C(size), \ | |
| "Unexpected size for " #type) | |
| /** | |
| * A macro that expands to an assertion for the size of a type. | |
| * | |
| * @param type A type. | |
| * @param size Expected size of the type. | |
| */ | |
| #define OT_ASSERT_SIZE(type, size) \ | |
| static_assert(sizeof(type) == UINT32_C(size), "Unexpected size for " #type) | |
| /** | |
| * A macro that expands to an assertion for an expected enum value. | |
| * | |
| * @param var An enum entry. | |
| * @param expected_value Expected enum value. | |
| */ | |
| #define OT_ASSERT_ENUM_VALUE(var, expected_value) \ | |
| static_assert(var == expected_value, "Unexpected value for " #var) | |
| /** | |
| * A macro representing the OpenTitan execution platform. | |
| */ | |
| #if __riscv_xlen == 32 | |
| #define OT_PLATFORM_RV32 1 | |
| #endif | |
| /** | |
| * A macro indicating whether software should assume reduced hardware | |
| * support (for the `top_englishbreakafst` toplevel). | |
| */ | |
| #ifdef OT_IS_ENGLISH_BREAKFAST_REDUCED_SUPPORT_FOR_INTERNAL_USE_ONLY_ | |
| #define OT_IS_ENGLISH_BREAKFAST 1 | |
| #endif | |
| /** | |
| * Attribute for functions which return errors that must be acknowledged. | |
| * | |
| * This attribute must be used to mark all DIFs which return an error value of | |
| * some kind, to ensure that callers do not accidentally drop the error on the | |
| * ground. | |
| * | |
| * Normally, the standard way to drop such a value on the ground explicitly is | |
| * with the syntax `(void)expr;`, in analogy with the behavior of C++'s | |
| * `[[nodiscard]]` attribute. | |
| * However, GCC does not implement this, so the idiom `if (expr) {}` should be | |
| * used instead, for the time being. | |
| * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509. | |
| */ | |
| #define OT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) | |
| /** | |
| * Attribute for weak functions that can be overridden, e.g., ISRs. | |
| */ | |
| #define OT_WEAK __attribute__((weak)) | |
| /** | |
| * Attribute to construct functions without prologue/epilogue sequences. | |
| * | |
| * Only basic asm statements can be safely included in naked functions. | |
| * | |
| * See https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html | |
| * #RISC-V-Function-Attributes | |
| */ | |
| #define OT_NAKED __attribute__((naked)) | |
| /** | |
| * Attribute to place symbols into particular sections. | |
| * | |
| * See https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html | |
| * #Common-Function-Attributes | |
| */ | |
| #define OT_SECTION(name) __attribute__((section(name))) | |
| /** | |
| * Attribute to suppress the inlining of a function at its call sites. | |
| * | |
| * See https://clang.llvm.org/docs/AttributeReference.html#noinline. | |
| */ | |
| #define OT_NOINLINE __attribute__((noinline)) | |
| /** | |
| * Returns the address of the current function stack frame. | |
| * | |
| * See https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html. | |
| */ | |
| #define OT_FRAME_ADDR() __builtin_frame_address(0) | |
| /** | |
| * Hints to the compiler that some point is not reachable. | |
| * | |
| * One use case could be a function that never returns. | |
| * | |
| * Please not that if the control flow reaches the point of the | |
| * __builtin_unreachable, the program is undefined. | |
| * | |
| * See https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html. | |
| */ | |
| #define OT_UNREACHABLE() __builtin_unreachable() | |
| /** | |
| * Attribute for weak alias that can be overridden, e.g., Mock overrides in | |
| * DIFs. | |
| */ | |
| #define OT_ALIAS(name) __attribute__((alias(name))) | |
| /** | |
| * Defines a local symbol named `kName_` whose address resolves to the | |
| * program counter value an inline assembly block at this location would | |
| * see. | |
| * | |
| * The primary intention of this macro is to allow for peripheral tests to be | |
| * written that want to assert that a specific program counter reported by the | |
| * hardware corresponds to actual code that executed. | |
| * | |
| * For example, suppose that we're waiting for an interrupt to fire, and want | |
| * to verify that it fired in a specific region. We have two volatile globals: | |
| * `irq_happened`, which the ISR sets before returning, and `irq_pc`, which | |
| * the ISR sets to whatever PC the hardware reports it came from. The | |
| * code below tests that the reported PC matches expectations. | |
| * | |
| * ``` | |
| * OT_ADDRESSABLE_LABEL(kIrqWaitStart); | |
| * enable_interrupts(); | |
| * while(!irq_happened) { | |
| * wait_for_interrupt(); | |
| * } | |
| * OT_ADDRESSABLE_LABEL(kIrqWaitEnd); | |
| * | |
| * CHECK(irq_pc >= &kIrqWaitStart && irq_pc < &IrqWaitEnd); | |
| * ``` | |
| * | |
| * Note that this only works if all functions called between the two labels | |
| * are actually inlined; if the interrupt fires inside of one of those two | |
| * functions, it will appear to not have the right PC, even though it is | |
| * logically inside the pair of labels. | |
| * | |
| * # Volatile Semantics | |
| * | |
| * This has the same semantics as a `volatile` inline assembly block: it | |
| * may be reordered with respect to all operations except other volatile | |
| * operations (i.e. volatile assembly and volatile read/write, such as | |
| * MMIO). For example, in the following code, `kBefore` and `kAfter` can | |
| * wind up having the same address: | |
| * | |
| * ``` | |
| * OT_ADDRESSABLE_LABEL(kBefore); | |
| * x += 5; | |
| * OT_ADDRESSABLE_LABEL(kAfter); | |
| * ``` | |
| * | |
| * Because it can be reordered and the compiler is free to emit whatever | |
| * instructions it likes, comparing a program counter value obtained from | |
| * the hardware with a symbol emitted by this macro is brittle (and, | |
| * ultimately, futile). Instead, it should be used in pairs to create a | |
| * range of addresses that a value can be checked for being within. | |
| * | |
| * For this primitive to work correctly there must be something that counts as | |
| * a volatile operation between the two labels. These include: | |
| * | |
| * - Direct reads or writes to MMIO registers or CSRs. | |
| * - A volatile assembly block with at least one instruction. | |
| * - Any DIF or driver call that may touch an MMIO register or a CSR. | |
| * - `LOG`ging, `printf`ing, or `CHECK`ing. | |
| * - `wait_for_interrupt()`. | |
| * - `barrier32()`, but NOT `launder32()`. | |
| * | |
| * This macro should not be used on the host side. It will compile, but will | |
| * probably not provide any meaningful values. In the future, it may start | |
| * producing a garbage value on the host side. | |
| * | |
| * # Symbol Access | |
| * | |
| * The symbol reference `kName_` will only be scoped to the current block | |
| * in a function, but it can be redeclared in the same file with | |
| * | |
| * ``` | |
| * extern const char kName_[]; | |
| * ``` | |
| * | |
| * if needed elsewhere (although this should be avoided for readability's sake). | |
| * The name of the constant is global to the current `.c` file only. | |
| * | |
| * # Example Uses | |
| */ | |
| #define OT_ADDRESSABLE_LABEL(kName_) \ | |
| extern const char kName_[]; \ | |
| asm volatile(".local " #kName_ "; " #kName_ ":;"); \ | |
| /* Force this to be at function scope. It could go at global scope, but it \ | |
| * would give a garbage value dependent on the whims of the linker. */ \ | |
| do { \ | |
| } while (false) | |
| /** | |
| * Evaluates and discards `expr_`. | |
| * | |
| * This is needed because ‘(void)expr;` does not work for gcc. | |
| */ | |
| #define OT_DISCARD(expr_) \ | |
| if (expr_) { \ | |
| } | |
| /** | |
| * This macro is used to align an offset to point to a 32b value. | |
| */ | |
| #define OT_ALIGN_MEM(x) (uint32_t)(4 + (((uintptr_t)(x)-1) & ~3)) | |
| #endif // OPENTITAN_SW_DEVICE_LIB_BASE_MACROS_H_ |