blob: ef0a0245e26b175a51914036db364efeabb31c42 [file] [log] [blame]
// Copyright Microsoft and CHERIoT Contributors.
// SPDX-License-Identifier: MIT
#pragma once
#include <cdefs.h>
#include <stdbool.h>
/**
* Helper macro for MMIO and pre-shared object imports, should not be used
* directly.
*/
#define IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER(type, \
name, \
prefix, \
mangledName, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable) \
({ \
type *ret; /* NOLINT(bugprone-macro-parentheses) */ \
__asm(".ifndef " mangledName "\n" \
" .type " mangledName ",@object\n" \
" .section .compartment_imports." #name \
",\"awG\",@progbits," #name ",comdat\n" \
" .globl " mangledName "\n" \
" .p2align 3\n" mangledName ":\n" \
" .word " #prefix #name "\n" \
" .word " #prefix #name "_end - " #prefix #name " + %c1\n" \
" .size " mangledName ", 8\n" \
" .previous\n" \
".endif\n" \
"1:" \
" auipcc %0," \
" %%cheriot_compartment_hi(" mangledName ")\n" \
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
: "=C"(ret) \
: "i"(((permitLoad) ? (1 << 31) : 0) + \
((permitStore) ? (1 << 30) : 0) + \
((permitLoadStoreCapabilities) ? (1 << 29) : 0) + \
((permitLoadMutable) ? (1 << 28) : 0))); \
ret; \
})
/**
* Helper macro, should not be used directly.
*/
#define MMIO_CAPABILITY_WITH_PERMISSIONS_HELPER(type, \
name, \
mangledName, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable) \
IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER(type, \
name, \
__export_mem_, \
mangledName, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable)
/**
* Provide a capability of the type `volatile type *` referring to the MMIO
* region exported in the linker script with `name` as its name. This macro
* can be used only in code (it cannot be used to initialise a global).
*
* The last arguments specify the set of permissions that this capability
* holds. MMIO capabilities are always global and without store local. They
* may optionally omit additional capabilities.
*/
#define MMIO_CAPABILITY_WITH_PERMISSIONS(type, \
name, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable) \
MMIO_CAPABILITY_WITH_PERMISSIONS_HELPER( \
volatile type, /* NOLINT(bugprone-macro-parentheses) */ \
name, \
"__import_mem_" #name "_" #permitLoad "_" #permitStore \
"_" #permitLoadStoreCapabilities "_" #permitLoadMutable, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable)
/**
* Provide a capability of the type `volatile type *` referring to the MMIO
* region exported in the linker script with `name` as its name. This macro
* can be used only in code (it cannot be used to initialise a global).
*
* MMIO capabilities produced by this macro have load and store permissions but
* cannot hold capabilities. For richer permissions use
* MMIO_CAPABILITY_WITH_PERMISSIONS.
*/
#define MMIO_CAPABILITY(type, name) \
MMIO_CAPABILITY_WITH_PERMISSIONS(type, name, true, true, false, false)
/**
* Provide a capability of the type `type *` referring to the pre-shared object
* with `name` as its name. This macro can be used only in code (it cannot be
* used to initialise a global).
*
* The last arguments specify the set of permissions that this capability
* holds. Pre-shared objects are always global and without store local. They
* may optionally omit additional permissions.
*/
#define SHARED_OBJECT_WITH_PERMISSIONS(type, \
name, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable) \
IMPORT_CAPABILITY_WITH_PERMISSIONS_HELPER( \
type, /* NOLINT(bugprone-macro-parentheses) */ \
name, \
__cheriot_shared_object_, \
"__import_cheriot_shared_object_" #name "_" #permitLoad "_" #permitStore \
"_" #permitLoadStoreCapabilities "_" #permitLoadMutable, \
permitLoad, \
permitStore, \
permitLoadStoreCapabilities, \
permitLoadMutable)
/**
* Provide a capability of the type `type *` referring to the pre-shared object
* with `name` as its name. This macro can be used only in code (it cannot be
* used to initialise a global).
*
* Pre-shared object capabilities produced by this macro have load, store,
* load-mutable, and load/store-capability permissions. To define a reduced
* set of permissions use `SHARED_OBJECT_WITH_PERMISSIONS`.
*/
#define SHARED_OBJECT(type, name) \
SHARED_OBJECT_WITH_PERMISSIONS(type, name, true, true, true, true)
/**
* Macro to test whether a device with a specific name exists in the board
* definition for the current target.
*/
#define DEVICE_EXISTS(x) defined(DEVICE_EXISTS_##x)
#define SEALING_CAP() \
({ \
void *ret; \
__asm("1: " \
" auipcc %0, %%cheriot_compartment_hi(__sealingkey)\n" \
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
: "=C"(ret)); \
ret; \
})
/**
* Helper macro, used by `STATIC_SEALING_TYPE`. Do not use this directly, it
* exists to avoid error-prone copying and pasting of the mangled name for a
* static sealing type.
*/
#define CHERIOT_EMIT_STATIC_SEALING_TYPE(name) \
({ \
SKey ret; /* NOLINT(bugprone-macro-parentheses) */ \
__asm( \
".ifndef __import." name "\n" \
" .type __import." name ",@object\n" \
" .section .compartment_imports." name ",\"awG\",@progbits," name \
",comdat\n" \
" .globl __import." name "\n" \
" .p2align 3\n" \
"__import." name ":\n" \
" .word __export." name "\n" \
" .word 0\n" \
" .previous\n" \
".endif\n" \
".ifndef __export." name "\n" \
" .type __export." name ",@object\n" \
" .section .compartment_exports." name ",\"awG\",@progbits," name \
",comdat\n" \
" .globl __export." name "\n" \
" .p2align 2\n" \
"__export." name ":\n" \
" .half 0\n" /* function start and stack size initialised to 0 */ \
" .byte 0\n" \
" .byte 0b100000\n" /* Set the flag that indicates that this is a \
sealing key. */ \
" .size __export." name ", 4\n" \
" .previous\n" \
".endif\n" \
"1:\n" \
" auipcc %0, %%cheriot_compartment_hi(__import." name ")\n" \
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
: "=C"(ret)); \
ret; \
})
/**
* Helper macro that evaluates to the compartment of the current compilation
* unit, as a string.
*/
#define COMPARTMENT_NAME_STRING __XSTRING(__CHERI_COMPARTMENT__)
/**
* Macro that evaluates to a static sealing type that is local to this
* compartment.
*/
#define STATIC_SEALING_TYPE(name) \
CHERIOT_EMIT_STATIC_SEALING_TYPE("sealing_type." COMPARTMENT_NAME_STRING \
"." #name)
/**
* Forward-declare a static sealed object. This declares an object of type
* `type` that can be referenced with the `STATIC_SEALED_VALUE` macro using
* `name`. The pointer returned by the latter macro will be sealed with the
* sealing key exported from `compartment` as `keyName` with the
* `STATIC_SEALING_TYPE` macro.
*
* The object created with this macro can be accessed only by code that has
* access to the sealing key.
*/
#define DECLARE_STATIC_SEALED_VALUE(type, compartment, keyName, name) \
struct __##name##_type; /* NOLINT(bugprone-macro-parentheses) */ \
extern __if_cxx("C") struct __##name##_type \
{ \
uint32_t key; \
uint32_t padding; \
type body; \
} name /* NOLINT(bugprone-macro-parentheses) */
/**
* Define a static sealed object. This creates an object of type `type`,
* initialised with `initialiser`, that can be referenced with the
* `STATIC_SEALED_VALUE` macro using `name`. The pointer returned by the
* latter macro will be sealed with the sealing key exported from `compartment`
* as `keyName` with the `STATIC_SEALING_TYPE` macro.
*
* The object created with this macro can be accessed only by code that has
* access to the sealing key.
*/
#define DEFINE_STATIC_SEALED_VALUE( \
type, compartment, keyName, name, initialiser, ...) \
extern __if_cxx("C") int __sealing_key_##compartment##_##keyName __asm( \
"__export.sealing_type." #compartment "." #keyName); \
__attribute__((section(".sealed_objects"), used)) \
__if_cxx(inline) struct __##name##_type \
name = /* NOLINT(bugprone-macro-parentheses) */ \
{(uint32_t)&__sealing_key_##compartment##_##keyName, \
0, \
{initialiser, ##__VA_ARGS__}}
/**
* Helper macro that declares and defines a sealed value.
*/
#define DECLARE_AND_DEFINE_STATIC_SEALED_VALUE( \
type, compartment, keyName, name, initialiser, ...) \
DECLARE_STATIC_SEALED_VALUE( \
type, \
compartment, \
keyName, \
name); /* NOLINT(bugprone-macro-parentheses) */ \
DEFINE_STATIC_SEALED_VALUE( \
type, \
compartment, \
keyName, \
name, \
initialiser, \
##__VA_ARGS__); /* NOLINT(bugprone-macro-parentheses) */
/**
* Returns a sealed capability to the named object created with
* `DECLARE_STATIC_SEALED_VALUE`.
*/
#define STATIC_SEALED_VALUE(name) \
({ \
struct SObjStruct *ret; /* NOLINT(bugprone-macro-parentheses) */ \
__asm(".ifndef __import.sealed_object." #name "\n" \
" .type __import.sealed_object." #name ",@object\n" \
" .section .compartment_imports." #name \
",\"awG\",@progbits," #name ",comdat\n" \
" .globl __import.sealed_object." #name "\n" \
" .p2align 3\n" \
"__import.sealed_object." #name ":\n" \
" .word " #name "\n" \
" .word %c1\n" \
" .size __import.sealed_object." #name ", 8\n" \
" .previous\n" \
".endif\n" \
"1:" \
" auipcc %0," \
" %%cheriot_compartment_hi(__import.sealed_object." #name \
")\n" \
" clc %0, %%cheriot_compartment_lo_i(1b)(%0)\n" \
: "=C"(ret) \
: "i"(sizeof(__typeof__(name)))); \
ret; \
})