blob: 9c7bbb76331e95cc76148c5b62a68ea8773e0247 [file] [edit]
/* ----------------------------------------------------------------------------
Copyright (c) 2026, Microsoft Research, Daan Leijen
This is free software; you can redistribute it and/or modify it under the
terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/
/* ----------------------------------------------------------------------------
Simulate a CHERI purecap target on 64-bit Linux or macOS (clang only) to test
the CHERI code paths. Pointers are not actually 16 bytes, and bounds and permissions
are not enforced, but an address with bit 62 set is treated as "untagged".
Use as:
-include test/cheri-sim.h -Wno-builtin-macro-redefined -U__SIZEOF_POINTER__ -D__SIZEOF_POINTER__=16
-----------------------------------------------------------------------------*/
#pragma once
#define __CHERI_PURE_CAPABILITY__ 1
#define __PTRADDR_TYPE__ unsigned long
#include <stdint.h>
#include <stdlib.h>
#define __builtin_cheri_address_set(c,a) ((void)(c), (void*)(uintptr_t)(a))
#define __builtin_cheri_address_get(p) ((unsigned long)(uintptr_t)(p))
#define __builtin_cheri_tag_get(p) ((((uintptr_t)(p)) & (1ULL<<62)) == 0)
static inline void* mi_sim_trap_untagged(const void* p) {
if (p==NULL || !__builtin_cheri_tag_get(p)) abort();
return (void*)p;
}
#define __builtin_cheri_bounds_set(p,n) ((void)(n), mi_sim_trap_untagged(p))
#define __builtin_cheri_perms_and(p,m) ((void)(m), mi_sim_trap_untagged(p))
#define __builtin_cheri_base_get(p) ((void)(p), 0UL)
#define __builtin_cheri_length_get(p) ((void)(p), ~0UL) // bounds are not modelled
#define __builtin_cheri_offset_get(p) ((void)(p), 0UL)
#define __builtin_cheri_sealed_get(p) ((void)(p), 0) // never sealed
#define __builtin_cheri_perms_get(p) ((void)(p), 0xFFFFUL) // all permissions
// exact CHERI-RISC-V 128 (MW=14) representability (Morello is about 4x more lax)
static inline unsigned long mi_sim_repr_mask(unsigned long n) {
if (n == 0) return ~0UL;
const int e = (64 - __builtin_clzl(n)) - 12;
if (e <= 0) return ~0UL;
unsigned long a = 1UL << (e+2);
const unsigned long r = (n + a - 1) & ~(a-1);
if ((64 - __builtin_clzl(r)) - 12 > e) { a <<= 1; }
return ~(a-1);
}
#define __builtin_cheri_representable_alignment_mask(n) mi_sim_repr_mask(n)
#define __builtin_cheri_round_representable_length(n) (((n) + ~mi_sim_repr_mask(n)) & mi_sim_repr_mask(n))
#define __CHERI_CAP_PERMISSION_PERMIT_EXECUTE__ 2
#define __CHERI_CAP_PERMISSION_PERMIT_LOAD__ 4
#define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8
#define __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ 16
#define __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ 32
#define __CHERI_CAP_PERMISSION_PERMIT_SEAL__ 128
#define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512
#define __CHERI_CAP_PERMISSION_ACCESS_SYSTEM_REGISTERS__ 1024
#if defined(__APPLE__) && defined(__aarch64__)
// for local testing on macOS: provide the thread pointer for the TLS slots (or the tests hang)
static inline void** mi_sim_tp(void) {
uint64_t tp;
__asm__ ("mrs %0, tpidrro_el0\n\tbic %0, %0, #7" : "=r" (tp));
return (void**)tp;
}
#define MI_PRIM_THREAD_POINTER mi_sim_tp
#endif