[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;