diff --git a/sdk/core/loader/boot.cc b/sdk/core/loader/boot.cc index 5bcb70c8..01e4ca7a 100644 --- a/sdk/core/loader/boot.cc +++ b/sdk/core/loader/boot.cc @@ -144,6 +144,14 @@ namespace FirstDynamicSoftware = 0x1000000, }; + // The switcher assembly includes the types of import table entries and + // trusted stacks. This enumeration and the assembly must be kept in sync. + // This will fail if the enumeration value changes. + static_assert(int(SealedImportTableEntries) == 9, + "If this fails, update switcher/entry.S to the new value"); + static_assert(int(SealedTrustedStacks) == 10, + "If this fails, update switcher/entry.S to the new value"); + // The allocator and static sealing types must be contiguous so that the // token library can hold a permit-unseal capability for both. static_assert(int(Allocator) + 1 == int(StaticToken), @@ -162,6 +170,18 @@ namespace static_assert(magic_enum::enum_count() <= 12, "Too many sealing types reserved for a 3-bit otype field"); +} // namespace + +/* + * Unusually late, include this where we have access to the above enum + * SealingType, but early enough that the constants defined herein are available + * to the rest of the code. + */ +#include "../switcher/misc-assembly.h" + +namespace +{ + constexpr auto StoreLPerm = Root::Permissions; /// PCC permissions for the switcher. constexpr auto SwitcherPccPermissions = diff --git a/sdk/core/switcher/entry.S b/sdk/core/switcher/entry.S index 3a3eeb1b..1ea2bbf9 100644 --- a/sdk/core/switcher/entry.S +++ b/sdk/core/switcher/entry.S @@ -3,6 +3,7 @@ #include "export-table-assembly.h" #include "trusted-stack-assembly.h" +#include "misc-assembly.h" #include .include "assembly-helpers.s" @@ -256,7 +257,7 @@ __Z26compartment_switcher_entryz: // Fetch the sealing key LoadCapPCC cs0, compartment_switcher_sealing_key - li gp, 9 + li gp, SEAL_TYPE_SealedImportTableEntries csetaddr cs0, cs0, gp // The target capability is in ct1. Unseal, check tag and load the entry point offset. cunseal ct1, ct1, cs0 @@ -489,7 +490,7 @@ exception_entry_asm: // If we hit one of the exception conditions that we should let // compartments handle then deliver it to the compartment. // CHERI exception code. - li a0, 0x1c + li a0, MCAUSE_CHERI beq a0, t1, .Lhandle_error // Misaligned instruction, instruction access, illegal instruction, // breakpoint, misaligned load, load fault, misaligned store, and store @@ -534,7 +535,7 @@ exception_entry_asm: // Switch onto the new thread's trusted stack LoadCapPCC ct0, compartment_switcher_sealing_key - li gp, 10 + li gp, SEAL_TYPE_SealedTrustedStacks csetaddr ct0, ct0, gp cunseal csp, ca0, ct0 clw t0, TrustedStack_offset_mcause(csp) @@ -548,11 +549,11 @@ exception_entry_asm: // mret, so reentrancy is no longer a concern. cspecialw mtdc, csp - // If mcause is 25, then we will jump into the error handler: another - // thread has signalled that this thread should be interrupted. 25 is a - // reserved exception number that we repurpose to indicate explicit - // interruption. - li t1, 25 + // If mcause is MCAUSE_THREAD_INTERRUPT, then we will jump into the error + // handler: another thread has signalled that this thread should be + // interrupted. MCAUSE_THREAD_INTERRUPT is a reserved exception number that + // we repurpose to indicate explicit interruption. + li t1, MCAUSE_THREAD_INTERRUPT beq t0, t1, .Lhandle_injected_error // Environment call from M-mode is exception code 11. @@ -858,7 +859,7 @@ exception_entry_asm: // Value 24 is reserved for custom use. .Lset_mcause_and_exit_thread: - csrw mcause, 24 + csrw mcause, MCAUSE_THREAD_EXIT // The thread exit code expects the trusted stack pointer to be in csp and // the stack pointer to be in mtdc. After thread exit, we don't need the // stack pointer so just put zero there. @@ -964,7 +965,7 @@ __Z25switcher_interrupt_threadPv: // Load the unsealing key into a register that we will clobber two // instructions later. LoadCapPCC ca1, compartment_switcher_sealing_key - li a2, 10 + li a2, SEAL_TYPE_SealedTrustedStacks csetaddr ca1, ca1, a2 // The target capability is in ct1. Unseal, check tag and load the entry point offset. cunseal ca1, ca0, ca1 @@ -1010,7 +1011,7 @@ __Z25switcher_interrupt_threadPv: // Mark the thread as interrupted. // Store a magic value in mcause - li a2, 25 + li a2, MCAUSE_THREAD_INTERRUPT csw a2, TrustedStack_offset_mcause(ca1) // Return success li a0, 1 @@ -1023,7 +1024,7 @@ __Z25switcher_interrupt_threadPv: .type __Z23switcher_current_threadv,@function __Z23switcher_current_threadv: LoadCapPCC ca0, compartment_switcher_sealing_key - li a1, 10 + li a1, SEAL_TYPE_SealedTrustedStacks csetaddr ca0, ca0, a1 cspecialr ca1, mtdc cseal ca0, ca1, ca0 diff --git a/sdk/core/switcher/misc-assembly.h b/sdk/core/switcher/misc-assembly.h new file mode 100644 index 00000000..f93293c1 --- /dev/null +++ b/sdk/core/switcher/misc-assembly.h @@ -0,0 +1,43 @@ +// Copyright CHERIoT Contributors. +// SPDX-License-Identifier: MIT + +#pragma once +#include + +/* + * Constant to represent the raw permissions of the compartment CSP. We use + * this in the switcher, to verify the permissions of the CSP that comes from + * the compartment are exactly what we expect. + */ +EXPORT_ASSEMBLY_EXPRESSION(COMPARTMENT_STACK_PERMISSIONS, + (CHERI::PermissionSet{ + CHERI::Permission::Load, + CHERI::Permission::Store, + CHERI::Permission::LoadStoreCapability, + CHERI::Permission::LoadMutable, + CHERI::Permission::StoreLocal, + CHERI::Permission::LoadGlobal} + .as_raw()), + 0x7e) + +/** + * Space reserved at the top of a stack on entry to the compartment. + * + * This *must* be a multiple of 16, which is the stack alignment. + */ +#define STACK_ENTRY_RESERVED_SPACE 16 + +#ifdef __cplusplus +using namespace priv; +#endif + +EXPORT_ASSEMBLY_NAME(MCAUSE_THREAD_EXIT, 24) +EXPORT_ASSEMBLY_NAME(MCAUSE_THREAD_INTERRUPT, 25) +EXPORT_ASSEMBLY_NAME(MCAUSE_CHERI, 28) + +EXPORT_ASSEMBLY_EXPRESSION(SEAL_TYPE_SealedImportTableEntries, + SealingType::SealedImportTableEntries, + 9) +EXPORT_ASSEMBLY_EXPRESSION(SEAL_TYPE_SealedTrustedStacks, + SealingType::SealedTrustedStacks, + 10) diff --git a/sdk/core/switcher/trusted-stack-assembly.h b/sdk/core/switcher/trusted-stack-assembly.h index 660a010c..79696624 100644 --- a/sdk/core/switcher/trusted-stack-assembly.h +++ b/sdk/core/switcher/trusted-stack-assembly.h @@ -57,18 +57,3 @@ EXPORT_ASSEMBLY_SIZE(TrustedStackFrame, (8 * 3)) #define TSTACKOFFSET_FIRSTFRAME \ (TrustedStack_offset_frameoffset + TSTACK_HEADER_SZ) - -/* Constant to represent the raw permissions of the compartment CSP. - * We use this in the switcher, to verify the CSP comes from the - * compartment is exactly what we expect. - * This represents the following permissions: - * Load, Store, LoadStoreCapability, LoadMutable StoreLocal and LoadGlobal - */ -#define COMPARTMENT_STACK_PERMISSIONS 0x7e - -/** - * Space reserved at the top of a stack on entry to the compartment. - * - * This *must* be a multiple of 16, which is the stack alignment. - */ -#define STACK_ENTRY_RESERVED_SPACE 16 diff --git a/sdk/core/switcher/tstack.h b/sdk/core/switcher/tstack.h index d782af81..dc8338bc 100644 --- a/sdk/core/switcher/tstack.h +++ b/sdk/core/switcher/tstack.h @@ -77,13 +77,3 @@ struct TrustedStackGeneric using TrustedStack = TrustedStackGeneric<0>; #include "trusted-stack-assembly.h" - -static_assert( - CheckSize::value); diff --git a/sdk/include/assembly-helpers.h b/sdk/include/assembly-helpers.h index cdc92d73..8228077d 100644 --- a/sdk/include/assembly-helpers.h +++ b/sdk/include/assembly-helpers.h @@ -21,6 +21,25 @@ struct CheckSize static constexpr bool value = Real == Expected; }; +/** + * Export a macro into assembly named `name` with value `value`. In C++, this + * macro will report an error if the provided value does not equal the constexpr + * evaluation of `expression`. + */ +# define EXPORT_ASSEMBLY_NAME(name, val) \ + static_assert(CheckSize::value, \ + "Value provided for assembly is incorrect"); + +/** + * Export a macro into assembly named `name` with value `value`. In C++, this + * macro will report an error if the provided value does not equal the constexpr + * evaluation of `expression`. + */ +# define EXPORT_ASSEMBLY_EXPRESSION(name, expression, val) \ + static constexpr size_t name = expression; \ + static_assert(CheckSize::value, \ + "Value provided for assembly is incorrect"); + /** * Export a macro into assembly of the form `{structure}_offset_{field}`. The * value of this macro will be `value`. In C++, this macro will report an error @@ -61,12 +80,18 @@ struct CheckSize static_assert(CheckSize::value, \ "Size provided for assembly is incorrect"); #elif defined(__ASSEMBLER__) +# define EXPORT_ASSEMBLY_NAME(name, value) \ + .set name, value +# define EXPORT_ASSEMBLY_EXPRESSION(name, expression, value) \ + .set name, value # define EXPORT_ASSEMBLY_OFFSET_NAMED(structure, field, value, name) \ - .set name value + .set name, value # define EXPORT_ASSEMBLY_OFFSET(structure, field, value) \ .set structure##_offset_##field, value # define EXPORT_ASSEMBLY_SIZE(structure, value) .set structure##_size, value #else +# define EXPORT_ASSEMBLY_NAME(name, value) +# define EXPORT_ASSEMBLY_EXPRESSION(name, expression, value) # define EXPORT_ASSEMBLY_OFFSET(structure, field, name, value) # define EXPORT_ASSEMBLY_SIZE(structure, name, value) # define EXPORT_ASSEMBLY_OFFSET_NAMED(structure, field, value, name) diff --git a/sdk/include/priv/riscv.h b/sdk/include/priv/riscv.h index d5c616e1..d8cc51cf 100644 --- a/sdk/include/priv/riscv.h +++ b/sdk/include/priv/riscv.h @@ -75,6 +75,7 @@ namespace priv constexpr size_t MCAUSE_LOAD_PAGE_FAULT = 13; constexpr size_t MCAUSE_STORE_PAGE_FAULT = 15; constexpr size_t MCAUSE_THREAD_EXIT = 24; + constexpr size_t MCAUSE_THREAD_INTERRUPT = 25; constexpr size_t MCAUSE_CHERI = 28; constexpr size_t MSTATUS_UIE = (1 << 0);