Skip to content

Commit

Permalink
Initial merge for capability systems
Browse files Browse the repository at this point in the history
FreeBSD data sections are scanned for roots and capability
tags are retained.

During the mark phase, capability metadata is checked and
capability addresses are adjusted to ensure they are
within bounds and have valid tags.

If the 'anchor' capability (the root pointer from which the
pointer used to scan is derived from - *current_p*) is already
greater than the upper bounds, guard against the derived
capability (*limit*) undershooting the 'root' capability and asserting.

Changes specific to CHERI capability systems are conditionally compiled
using the macro __CHERI_PURE_CAPABILITY__
  • Loading branch information
Dejice Jacob committed Jul 27, 2021
1 parent b104cdc commit 8120c8b
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 36 deletions.
4 changes: 4 additions & 0 deletions include/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1373,8 +1373,12 @@ GC_API int GC_CALL GC_invoke_finalizers(void);
/* The function is sometimes called keep_alive in other */
/* settings. */
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
#if 0 //FIXME CHERI
# define GC_reachable_here(ptr) \
__asm__ __volatile__(" " : : "X"(ptr) : "memory")
#endif //FIXME CHERI
# define GC_reachable_here(ptr) \
__asm__ __volatile__(" " : : "g"(ptr) : "memory")
#else
GC_API void GC_CALL GC_noop1(GC_word);
# ifdef LINT2
Expand Down
6 changes: 5 additions & 1 deletion include/gc_tiny_fl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@
|| defined(__s390x__) \
|| (defined(__x86_64__) && !defined(__ILP32__)) \
|| defined(__alpha__) || defined(__powerpc64__) \
|| defined(__arch64__)
|| defined(__arch64__) \
|| (defined(__riscv) && __riscv_xlen == 64)
# if defined(__CHERI_PURE_CAPABILITY__)
# error FIXME Expand Granule size and subsequent uses for pointer sizes being different from word sizes
# endif
# define GC_GRANULE_BYTES 16
# define GC_GRANULE_WORDS 2
# else
Expand Down
26 changes: 20 additions & 6 deletions include/private/gc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -856,12 +856,26 @@ EXTERN_C_BEGIN
#endif

#if CPP_WORDSZ == 64
# define WORDS_TO_BYTES(x) ((x)<<3)
# define BYTES_TO_WORDS(x) ((x)>>3)
# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */
# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
# if ALIGNMENT != 8
# define UNALIGNED_PTRS
# if defined(__CHERI_PURE_CAPABILITY__)
# if __CHERI_CAPABILITY_WIDTH__ == 128
# define WORDS_TO_BYTES(x) ((x)<<4)
# define BYTES_TO_WORDS(x) ((x)>>4)
# define LOGWL ((word)7) /* log[2] of CPP_WORDSZ */
# define modWORDSZ(n) ((n) & 0x7f) /* n mod size of word */
# if ALIGNMENT != 16
# define UNALIGNED_PTRS
# endif
# else
# error Unsupported Capability Width
# endif
# elif
# define WORDS_TO_BYTES(x) ((x)<<3)
# define BYTES_TO_WORDS(x) ((x)>>3)
# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */
# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
# if ALIGNMENT != 8
# define UNALIGNED_PTRS
# endif
# endif
#endif

Expand Down
10 changes: 8 additions & 2 deletions include/private/gcconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -2915,7 +2915,11 @@ EXTERN_C_BEGIN
# ifdef RISCV
# define MACH_TYPE "RISC-V"
# define CPP_WORDSZ __riscv_xlen /* 32 or 64 */
# define ALIGNMENT (CPP_WORDSZ/8)
# if defined(__CHERI_PURE_CAPABILITY__)
# define ALIGNMENT (__riscv_clen >> 3)
# else
# define ALIGNMENT (CPP_WORDSZ/8)
# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# ifndef GC_FREEBSD_THREADS
Expand All @@ -2924,7 +2928,9 @@ EXTERN_C_BEGIN
# define SIG_SUSPEND SIGUSR1
# define SIG_THR_RESTART SIGUSR2
# define FREEBSD_STACKBOTTOM
# define DYNAMIC_LOADING
# if 0 //FIXME CHERI - commented to simplify initial port
# define DYNAMIC_LOADING
# endif
extern char etext[];
# define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
# define DATASTART_USES_BSDGETDATASTART
Expand Down
54 changes: 52 additions & 2 deletions mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "private/gc_pmark.h"

#include <stdio.h>
#if defined(__CHERI_PURE_CAPABILITY__)
#include <cheri/cheric.h>
#endif

