[sw] Hacks needed for a CHERIoT test_rom. - mark memory.h shadow definitions __cheri_libcall to match string.h (NB: only when !baremetal where direct calls are made) - abs_mmio_* ignores ptr provenance, switch to uintptr_t - hardened* treat uintptr_t as an unsigned, add explicit conversion - temporarily disable static_assert in logging code (needs proper fix) - band-aid portability issue in base_log_internal_core - compat shim for clang's __has_feature intrinsic Bypass-Presubmit-Reason: verified as part of topic Change-Id: I132d6dbc2aaff0c48b5dcba797647aacafe15afd
diff --git a/sw/device/lib/base/abs_mmio.c b/sw/device/lib/base/abs_mmio.c index 6498e51..309cca5 100644 --- a/sw/device/lib/base/abs_mmio.c +++ b/sw/device/lib/base/abs_mmio.c
@@ -6,9 +6,9 @@ // `extern` declarations to give the inline functions in the corresponding // header a link location. -extern uint8_t abs_mmio_read8(uint32_t addr); -extern void abs_mmio_write8(uint32_t addr, uint8_t value); -extern void abs_mmio_write8_shadowed(uint32_t addr, uint8_t value); -extern uint32_t abs_mmio_read32(uint32_t addr); -extern void abs_mmio_write32(uint32_t addr, uint32_t value); -extern void abs_mmio_write32_shadowed(uint32_t addr, uint32_t value); +extern uint8_t abs_mmio_read8(uintptr_t addr); +extern void abs_mmio_write8(uintptr_t addr, uint8_t value); +extern void abs_mmio_write8_shadowed(uintptr_t addr, uint8_t value); +extern uint32_t abs_mmio_read32(uintptr_t addr); +extern void abs_mmio_write32(uintptr_t addr, uint32_t value); +extern void abs_mmio_write32_shadowed(uintptr_t addr, uint32_t value);
diff --git a/sw/device/lib/base/abs_mmio.h b/sw/device/lib/base/abs_mmio.h index 654fc5a..69031f4 100644 --- a/sw/device/lib/base/abs_mmio.h +++ b/sw/device/lib/base/abs_mmio.h
@@ -36,7 +36,7 @@ * @return the read value. */ OT_WARN_UNUSED_RESULT -inline uint8_t abs_mmio_read8(uint32_t addr) { +inline uint8_t abs_mmio_read8(uintptr_t addr) { return *((volatile uint8_t *)addr); } @@ -46,7 +46,7 @@ * @param addr the address to write to. * @param value the value to write. */ -inline void abs_mmio_write8(uint32_t addr, uint8_t value) { +inline void abs_mmio_write8(uintptr_t addr, uint8_t value) { *((volatile uint8_t *)addr) = value; } @@ -57,7 +57,7 @@ * @param addr the address to write to. * @param value the value to write. */ -inline void abs_mmio_write8_shadowed(uint32_t addr, uint8_t value) { +inline void abs_mmio_write8_shadowed(uintptr_t addr, uint8_t value) { *((volatile uint8_t *)addr) = value; *((volatile uint8_t *)addr) = value; } @@ -69,7 +69,7 @@ * @return the read value. */ OT_WARN_UNUSED_RESULT -inline uint32_t abs_mmio_read32(uint32_t addr) { +inline uint32_t abs_mmio_read32(uintptr_t addr) { return *((volatile uint32_t *)addr); } @@ -79,7 +79,7 @@ * @param addr the address to write to. * @param value the value to write. */ -inline void abs_mmio_write32(uint32_t addr, uint32_t value) { +inline void abs_mmio_write32(uintptr_t addr, uint32_t value) { *((volatile uint32_t *)addr) = value; } @@ -90,19 +90,19 @@ * @param addr the address to write to. * @param value the value to write. */ -inline void abs_mmio_write32_shadowed(uint32_t addr, uint32_t value) { +inline void abs_mmio_write32_shadowed(uintptr_t addr, uint32_t value) { *((volatile uint32_t *)addr) = value; *((volatile uint32_t *)addr) = value; } #else // OT_PLATFORM_RV32 -extern uint8_t abs_mmio_read8(uint32_t addr); -extern void abs_mmio_write8(uint32_t addr, uint8_t value); -extern void abs_mmio_write8_shadowed(uint32_t addr, uint8_t value); -extern uint32_t abs_mmio_read32(uint32_t addr); -extern void abs_mmio_write32(uint32_t addr, uint32_t value); -extern void abs_mmio_write32_shadowed(uint32_t addr, uint32_t value); +extern uint8_t abs_mmio_read8(uintptr_t addr); +extern void abs_mmio_write8(uintptr_t addr, uint8_t value); +extern void abs_mmio_write8_shadowed(uintptr_t addr, uint8_t value); +extern uint32_t abs_mmio_read32(uintptr_t addr); +extern void abs_mmio_write32(uintptr_t addr, uint32_t value); +extern void abs_mmio_write32_shadowed(uintptr_t addr, uint32_t value); #endif // OT_PLATFORM_RV32
diff --git a/sw/device/lib/base/hardened.h b/sw/device/lib/base/hardened.h index 77b18f4..41243ab 100644 --- a/sw/device/lib/base/hardened.h +++ b/sw/device/lib/base/hardened.h
@@ -256,7 +256,11 @@ * runtime. */ inline uintptr_t launderw(uintptr_t val) { +#if __has_feature(capabilities) + asm volatile("" : "+C"(val)); +#else asm volatile("" : "+r"(val)); +#endif return val; } @@ -356,7 +360,13 @@ * * @param val A value to create a barrier for. */ -inline void barrierw(uintptr_t val) { asm volatile("" ::"r"(val)); } +inline void barrierw(uintptr_t val) { +#if __has_feature(capabilities) + asm volatile("" ::"C"(val)); +#else + asm volatile("" ::"r"(val)); +#endif +} /** * A constant-time, 32-bit boolean value. @@ -485,9 +495,17 @@ * * @return `a < b`. */ +#if __has_feature(capabilities) +inline ct_boolw_t ct_sltuw(uintptr_t _a, uintptr_t _b) { + unsigned a = __builtin_cheri_address_get(_a); + unsigned b = __builtin_cheri_address_get(_b); + return ct_sltzw((a & ~b) | ((a ^ ~b) & (a - b))); +} +#else inline ct_boolw_t ct_sltuw(uintptr_t a, uintptr_t b) { return ct_sltzw((a & ~b) | ((a ^ ~b) & (a - b))); } +#endif /** * Performs constant-time zero equality. @@ -496,7 +514,14 @@ * * @return `a == 0`. */ +#if __has_feature(capabilities) +inline ct_boolw_t ct_seqzw(uintptr_t _a) { + unsigned a = __builtin_cheri_address_get(_a); + return ct_sltzw(~a & (a - 1)); +} +#else inline ct_boolw_t ct_seqzw(uintptr_t a) { return ct_sltzw(~a & (a - 1)); } +#endif /** * Performs constant-time equality. @@ -505,7 +530,15 @@ * * @return `a == b`. */ +#if __has_feature(capabilities) +inline ct_boolw_t ct_seqw(uintptr_t _a, uintptr_t _b) { + unsigned a = __builtin_cheri_address_get(_a); + unsigned b = __builtin_cheri_address_get(_b); + return ct_seqzw(a ^ b); +} +#else inline ct_boolw_t ct_seqw(uintptr_t a, uintptr_t b) { return ct_seqzw(a ^ b); } +#endif /** * Performs a constant-time select. @@ -520,9 +553,18 @@ * @param b The value to return on false. * @return `c ? a : b`. */ +#if __has_feature(capabilities) +inline uintptr_t ct_cmovw(ct_boolw_t _c, uintptr_t _a, uintptr_t _b) { + unsigned a = __builtin_cheri_address_get(_a); + unsigned b = __builtin_cheri_address_get(_b); + unsigned c = __builtin_cheri_address_get(_c); + return (launder32(c) & a) | (launder32(~c) & b); +} +#else inline uintptr_t ct_cmovw(ct_boolw_t c, uintptr_t a, uintptr_t b) { return (launderw(c) & a) | (launderw(~c) & b); } +#endif // Implementation details shared across shutdown macros. #ifdef OT_PLATFORM_RV32
diff --git a/sw/device/lib/base/macros.h b/sw/device/lib/base/macros.h index b06cac6..0b46b1f 100644 --- a/sw/device/lib/base/macros.h +++ b/sw/device/lib/base/macros.h
@@ -431,4 +431,11 @@ #define __cheri_libcall #endif +/** + * Compat shim for clang extension not implemented in some gcc versions. + */ +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + #endif // OPENTITAN_SW_DEVICE_LIB_BASE_MACROS_H_
diff --git a/sw/device/lib/base/memory.c b/sw/device/lib/base/memory.c index 22fc0eb..0bcfcdb 100644 --- a/sw/device/lib/base/memory.c +++ b/sw/device/lib/base/memory.c
@@ -8,8 +8,9 @@ #include "sw/device/lib/base/macros.h" +// NB: must match memory.h, cannot reuse as it's #undef'd at the end of block #ifdef OT_PLATFORM_RV32 -#define OT_PREFIX_IF_NOT_RV32(name) name +#define OT_PREFIX_IF_NOT_RV32(name) __cheri_libcall name #else #define OT_PREFIX_IF_NOT_RV32(name) ot_##name #endif
diff --git a/sw/device/lib/base/memory.h b/sw/device/lib/base/memory.h index 11a1b65..c4a1682 100644 --- a/sw/device/lib/base/memory.h +++ b/sw/device/lib/base/memory.h
@@ -17,6 +17,12 @@ #include <stddef.h> #include <stdint.h> +// NB: --mabi=cheriot-baremetal generates direct C calls & unmangled symbols +#ifdef _CHERIOT_BAREMETAL_ +#undef __cheri_libcall +#define __cheri_libcall +#endif + #ifndef OT_PLATFORM_RV32 #include <string.h> #endif @@ -40,7 +46,7 @@ // around this ASan bug, enabling us to run the unit tests with ASan enabled. // See https://github.com/lowRISC/opentitan/issues/13826. #ifdef OT_PLATFORM_RV32 -#define OT_PREFIX_IF_NOT_RV32(name) name +#define OT_PREFIX_IF_NOT_RV32(name) __cheri_libcall name #else #define OT_PREFIX_IF_NOT_RV32(name) ot_##name #endif
diff --git a/sw/device/lib/base/mock_abs_mmio.cc b/sw/device/lib/base/mock_abs_mmio.cc index 2f39d30..56f4746 100644 --- a/sw/device/lib/base/mock_abs_mmio.cc +++ b/sw/device/lib/base/mock_abs_mmio.cc
@@ -6,27 +6,27 @@ namespace rom_test { extern "C" { -uint8_t abs_mmio_read8(uint32_t addr) { +uint8_t abs_mmio_read8(uintptr_t addr) { return MockAbsMmio::Instance().Read8(addr); } -void abs_mmio_write8(uint32_t addr, uint8_t value) { +void abs_mmio_write8(uintptr_t addr, uint8_t value) { MockAbsMmio::Instance().Write8(addr, value); } -void abs_mmio_write8_shadowed(uint32_t addr, uint8_t value) { +void abs_mmio_write8_shadowed(uintptr_t addr, uint8_t value) { MockAbsMmio::Instance().Write8Shadowed(addr, value); } -uint32_t abs_mmio_read32(uint32_t addr) { +uint32_t abs_mmio_read32(uintptr_t addr) { return MockAbsMmio::Instance().Read32(addr); } -void abs_mmio_write32(uint32_t addr, uint32_t value) { +void abs_mmio_write32(uintptr_t addr, uint32_t value) { MockAbsMmio::Instance().Write32(addr, value); } -void abs_mmio_write32_shadowed(uint32_t addr, uint32_t value) { +void abs_mmio_write32_shadowed(uintptr_t addr, uint32_t value) { MockAbsMmio::Instance().Write32Shadowed(addr, value); } } // extern "C"
diff --git a/sw/device/lib/base/mock_abs_mmio.h b/sw/device/lib/base/mock_abs_mmio.h index 930e1a1..2e7f02b 100644 --- a/sw/device/lib/base/mock_abs_mmio.h +++ b/sw/device/lib/base/mock_abs_mmio.h
@@ -16,12 +16,12 @@ */ class MockAbsMmio : public global_mock::GlobalMock<MockAbsMmio> { public: - MOCK_METHOD(uint8_t, Read8, (uint32_t addr)); - MOCK_METHOD(void, Write8, (uint32_t addr, uint8_t value)); - MOCK_METHOD(void, Write8Shadowed, (uint32_t addr, uint8_t value)); - MOCK_METHOD(uint32_t, Read32, (uint32_t addr)); - MOCK_METHOD(void, Write32, (uint32_t addr, uint32_t value)); - MOCK_METHOD(void, Write32Shadowed, (uint32_t addr, uint32_t value)); + MOCK_METHOD(uint8_t, Read8, (uintptr_t addr)); + MOCK_METHOD(void, Write8, (uintptr_t addr, uint8_t value)); + MOCK_METHOD(void, Write8Shadowed, (uintptr_t addr, uint8_t value)); + MOCK_METHOD(uint32_t, Read32, (uintptr_t addr)); + MOCK_METHOD(void, Write32, (uintptr_t addr, uint32_t value)); + MOCK_METHOD(void, Write32Shadowed, (uintptr_t addr, uint32_t value)); }; } // namespace internal
diff --git a/sw/device/lib/runtime/log.c b/sw/device/lib/runtime/log.c index b442b39..284d0ef 100644 --- a/sw/device/lib/runtime/log.c +++ b/sw/device/lib/runtime/log.c
@@ -11,6 +11,8 @@ #include "sw/device/lib/base/mmio.h" #include "sw/device/lib/runtime/print.h" +#if !__has_feature(capabilities) +// TODO(sleffler) (CHERI) sizeof(const char *format) is assumed to == sizeof(uint32_t) /** * Ensure that log_fields_t is always 20 bytes. * @@ -19,6 +21,7 @@ */ static_assert(sizeof(log_fields_t) == 20, "log_fields_t must always be 20 bytes."); +#endif /** * Converts a severity to a static string. @@ -45,8 +48,14 @@ * @param ... format parameters matching the format string. */ void base_log_internal_core(log_fields_t log, ...) { - size_t file_name_len = - ((char *)memchr(log.file_name, '\0', PTRDIFF_MAX)) - log.file_name; + // NB: be careful calculating the filename length with the internal + // memchr as it optimizes its work by operating on aligned uint32_t + // values. But on CHERI systems the true length of log.file_name is + // enforced so reading past the end of the string will trap. Instead + // use a safe (but potentially slower) approach. + size_t file_name_len = 0; + while (log.file_name[file_name_len] != '\0') ++file_name_len; + const char *base_name = memrchr(log.file_name, '/', file_name_len); if (base_name == NULL) { base_name = log.file_name;