From 8aaa732c0a953d00ee0930059f01efd4cf7b0052 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 16:07:00 -0800 Subject: [PATCH 01/18] Drop "All rights reserved." from license texts This is no longer required. --- cheri_compressed_cap.c | 1 - cheri_compressed_cap.h | 1 - cheri_compressed_cap_128.h | 1 - cheri_compressed_cap_128m.h | 1 - cheri_compressed_cap_128r.h | 1 - cheri_compressed_cap_64.h | 1 - cheri_compressed_cap_common.h | 1 - cheri_compressed_cap_macros.h | 1 - decompress_cap_common.cpp | 1 - test/fuzz_decompress.cpp | 1 - 10 files changed, 10 deletions(-) diff --git a/cheri_compressed_cap.c b/cheri_compressed_cap.c index f2eb12a..b7dd1d3 100644 --- a/cheri_compressed_cap.c +++ b/cheri_compressed_cap.c @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap.h b/cheri_compressed_cap.h index ccc8e8b..6b330f2 100644 --- a/cheri_compressed_cap.h +++ b/cheri_compressed_cap.h @@ -3,7 +3,6 @@ * * Copyright (c) 2018 Lawrence Esswood * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_128.h b/cheri_compressed_cap_128.h index 90fe98b..ca33c1f 100644 --- a/cheri_compressed_cap_128.h +++ b/cheri_compressed_cap_128.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_128m.h b/cheri_compressed_cap_128m.h index 24a19f3..3af99fc 100644 --- a/cheri_compressed_cap_128m.h +++ b/cheri_compressed_cap_128m.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_128r.h b/cheri_compressed_cap_128r.h index 7be971c..fcad817 100644 --- a/cheri_compressed_cap_128r.h +++ b/cheri_compressed_cap_128r.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2025 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_64.h b/cheri_compressed_cap_64.h index c950762..b16ac4e 100644 --- a/cheri_compressed_cap_64.h +++ b/cheri_compressed_cap_64.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index 10c7d52..a7bb093 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -3,7 +3,6 @@ * * Copyright (c) 2018 Lawrence Esswood * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/cheri_compressed_cap_macros.h b/cheri_compressed_cap_macros.h index 8746ce8..e65d3ec 100644 --- a/cheri_compressed_cap_macros.h +++ b/cheri_compressed_cap_macros.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2020 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/decompress_cap_common.cpp b/decompress_cap_common.cpp index 3aa84c3..2820798 100644 --- a/decompress_cap_common.cpp +++ b/decompress_cap_common.cpp @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 diff --git a/test/fuzz_decompress.cpp b/test/fuzz_decompress.cpp index b296ce1..76b5e47 100644 --- a/test/fuzz_decompress.cpp +++ b/test/fuzz_decompress.cpp @@ -3,7 +3,6 @@ * * Copyright (c) 2018 Lawrence Esswood * Copyright (c) 2018 Alex Richardson - * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory (Department of Computer Science and From f210b4f22bde95c5dded3ef32af9d19ca4bc2bb4 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Wed, 15 May 2024 07:48:26 -0700 Subject: [PATCH 02/18] Bounds encoding test for 128r, exponent 0 Test the encoding of a capability from base, address and top for MXLEN=64. This test case uses exponent 0. Co-authored-by: Alex Richardson --- test/simple_test_128r.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/simple_test_128r.cpp b/test/simple_test_128r.cpp index f43be72..1e60835 100644 --- a/test/simple_test_128r.cpp +++ b/test/simple_test_128r.cpp @@ -53,3 +53,21 @@ TEST_CASE("Malformed bounds return zero", "[bounds]") { CHECK(cap.top() == 0); CHECK(cap.cr_exp == 51); } + +TEST_CASE("bounds encoding exponent 0", "[bounds]") { + /* params are base, cursor, top */ + _cc_cap_t cap = CompressedCap128r::make_max_perms_cap(0x0, 0x10, 0x20); + + /* + * EF == 1 -> exponent 0 + * { T, TE } == 0b0000_0010_0000 + * { B, BE } == 0 + * all of LCout, LMSB, c_t, c_b are 0 + * + * top == 0x20, base == 0x0 + */ + CHECK(cap.cr_pesbt == 0x01f3f00004080000); + cc128r_update_perms(&cap, 0); + cc128r_update_uperms(&cap, 0); + CHECK(cap.cr_pesbt == 0x0000000004080000); +} From 4e4355fdb6f75bf8ffdcd90e76723b5c9505788b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 16 May 2024 11:12:49 +0200 Subject: [PATCH 03/18] Bounds encoding test for 128r, internal exponent Test the encoding of a capability from base, address and top for MXLEN=64. This test case uses an internal exponent. Co-authored-by: Alex Richardson --- test/simple_test_128r.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/simple_test_128r.cpp b/test/simple_test_128r.cpp index 1e60835..bebe977 100644 --- a/test/simple_test_128r.cpp +++ b/test/simple_test_128r.cpp @@ -71,3 +71,24 @@ TEST_CASE("bounds encoding exponent 0", "[bounds]") { cc128r_update_uperms(&cap, 0); CHECK(cap.cr_pesbt == 0x0000000004080000); } + +TEST_CASE("bounds encoding exponent > 0", "[bounds]") { + _cc_cap_t cap = CompressedCap128r::make_max_perms_cap(0x8000, 0x41DF, 0xA6400); + + /* + * EF == 0 -> internal exponent + * E = 52 - 45 = 7 + * + * T[11:3] == 0 1001 1001 + * TE == 101 + * B[13:3] == 000 0010 0000 + * BE == 101 + * + * LCout = 0, LMSB = 1 + * c_t = 0, c_b = 0 + */ + CHECK(cap.cr_pesbt == 0x01f3f00001334105); + cc128r_update_perms(&cap, 0); + cc128r_update_uperms(&cap, 0); + CHECK(cap.cr_pesbt == 0x0000000001334105); +} From 9e121b50794b3c5124e47d148402f743ca67e9d4 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2025 16:33:39 -0800 Subject: [PATCH 04/18] Add initial support for formats using the MSB of the capability length This is used in the RV32 format to reduce the number of exponents bits taken from the T/B fields (L8 in the spec). We will have to relax these static_asserts before adding the new cc64r format. Co-authored-by: Martin Kaiser --- cheri_compressed_cap_128.h | 1 + cheri_compressed_cap_128m.h | 1 + cheri_compressed_cap_128r.h | 1 + cheri_compressed_cap_64.h | 1 + cheri_compressed_cap_common.h | 22 ++++++++++++++++------ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cheri_compressed_cap_128.h b/cheri_compressed_cap_128.h index ca33c1f..a112f46 100644 --- a/cheri_compressed_cap_128.h +++ b/cheri_compressed_cap_128.h @@ -153,6 +153,7 @@ _CC_STATIC_ASSERT_SAME(CC128_MANTISSA_WIDTH, CC128_FIELD_EXP_ZERO_BOTTOM_SIZE); #define CC128_RESERVED_BITS CC128_FIELD_RESERVED_SIZE #define CC128_HAS_BASE_TOP_SPECIAL_CASES 0 #define CC128_USES_V9_CORRECTION_FACTORS 1 +#define CC128_USES_LEN_MSB 0 #include "cheri_compressed_cap_common.h" diff --git a/cheri_compressed_cap_128m.h b/cheri_compressed_cap_128m.h index 3af99fc..c0da31a 100644 --- a/cheri_compressed_cap_128m.h +++ b/cheri_compressed_cap_128m.h @@ -189,6 +189,7 @@ _CC_STATIC_ASSERT_SAME(CC128M_MANTISSA_WIDTH, CC128M_FIELD_EXP_ZERO_BOTTOM_SIZE) #define CC128M_RESERVED_BITS 0 #define CC128M_HAS_BASE_TOP_SPECIAL_CASES 1 #define CC128M_USES_V9_CORRECTION_FACTORS 1 +#define CC128M_USES_LEN_MSB 0 #include "cheri_compressed_cap_common.h" diff --git a/cheri_compressed_cap_128r.h b/cheri_compressed_cap_128r.h index fcad817..f7e28be 100644 --- a/cheri_compressed_cap_128r.h +++ b/cheri_compressed_cap_128r.h @@ -150,6 +150,7 @@ _CC_STATIC_ASSERT_SAME(CC128R_MANTISSA_WIDTH, CC128R_FIELD_EXP_ZERO_BOTTOM_SIZE) #define CC128R_RESERVED_BITS (CC128R_FIELD_RESERVED0_SIZE + CC128R_FIELD_RESERVED1_SIZE) #define CC128R_HAS_BASE_TOP_SPECIAL_CASES 1 #define CC128R_USES_V9_CORRECTION_FACTORS 0 +#define CC128R_USES_LEN_MSB 0 #include "cheri_compressed_cap_common.h" diff --git a/cheri_compressed_cap_64.h b/cheri_compressed_cap_64.h index b16ac4e..0689c49 100644 --- a/cheri_compressed_cap_64.h +++ b/cheri_compressed_cap_64.h @@ -142,6 +142,7 @@ _CC_STATIC_ASSERT_SAME(CC64_MANTISSA_WIDTH, CC64_FIELD_EXP_ZERO_BOTTOM_SIZE); #define CC64_RESERVED_BITS CC64_FIELD_RESERVED_SIZE #define CC64_HAS_BASE_TOP_SPECIAL_CASES 0 #define CC64_USES_V9_CORRECTION_FACTORS 1 +#define CC64_USES_LEN_MSB 0 #include "cheri_compressed_cap_common.h" diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index a7bb093..628341f 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -82,6 +82,11 @@ enum { #define _CC_MAX_ADDR _CC_N(MAX_ADDR) #define _CC_MAX_TOP _CC_N(MAX_TOP) #define _CC_CURSOR_MASK _CC_N(CURSOR_MASK) + +#if _CC_N(USES_LEN_MSB) == 0 +enum { _CC_N(FIELD_LEN_MSB_SIZE) = 0 }; +#endif + // Check that the sizes of the individual fields match up _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_EBT_SIZE) + _CC_N(FIELD_OTYPE_SIZE) + _CC_N(FIELD_FLAGS_SIZE) + _CC_N(RESERVED_BITS) + _CC_N(FIELD_HWPERMS_SIZE) + _CC_N(FIELD_UPERMS_SIZE), @@ -89,12 +94,12 @@ _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_EBT_SIZE) + _CC_N(FIELD_OTYPE_SIZE) + _CC_N(F _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_EXP_ZERO_TOP_SIZE) + _CC_N(FIELD_EXP_ZERO_BOTTOM_SIZE), _CC_N(FIELD_EBT_SIZE)); -_CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_TOP_ENCODED_SIZE) + +_CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_LEN_MSB_SIZE) + _CC_N(FIELD_TOP_ENCODED_SIZE) + _CC_N(FIELD_BOTTOM_ENCODED_SIZE), _CC_N(FIELD_EBT_SIZE)); -_CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_EXP_NONZERO_TOP_SIZE) + - _CC_N(FIELD_EXP_NONZERO_BOTTOM_SIZE) + _CC_N(FIELD_EXPONENT_HIGH_PART_SIZE) + - _CC_N(FIELD_EXPONENT_LOW_PART_SIZE), +_CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_LEN_MSB_SIZE) + + _CC_N(FIELD_EXP_NONZERO_TOP_SIZE) + _CC_N(FIELD_EXP_NONZERO_BOTTOM_SIZE) + + _CC_N(FIELD_EXPONENT_HIGH_PART_SIZE) + _CC_N(FIELD_EXPONENT_LOW_PART_SIZE), _CC_N(FIELD_EBT_SIZE)); // The code below assumes that encoding the EBT fields inside pesbt and just obtaining EBT is the same. _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_EBT_START), 0); @@ -770,13 +775,18 @@ static inline bool _cc_N(setbounds_impl)(_cc_cap_t* cap, _cc_length_t req_len, _ if (req_base < cap->cr_base || req_top > cap->_cr_top) { cap->cr_tag = 0; } +#if _CC_N(USES_LEN_MSB) != 0 + _CC_STATIC_ASSERT(_CC_EXP_LOW_WIDTH == 2, "expected 2 bits to be used by"); + _CC_STATIC_ASSERT(_CC_EXP_HIGH_WIDTH == 2, "expected 2 bits to be used by"); +#else + _CC_STATIC_ASSERT(_CC_EXP_LOW_WIDTH == 3, "expected 3 bits to be used by"); + _CC_STATIC_ASSERT(_CC_EXP_HIGH_WIDTH == 3, "expected 3 bits to be used by"); +#endif /* * With compressed capabilities we may need to increase the range of * memory addresses to be wider than requested so it is * representable. */ - _CC_STATIC_ASSERT(_CC_EXP_LOW_WIDTH == 3, "expected 3 bits to be used by"); // expected 3 bits to - _CC_STATIC_ASSERT(_CC_EXP_HIGH_WIDTH == 3, "expected 3 bits to be used by"); // expected 3 bits to bool exact = false; uint32_t new_ebt = _cc_N(compute_ebt)(req_base, req_top, alignment_mask, &exact); _cc_addr_t new_base; From 11c2af5d199296f74e76bdcb1e552128a4384a3a Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 30 Apr 2024 14:21:42 +0200 Subject: [PATCH 05/18] Initial version of new 64r format This is an initial draft of the 64r capability format for 64-bit capabilities as defined in the RISC-V CHERI specification. Note that this does not handle the decoding of raw permissions to the architectural ones. Future commits will add a new encode and decode function, but for now just set CC64R_PERMS_ALL to the infinite cap value. Co-authored-by: Alex Richardson --- cheri_compressed_cap.h | 1 + cheri_compressed_cap_128r.h | 3 +- cheri_compressed_cap_64r.h | 180 ++++++++++++++++++++++++++++++++++ cheri_compressed_cap_common.h | 5 +- 4 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 cheri_compressed_cap_64r.h diff --git a/cheri_compressed_cap.h b/cheri_compressed_cap.h index 6b330f2..e744535 100644 --- a/cheri_compressed_cap.h +++ b/cheri_compressed_cap.h @@ -47,6 +47,7 @@ // clang-format off #include "cheri_compressed_cap_64.h" +#include "cheri_compressed_cap_64r.h" #include "cheri_compressed_cap_128.h" #include "cheri_compressed_cap_128m.h" #include "cheri_compressed_cap_128r.h" diff --git a/cheri_compressed_cap_128r.h b/cheri_compressed_cap_128r.h index f7e28be..aafa539 100644 --- a/cheri_compressed_cap_128r.h +++ b/cheri_compressed_cap_128r.h @@ -43,8 +43,9 @@ #define CC128R_CAP_BITS 128 #define CC128R_ADDR_WIDTH 64 #define CC128R_LEN_WIDTH 65 -/* Max exponent is the largest exponent _required_, not that can be encoded. */ + #define CC128R_MANTISSA_WIDTH 14 +// Max exponent is the largest exponent _required_, not that can be encoded. #define CC128R_MAX_EXPONENT 52 #define CC128R_CURSOR_MASK 0xFFFFFFFFFFFFFFFF #define CC128R_MAX_ADDRESS_PLUS_ONE ((cc128r_length_t)1u << CC128R_ADDR_WIDTH) diff --git a/cheri_compressed_cap_64r.h b/cheri_compressed_cap_64r.h new file mode 100644 index 0000000..57c6da7 --- /dev/null +++ b/cheri_compressed_cap_64r.h @@ -0,0 +1,180 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018-2025 Alex Richardson + * Copyright (c) 2024 Codasip + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the + * DARPA SSITH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// CHERI compressed capability format for the RISC-V standard + +// The following macros are expected to be defined +#define CC_FORMAT_LOWER 64r +#define CC_FORMAT_UPPER 64R +#define CC64R_CAP_SIZE 8 +#define CC64R_CAP_BITS 64 +#define CC64R_ADDR_WIDTH 32 +#define CC64R_LEN_WIDTH 33 + +#define CC64R_MANTISSA_WIDTH 10 +// Max exponent is the largest exponent _required_, not that can be encoded. +#define CC64R_MAX_EXPONENT 24 +#define CC64R_CURSOR_MASK 0xFFFFFFFF +#define CC64R_MAX_ADDRESS_PLUS_ONE ((cc64r_length_t)1u << CC64R_ADDR_WIDTH) +#define CC64R_NULL_TOP CC64R_MAX_ADDRESS_PLUS_ONE +#define CC64R_NULL_LENGTH CC64R_MAX_ADDRESS_PLUS_ONE +#define CC64R_MAX_LENGTH CC64R_MAX_ADDRESS_PLUS_ONE +#define CC64R_MAX_TOP CC64R_MAX_ADDRESS_PLUS_ONE +#define CC64R_MAX_ADDR UINT32_MAX + +/* Special otypes are allocated upwards from 0 */ +#define CC64R_SPECIAL_OTYPE_VAL(val) (val##u) +#define CC64R_SPECIAL_OTYPE_VAL_SIGNED(val) (val##u) + +/* Use uint64_t to represent 33 bit length */ +typedef uint64_t cc64r_length_t; +typedef int64_t cc64r_offset_t; +typedef uint32_t cc64r_addr_t; +typedef int32_t cc64r_saddr_t; +#include "cheri_compressed_cap_macros.h" + +/* ignore ISO C restricts enumerator values to range of 'int' */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +enum { + _CC_FIELD(UPERMS, 63, 62), + _CC_FIELD(HWPERMS, 61, 57), + _CC_FIELD(FLAGS, 57, 57), // For now pretend that the M bit is always present, not just for X caps + // TODO: Level should be separate: _CC_FIELD(LEVEL, 56, 56) + _CC_FIELD(RESERVED, 55, 53), + _CC_FIELD(OTYPE, 52, 52), + _CC_FIELD(EBT, 51, 32), + + _CC_FIELD(EXPONENT_FORMAT, 51, 51), + _CC_FIELD(LEN_MSB, 50, 50), + // The FIELD_INTERNAL_EXPONENT_SIZE name is currently required by various static assertions. + _CC_N(FIELD_INTERNAL_EXPONENT_SIZE) = _CC_N(FIELD_EXPONENT_FORMAT_SIZE), + _CC_FIELD(TOP_ENCODED, 49, 42), + _CC_FIELD(BOTTOM_ENCODED, 41, 32), + + // Top/bottom offsets depending on INTERNAL_EXPONENT flag: + // Without internal exponent: + _CC_FIELD(EXP_ZERO_TOP, 49, 42), + _CC_FIELD(EXP_ZERO_BOTTOM, 41, 32), + // With internal exponent: + _CC_FIELD(EXP_NONZERO_TOP, 49, 44), + _CC_FIELD(EXPONENT_HIGH_PART, 43, 42), + _CC_FIELD(EXP_NONZERO_BOTTOM, 41, 34), + _CC_FIELD(EXPONENT_LOW_PART, 33, 32), +}; +#pragma GCC diagnostic pop + +#define CC64R_OTYPE_BITS CC64R_FIELD_OTYPE_SIZE +#define CC64R_BOT_WIDTH CC64R_FIELD_EXP_ZERO_BOTTOM_SIZE +#define CC64R_BOT_INTERNAL_EXP_WIDTH CC64R_FIELD_EXP_NONZERO_BOTTOM_SIZE +#define CC64R_EXP_LOW_WIDTH CC64R_FIELD_EXPONENT_LOW_PART_SIZE + +#define CC64R_PERM_CAPABILITY (1 << 0) +#define CC64R_PERM_WRITE (1 << 1) +#define CC64R_PERM_READ (1 << 2) +#define CC64R_PERM_EXECUTE (1 << 3) +#define CC64R_PERM_ACCESS_SYS_REGS (1 << 4) +#define CC64R_PERM_LOAD_MUTABLE (1 << 5) +#define CC64R_PERM_ELEVATE_LEVEL (1 << 6) +#define CC64R_PERM_STORE_LEVEL (1 << 7) + +// Note: shift by one 1 due to level currently being part of perms +#define CC64R_HIGHEST_PERM (CC64R_PERM_STORE_LEVEL << 1) + +#define CC64R_PERMS_ALL (0x9) // See Infinite Capability in the spec: 0x8 or 0x9 depending on mode. +#define CC64R_UPERMS_ALL (0x3) // 2 bits +_CC_STATIC_ASSERT_SAME(CC64R_UPERMS_ALL, CC64R_FIELD_UPERMS_MAX_VALUE); +#define CC64R_UPERMS_SHFT (6) +#define CC64R_UPERMS_MEM_SHFT (0) +#define CC64R_MAX_UPERM (1) + +// Currently, only one type (sentry) is defined. +// However, other extensions (e.g. CHERIoT) define additional otypes beyond this. +enum _CC_N(OTypes) { + CC64R_MAX_REPRESENTABLE_OTYPE = ((1u << CC64R_OTYPE_BITS) - 1u), + _CC_SPECIAL_OTYPE(OTYPE_UNSEALED, 0), + _CC_SPECIAL_OTYPE(OTYPE_SENTRY, 1), + _CC_N(MIN_RESERVED_OTYPE) = _CC_N(OTYPE_UNSEALED), + _CC_N(MAX_RESERVED_OTYPE) = _CC_N(OTYPE_SENTRY), +}; + +#define CC64R_LS_SPECIAL_OTYPES(ITEM, ...) \ + ITEM(OTYPE_UNSEALED, __VA_ARGS__) \ + ITEM(OTYPE_SENTRY, __VA_ARGS__) + +_CC_STATIC_ASSERT_SAME(CC64R_MANTISSA_WIDTH, CC64R_FIELD_EXP_ZERO_BOTTOM_SIZE); + +// The RISC-V extension uses an "exponent zero" flag. +#define CC64R_ENCODE_IE(IE) _CC_ENCODE_FIELD(!(IE), EXPONENT_FORMAT) +#define CC64R_EXTRACT_IE(value) (!_CC_EXTRACT_FIELD(value, EXPONENT_FORMAT)) +// The exponent bits in memory are subtracted from the max exponent when decoding in the IE case. +// FIXME: this is currently not correct, we are missing the L8 bit +#define CC64R_ENCODE_EXPONENT(E) _CC_ENCODE_SPLIT_EXPONENT(CC64R_MAX_EXPONENT - (E)) +#define CC64R_EXTRACT_EXPONENT(pesbt) (CC64R_MAX_EXPONENT - _CC_EXTRACT_SPLIT_EXPONENT(pesbt)) +#define CC64R_RESERVED_FIELDS 1 +#define CC64R_RESERVED_BITS CC64R_FIELD_RESERVED_SIZE +#define CC64R_HAS_BASE_TOP_SPECIAL_CASES 1 +#define CC64R_USES_V9_CORRECTION_FACTORS 0 +#define CC64R_USES_LEN_MSB 1 + +#include "cheri_compressed_cap_common.h" + +static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { + // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to + // the maximum exponent instead. + bool malformedLSB = bounds.E > _CC_MAX_EXPONENT; + bool malformedMSB = (bounds.E == _CC_MAX_EXPONENT && bounds.B != 0) || + (bounds.E == _CC_MAX_EXPONENT - 1 && (bounds.B & (1u << (_CC_MANTISSA_WIDTH - 1))) != 0); + return bounds.IE && (malformedLSB || malformedMSB); +} + +static inline bool _cc_N(compute_base_top_special_cases)(_cc_bounds_bits bounds, _cc_addr_t* base_out, + _cc_length_t* top_out, bool* valid) { + if (_cc_N(bounds_malformed)(bounds)) { + *base_out = 0; + *top_out = 0; + *valid = false; + return true; + } + return false; +} + +// Check that there is no XOR mask for this encoding format (i.e. NULL encodes to all-zeroes in memory). +_CC_STATIC_ASSERT_SAME(CC64R_MEM_XOR_MASK, UINT64_C(0)); + +#undef CC_FORMAT_LOWER +#undef CC_FORMAT_UPPER diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index 628341f..b5fa489 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -88,11 +88,8 @@ enum { _CC_N(FIELD_LEN_MSB_SIZE) = 0 }; #endif // Check that the sizes of the individual fields match up -_CC_STATIC_ASSERT_SAME(_CC_N(FIELD_EBT_SIZE) + _CC_N(FIELD_OTYPE_SIZE) + _CC_N(FIELD_FLAGS_SIZE) + - _CC_N(RESERVED_BITS) + _CC_N(FIELD_HWPERMS_SIZE) + _CC_N(FIELD_UPERMS_SIZE), - _CC_ADDR_WIDTH); _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_EXP_ZERO_TOP_SIZE) + - _CC_N(FIELD_EXP_ZERO_BOTTOM_SIZE), + _CC_N(FIELD_LEN_MSB_SIZE) + _CC_N(FIELD_EXP_ZERO_BOTTOM_SIZE), _CC_N(FIELD_EBT_SIZE)); _CC_STATIC_ASSERT_SAME(_CC_N(FIELD_INTERNAL_EXPONENT_SIZE) + _CC_N(FIELD_LEN_MSB_SIZE) + _CC_N(FIELD_TOP_ENCODED_SIZE) + _CC_N(FIELD_BOTTOM_ENCODED_SIZE), From 502153eb70e3dde2993ac880e85867d5658de4c7 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2025 16:29:26 -0800 Subject: [PATCH 06/18] Split sail_wrapper_128r into two files In preparation for the 32-bit format --- test/sail_wrapper_128r.c | 115 +----------------------- test/sail_wrapper_common_riscv.c | 148 +++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 114 deletions(-) create mode 100644 test/sail_wrapper_common_riscv.c diff --git a/test/sail_wrapper_128r.c b/test/sail_wrapper_128r.c index b385112..d4eb062 100644 --- a/test/sail_wrapper_128r.c +++ b/test/sail_wrapper_128r.c @@ -35,120 +35,7 @@ /* Provide the RISC-V standard 128-bit APIs for sail_wrapper_common.c */ #define SAIL_COMPRESSION_GENERATED_C_FILE "contrib/sail_compression_128r.c" -#define SAIL_INFINITE_CAP zinfinite_cap -#define sail_bounds_tuple zoptionzIz8bzCbz9zK -#define sail_bounds_tuple_base(t) (t).zSomezIz8bzCbz9zK.ztup0 -#define sail_bounds_tuple_top(t) (t).zSomezIz8bzCbz9zK.ztup1 - #define SAIL_WRAPPER_CC_FORMAT_LOWER 128r #define SAIL_WRAPPER_CC_FORMAT_UPPER 128R -#include "sail_wrapper_common.c" - -static inline void set_top_base_from_sail(const struct zCapability* sail, _cc_cap_t* c) { - // Would be nice to have a stable name for this tuple: - struct sail_bounds_tuple base_top; - _CC_CONCAT(create_, sail_bounds_tuple)(&base_top); - sailgen_getCapBoundsBits(&base_top, *sail); - if (base_top.kind == Kind_zNonezIz8bzCbz9zK) { - c->_cr_top = 0; - c->cr_base = 0; - c->cr_bounds_valid = false; - assert(sailgen_boundsMalformed(*sail)); - return; - } - assert(base_top.kind == Kind_zSomezIz8bzCbz9zK); - - sail_int base_len; - CREATE(sail_int)(&base_len); - length_lbits(&base_len, sail_bounds_tuple_base(base_top)); - assert(CONVERT_OF(mach_int, sail_int)(base_len) == 64); - c->cr_base = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_base(base_top), true); - KILL(sail_int)(&base_len); - - sail_int top_len; - CREATE(sail_int)(&top_len); - length_lbits(&top_len, sail_bounds_tuple_top(base_top)); - assert(CONVERT_OF(mach_int, sail_int)(top_len) == 65); - KILL(sail_int)(&top_len); - fbits top_high = extract_bits(sail_bounds_tuple_top(base_top), 64, 1); - fbits top_low = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_top(base_top), true); - c->_cr_top = (((cc128_length_t)top_high) << 64) | (cc128_length_t)top_low; - _CC_CONCAT(kill_, sail_bounds_tuple)(&base_top); -} - -static uint64_t _compress_sailcap_raw(struct zCapability sailcap) { return sailgen_capToMetadataBits(sailcap).zbits; } - -static struct zCapability cap_t_to_sail_cap(const _cc_cap_t* c) { - struct zCapability result; - result = znull_cap; - result.ztag = c->cr_tag; - result.zreserved_0 = _CC_EXTRACT_FIELD(c->cr_pesbt, RESERVED0); - result.zreserved_1 = _CC_EXTRACT_FIELD(c->cr_pesbt, RESERVED1); - result.zaddress = c->_cr_cursor; - result.zsealed = _cc_N(get_otype)(c) != 0; - result.zsd_perms = _cc_N(get_uperms)(c); - result.zap_m = _CC_EXTRACT_FIELD(c->cr_pesbt, HWPERMS); - - // 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_exponent = c_bounds.IE; - result.zE = c_bounds.E; - result.zT = c_bounds.T; - result.zB = c_bounds.B; - return result; -} - -static _cc_cap_t sail_cap_to_cap_t(const struct zCapability* sail) { - _cc_cap_t c; - memset(&c, 0, sizeof(c)); - c._cr_cursor = sail->zaddress; - set_top_base_from_sail(sail, &c); - c.cr_tag = sail->ztag; - if (sailgen_boundsMalformed(*sail)) { - assert(!sail->ztag && "Input cannot be tagged with malformed bounds"); - } - c.cr_exp = sail->zE; - c.cr_bounds_valid = !sailgen_boundsMalformed(*sail); - c.cr_pesbt = _compress_sailcap_raw(*sail); - return c; -} - -static struct zCapability _sail_decode(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { - sail_cap_bits sail_all_bits; - pesbt_and_addr_to_sail_cap_bits(&sail_all_bits, pesbt, cursor); - struct zCapability sail_result = sailgen_bitsToCap(tag, sail_all_bits); - KILL(sail_cap_bits)(&sail_all_bits); - return sail_result; -} - -/* Exported API */ -_cc_bounds_bits _cc_sail(extract_bounds_bits)(_cc_addr_t pesbt) { - _cc_bounds_bits result; - struct zCapability sail_result = _sail_decode(pesbt, 0, false); - result.E = sail_result.zE; - result.B = sail_result.zB; - result.T = sail_result.zT; - result.IE = sail_result.zinternal_exponent; - return result; -} -_cc_addr_t sail_representable_mask_128r(_cc_addr_t len) { return sailgen_getRepresentableAlignmentMask(len); } -_cc_addr_t sail_representable_length_128r(_cc_addr_t len) { return sailgen_getRepresentableLength(len); } -bool _cc_sail(fast_is_representable)(const _cc_cap_t* cap, _cc_addr_t new_addr) { - // The RISC-V standard version no longer uses the fast representability check. - return _cc_sail(precise_is_representable)(cap, new_addr); -} - -_cc_cap_t _cc_sail(decode_mem)(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { - struct zCapability sail_result = _sail_decode(pesbt, cursor, tag); - return sail_cap_to_cap_t(&sail_result); -} - -_cc_addr_t _cc_sail(compress_mem)(const _cc_cap_t* csp) { return _compress_sailcap_raw(cap_t_to_sail_cap(csp)); } - -// No difference between in-register and in-memory format. -_cc_cap_t _cc_sail(decode_raw)(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { - return _cc_sail(decode_mem)(pesbt, cursor, tag); -} -_cc_addr_t _cc_sail(compress_raw)(const _cc_cap_t* csp) { return _cc_sail(compress_mem)(csp); } +#include "sail_wrapper_common_riscv.c" diff --git a/test/sail_wrapper_common_riscv.c b/test/sail_wrapper_common_riscv.c new file mode 100644 index 0000000..3749b4c --- /dev/null +++ b/test/sail_wrapper_common_riscv.c @@ -0,0 +1,148 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Alex Richardson + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the + * DARPA SSITH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "contrib/sail.h" + +#define SAIL_INFINITE_CAP zinfinite_cap +#define sail_bounds_tuple zoptionzIz8bzCbz9zK +#define sail_bounds_tuple_base(t) (t).zSomezIz8bzCbz9zK.ztup0 +#define sail_bounds_tuple_top(t) (t).zSomezIz8bzCbz9zK.ztup1 + +#include "sail_wrapper_common.c" + +static inline void set_top_base_from_sail(const struct zCapability* sail, _cc_cap_t* c) { + // Would be nice to have a stable name for this tuple: + struct sail_bounds_tuple base_top; + _CC_CONCAT(create_, sail_bounds_tuple)(&base_top); + sailgen_getCapBoundsBits(&base_top, *sail); + if (base_top.kind == Kind_zNonezIz8bzCbz9zK) { + c->_cr_top = 0; + c->cr_base = 0; + c->cr_bounds_valid = false; + assert(sailgen_boundsMalformed(*sail)); + return; + } + assert(base_top.kind == Kind_zSomezIz8bzCbz9zK); + + sail_int base_len; + CREATE(sail_int)(&base_len); + length_lbits(&base_len, sail_bounds_tuple_base(base_top)); + assert(CONVERT_OF(mach_int, sail_int)(base_len) == 64); + c->cr_base = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_base(base_top), true); + KILL(sail_int)(&base_len); + + sail_int top_len; + CREATE(sail_int)(&top_len); + length_lbits(&top_len, sail_bounds_tuple_top(base_top)); + assert(CONVERT_OF(mach_int, sail_int)(top_len) == 65); + KILL(sail_int)(&top_len); + fbits top_high = extract_bits(sail_bounds_tuple_top(base_top), 64, 1); + fbits top_low = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_top(base_top), true); + c->_cr_top = (((cc128_length_t)top_high) << 64) | (cc128_length_t)top_low; + _CC_CONCAT(kill_, sail_bounds_tuple)(&base_top); +} + +static uint64_t _compress_sailcap_raw(struct zCapability sailcap) { return sailgen_capToMetadataBits(sailcap).zbits; } + +static struct zCapability cap_t_to_sail_cap(const _cc_cap_t* c) { + struct zCapability result; + result = znull_cap; + result.ztag = c->cr_tag; + result.zreserved_0 = _CC_EXTRACT_FIELD(c->cr_pesbt, RESERVED0); + result.zreserved_1 = _CC_EXTRACT_FIELD(c->cr_pesbt, RESERVED1); + result.zaddress = c->_cr_cursor; + result.zsealed = _cc_N(get_otype)(c) != 0; + result.zsd_perms = _cc_N(get_uperms)(c); + result.zap_m = _CC_EXTRACT_FIELD(c->cr_pesbt, HWPERMS); + + // 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_exponent = c_bounds.IE; + result.zE = c_bounds.E; + result.zT = c_bounds.T; + result.zB = c_bounds.B; + return result; +} + +static _cc_cap_t sail_cap_to_cap_t(const struct zCapability* sail) { + _cc_cap_t c; + memset(&c, 0, sizeof(c)); + c._cr_cursor = sail->zaddress; + set_top_base_from_sail(sail, &c); + c.cr_tag = sail->ztag; + if (sailgen_boundsMalformed(*sail)) { + assert(!sail->ztag && "Input cannot be tagged with malformed bounds"); + } + c.cr_exp = sail->zE; + c.cr_bounds_valid = !sailgen_boundsMalformed(*sail); + c.cr_pesbt = _compress_sailcap_raw(*sail); + return c; +} + +static struct zCapability _sail_decode(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { + sail_cap_bits sail_all_bits; + pesbt_and_addr_to_sail_cap_bits(&sail_all_bits, pesbt, cursor); + struct zCapability sail_result = sailgen_bitsToCap(tag, sail_all_bits); + KILL(sail_cap_bits)(&sail_all_bits); + return sail_result; +} + +/* Exported API */ +_cc_bounds_bits _cc_sail(extract_bounds_bits)(_cc_addr_t pesbt) { + _cc_bounds_bits result; + struct zCapability sail_result = _sail_decode(pesbt, 0, false); + result.E = sail_result.zE; + result.B = sail_result.zB; + result.T = sail_result.zT; + result.IE = sail_result.zinternal_exponent; + return result; +} +_cc_addr_t sail_representable_mask_128r(_cc_addr_t len) { return sailgen_getRepresentableAlignmentMask(len); } +_cc_addr_t sail_representable_length_128r(_cc_addr_t len) { return sailgen_getRepresentableLength(len); } +bool _cc_sail(fast_is_representable)(const _cc_cap_t* cap, _cc_addr_t new_addr) { + // The RISC-V standard version no longer uses the fast representability check. + return _cc_sail(precise_is_representable)(cap, new_addr); +} + +_cc_cap_t _cc_sail(decode_mem)(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { + struct zCapability sail_result = _sail_decode(pesbt, cursor, tag); + return sail_cap_to_cap_t(&sail_result); +} + +_cc_addr_t _cc_sail(compress_mem)(const _cc_cap_t* csp) { return _compress_sailcap_raw(cap_t_to_sail_cap(csp)); } + +// No difference between in-register and in-memory format. +_cc_cap_t _cc_sail(decode_raw)(_cc_addr_t pesbt, _cc_addr_t cursor, bool tag) { + return _cc_sail(decode_mem)(pesbt, cursor, tag); +} +_cc_addr_t _cc_sail(compress_raw)(const _cc_cap_t* csp) { return _cc_sail(compress_mem)(csp); } From 80aa53b43a0103e02f90bdf06b02efcd020310d5 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2025 16:30:28 -0800 Subject: [PATCH 07/18] Add a 64r version of the sail wrapper Very minor changes needed compared to the 128r version. --- CMakeLists.txt | 1 + test/sail_wrapper.h | 4 ++++ test/sail_wrapper_64r.c | 41 ++++++++++++++++++++++++++++++++ test/sail_wrapper_common_riscv.c | 16 ++++++++----- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 test/sail_wrapper_64r.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bbf4e7..0454f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ function(add_sail_wrappers _format) endfunction() add_sail_wrappers(64) +add_sail_wrappers(64r) add_sail_wrappers(128) add_sail_wrappers(128m) add_sail_wrappers(128r) diff --git a/test/sail_wrapper.h b/test/sail_wrapper.h index 92ca36a..e341e08 100644 --- a/test/sail_wrapper.h +++ b/test/sail_wrapper.h @@ -36,6 +36,10 @@ #include "sail_wrapper_api.inc" #undef SAIL_WRAPPER_FORMAT_LOWER +#define SAIL_WRAPPER_FORMAT_LOWER 64r +#include "sail_wrapper_api.inc" +#undef SAIL_WRAPPER_FORMAT_LOWER + #define SAIL_WRAPPER_FORMAT_LOWER 128 #include "sail_wrapper_api.inc" #undef SAIL_WRAPPER_FORMAT_LOWER diff --git a/test/sail_wrapper_64r.c b/test/sail_wrapper_64r.c new file mode 100644 index 0000000..427ef1f --- /dev/null +++ b/test/sail_wrapper_64r.c @@ -0,0 +1,41 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Alex Richardson + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory (Department of Computer Science and + * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the + * DARPA SSITH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "contrib/sail.h" + +/* Provide the RISC-V standard 128-bit APIs for sail_wrapper_common.c */ + +#define SAIL_COMPRESSION_GENERATED_C_FILE "contrib/sail_compression_64r.c" +#define SAIL_WRAPPER_CC_FORMAT_LOWER 64r +#define SAIL_WRAPPER_CC_FORMAT_UPPER 64R + +#include "sail_wrapper_common_riscv.c" diff --git a/test/sail_wrapper_common_riscv.c b/test/sail_wrapper_common_riscv.c index 3749b4c..7c56def 100644 --- a/test/sail_wrapper_common_riscv.c +++ b/test/sail_wrapper_common_riscv.c @@ -56,22 +56,26 @@ static inline void set_top_base_from_sail(const struct zCapability* sail, _cc_ca sail_int base_len; CREATE(sail_int)(&base_len); length_lbits(&base_len, sail_bounds_tuple_base(base_top)); - assert(CONVERT_OF(mach_int, sail_int)(base_len) == 64); + assert(CONVERT_OF(mach_int, sail_int)(base_len) == _CC_ADDR_WIDTH); c->cr_base = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_base(base_top), true); KILL(sail_int)(&base_len); sail_int top_len; CREATE(sail_int)(&top_len); length_lbits(&top_len, sail_bounds_tuple_top(base_top)); - assert(CONVERT_OF(mach_int, sail_int)(top_len) == 65); + assert(CONVERT_OF(mach_int, sail_int)(top_len) == _CC_LEN_WIDTH); KILL(sail_int)(&top_len); - fbits top_high = extract_bits(sail_bounds_tuple_top(base_top), 64, 1); fbits top_low = CONVERT_OF(fbits, lbits)(sail_bounds_tuple_top(base_top), true); +#if _CC_LEN_WIDTH <= 64 + c->_cr_top = top_low; +#else + fbits top_high = extract_bits(sail_bounds_tuple_top(base_top), 64, 1); c->_cr_top = (((cc128_length_t)top_high) << 64) | (cc128_length_t)top_low; +#endif _CC_CONCAT(kill_, sail_bounds_tuple)(&base_top); } -static uint64_t _compress_sailcap_raw(struct zCapability sailcap) { return sailgen_capToMetadataBits(sailcap).zbits; } +static _cc_addr_t _compress_sailcap_raw(struct zCapability sailcap) { return sailgen_capToMetadataBits(sailcap).zbits; } static struct zCapability cap_t_to_sail_cap(const _cc_cap_t* c) { struct zCapability result; @@ -127,8 +131,8 @@ _cc_bounds_bits _cc_sail(extract_bounds_bits)(_cc_addr_t pesbt) { result.IE = sail_result.zinternal_exponent; return result; } -_cc_addr_t sail_representable_mask_128r(_cc_addr_t len) { return sailgen_getRepresentableAlignmentMask(len); } -_cc_addr_t sail_representable_length_128r(_cc_addr_t len) { return sailgen_getRepresentableLength(len); } +_cc_addr_t _cc_sail(representable_mask)(_cc_addr_t len) { return sailgen_getRepresentableAlignmentMask(len); } +_cc_addr_t _cc_sail(representable_length)(_cc_addr_t len) { return sailgen_getRepresentableLength(len); } bool _cc_sail(fast_is_representable)(const _cc_cap_t* cap, _cc_addr_t new_addr) { // The RISC-V standard version no longer uses the fast representability check. return _cc_sail(precise_is_representable)(cap, new_addr); From 02eb4440c35ddb3d863f2b52847d90f1f1228e95 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2025 16:34:57 -0800 Subject: [PATCH 08/18] Split the 64r reserved field into two This matches the current version of the sail that does not yet support the levels extension. --- cheri_compressed_cap_64r.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cheri_compressed_cap_64r.h b/cheri_compressed_cap_64r.h index 57c6da7..c9c37f3 100644 --- a/cheri_compressed_cap_64r.h +++ b/cheri_compressed_cap_64r.h @@ -73,9 +73,10 @@ typedef int32_t cc64r_saddr_t; enum { _CC_FIELD(UPERMS, 63, 62), _CC_FIELD(HWPERMS, 61, 57), - _CC_FIELD(FLAGS, 57, 57), // For now pretend that the M bit is always present, not just for X caps + _CC_FIELD(FLAGS, 57, 57), // For now pretend that the M bit is always present, not just for X caps + _CC_FIELD(RESERVED1, 56, 56), // Actually the CL field, but reserverd to match sail // TODO: Level should be separate: _CC_FIELD(LEVEL, 56, 56) - _CC_FIELD(RESERVED, 55, 53), + _CC_FIELD(RESERVED0, 55, 53), _CC_FIELD(OTYPE, 52, 52), _CC_FIELD(EBT, 51, 32), @@ -145,14 +146,18 @@ _CC_STATIC_ASSERT_SAME(CC64R_MANTISSA_WIDTH, CC64R_FIELD_EXP_ZERO_BOTTOM_SIZE); // FIXME: this is currently not correct, we are missing the L8 bit #define CC64R_ENCODE_EXPONENT(E) _CC_ENCODE_SPLIT_EXPONENT(CC64R_MAX_EXPONENT - (E)) #define CC64R_EXTRACT_EXPONENT(pesbt) (CC64R_MAX_EXPONENT - _CC_EXTRACT_SPLIT_EXPONENT(pesbt)) -#define CC64R_RESERVED_FIELDS 1 -#define CC64R_RESERVED_BITS CC64R_FIELD_RESERVED_SIZE +#define CC64R_RESERVED_FIELDS 2 +#define CC64R_RESERVED_BITS (CC128R_FIELD_RESERVED0_SIZE + CC128R_FIELD_RESERVED1_SIZE) #define CC64R_HAS_BASE_TOP_SPECIAL_CASES 1 #define CC64R_USES_V9_CORRECTION_FACTORS 0 #define CC64R_USES_LEN_MSB 1 #include "cheri_compressed_cap_common.h" +static inline uint8_t _cc_N(get_reserved)(const _cc_cap_t* cap) { + return _CC_EXTRACT_SPLIT_FIELD(cap->cr_pesbt, RESERVED1, RESERVED0); +} + static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to // the maximum exponent instead. From 6b9f98b81b5be6289830d47294aaafd361938d17 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2025 16:39:48 -0800 Subject: [PATCH 09/18] Add the simple test for the 64r format --- CMakeLists.txt | 5 ++++- test/simple_test_64r.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/simple_test_64r.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0454f4a..fbe321d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ function(add_decompress_cap _format) endfunction() add_decompress_cap(64) +add_decompress_cap(64r) add_decompress_cap(128) add_decompress_cap(128m) add_decompress_cap(128r) @@ -203,13 +204,14 @@ endfunction() function(add_cc_tests _format) add_cc_tests_target(${_format} simple_test) - if (NOT _format STREQUAL "256") + if (NOT _format STREQUAL "256" AND NOT _format STREQUAL "64r") add_cc_tests_target(${_format} setbounds_test) add_cc_tests_target(${_format} random_inputs_test) endif() endfunction() add_cc_tests(64) +add_cc_tests(64r) add_cc_tests(128) add_cc_tests(128m) add_cc_tests(128r) @@ -238,6 +240,7 @@ function(add_fuzz_tests _format) endfunction() add_fuzz_tests(64) +add_fuzz_tests(64r) add_fuzz_tests(128) add_fuzz_tests(128m) add_fuzz_tests(128r) diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp new file mode 100644 index 0000000..88c92b6 --- /dev/null +++ b/test/simple_test_64r.cpp @@ -0,0 +1 @@ +#include "simple_test_common.cpp" From 74e212b7373cb725340e5b8328fda0b4052dc301 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 28 Jan 2025 10:19:14 -0800 Subject: [PATCH 10/18] Encode the L8 bit in EBT for cc64r This fixes the encoding of base, length and top for CHERI RISC-V with MXLEN=32. In addition to EF, E, B[9:0] and T[7:0], we also have to store bit 8 of the length in the L8 field. Also explain in detail why L8 is needed for recovering T[9:8]. Co-authored-by: Paul Buxton Co-authored-by: Alex Richardson --- cheri_compressed_cap_common.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index b5fa489..40db994 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -556,6 +556,32 @@ static inline uint32_t _cc_N(compute_ebt)(_cc_addr_t req_base, _cc_length_t req_ // incE : bool = false; uint32_t ebt_bits = _CC_N(ENCODE_IE)(false) | _CC_ENCODE_FIELD(req_top, EXP_ZERO_TOP) | _CC_ENCODE_FIELD(req_base, EXP_ZERO_BOTTOM); +#if _CC_N(USES_LEN_MSB) != 0 + // LEN_MSB is bit N of the bounds length, with N being the length of T plus one. + // + // For RV32 and exponent E == 0, both B and T are 10 bits wide. + // A capability stores B[9:0] and T[7:0]. For the bounds length l (the req_length64 variable), we know + // T = B + l. If l[9] was 1 we'd not have exponent 0, so l[9] must be 0. + // + // T[9:8] are not stored. Apart from B[9:0] and T[7:0], what else is required to recover T[9:8] from a stored + // capability? + // + // B .. .... .... + // + l 0. #### #### + // ------------ + // = T xx .... .... + // + // (. == known bit (stored), # == known bit (not stored), x == unknown bit). + // + // T[9:8] = B[9:8] + l[8] + carry bit + // The carry bit is 1 if B[7:0] > T [7:0] + // + // Long story short: If we also store l[8] in the capability, we can recover T[9:8]. + // + _CC_STATIC_ASSERT(_CC_N(FIELD_EXP_ZERO_TOP_SIZE) == 8, "We only support formats that use L8"); + uint8_t len_msb = _cc_N(getbits)(req_length64, _CC_N(FIELD_EXP_ZERO_TOP_SIZE), 1); + ebt_bits |= _CC_ENCODE_FIELD(len_msb, LEN_MSB); +#endif if (alignment_mask) *alignment_mask = _CC_MAX_ADDR; // no adjustment to base required *exact = true; From 7d88ea63d268668b0ae53cca82a28a01033ae172 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 11:10:21 -0800 Subject: [PATCH 11/18] Handle the L8 bit when {en,de}coding the exponent for cc64r When EXPONENT_FORMAT=0, the MSB of the exponent is stored in the LEN_MSB field. Co-authored-by: Martin Kaiser --- cheri_compressed_cap_64r.h | 10 ++++++---- cheri_compressed_cap_common.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cheri_compressed_cap_64r.h b/cheri_compressed_cap_64r.h index c9c37f3..f08ad1a 100644 --- a/cheri_compressed_cap_64r.h +++ b/cheri_compressed_cap_64r.h @@ -81,7 +81,7 @@ enum { _CC_FIELD(EBT, 51, 32), _CC_FIELD(EXPONENT_FORMAT, 51, 51), - _CC_FIELD(LEN_MSB, 50, 50), + _CC_FIELD(LEN_MSB, 50, 50), // Either MSB of exponent or MSB of length depending on EXPONENT_FORMAT. // The FIELD_INTERNAL_EXPONENT_SIZE name is currently required by various static assertions. _CC_N(FIELD_INTERNAL_EXPONENT_SIZE) = _CC_N(FIELD_EXPONENT_FORMAT_SIZE), _CC_FIELD(TOP_ENCODED, 49, 42), @@ -143,9 +143,11 @@ _CC_STATIC_ASSERT_SAME(CC64R_MANTISSA_WIDTH, CC64R_FIELD_EXP_ZERO_BOTTOM_SIZE); #define CC64R_ENCODE_IE(IE) _CC_ENCODE_FIELD(!(IE), EXPONENT_FORMAT) #define CC64R_EXTRACT_IE(value) (!_CC_EXTRACT_FIELD(value, EXPONENT_FORMAT)) // The exponent bits in memory are subtracted from the max exponent when decoding in the IE case. -// FIXME: this is currently not correct, we are missing the L8 bit -#define CC64R_ENCODE_EXPONENT(E) _CC_ENCODE_SPLIT_EXPONENT(CC64R_MAX_EXPONENT - (E)) -#define CC64R_EXTRACT_EXPONENT(pesbt) (CC64R_MAX_EXPONENT - _CC_EXTRACT_SPLIT_EXPONENT(pesbt)) +#define _CC64R_ENCODE_EXPONENT_RAW(e_enc) _CC_ENCODE_SPLIT_EXPONENT(e_enc) | _CC_ENCODE_FIELD(((e_enc) >> 4), LEN_MSB) +#define _CC64R_EXTRACT_EXPONENT_RAW(pesbt) \ + ((_CC_EXTRACT_FIELD(pesbt, LEN_MSB) << 4) | _CC_EXTRACT_SPLIT_EXPONENT(pesbt)) +#define CC64R_ENCODE_EXPONENT(E) _CC64R_ENCODE_EXPONENT_RAW(CC64R_MAX_EXPONENT - (E)) +#define CC64R_EXTRACT_EXPONENT(pesbt) (CC64R_MAX_EXPONENT - _CC64R_EXTRACT_EXPONENT_RAW(pesbt)) #define CC64R_RESERVED_FIELDS 2 #define CC64R_RESERVED_BITS (CC128R_FIELD_RESERVED0_SIZE + CC128R_FIELD_RESERVED1_SIZE) #define CC64R_HAS_BASE_TOP_SPECIAL_CASES 1 diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index 40db994..0a61306 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -654,7 +654,7 @@ static inline uint32_t _cc_N(compute_ebt)(_cc_addr_t req_base, _cc_length_t req_ const uint8_t newE = E + (incE ? 1 : 0); // let exact = not(lostSignificantBase | lostSignificantTop); *exact = !lostSignificantBase && !lostSignificantTop; - // Split E between T and B, use the remaining bits to encode Bbits/TBits + // Split E between T and B (and L_MSB), use the remaining bits to encode Bbits/TBits const _cc_addr_t expBits = _CC_N(ENCODE_EXPONENT)(newE); return expBits | _CC_N(ENCODE_IE)(true) | _CC_ENCODE_FIELD(top_ie, EXP_NONZERO_TOP) | _CC_ENCODE_FIELD(bot_ie, EXP_NONZERO_BOTTOM); From 4e3d5dae0747b03820bc1357335d4326cc0f3eb0 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 28 Jan 2025 10:17:13 -0800 Subject: [PATCH 12/18] Bounds encoding test for 64r, T8 = 1 Test the encoding of a capability from base, address and top for MXLEN=32. This test case uses an internal exponent such that T8 = 1. fixup test --- test/simple_test_64r.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp index 88c92b6..7d54be5 100644 --- a/test/simple_test_64r.cpp +++ b/test/simple_test_64r.cpp @@ -1 +1,27 @@ #include "simple_test_common.cpp" + +TEST_CASE("bounds encoding, internal exponent, T8 = 1", "[bounds]") { + /* params are base, cursor, top */ + _cc_cap_t cap = CompressedCap64r::make_max_perms_cap(0x0, 0x1000, 0x8000); + + /* + * 11 SDP + * 01001 AP quadrant 1, almighty, integer mode + * 0000 reserved + * 0 S + * 0 EF + * 1 T8 + * 000000 T[7:2] + * 00 TE + * 00000000 B[9:2] + * 01 BE + * + * internal exponent, E = 24 - 0b10001 = 7 + * LCout = 0, LMSB = 1 + * c_t = 0, c_b = 0 + */ + CHECK(cap.cr_pesbt == 0xd2040001); + cc64r_update_perms(&cap, 0); + cc64r_update_uperms(&cap, 0); + CHECK(cap.cr_pesbt == 0x00040001); +} From 06cd693f3018cbf380ca95bcb4c1499ab9360264 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Fri, 17 May 2024 14:37:24 +0200 Subject: [PATCH 13/18] Bounds encoding test for 64r, T8 = 0 Test the encoding of a capability from base, address and top for MXLEN=32. This test case uses an internal exponent such that T8 = 0. --- test/simple_test_64r.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp index 7d54be5..fd5ca7a 100644 --- a/test/simple_test_64r.cpp +++ b/test/simple_test_64r.cpp @@ -25,3 +25,28 @@ TEST_CASE("bounds encoding, internal exponent, T8 = 1", "[bounds]") { cc64r_update_uperms(&cap, 0); CHECK(cap.cr_pesbt == 0x00040001); } + +TEST_CASE("bounds encoding, exponent > 0, T8==0", "[bounds]") { + _cc_cap_t cap = CompressedCap64r::make_max_perms_cap(0x4C000000, 0x90000000, 0xAC000000); + + /* + * 00 SDP + * 01001 AP quadrant 1, almighty, integer mode + * 0000 reserved + * 0 S + * 0 EF + * 0 T8 + * 101100 T[7:2] + * 00 TE + * 01001100 B[9:2] + * 10 BE + * + * internal exponent, E = 24 - 0b00010 = 22 + * LCout = 0, LMSB = 1 + * c_t = 0, c_b = 0 + */ + CHECK(cap.cr_pesbt == 0xd202c132); + cc64r_update_perms(&cap, 0); + cc64r_update_uperms(&cap, 0); + CHECK(cap.cr_pesbt == 0x0002c132); +} From d571a40c18087dbfa1eaef983bd7ce14b70f4df9 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 23 May 2024 09:53:33 +0200 Subject: [PATCH 14/18] Bounds encoding test for 64r, c_b = -1 Add a bounds encoding test case for MXLEN=32 where the base correction c_b is not 0. --- test/simple_test_64r.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp index fd5ca7a..9fcdbf8 100644 --- a/test/simple_test_64r.cpp +++ b/test/simple_test_64r.cpp @@ -50,3 +50,29 @@ TEST_CASE("bounds encoding, exponent > 0, T8==0", "[bounds]") { cc64r_update_uperms(&cap, 0); CHECK(cap.cr_pesbt == 0x0002c132); } + +TEST_CASE("bounds encoding, exponent > 0, T8==0, c_b==-1", "[bounds]") { + _cc_cap_t cap = CompressedCap64r::make_max_perms_cap(0x9F000000, 0xA0000000, 0xAC000000); + + /* + * 00 SDP + * 01001 AP quadrant 1, almighty, integer mode + * 0000 reserved + * 0 S + * 0 EF + * 0 T8 + * 100000 T[7:2] + * 01 TE + * 11111000 B[9:2] + * 01 BE + * + * internal exponent, E = 24 - 0b00101 = 19 + * LCout = 1, LMSB = 1 + * A < R is true, B < R is false, T < R is true + * c_t = 0, c_b = -1 + */ + CHECK(cap.cr_pesbt == 0xd20207e1); + cc64r_update_perms(&cap, 0); + cc64r_update_uperms(&cap, 0); + CHECK(cap.cr_pesbt == 0x000207e1); +} From 14ef86114e35ec7d866a24c55dc474e5f2d1f792 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 11:40:01 -0800 Subject: [PATCH 15/18] Handle the L8 bit in extract_bounds_bits for cc64r format We have to read the LEN_MSB for the cc64r format to infer the correct top. Add a regression test found via fuzzing. --- cheri_compressed_cap_common.h | 4 ++++ test/simple_test_64r.cpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/cheri_compressed_cap_common.h b/cheri_compressed_cap_common.h index 0a61306..bf4e2cf 100644 --- a/cheri_compressed_cap_common.h +++ b/cheri_compressed_cap_common.h @@ -285,7 +285,11 @@ static inline _cc_bounds_bits _cc_N(extract_bounds_bits)(_cc_addr_t pesbt) { L_msb = 1; } else { result.E = 0; +#if _CC_N(USES_LEN_MSB) != 0 + L_msb = _CC_EXTRACT_FIELD(pesbt, LEN_MSB); +#else L_msb = 0; +#endif result.B = (uint16_t)_CC_EXTRACT_FIELD(pesbt, EXP_ZERO_BOTTOM); result.T = (uint16_t)_CC_EXTRACT_FIELD(pesbt, EXP_ZERO_TOP); } diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp index 9fcdbf8..ccfbaa5 100644 --- a/test/simple_test_64r.cpp +++ b/test/simple_test_64r.cpp @@ -76,3 +76,23 @@ TEST_CASE("bounds encoding, exponent > 0, T8==0, c_b==-1", "[bounds]") { cc64r_update_uperms(&cap, 0); CHECK(cap.cr_pesbt == 0x000207e1); } + +TEST_CASE("Incorrect bounds bits", "[bounds]") { + // Regression test: the new format was still using the old V9 correctionTop algorithm. + constexpr _cc_addr_t input_pesbt = 0x97bd62bc; + constexpr _cc_addr_t input_cursor = 0xb43a7561; + auto bounds_bits = TestAPICC::extract_bounds_bits(input_pesbt); + auto sail_bounds_bits = TestAPICC::sail_extract_bounds_bits(input_pesbt); + CHECK(bounds_bits == sail_bounds_bits); + CHECK(bounds_bits.E == 0); + CHECK(bounds_bits.IE == 0); + CHECK(bounds_bits.B == 700); + CHECK(bounds_bits.T == 88); // Previously reported 856 + auto cap = TestAPICC::decompress_raw(input_pesbt, input_cursor, false); + auto sail_cap = TestAPICC::sail_decode_raw(input_pesbt, input_cursor, false); + CHECK(cap == sail_cap); + CHECK(cap.base() == 0x000000b43a72bc); + // This previously reported top=0x000000000b43a7358 (72bc instead of 7458) + CHECK(cap.top() == 0x000000000b43a7458); + CHECK((int64_t)cap.offset() == 0x2a5); +} From 615bb4521e481c6c03143af45694e0ad51a17fed Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 11:48:52 -0800 Subject: [PATCH 16/18] Handle the L8 bit in bounds_malformed for cc64r We also have to reject `IE && E==0` for formats that use LEN_MSB. --- cheri_compressed_cap_64r.h | 3 ++- test/simple_test_64r.cpp | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cheri_compressed_cap_64r.h b/cheri_compressed_cap_64r.h index f08ad1a..1a74536 100644 --- a/cheri_compressed_cap_64r.h +++ b/cheri_compressed_cap_64r.h @@ -163,7 +163,8 @@ static inline uint8_t _cc_N(get_reserved)(const _cc_cap_t* cap) { static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to // the maximum exponent instead. - bool malformedLSB = bounds.E > _CC_MAX_EXPONENT; + // For MXLEN==32, we also report invalid bounds for IE && E == 0 + bool malformedLSB = bounds.E > _CC_MAX_EXPONENT || (bounds.E == 0); bool malformedMSB = (bounds.E == _CC_MAX_EXPONENT && bounds.B != 0) || (bounds.E == _CC_MAX_EXPONENT - 1 && (bounds.B & (1u << (_CC_MANTISSA_WIDTH - 1))) != 0); return bounds.IE && (malformedLSB || malformedMSB); diff --git a/test/simple_test_64r.cpp b/test/simple_test_64r.cpp index ccfbaa5..c2e3e95 100644 --- a/test/simple_test_64r.cpp +++ b/test/simple_test_64r.cpp @@ -96,3 +96,25 @@ TEST_CASE("Incorrect bounds bits", "[bounds]") { CHECK(cap.top() == 0x000000000b43a7458); CHECK((int64_t)cap.offset() == 0x2a5); } + +TEST_CASE("Malformed bounds L8", "[bounds]") { + // Regression test: the new format was still using the old V9 correctionTop algorithm. + constexpr _cc_addr_t input_pesbt = 0x1ab768a0; + constexpr _cc_addr_t input_cursor = 0xc58dfe0; + auto bounds_bits = TestAPICC::extract_bounds_bits(input_pesbt); + auto sail_bounds_bits = TestAPICC::sail_extract_bounds_bits(input_pesbt); + CHECK(bounds_bits == sail_bounds_bits); + CHECK(bounds_bits.E == 0); + CHECK(bounds_bits.IE == 1); + CHECK(bounds_bits.B == 160); + CHECK(bounds_bits.T == 472); + auto cap = TestAPICC::decompress_raw(input_pesbt, input_cursor, false); + auto sail_cap = TestAPICC::sail_decode_raw(input_pesbt, input_cursor, false); + CHECK(cap == sail_cap); + CHECK(!cap.cr_bounds_valid); // Should be malformed + CHECK(cap.base() == 0); // this previously reported base=0x0000000c58e0a0 + CHECK(cap.top() == 0); // This previously reported top=0x0000000000c58e1d8 + CHECK((int64_t)cap.offset() == input_cursor); // Previously reported 0xffffffffffffff40 + CHECK(cap.reserved_bits() == 5); + CHECK(cap.type() == CC64R_OTYPE_SENTRY); +} From 38d3d31a55d88f55201ecfe274a3db7ef39eb120 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 11:49:02 -0800 Subject: [PATCH 17/18] Enable the remaining tests for cc64r --- CMakeLists.txt | 2 +- test/random_inputs_test_64r.cpp | 1 + test/setbounds_test_64r.cpp | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/random_inputs_test_64r.cpp create mode 100644 test/setbounds_test_64r.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fbe321d..ae0c0df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,7 @@ endfunction() function(add_cc_tests _format) add_cc_tests_target(${_format} simple_test) - if (NOT _format STREQUAL "256" AND NOT _format STREQUAL "64r") + if (NOT _format STREQUAL "256") add_cc_tests_target(${_format} setbounds_test) add_cc_tests_target(${_format} random_inputs_test) endif() diff --git a/test/random_inputs_test_64r.cpp b/test/random_inputs_test_64r.cpp new file mode 100644 index 0000000..edd32b2 --- /dev/null +++ b/test/random_inputs_test_64r.cpp @@ -0,0 +1 @@ +#include "random_inputs_test_common.cpp" diff --git a/test/setbounds_test_64r.cpp b/test/setbounds_test_64r.cpp new file mode 100644 index 0000000..814c947 --- /dev/null +++ b/test/setbounds_test_64r.cpp @@ -0,0 +1,3 @@ +// TODO: Generate test cases from sail + +#include "setbounds_test_common.cpp" From f0f8b233bcf5a6b096e432dace1d5cc4039fff86 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 28 Jan 2025 16:26:58 -0800 Subject: [PATCH 18/18] Share more code between 64r and 128r format --- cheri_compressed_cap_128r.h | 31 +------------------------ cheri_compressed_cap_64r.h | 32 +------------------------- cheri_compressed_cap_riscv_common.h | 35 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 61 deletions(-) create mode 100644 cheri_compressed_cap_riscv_common.h diff --git a/cheri_compressed_cap_128r.h b/cheri_compressed_cap_128r.h index aafa539..788f5b7 100644 --- a/cheri_compressed_cap_128r.h +++ b/cheri_compressed_cap_128r.h @@ -154,33 +154,4 @@ _CC_STATIC_ASSERT_SAME(CC128R_MANTISSA_WIDTH, CC128R_FIELD_EXP_ZERO_BOTTOM_SIZE) #define CC128R_USES_LEN_MSB 0 #include "cheri_compressed_cap_common.h" - -static inline uint8_t cc128r_get_reserved(const cc128r_cap_t* cap) { - return _CC_EXTRACT_SPLIT_FIELD(cap->cr_pesbt, RESERVED1, RESERVED0); -} - -static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { - // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to - // the maximum exponent instead. - bool malformedLSB = bounds.E > _CC_MAX_EXPONENT; - bool malformedMSB = (bounds.E == _CC_MAX_EXPONENT && bounds.B != 0) || - (bounds.E == _CC_MAX_EXPONENT - 1 && (bounds.B & (1u << (_CC_MANTISSA_WIDTH - 1))) != 0); - return bounds.IE && (malformedLSB || malformedMSB); -} - -static inline bool _cc_N(compute_base_top_special_cases)(_cc_bounds_bits bounds, _cc_addr_t* base_out, - _cc_length_t* top_out, bool* valid) { - if (_cc_N(bounds_malformed)(bounds)) { - *base_out = 0; - *top_out = 0; - *valid = false; - return true; - } - return false; -} - -// Check that there is no XOR mask for this encoding format (i.e. NULL encodes to all-zeroes in memory). -_CC_STATIC_ASSERT_SAME(CC128R_MEM_XOR_MASK, UINT64_C(0)); - -#undef CC_FORMAT_LOWER -#undef CC_FORMAT_UPPER +#include "cheri_compressed_cap_riscv_common.h" diff --git a/cheri_compressed_cap_64r.h b/cheri_compressed_cap_64r.h index 1a74536..5e0a8c7 100644 --- a/cheri_compressed_cap_64r.h +++ b/cheri_compressed_cap_64r.h @@ -155,34 +155,4 @@ _CC_STATIC_ASSERT_SAME(CC64R_MANTISSA_WIDTH, CC64R_FIELD_EXP_ZERO_BOTTOM_SIZE); #define CC64R_USES_LEN_MSB 1 #include "cheri_compressed_cap_common.h" - -static inline uint8_t _cc_N(get_reserved)(const _cc_cap_t* cap) { - return _CC_EXTRACT_SPLIT_FIELD(cap->cr_pesbt, RESERVED1, RESERVED0); -} - -static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { - // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to - // the maximum exponent instead. - // For MXLEN==32, we also report invalid bounds for IE && E == 0 - bool malformedLSB = bounds.E > _CC_MAX_EXPONENT || (bounds.E == 0); - bool malformedMSB = (bounds.E == _CC_MAX_EXPONENT && bounds.B != 0) || - (bounds.E == _CC_MAX_EXPONENT - 1 && (bounds.B & (1u << (_CC_MANTISSA_WIDTH - 1))) != 0); - return bounds.IE && (malformedLSB || malformedMSB); -} - -static inline bool _cc_N(compute_base_top_special_cases)(_cc_bounds_bits bounds, _cc_addr_t* base_out, - _cc_length_t* top_out, bool* valid) { - if (_cc_N(bounds_malformed)(bounds)) { - *base_out = 0; - *top_out = 0; - *valid = false; - return true; - } - return false; -} - -// Check that there is no XOR mask for this encoding format (i.e. NULL encodes to all-zeroes in memory). -_CC_STATIC_ASSERT_SAME(CC64R_MEM_XOR_MASK, UINT64_C(0)); - -#undef CC_FORMAT_LOWER -#undef CC_FORMAT_UPPER +#include "cheri_compressed_cap_riscv_common.h" diff --git a/cheri_compressed_cap_riscv_common.h b/cheri_compressed_cap_riscv_common.h new file mode 100644 index 0000000..90f0094 --- /dev/null +++ b/cheri_compressed_cap_riscv_common.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-2-Clause + +static inline uint8_t _cc_N(get_reserved)(const _cc_cap_t* cap) { + return _CC_EXTRACT_SPLIT_FIELD(cap->cr_pesbt, RESERVED1, RESERVED0); +} + +static inline bool _cc_N(bounds_malformed)(_cc_bounds_bits bounds) { + // The spec defines this check as checking for E < 0, but since we store it as an unsigned number, we compare it to + // the maximum exponent instead. + bool malformedLSB = bounds.E > _CC_MAX_EXPONENT; +#if _CC_N(USES_LEN_MSB) != 0 + // For MXLEN==32, we also report invalid bounds for IE && E == 0 + malformedLSB = malformedLSB || (bounds.E == 0); +#endif + bool malformedMSB = (bounds.E == _CC_MAX_EXPONENT && bounds.B != 0) || + (bounds.E == _CC_MAX_EXPONENT - 1 && (bounds.B & (1u << (_CC_MANTISSA_WIDTH - 1))) != 0); + return bounds.IE && (malformedLSB || malformedMSB); +} + +static inline bool _cc_N(compute_base_top_special_cases)(_cc_bounds_bits bounds, _cc_addr_t* base_out, + _cc_length_t* top_out, bool* valid) { + if (_cc_N(bounds_malformed)(bounds)) { + *base_out = 0; + *top_out = 0; + *valid = false; + return true; + } + return false; +} + +// Check that there is no XOR mask for this encoding format (i.e. NULL encodes to all-zeroes in memory). +_CC_STATIC_ASSERT_SAME(_CC_N(MEM_XOR_MASK), UINT64_C(0)); + +#undef CC_FORMAT_LOWER +#undef CC_FORMAT_UPPER