#if defined(MSWIN32) && defined(__GNUC__)
# include <excpt.h>
Expand Down Expand Up @@ -692,7 +695,7 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# endif
/* Make sure that pointers overlapping the two ranges are */
/* considered. */
limit += sizeof(word) - ALIGNMENT;
limit += sizeof(ptr_t) - ALIGNMENT;
break;
case GC_DS_BITMAP:
mark_stack_top--;
Expand Down Expand Up @@ -794,13 +797,14 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
/* The simple case in which we're scanning a range. */
GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
credit -= limit - current_p;
limit -= sizeof(word);
limit -= sizeof(ptr_t);
{
# define PREF_DIST 4

# ifndef SMALL_CONFIG
word deferred;

# if !defined(__CHERI_PURE_CAPABILITY__)
/* Try to prefetch the next pointer to be examined ASAP. */
/* Empirically, this also seems to help slightly without */
/* prefetches, at least on linux/X86. Presumably this loop */
Expand Down Expand Up @@ -829,6 +833,41 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
}
if ((word)current_p > (word)limit) goto next_object;
}
# else /* !defined(__CHERI_PURE_CAPABILITY__) */
/* Check each pointer for validity before dereferencing */
/* to prevent capability exceptions. */
/* Utilise the pointer meta-data to speed-up the loop. */
/* If the loop is below the pointer bounds, skip the rest of */
/* marking for that chunk. */
/* If the *limit* capability restricts us to reading fewer than */
/* sizeof(ptr_t), */
/* a. there can't possibly be a pointer at limit's pointer */
/* b. reading at that location will raise a capability */
/* exception */
if (cheri_getaddress(limit) + sizeof(ptr_t) - 1
>= (cheri_getbase(limit) + cheri_getlength(limit))) {
/* Decrement limit so that it's within current_p's bounds */
limit = cheri_setaddress( current_p, ((cheri_getbase(limit)
+ cheri_getlength(limit) - sizeof(ptr_t))
& ~(sizeof(ptr_t)-1)));
if ((word)current_p > (word)limit) goto next_object;
}
for(;;) {
GC_ASSERT((word)limit >= (word)current_p);
if (cheri_getaddress(limit) < cheri_getbase(limit)) goto next_object;

if (cheri_gettag(limit) == 0) {
limit -= ALIGNMENT;
} else {
deferred = *(word *)limit;
FIXUP_POINTER(deferred);
limit -= ALIGNMENT;
if (deferred >= (word)least_ha && deferred < (word)greatest_ha)
break;
}
if ((word)current_p > (word)limit) goto next_object;
}
# endif // defined(__CHERI_PURE_CAPABILITY__)
# endif

