From 23631a4ded59db4c4fe627cecae5122078456761 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 22 Jul 2021 03:38:34 +0100 Subject: [PATCH] WIP: don't unpack caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Profiling showed that we were spending unncessary amounts of time unpacking these fields. This speeds up a QEMU purecap kernel boot by about 5 seconds: ``` hyperfine -L qemu 'qemu-system-riscv64cheri.e2d8499d9a,qemu-system-riscv64cheri' '/home/alr48/devel/cheribuild/test-scripts/run_cheribsd_tests.py --ssh-key /home/alr48/.ssh/insecure_id_ed25519.pub --architecture riscv64-purecap --kernel /local/scratch/alr48/cheri/output/rootfs-riscv64-purecap/boot/kernel.CHERI-PURECAP-QEMU/kernel --qemu-cmd /local/scratch/alr48/cheri/output/sdk/bin/{qemu} --disk-image /local/scratch/alr48/cheri/output/cheribsd-riscv64-purecap.img --no-run-cheribsdtest' -m 5 Benchmark #1: /home/alr48/devel/cheribuild/test-scripts/run_cheribsd_tests.py --ssh-key /home/alr48/.ssh/insecure_id_ed25519.pub --architecture riscv64-purecap --kernel /local/scratch/alr48/cheri/output/rootfs-riscv64-purecap/boot/kernel.CHERI-PURECAP-QEMU/kernel --qemu-cmd /local/scratch/alr48/cheri/output/sdk/bin/qemu-system-riscv64cheri.e2d8499d9a --disk-image /local/scratch/alr48/cheri/output/cheribsd-riscv64-purecap.img --no-run-cheribsdtest Time (mean ± σ): 215.379 s ± 1.550 s [User: 203.415 s, System: 2.209 s] Range (min … max): 212.726 s … 216.815 s 5 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet PC without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Benchmark #2: /home/alr48/devel/cheribuild/test-scripts/run_cheribsd_tests.py --ssh-key /home/alr48/.ssh/insecure_id_ed25519.pub --architecture riscv64-purecap --kernel /local/scratch/alr48/cheri/output/rootfs-riscv64-purecap/boot/kernel.CHERI-PURECAP-QEMU/kernel --qemu-cmd /local/scratch/alr48/cheri/output/sdk/bin/qemu-system-riscv64cheri --disk-image /local/scratch/alr48/cheri/output/cheribsd-riscv64-purecap.img --no-run-cheribsdtest Time (mean ± σ): 210.971 s ± 1.600 s [User: 199.158 s, System: 2.056 s] Range (min … max): 208.997 s … 212.825 s 5 runs Summary '/home/alr48/devel/cheribuild/test-scripts/run_cheribsd_tests.py --ssh-key /home/alr48/.ssh/insecure_id_ed25519.pub --architecture riscv64-purecap --kernel /local/scratch/alr48/cheri/output/rootfs-riscv64-purecap/boot/kernel.CHERI-PURECAP-QEMU/kernel --qemu-cmd /local/scratch/alr48/cheri/output/sdk/bin/qemu-system-riscv64cheri --disk-image /local/scratch/alr48/cheri/output/cheribsd-riscv64-purecap.img --no-run-cheribsdtest' ran 1.02 ± 0.01 times faster than '/home/alr48/devel/cheribuild/test-scripts/run_cheribsd_tests.py --ssh-key /home/alr48/.ssh/insecure_id_ed25519.pub --architecture riscv64-purecap --kernel /local/scratch/alr48/cheri/output/rootfs-riscv64-purecap/boot/kernel.CHERI-PURECAP-QEMU/kernel --qemu-cmd /local/scratch/alr48/cheri/output/sdk/bin/qemu-system-riscv64cheri.e2d8499d9a --disk-image /local/scratch/alr48/cheri/output/cheribsd-riscv64-purecap.img --no-run-cheribsdtest' ``` --- .../cheri_compressed_cap.h | 3 +- .../cheri_compressed_cap_common.h | 119 ++++++------------ .../test/random_inputs_test.cpp | 2 +- .../test/sail_wrapper_common.c | 8 +- .../test/setbounds_test.cpp | 12 +- .../cheri-compressed-cap/test/simple_test.cpp | 12 +- .../cheri-common/cheri-lazy-capregs-types.h | 6 +- target/cheri-common/cheri-lazy-capregs.h | 47 +++---- target/cheri-common/cheri_utils.h | 21 ++-- target/cheri-common/op_helper_cheri_common.c | 16 +-- target/riscv/translate.c | 2 +- 11 files changed, 99 insertions(+), 149 deletions(-) diff --git a/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap.h b/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap.h index ee522cc7a30..1fa522b9bad 100644 --- a/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap.h +++ b/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap.h @@ -124,7 +124,7 @@ typedef union _inmemory_chericap256 { uint32_t u32s[8]; uint64_t u64s[4]; } inmemory_chericap256; - +#if 0 static inline bool cc256_is_cap_sealed(const cc256_cap_t* cp) { return cp->cr_otype != CC256_OTYPE_UNSEALED; } static inline void decompress_256cap(inmemory_chericap256 mem, cc256_cap_t* cdp, bool tagged) { @@ -160,5 +160,6 @@ static inline void compress_256cap(inmemory_chericap256* buffer, const cc256_cap uint64_t length64 = length65 > UINT64_MAX ? UINT64_MAX : (uint64_t)length65; buffer->u64s[3] = length64 ^ CC256_NULL_LENGTH; } +#endif #endif /* CHERI_COMPRESSED_CAP_H */ diff --git a/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap_common.h b/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap_common.h index 950e6c177c6..2bc39a2a217 100644 --- a/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap_common.h +++ b/target/cheri-common/cheri-compressed-cap/cheri_compressed_cap_common.h @@ -108,19 +108,14 @@ struct _cc_N(cap) { #ifdef _CC_REVERSE_PESBT_CURSOR_ORDER /* Original PESBT from the decompressed capability. If you modify * other fields, you must be sure to either recalculate this field to match */ - _cc_addr_t cached_pesbt; + _cc_addr_t cr_pesbt; _cc_addr_t _cr_cursor; /* Capability cursor */ #else _cc_addr_t _cr_cursor; - _cc_addr_t cached_pesbt; + _cc_addr_t cr_pesbt; #endif _cc_length_t _cr_top; /* Capability top */ _cc_addr_t cr_base; /* Capability base addr */ - uint32_t cr_perms; /* Permissions */ - uint32_t cr_uperms; /* User Permissions */ - uint32_t cr_otype; /* Object Type, 24/16 bits */ - uint8_t cr_flags; /* Flags */ - uint8_t cr_reserved; /* Remaining hardware-reserved bits to preserve */ uint8_t cr_tag; /* Tag */ uint8_t cr_bounds_valid; /* Set if bounds decode was given an invalid cap */ #ifdef __cplusplus @@ -147,8 +142,8 @@ struct _cc_N(cap) { typedef struct _cc_N(cap) _cc_N(cap_t); #define _cc_cap_t _cc_N(cap_t) -static inline bool _cc_N(exactly_equal)(struct _cc_N(cap) const* a, struct _cc_N(cap) const* b) { - return a->cr_tag == b->cr_tag && a->_cr_cursor == b->_cr_cursor && a->cached_pesbt == b->cached_pesbt; +static inline bool _cc_N(exactly_equal)(const _cc_cap_t* a, const _cc_cap_t* b) { + return a->cr_tag == b->cr_tag && a->_cr_cursor == b->_cr_cursor && a->cr_pesbt == b->cr_pesbt; } /* Returns the index of the most significant bit set in x */ @@ -224,6 +219,23 @@ struct _cc_N(bounds_bits) { }; #define _cc_bounds_bits struct _cc_N(bounds_bits) +#define ALL_WRAPPERS(X, FN, type) \ + static inline _cc_addr_t _cc_N(cap_pesbt_extract_##FN)(_cc_addr_t pesbt) { return _CC_EXTRACT_FIELD(pesbt, X); } \ + static inline _cc_addr_t _cc_N(cap_pesbt_encode_##FN)(type value) { return _CC_ENCODE_FIELD(value, X); } \ + static inline _cc_addr_t _cc_N(cap_pesbt_deposit_##FN)(_cc_addr_t pesbt, type value) { \ + return (pesbt & ~_CC_N(FIELD_##X##_MASK64)) | _CC_ENCODE_FIELD(value, X); \ + } \ + static inline type _cc_N(get_##FN)(const _cc_cap_t* cap) { return _cc_N(cap_pesbt_extract_##FN)(cap->cr_pesbt); } \ + static inline void _cc_N(update_##FN)(_cc_cap_t * cap, _cc_addr_t value) { \ + cap->cr_pesbt = _cc_N(cap_pesbt_deposit_##FN)(cap->cr_pesbt, value); \ + } +ALL_WRAPPERS(HWPERMS, perms, uint32_t) +ALL_WRAPPERS(UPERMS, uperms, uint32_t) +ALL_WRAPPERS(OTYPE, otype, uint32_t) +ALL_WRAPPERS(FLAGS, flags, uint8_t) +ALL_WRAPPERS(RESERVED, reserved, uint8_t) +#undef ALL_WRAPPERS + /// Extract the bits used for bounds and infer the top two bits of T static inline _cc_bounds_bits _cc_N(extract_bounds_bits)(_cc_addr_t pesbt) { _CC_STATIC_ASSERT(_CC_MANTISSA_WIDTH == _CC_N(BOT_WIDTH), "Wrong bot width?"); @@ -390,12 +402,7 @@ static inline bool _cc_N(compute_base_top)(_cc_bounds_bits bounds, _cc_addr_t cu static inline void _cc_N(decompress_raw)(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag, _cc_cap_t* cdp) { cdp->cr_tag = tag; cdp->_cr_cursor = cursor; - cdp->cr_perms = (uint32_t)_CC_EXTRACT_FIELD(pesbt, HWPERMS); - cdp->cr_uperms = (uint32_t)_CC_EXTRACT_FIELD(pesbt, UPERMS); - cdp->cr_otype = (uint32_t)_CC_EXTRACT_FIELD(pesbt, OTYPE); - cdp->cr_flags = (uint8_t)_CC_EXTRACT_FIELD(pesbt, FLAGS); - cdp->cr_reserved = (uint8_t)_CC_EXTRACT_FIELD(pesbt, RESERVED); - cdp->cached_pesbt = pesbt; + cdp->cr_pesbt = pesbt; _cc_bounds_bits bounds = _cc_N(extract_bounds_bits)(pesbt); bool valid = _cc_N(compute_base_top)(bounds, cursor, &cdp->cr_base, &cdp->_cr_top); @@ -407,7 +414,7 @@ static inline void _cc_N(decompress_raw)(_cc_addr_t pesbt, _cc_addr_t cursor, bo _cc_debug_assert(cdp->_cr_top <= _CC_N(MAX_TOP)); _cc_debug_assert(cdp->cr_base <= cdp->_cr_top); #endif - _cc_debug_assert(cdp->cr_reserved == 0); + _cc_debug_assert(_CC_EXTRACT_FIELD(pesbt, RESERVED) == 0); } } @@ -418,31 +425,22 @@ static inline void _cc_N(decompress_mem)(uint64_t pesbt, uint64_t cursor, bool t _cc_N(decompress_raw)(pesbt ^ _CC_N(NULL_XOR_MASK), cursor, tag, cdp); } -static inline bool _cc_N(is_cap_sealed)(const _cc_cap_t* cp) { return cp->cr_otype != _CC_N(OTYPE_UNSEALED); } +static inline bool _cc_N(is_cap_sealed)(const _cc_cap_t* cp) { return _cc_N(get_otype)(cp) != _CC_N(OTYPE_UNSEALED); } // Update ebt bits in pesbt static inline void _cc_N(update_ebt)(_cc_cap_t* csp, _cc_addr_t new_ebt) { - csp->cached_pesbt = (csp->cached_pesbt & ~_CC_N(FIELD_EBT_MASK64)) | new_ebt; -} - -// Recompute non-ebt part of pesbt if multiple non-ebt fields are changed -static inline _cc_addr_t _cc_N(recompute_pesbt_non_ebt)(const _cc_cap_t* csp) { - return _CC_ENCODE_FIELD(csp->cr_uperms, UPERMS) | _CC_ENCODE_FIELD(csp->cr_perms, HWPERMS) | - _CC_ENCODE_FIELD(csp->cr_otype, OTYPE) | _CC_ENCODE_FIELD(csp->cr_reserved, RESERVED) | - _CC_ENCODE_FIELD(csp->cr_flags, FLAGS); + csp->cr_pesbt = (csp->cr_pesbt & ~_CC_N(FIELD_EBT_MASK64)) | new_ebt; } /* * Compress a capability to 128 bits. - * Note: if you have not been manually modifying fields, just access csp->cached_pesbt. + * Note: if you have not been manually modifying fields, just access csp->cr_pesbt. * cap_set_decompressed_X will set fields and keep pesbt in sync. */ static inline _cc_addr_t _cc_N(compress_raw)(const _cc_cap_t* csp) { - _cc_debug_assert(!(csp->cr_tag && csp->cr_reserved) && "Unknown reserved bits set it tagged capability"); - _cc_addr_t pesbt = _CC_ENCODE_FIELD(csp->cr_uperms, UPERMS) | _CC_ENCODE_FIELD(csp->cr_perms, HWPERMS) | - _CC_ENCODE_FIELD(csp->cr_otype, OTYPE) | _CC_ENCODE_FIELD(csp->cr_reserved, RESERVED) | - _CC_ENCODE_FIELD(csp->cr_flags, FLAGS) | (csp->cached_pesbt & _CC_N(FIELD_EBT_MASK64)); - return pesbt; + _cc_debug_assert((!csp->cr_tag || _cc_N(get_reserved)(csp) == 0) && + "Unknown reserved bits set it tagged capability"); + return csp->cr_pesbt; } static inline _cc_addr_t _cc_N(compress_mem)(const _cc_cap_t* csp) { @@ -489,13 +487,7 @@ static inline bool _cc_N(is_representable_cap_exact)(const _cc_cap_t* cap) { _cc_N(decompress_raw)(pesbt, cap->_cr_cursor, cap->cr_tag, &decompressed_cap); // These fields must not change: _cc_debug_assert(decompressed_cap._cr_cursor == cap->_cr_cursor); - _cc_debug_assert(decompressed_cap.cr_perms == cap->cr_perms); - _cc_debug_assert(decompressed_cap.cr_uperms == cap->cr_uperms); - _cc_debug_assert(decompressed_cap.cr_otype == cap->cr_otype); - _cc_debug_assert((decompressed_cap.cached_pesbt & _CC_N(FIELD_EBT_MASK64)) == - (cap->cached_pesbt & _CC_N(FIELD_EBT_MASK64))); - _cc_debug_assert(decompressed_cap.cr_flags == cap->cr_flags); - _cc_debug_assert(decompressed_cap.cr_reserved == cap->cr_reserved); + _cc_debug_assert(decompressed_cap.cr_pesbt == cap->cr_pesbt); // If any of these fields changed then the capability is not representable: if (decompressed_cap.cr_base != cap->cr_base || decompressed_cap._cr_top != cap->_cr_top) { return false; @@ -681,10 +673,11 @@ static inline bool _cc_N(is_representable_new_addr)(bool sealed, _cc_addr_t base c.cr_base = base; c._cr_top = top; c._cr_cursor = cursor; - c.cr_otype = sealed ? 42 : _CC_N(OTYPE_UNSEALED); // important to set as compress assumes this is in bounds + // important to set as compress assumes this is in bounds + c.cr_pesbt = _CC_ENCODE_FIELD(_CC_N(UPERMS_ALL), UPERMS) | _CC_ENCODE_FIELD(_CC_N(PERMS_ALL), HWPERMS) | + _CC_ENCODE_FIELD(sealed ? 42 : _CC_N(OTYPE_UNSEALED), OTYPE); /* Get an EBT */ bool exact_input = false; - c.cached_pesbt = _cc_N(recompute_pesbt_non_ebt)(&c); _cc_N(update_ebt)(&c, _cc_N(compute_ebt)(base, top, NULL, &exact_input)); // Looks like this assert gets hit by negative length capabilities. Probably the "exact input" return is wrong. if (top > (_cc_length_t)base) @@ -699,7 +692,7 @@ static inline bool _cc_N(is_representable_new_addr)(bool sealed, _cc_addr_t base } static inline bool _cc_N(cap_bounds_uses_value)(const _cc_cap_t* cap) { - _cc_bounds_bits bounds = _cc_N(extract_bounds_bits)(cap->cached_pesbt); + _cc_bounds_bits bounds = _cc_N(extract_bounds_bits)(cap->cr_pesbt); return bounds.E + _CC_N(FIELD_BOTTOM_ENCODED_SIZE) < (sizeof(_cc_addr_t) * 8); } @@ -840,7 +833,8 @@ static inline bool _cc_N(setbounds_impl)(_cc_cap_t* cap, _cc_addr_t req_base, _c } _cc_debug_assert(new_top >= new_base); - _cc_debug_assert(!(cap->cr_tag && cap->cr_reserved) && "Unknown reserved bits set in tagged capability"); + _cc_debug_assert((!cap->cr_tag || _cc_N(get_reserved)(cap) == 0) && + "Unknown reserved bits set in tagged capability"); cap->cr_base = new_base; cap->_cr_top = new_top; _cc_N(update_ebt)(cap, new_ebt); @@ -872,7 +866,8 @@ static inline _cc_addr_t _cc_N(get_alignment_mask)(_cc_addr_t req_length) { memset(&tmpcap, 0, sizeof(tmpcap)); tmpcap.cr_tag = 1; tmpcap._cr_top = _CC_MAX_TOP; - tmpcap.cr_otype = _CC_N(OTYPE_UNSEALED); + _cc_N(update_otype)(&tmpcap, _CC_N(OTYPE_UNSEALED)); + _cc_N(update_ebt)(&tmpcap, _CC_N(RESET_EBT)); _cc_addr_t mask = 0; _cc_N(setbounds_impl)(&tmpcap, 0, req_length, &mask); return mask; @@ -889,12 +884,10 @@ static inline _cc_cap_t _cc_N(make_max_perms_cap)(_cc_addr_t base, _cc_addr_t cu creg.cr_flags = 0; #endif creg._cr_top = top; - creg.cr_perms = _CC_N(PERMS_ALL); - creg.cr_uperms = _CC_N(UPERMS_ALL); - creg.cr_otype = _CC_N(OTYPE_UNSEALED); + creg.cr_pesbt = _CC_ENCODE_FIELD(_CC_N(UPERMS_ALL), UPERMS) | _CC_ENCODE_FIELD(_CC_N(PERMS_ALL), HWPERMS) | + _CC_ENCODE_FIELD(_CC_N(OTYPE_UNSEALED), OTYPE); creg.cr_tag = true; bool exact_input = false; - creg.cached_pesbt = _cc_N(recompute_pesbt_non_ebt)(&creg); _cc_N(update_ebt)(&creg, _cc_N(compute_ebt)(creg.cr_base, creg._cr_top, NULL, &exact_input)); assert(exact_input && "Invalid arguments"); assert(_cc_N(is_representable_cap_exact)(&creg)); @@ -912,38 +905,6 @@ static inline _cc_addr_t _cc_N(get_representable_length)(_cc_addr_t req_length) return (req_length + ~mask) & mask; } -#define EXTRACT_WRAPPER(X) \ - static inline _cc_addr_t _cc_N(cap_pesbt_extract_##X)(_cc_addr_t pesbt) { return _CC_EXTRACT_FIELD(pesbt, X); } -#define ENCODE_WRAPPER(X) \ - static inline _cc_addr_t _cc_N(cap_pesbt_encode_##X)(_cc_addr_t value) { return _CC_ENCODE_FIELD(value, X); } -#define DEPOSIT_WRAPPER(X) \ - static inline _cc_addr_t _cc_N(cap_pesbt_deposit_##X)(_cc_addr_t pesbt, _cc_addr_t value) { \ - return (pesbt & ~_CC_N(FIELD_##X##_MASK64)) | _CC_ENCODE_FIELD(value, X); \ - } -#define SET_DECOMPRESSED(X, FN) \ - static inline void _cc_N(cap_set_decompressed_##FN)(_cc_cap_t * cap, _cc_addr_t value) { \ - cap->cached_pesbt = _cc_N(cap_pesbt_deposit_##X)(cap->cached_pesbt, value); \ - cap->FN = value; \ - } - -#define ALL_WRAPPERS(X) EXTRACT_WRAPPER(X) ENCODE_WRAPPER(X) DEPOSIT_WRAPPER(X) - -ALL_WRAPPERS(HWPERMS) -ALL_WRAPPERS(UPERMS) -ALL_WRAPPERS(OTYPE) -ALL_WRAPPERS(FLAGS) - -SET_DECOMPRESSED(HWPERMS, cr_perms) -SET_DECOMPRESSED(UPERMS, cr_uperms) -SET_DECOMPRESSED(OTYPE, cr_otype) -SET_DECOMPRESSED(FLAGS, cr_flags) - -#undef EXTRACT_WRAPPER -#undef ENCODE_WRAPPER -#undef DEPOSIT_WRAPPER -#undef SET_DECOMPRESSED -#undef ALL_WRAPPERS - /// Provide a C++ class with the same function names /// to simplify writing code that handles both 128 and 64-bit capabilities #ifdef __cplusplus diff --git a/target/cheri-common/cheri-compressed-cap/test/random_inputs_test.cpp b/target/cheri-common/cheri-compressed-cap/test/random_inputs_test.cpp index e3b9e7c1120..83b153be51f 100644 --- a/target/cheri-common/cheri-compressed-cap/test/random_inputs_test.cpp +++ b/target/cheri-common/cheri-compressed-cap/test/random_inputs_test.cpp @@ -49,7 +49,7 @@ static bool check_fields_match(const typename Handler::cap_t& result, const test CHECK_AND_SAVE_SUCCESS(sail_result._cr_cursor == result._cr_cursor); CHECK_AND_SAVE_SUCCESS(sail_result._cr_top == result._cr_top); CHECK_AND_SAVE_SUCCESS(sail_result.cr_base == result.cr_base); - CHECK_AND_SAVE_SUCCESS(sail_result.cached_pesbt == result.cached_pesbt); + CHECK_AND_SAVE_SUCCESS(sail_result.cr_pesbt == result.cr_pesbt); CHECK_AND_SAVE_SUCCESS(sail_result.cr_flags == result.cr_flags); CHECK_AND_SAVE_SUCCESS(sail_result.cr_otype == result.cr_otype); CHECK_AND_SAVE_SUCCESS(sail_result.cr_perms == result.cr_perms); diff --git a/target/cheri-common/cheri-compressed-cap/test/sail_wrapper_common.c b/target/cheri-common/cheri-compressed-cap/test/sail_wrapper_common.c index e8c00ae9ae3..fab48b6a145 100644 --- a/target/cheri-common/cheri-compressed-cap/test/sail_wrapper_common.c +++ b/target/cheri-common/cheri-compressed-cap/test/sail_wrapper_common.c @@ -119,7 +119,7 @@ void sail_decode_common_mem(uint64_t mem_pesbt, uint64_t mem_cursor, bool tag, c cdp->cr_flags = 0; cdp->cr_uperms = 0; - cdp->cached_pesbt = mem_pesbt; + cdp->cr_pesbt = mem_pesbt; // Destroy cap KILL(lbits)(&capbits); @@ -175,7 +175,7 @@ static void sail_cap_to_cap_t(const struct zCapability* sail, _cc_cap_t* c) { // extract cc128 EBT field: // TODO: avoid roundtrip via sailgen_capToBits? uint64_t sail_pesbt = _compress_sailcap_raw(*sail); - c->cached_pesbt = sail_pesbt; + c->cr_pesbt = sail_pesbt; } static void sail_decode_common_mem(_cc_addr_t mem_pesbt, _cc_addr_t mem_cursor, bool tag, _cc_cap_t* cdp) { @@ -221,8 +221,8 @@ static struct zCapability cap_t_to_sail_cap(const _cc_cap_t* c) { result.zotype = c->cr_otype; result.zflag_cap_mode = c->cr_flags; - // Extract E,B,T,IE from the cached_pesbt field: - _cc_addr_t fake_pesbt = c->cached_pesbt; + // Extract E,B,T,IE from the cr_pesbt field: + _cc_addr_t fake_pesbt = c->cr_pesbt; _cc_bounds_bits c_bounds = _cc_N(extract_bounds_bits)(fake_pesbt); result.zinternal_E = c_bounds.IE; result.zE = c_bounds.E; diff --git a/target/cheri-common/cheri-compressed-cap/test/setbounds_test.cpp b/target/cheri-common/cheri-compressed-cap/test/setbounds_test.cpp index 2baba2b81d1..65b2a0c5b48 100644 --- a/target/cheri-common/cheri-compressed-cap/test/setbounds_test.cpp +++ b/target/cheri-common/cheri-compressed-cap/test/setbounds_test.cpp @@ -63,15 +63,15 @@ static typename Handler::cap_t do_csetbounds(const typename Handler::cap_t& init CHECK(sail_exact == exact); check_csetbounds_invariants(initial_cap, with_bounds, exact, requested_base, requested_top); - // Check that the cached_pesbt is updated correctly and matches sail - CHECK(with_bounds.cached_pesbt == Handler::compress_raw(&with_bounds)); - CHECK(with_bounds.cached_pesbt == Handler::sail_compress_raw(&with_bounds)); + // Check that the cr_pesbt is updated correctly and matches sail + CHECK(with_bounds.cr_pesbt == Handler::compress_raw(&with_bounds)); + CHECK(with_bounds.cr_pesbt == Handler::sail_compress_raw(&with_bounds)); // Re-create the bounded capability and assert that the current pesbt values matches that one. auto new_cap = Handler::make_max_perms_cap(with_bounds.base(), with_bounds.address(), with_bounds.top()); CHECK(new_cap == with_bounds); - CHECK(new_cap.cached_pesbt == with_bounds.cached_pesbt); - CHECK(new_cap.cached_pesbt == Handler::compress_raw(&with_bounds)); - CHECK(new_cap.cached_pesbt == Handler::sail_compress_raw(&with_bounds)); + CHECK(new_cap.cr_pesbt == with_bounds.cr_pesbt); + CHECK(new_cap.cr_pesbt == Handler::compress_raw(&with_bounds)); + CHECK(new_cap.cr_pesbt == Handler::sail_compress_raw(&with_bounds)); if (was_exact) *was_exact = exact; diff --git a/target/cheri-common/cheri-compressed-cap/test/simple_test.cpp b/target/cheri-common/cheri-compressed-cap/test/simple_test.cpp index befbbe38e6d..53255a8a691 100644 --- a/target/cheri-common/cheri-compressed-cap/test/simple_test.cpp +++ b/target/cheri-common/cheri-compressed-cap/test/simple_test.cpp @@ -15,10 +15,10 @@ TEST_CASE("Compressed NULL cap encodes to zeroes", "[nullcap]") { memset(&null_cap, 0, sizeof(null_cap)); null_cap.cr_otype = CC128_OTYPE_UNSEALED; null_cap._cr_top = CC128_NULL_TOP; - null_cap.cached_pesbt = CC128_NULL_PESBT; + null_cap.cr_pesbt = CC128_NULL_PESBT; bool ebt_exact = true; uint32_t computed_ebt = cc128_compute_ebt(null_cap.cr_base, null_cap._cr_top, NULL, &ebt_exact); - REQUIRE((computed_ebt & CC128_FIELD_EBT_MASK64) == (null_cap.cached_pesbt & CC128_FIELD_EBT_MASK64)); + REQUIRE((computed_ebt & CC128_FIELD_EBT_MASK64) == (null_cap.cr_pesbt & CC128_FIELD_EBT_MASK64)); REQUIRE(ebt_exact); auto pesbt = cc128_compress_mem(&null_cap); auto pesbt_from_sail = sail_compress_128_mem(&null_cap); @@ -36,7 +36,7 @@ TEST_CASE("Compressed NULL cap encodes to zeroes", "[nullcap]") { CHECK(decompressed.address() == 0); CHECK_FIELD(decompressed, software_permissions, 0); CHECK_FIELD(decompressed, permissions, 0); - CHECK((decompressed.cached_pesbt & CC128_FIELD_EBT_MASK64) == (CC128_NULL_PESBT & CC128_FIELD_EBT_MASK64)); + CHECK((decompressed.cr_pesbt & CC128_FIELD_EBT_MASK64) == (CC128_NULL_PESBT & CC128_FIELD_EBT_MASK64)); CHECK(decompressed.cr_reserved == 0); // reserved bits CHECK(decompressed.length() == CC128_NULL_LENGTH); CHECK(decompressed.top() == CC128_NULL_TOP); @@ -79,7 +79,7 @@ TEST_CASE("Zeroes decode to NULL cap", "[nullcap]") { CHECK_FIELD(result128, offset, 0); CHECK_FIELD(result128, software_permissions, 0); CHECK_FIELD(result128, permissions, 0); - CHECK((result128.cached_pesbt & CC128_FIELD_EBT_MASK64) == (CC128_NULL_PESBT & CC128_FIELD_EBT_MASK64)); + CHECK((result128.cr_pesbt & CC128_FIELD_EBT_MASK64) == (CC128_NULL_PESBT & CC128_FIELD_EBT_MASK64)); CHECK(result128.cr_reserved == 0); // reserved bits CHECK_FIELD_RAW(result128.length(), CC128_NULL_LENGTH); CHECK_FIELD(result128, type, CC128_OTYPE_UNSEALED); @@ -94,7 +94,7 @@ TEST_CASE("Zeroes decode to NULL cap", "[nullcap]") { CHECK_FIELD(result64, offset, 0); CHECK_FIELD(result64, software_permissions, 0); CHECK_FIELD(result64, permissions, 0); - CHECK((result64.cached_pesbt & CC64_FIELD_EBT_MASK64) == (CC64_NULL_PESBT & CC64_FIELD_EBT_MASK64)); + CHECK((result64.cr_pesbt & CC64_FIELD_EBT_MASK64) == (CC64_NULL_PESBT & CC64_FIELD_EBT_MASK64)); CHECK(result64.cr_reserved == 0); // reserved bits CHECK_FIELD_RAW(result64.length(), CC64_NULL_LENGTH); CHECK_FIELD(result64, type, CC64_OTYPE_UNSEALED); @@ -131,7 +131,7 @@ static void check_representable(uint64_t base, cc128_length_t length, uint64_t o cap.cr_tag = true; cap.cr_otype = CC128_OTYPE_UNSEALED; bool exact_input = false; - cap.cached_pesbt = cc128_compute_ebt(cap.cr_base, cap._cr_top, NULL, &exact_input); + cap.cr_pesbt = cc128_compute_ebt(cap.cr_base, cap._cr_top, NULL, &exact_input); REQUIRE(exact_input == should_work); uint64_t compressed = cc128_compress_mem(&cap); cc128_cap_t decompressed; diff --git a/target/cheri-common/cheri-lazy-capregs-types.h b/target/cheri-common/cheri-lazy-capregs-types.h index 8c9dae1bd5e..a3935a19506 100644 --- a/target/cheri-common/cheri-lazy-capregs-types.h +++ b/target/cheri-common/cheri-lazy-capregs-types.h @@ -69,13 +69,11 @@ typedef enum CapRegState { // Cap registers should be padded so they are easier to move. #if TARGET_LONG_BITS == 32 -_Static_assert(sizeof(cap_register_t) == 40, ""); -#else -_Static_assert(sizeof(cap_register_t) == 64, ""); +_Static_assert(sizeof(cap_register_t) == 24, ""); #endif // pesbt should come directly before reg._cr_cursor, so that the two can be // moved with a single 128bit vector op. -_Static_assert((offsetof(cap_register_t, cached_pesbt) - +_Static_assert((offsetof(cap_register_t, cr_pesbt) - offsetof(cap_register_t, _cr_cursor)) == sizeof(target_ulong), ""); diff --git a/target/cheri-common/cheri-lazy-capregs.h b/target/cheri-common/cheri-lazy-capregs.h index 58c614440dd..a6c903ce3dd 100644 --- a/target/cheri-common/cheri-lazy-capregs.h +++ b/target/cheri-common/cheri-lazy-capregs.h @@ -64,7 +64,7 @@ static inline void sanity_check_capreg(GPCapRegs *gpcrs, unsigned regnum) const cap_register_t *c = &gpcrs->decompressed[regnum]; // Check that the compressed and decompressed caps are in sync cheri_debug_assert(CAP_cc(compress_raw)(c) == - gpcrs->decompressed[regnum].cached_pesbt); + gpcrs->decompressed[regnum].cr_pesbt); cheri_debug_assert((c->cr_tag == 0 || c->cr_tag == 1) && "Unitialized value used?"); } else { @@ -72,13 +72,13 @@ static inline void sanity_check_capreg(GPCapRegs *gpcrs, unsigned regnum) // accessed. However, the cursor and pesbt must remain valid. cap_register_t *decompressed = &gpcrs->decompressed[regnum]; target_ulong cursor = decompressed->_cr_cursor; - target_ulong pesbt = decompressed->cached_pesbt; + target_ulong pesbt = decompressed->cr_pesbt; memset(decompressed, 0xaa, sizeof(*decompressed)); decompressed->_cr_cursor = cursor; - decompressed->cached_pesbt = pesbt; + decompressed->cr_pesbt = pesbt; } if (regnum == NULL_CAPREG_INDEX) { - cheri_debug_assert(gpcrs->decompressed[regnum].cached_pesbt == + cheri_debug_assert(gpcrs->decompressed[regnum].cr_pesbt == CAP_NULL_PESBT); cheri_debug_assert(gpcrs->decompressed[regnum]._cr_cursor == 0); cheri_debug_assert(CAP_cc(compress_raw)(&gpcrs->decompressed[regnum]) == @@ -91,7 +91,7 @@ static inline void sanity_check_capreg(GPCapRegs *gpcrs, unsigned regnum) // integer registers always hold CAP_NULL_PESBT. This is not currently // true since we don't update PESBT when changing a register from // capability to integer. - cheri_debug_assert(gpcrs->decompressed[regnum].cached_pesbt == + cheri_debug_assert(gpcrs->decompressed[regnum].cr_pesbt == CAP_NULL_PESBT); } #endif // CONFIG_DEBUG_TCG @@ -116,7 +116,7 @@ static inline const cap_register_t * _update_from_compressed(GPCapRegs *gpcrs, unsigned regnum, bool tag) { // Note: The _cr_cusor field is always valid. All others are lazy. - CAP_cc(decompress_raw)(gpcrs->decompressed[regnum].cached_pesbt, + CAP_cc(decompress_raw)(gpcrs->decompressed[regnum].cr_pesbt, gpcrs->decompressed[regnum]._cr_cursor, tag, &gpcrs->decompressed[regnum]); set_capreg_state(gpcrs, regnum, CREG_FULLY_DECOMPRESSED); @@ -136,7 +136,7 @@ get_readonly_capreg(CPUArchState *env, unsigned regnum) switch (get_capreg_state(gpcrs, regnum)) { case CREG_INTEGER: { // Update capreg to a decompressed integer value and clear pesbt - cheri_debug_assert(gpcrs->decompressed[regnum].cached_pesbt == + cheri_debug_assert(gpcrs->decompressed[regnum].cr_pesbt == CAP_NULL_PESBT); const cap_register_t *result = int_to_cap(gpcrs->decompressed[regnum]._cr_cursor, @@ -224,7 +224,7 @@ static inline void update_capreg(CPUArchState *env, unsigned regnum, cap_register_t *target = &gpcrs->decompressed[regnum]; *target = *newval; // Update the compressed values for fast access from TCG - gpcrs->decompressed[regnum].cached_pesbt = CAP_cc(compress_raw)(target); + gpcrs->decompressed[regnum].cr_pesbt = CAP_cc(compress_raw)(target); set_capreg_state(gpcrs, regnum, CREG_FULLY_DECOMPRESSED); sanity_check_capreg(gpcrs, regnum); rvfi_changed_capreg(env, regnum, newval->_cr_cursor); @@ -272,7 +272,7 @@ static inline void update_compressed_capreg(CPUArchState *env, unsigned regnum, GPCapRegs *gpcrs = cheri_get_gpcrs(env); gpcrs->decompressed[regnum]._cr_cursor = cursor; - gpcrs->decompressed[regnum].cached_pesbt = pesbt; + gpcrs->decompressed[regnum].cr_pesbt = pesbt; CapRegState new_state = tag ? CREG_TAGGED_CAP : CREG_UNTAGGED_CAP; set_capreg_state(gpcrs, regnum, new_state); cheri_debug_assert(get_capreg_state(gpcrs, regnum) == new_state); @@ -294,7 +294,7 @@ static inline target_ulong get_capreg_pesbt(CPUArchState *env, unsigned regnum) if (get_capreg_state(gpcrs, regnum) == CREG_INTEGER) { return CAP_NULL_PESBT; } - return gpcrs->decompressed[regnum].cached_pesbt; + return gpcrs->decompressed[regnum].cr_pesbt; } static inline void update_capreg_to_intval(CPUArchState *env, unsigned regnum, @@ -306,7 +306,7 @@ static inline void update_capreg_to_intval(CPUArchState *env, unsigned regnum, GPCapRegs *gpcrs = cheri_get_gpcrs(env); gpcrs->decompressed[regnum]._cr_cursor = newval; - gpcrs->decompressed[regnum].cached_pesbt = CAP_NULL_PESBT; + gpcrs->decompressed[regnum].cr_pesbt = CAP_NULL_PESBT; set_capreg_state(gpcrs, regnum, CREG_INTEGER); sanity_check_capreg(gpcrs, regnum); rvfi_changed_capreg(env, regnum, newval); @@ -352,7 +352,8 @@ static inline target_ulong get_capreg_tag_filtered(CPUArchState *env, unsigned r const cap_register_t *csp = get_readonly_capreg(env, regnum); - // TODO: Also revoke if (lo <= type < hi) && (csp->cr_perms & MAGIC_REVOKE_TYPE) + // TODO: Also revoke if (lo <= type < hi) && (csp->cr_perms & + // MAGIC_REVOKE_TYPE) if (csp->cr_base >= env->cheri_capfilter_lo && csp->_cr_top <= env->cheri_capfilter_hi && (cap_get_perms(csp) & env->cheri_capfilter_perms) == cap_get_perms(csp)) @@ -368,22 +369,12 @@ static inline uint32_t get_capreg_hwperms(CPUArchState *env, unsigned regnum) { GPCapRegs *gpcrs = cheri_get_gpcrs(env); sanity_check_capreg(gpcrs, regnum); - // We can determine the value of the tag by looking at the current state: - // Three of them directly encode the tag value and in the fully decompressed - // state we simply read the cr_tag member. - switch (get_capreg_state(gpcrs, regnum)) { - case CREG_FULLY_DECOMPRESSED: - return cap_get_perms(&gpcrs->decompressed[regnum]); - case CREG_INTEGER: - return 0; /* No permissions */ - case CREG_TAGGED_CAP: - case CREG_UNTAGGED_CAP: - return (uint32_t)CAP_CC(EXTRACT_FIELD)( - gpcrs->decompressed[regnum].cached_pesbt, HWPERMS); - default: - __builtin_unreachable(); + // Permissions can be read directly from pebst, no need to decompress + uint32_t result = cap_get_perms(&gpcrs->decompressed[regnum]); + if (get_capreg_state(gpcrs, regnum) == CREG_INTEGER) { + cheri_debug_assert(result == 0); } - tcg_abort(); + return result; } static inline void nullify_capreg(CPUArchState *env, unsigned regnum) @@ -428,7 +419,7 @@ static inline void set_max_perms_capregs(CPUArchState *env) continue; set_max_perms_capability(&gpcrs->decompressed[i], 0); - gpcrs->decompressed[i].cached_pesbt = + gpcrs->decompressed[i].cr_pesbt = CAP_cc(compress_raw)(&gpcrs->decompressed[i]); // Mark register as fully decompressed cheri_debug_assert(get_capreg_state(gpcrs, i) == diff --git a/target/cheri-common/cheri_utils.h b/target/cheri-common/cheri_utils.h index 5db36bc0577..f4591f52495 100644 --- a/target/cheri-common/cheri_utils.h +++ b/target/cheri-common/cheri_utils.h @@ -74,22 +74,22 @@ static inline cap_offset_t cap_get_offset(const cap_register_t *c) static inline uint32_t cap_get_uperms(const cap_register_t *c) { - return c->cr_uperms; + return CAP_cc(get_uperms)(c); } static inline uint32_t cap_get_perms(const cap_register_t *c) { - return c->cr_perms; + return CAP_cc(get_perms)(c); } static inline uint8_t cap_get_flags(const cap_register_t *c) { - return c->cr_flags; + return CAP_cc(get_flags)(c); } static inline bool cap_has_reserved_bits_set(const cap_register_t *c) { - return c->cr_reserved != 0; + return CAP_cc(get_reserved) != 0; } // The top of the capability (exclusive -- i.e., one past the end) @@ -121,7 +121,7 @@ static inline cap_length_t cap_get_top_full(const cap_register_t *c) static inline target_ulong cap_get_otype_unsigned(const cap_register_t *c) { - return (target_ulong)c->cr_otype; + return CAP_cc(get_otype)(c); } static inline target_long cap_get_otype_signext(const cap_register_t *c) @@ -217,7 +217,7 @@ static inline void cap_set_sealed(cap_register_t *c, uint32_t type) "should not use this on caps with reserved otypes"); assert(type <= CAP_LAST_NONRESERVED_OTYPE); _Static_assert(CAP_LAST_NONRESERVED_OTYPE < CAP_OTYPE_UNSEALED, ""); - CAP_cc(cap_set_decompressed_cr_otype)(c, type); + CAP_cc(update_otype)(c, type); } static inline void cap_set_unsealed(cap_register_t *c) @@ -226,7 +226,7 @@ static inline void cap_set_unsealed(cap_register_t *c) assert(cap_is_sealed_with_type(c)); assert(cap_get_otype_unsigned(c) <= CAP_LAST_NONRESERVED_OTYPE && "should not use this to unsealed reserved types"); - CAP_cc(cap_set_decompressed_cr_otype)(c, CAP_OTYPE_UNSEALED); + CAP_cc(update_otype)(c, CAP_OTYPE_UNSEALED); } static inline bool cap_is_sealed_entry(const cap_register_t *c) @@ -238,14 +238,14 @@ static inline void cap_unseal_entry(cap_register_t *c) { assert(c->cr_tag && cap_is_sealed_entry(c) && "Should only be used with sentry capabilities"); - CAP_cc(cap_set_decompressed_cr_otype)(c, CAP_OTYPE_UNSEALED); + CAP_cc(update_otype)(c, CAP_OTYPE_UNSEALED); } static inline void cap_make_sealed_entry(cap_register_t *c) { assert(c->cr_tag && cap_is_unsealed(c) && "Should only be used with unsealed capabilities"); - CAP_cc(cap_set_decompressed_cr_otype)(c, CAP_OTYPE_SENTRY); + CAP_cc(update_otype)(c, CAP_OTYPE_SENTRY); } static inline bool cap_is_representable(const cap_register_t *c) @@ -266,8 +266,7 @@ static inline cap_register_t *null_capability(cap_register_t *cp) { memset(cp, 0, sizeof(*cp)); // Set everything to zero including padding cp->_cr_top = CAP_MAX_TOP; - cp->cr_otype = CAP_OTYPE_UNSEALED; // and otype should be unsealed - cp->cached_pesbt = CAP_NULL_PESBT; + cp->cr_pesbt = CAP_NULL_PESBT; cheri_debug_assert(cap_is_representable(cp)); return cp; } diff --git a/target/cheri-common/op_helper_cheri_common.c b/target/cheri-common/op_helper_cheri_common.c index 24de1093790..81d7fbab054 100644 --- a/target/cheri-common/op_helper_cheri_common.c +++ b/target/cheri-common/op_helper_cheri_common.c @@ -527,7 +527,7 @@ void CHERI_HELPER_IMPL(cbuildcap(CPUArchState *env, uint32_t cd, uint32_t cb, } else { cap_register_t result = *ctp; - CAP_cc(cap_set_decompressed_cr_otype)(&result, CAP_OTYPE_UNSEALED); + CAP_cc(update_otype)(&result, CAP_OTYPE_UNSEALED); result.cr_tag = 1; /* @@ -663,12 +663,14 @@ void CHERI_HELPER_IMPL(cunseal(CPUArchState *env, uint32_t cd, uint32_t cs, raise_cheri_exception(env, CapEx_LengthViolation, ct); } else { cap_register_t result = *csp; + target_ulong new_perms = cap_get_perms(&result); if (cap_has_perms(csp, CAP_PERM_GLOBAL) && cap_has_perms(ctp, CAP_PERM_GLOBAL)) { - result.cr_perms |= CAP_PERM_GLOBAL; + new_perms |= CAP_PERM_GLOBAL; } else { - result.cr_perms &= ~CAP_PERM_GLOBAL; + new_perms &= ~CAP_PERM_GLOBAL; } + CAP_cc(update_perms)(&result, new_perms); cap_set_unsealed(&result); update_capreg(env, cd, &result); } @@ -749,10 +751,8 @@ void CHERI_HELPER_IMPL(candperm(CPUArchState *env, uint32_t cd, uint32_t cb, uint32_t rt_uperms = ((uint32_t)rt >> CAP_UPERMS_SHFT) & CAP_UPERMS_ALL; cap_register_t result = *cbp; - CAP_cc(cap_set_decompressed_cr_perms)(&result, - cap_get_perms(cbp) & rt_perms); - CAP_cc(cap_set_decompressed_cr_uperms)(&result, - cap_get_uperms(cbp) & rt_uperms); + CAP_cc(update_perms)(&result, cap_get_perms(cbp) & rt_perms); + CAP_cc(update_uperms)(&result, cap_get_uperms(cbp) & rt_uperms); update_capreg(env, cd, &result); } } @@ -902,7 +902,7 @@ void CHERI_HELPER_IMPL(csetflags(CPUArchState *env, uint32_t cd, uint32_t cb, cap_register_t result = *cbp; flags &= CAP_FLAGS_ALL_BITS; _Static_assert(CAP_FLAGS_ALL_BITS == 1, "Only one flag should exist"); - CAP_cc(cap_set_decompressed_cr_flags)(&result, flags); + CAP_cc(update_flags)(&result, flags); update_capreg(env, cd, &result); } diff --git a/target/riscv/translate.c b/target/riscv/translate.c index f58770c5781..21753ed183a 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1085,7 +1085,7 @@ void riscv_translate_init(void) riscv_int_regnames[i]); _cpu_pesbt_do_not_access_directly[i] = tcg_global_mem_new( cpu_env, - offsetof(CPURISCVState, gpcapregs.decompressed[i].cached_pesbt), + offsetof(CPURISCVState, gpcapregs.decompressed[i].cr_pesbt), cheri_gp_regnames[i]); } #endif