blob: 718115e864df80b865b65958e68d376e2d80bf3c [file] [log] [blame]
// 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_