while ((word)current_p <= (word)limit) {
Expand Down Expand Up @@ -1315,8 +1354,13 @@ GC_API void GC_CALL GC_push_all(void *bottom, void *top)
{
word length;

# if defined(__CHERI_PURE_CAPABILITY__)
bottom = cheri_setaddress(bottom, (((word)cheri_getaddress(bottom) + ALIGNMENT-1) & ~(ALIGNMENT-1)));
top = cheri_setaddress(top, ((word)cheri_getaddress(top) & ~(ALIGNMENT-1)));
# else
bottom = (void *)(((word)bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
top = (void *)((word)top & ~(ALIGNMENT-1));
#endif
if ((word)bottom >= (word)top) return;

GC_mark_stack_top++;
Expand Down Expand Up @@ -1553,8 +1597,14 @@ GC_API void GC_CALL GC_print_trace(word gc_no)
GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
{
# if defined(__CHERI_PURE_CAPABILITY__)
word * b = (word *)cheri_setaddress(bottom, (((vaddr_t) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1)));
word * t = (word *)cheri_setaddress(top, (((vaddr_t) top) & ~(ALIGNMENT-1)));
# else
word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
# endif

REGISTER word *p;
REGISTER word *lim;
REGISTER ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
Expand Down
4 changes: 2 additions & 2 deletions mark_rts.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,14 @@ STATIC void GC_remove_tmp_roots(void)

GC_INNER ptr_t GC_approx_sp(void)
{
volatile word sp;
volatile ptr_t sp;
# if defined(S390) && !defined(CPPCHECK) && (__clang_major__ < 8)
/* Workaround a crash in SystemZTargetLowering of libLLVM-3.8. */
sp = (word)&sp;
# elif defined(CPPCHECK) || (__GNUC__ >= 4 /* GC_GNUC_PREREQ(4, 0) */ \
&& !defined(STACK_NOT_SCANNED))
/* TODO: Use GC_GNUC_PREREQ after fixing a bug in cppcheck. */
sp = (word)__builtin_frame_address(0);
sp = (ptr_t)__builtin_frame_address(0);
# else
sp = (word)&sp;
# endif
Expand Down
4 changes: 3 additions & 1 deletion misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,9 @@ GC_API void GC_CALL GC_init(void)
}
# endif
# if !defined(CPPCHECK)
GC_STATIC_ASSERT(sizeof(ptr_t) == sizeof(word));
# if !defined(__CHERI_PURE_CAPABILITY__)
GC_STATIC_ASSERT(sizeof(ptr_t) == sizeof(word));
# endif
GC_STATIC_ASSERT(sizeof(signed_word) == sizeof(word));
# if !defined(_AUX_SOURCE) || defined(__GNUC__)
GC_STATIC_ASSERT((word)(-1) > (word)0);
Expand Down
72 changes: 50 additions & 22 deletions os_dep.c
Original file line number Diff line number Diff line change
Expand Up @@ -2015,29 +2015,57 @@ void GC_register_data_segments(void)
/* For now we don't assume that there is always an empty page after */
/* etext. But in some cases there actually seems to be slightly more. */
/* This also deals with holes between read-only data and writable data. */
GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t max_page_size,
ptr_t etext_addr)
{
word text_end = ((word)(etext_addr) + sizeof(word) - 1)
& ~(word)(sizeof(word) - 1);
/* etext rounded to word boundary */
volatile word next_page = (text_end + (word)max_page_size - 1)
& ~((word)max_page_size - 1);
volatile ptr_t result = (ptr_t)text_end;
GC_setup_temporary_fault_handler();
if (SETJMP(GC_jmp_buf) == 0) {
/* Try reading at the address. */
/* This should happen before there is another thread. */
for (; next_page < (word)DATAEND; next_page += (word)max_page_size)
*(volatile char *)next_page;
GC_reset_fault_handler();
} else {
GC_reset_fault_handler();
/* As above, we go to plan B */
result = (ptr_t)GC_find_limit(DATAEND, FALSE);
# if !defined(__CHERI_PURE_CAPABILITY__)
GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t max_page_size,
ptr_t etext_addr)
{
word text_end = ((word)(etext_addr) + sizeof(word) - 1)
& ~(word)(sizeof(word) - 1);
/* etext rounded to word boundary */
volatile word next_page = (text_end + (word)max_page_size - 1)
& ~((word)max_page_size - 1);
volatile ptr_t result = (ptr_t)text_end;
GC_setup_temporary_fault_handler();
if (SETJMP(GC_jmp_buf) == 0) {
/* Try reading at the address. */
/* This should happen before there is another thread. */
for (; next_page < (word)DATAEND; next_page += (word)max_page_size)
*(volatile char *)next_page;
GC_reset_fault_handler();
} else {
GC_reset_fault_handler();
/* As above, we go to plan B */
result = (ptr_t)GC_find_limit(DATAEND, FALSE);
}
return(result);
}
return(result);
}
# else /* !defined(__CHERI_PURE_CAPABILITY__) */
GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t max_page_size,
ptr_t etext_addr)
{
volatile ptr_t cap_next_page = NULL;
vaddr_t text_end = ((vaddr_t)(cheri_getaddress(etext_addr)) + sizeof(ptr_t) - 1)
& ~(vaddr_t)(sizeof(ptr_t) - 1);
volatile vaddr_t next_page = (text_end + (word)max_page_size - 1)
& ~((word)max_page_size - 1);
/* etext rounded to word boundary */
volatile ptr_t result = (ptr_t)cheri_setaddress(etext_addr, text_end);
GC_setup_temporary_fault_handler();
if (SETJMP(GC_jmp_buf) == 0) {
/* Try reading at the address. */
/* This should happen before there is another thread. */
for (; next_page < (word)DATAEND; next_page += (word)max_page_size)
cap_next_page = cheri_setaddress(etext_addr, next_page);
*cap_next_page;
GC_reset_fault_handler();
} else {
GC_reset_fault_handler();
/* As above, we go to plan B */
result = (ptr_t)GC_find_limit(DATAEND, FALSE);
}
return(result);
}
# endif /* !defined(__CHERI_PURE_CAPABILITY__) */
#endif /* DATASTART_USES_BSDGETDATASTART */

#ifdef AMIGA
Expand Down
20 changes: 20 additions & 0 deletions riscv64-purecap.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
set(CMAKE_SYSTEM_NAME Linux)

# Default SDK path
set(SDK "$ENV{HOME}/cheri/output/sdk" CACHE PATH "path to cheri SDK")

# Set toolchain compilers
set(CMAKE_C_COMPILER ${SDK}/bin/clang)
set(CMAKE_CXX_COMPILER ${SDK}/bin/clang++)

# Don't run the linker on compiler check
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# Use only cross compiler tools for compilation and linking
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# Set correct machine and abi flags
add_compile_options(--config cheribsd-riscv64-purecap.cfg)
add_link_options(-fuse-ld=lld --config cheribsd-riscv64-purecap.cfg)

0 comments on commit 8120c8b

Please sign in to comment.