From f1837b9fb6c3a8787c184239a29bace74a2c322d Mon Sep 17 00:00:00 2001 From: gameboo Date: Thu, 23 Sep 2021 19:23:28 +0100 Subject: [PATCH 01/10] Mock up of the getBoundsInfo API update --- CHERICC_Fat.bsv | 104 ++++++++++++-- CHERICap.bsv | 365 +++++++++++++++++++++++++++++------------------- 2 files changed, 315 insertions(+), 154 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index f8b2c08..e25f627 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -258,6 +258,98 @@ typedef MetaInfo TempFields; // Interface functions //------------------------------------------------------------------------------ +function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf); + // XXX TODO base top length repBase repTop repLength + // XXX DONE base top length + + // shared useful bindings and precomputed values + ////////////////////////////////////////////////////////////////////////////// + + // bind the Bounds field of the CapFat to shorter handy names + Exp exp = cap.bounds.exp; + Bit #(MW) baseBits = cap.bounds.baseBits; + Bit #(MW) topBits = cap.bounds.topBits; + + // Get the top and base bits with the 2 correction bits prepended + Bit #(TAdd #(MW, 2)) correctBase = {pack(tf.baseCorrection), baseBits}; + Bit #(TAdd #(MW, 2)) correctTop = {pack(tf.topCorrection), topBits}; + + // Build a mask on the high bits of a full length value + Bit #(TSub #(CapAddrW, MW)) maskBase = ~0 << exp; + Bit #(TSub #(TAdd #(CapAddrW, 1), MW)) maskTop = ~0 << exp; + + // compute base + ////////////////////////////////////////////////////////////////////////////// + + // First, construct a full length value with the base bits and the correction + // bits above, and shift that value to the appropriate spot. + CapAddr addBase = signExtend (correctBase) << exp; + // Extract the high bits of the address (and append the implied zeros at the + // bottom), and add with the previously prepared value. + CapAddr base = {truncateLSB (cap.address) & maskBase, 0} + addBase; + + // compute top + ////////////////////////////////////////////////////////////////////////////// + + // First, construct a full length value with the top bits and the correction + // bits above, and shift that value to the appropriate spot. + CapAddrPlus1 addTop = signExtend (correctTop) << exp; + // Extract the high bits of the address (and append the implied zeros at the + // bottom), and add with the previously prepared value. + CapAddrPlus1 top = {truncateLSB ({1'b0, cap.address}) & maskTop, 0} + addTop; + // If the base and top are more than an address space away from eachother, + // invert the 64th/32nd bit of Top. This corrects for errors that happen when + // the representable space wraps the address space. + Bit #(2) topTip = truncateLSB (top); + Bit #(2) baseTip = {1'b0, msb (base)}; + // If the bit we're interested in are actually coming from baseBits, select + // the correct one from there. + // exp == (resetExp - 1) doesn't matter since we will not flip unless + // exp < resetExp - 1. + if (exp == (resetExp - 2)) baseTip = {1'b0, baseBits[valueOf(MW) - 1]}; + // Do the final check. + // If exp >= resetExp - 1, the bits we're looking at are coming directly from + // topBits and baseBits, are not being inferred, and therefore do not need + // correction. If we are below this range, check that the difference between + // the resulting top and bottom is less than one address space. If not, flip + // the msb of the top. + if (exp < (resetExp - 1) && (topTip - baseTip) > 1) + top[valueOf(CapAddrW)] = ~top[valueOf(CapAddrW)]; + + // compute length + ////////////////////////////////////////////////////////////////////////////// + + // Get the length by subtracting base from top and shifting appropriately, and + // saturate in case of big exponent + CapAddrPlus1 length = + (exp >= resetExp) ? ~0 : zeroExtend (correctTop - correctBase) << exp; + + // compute repBase + ////////////////////////////////////////////////////////////////////////////// + + CapAddr repBase = error ("TODO implement CapFat repBase"); + + // compute repTop + ////////////////////////////////////////////////////////////////////////////// + + CapAddrPlus1 repTop = error ("TODO implement CapFat repTop"); + + // compute repLength + ////////////////////////////////////////////////////////////////////////////// + + CapAddrPlus1 repLength = error ("TODO implement CapFat repLength"); + + // return populated BoundsInfo structure + ////////////////////////////////////////////////////////////////////////////// + + return BoundsInfo { base: base + , top: top + , length: length + , repBase: repBase + , repTop: repTop + , repLength: repLength }; +endfunction + function CapAddr getBotFat(CapFat cap, TempFields tf); // First, construct a full length value with the base bits and the // correction bits above, and shift that value to the appropriate spot. @@ -910,10 +1002,7 @@ instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); setAddrUnsafe(capMem, getAddr(capMem) + signExtend(inc)); function getOffset = error("getOffset not implemented for CapMem"); function modifyOffset = error("modifyOffset not implemented for CapMem"); - function getBase = error("getBase not implemented for CapMem"); - function getTop = error("getTop not implemented for CapMem"); - function getLength = error("getLength not implemented for CapMem"); - function isInBounds = error("isInBounds not implemented for CapMem"); + function getBoundsInfo = error("getBoundsInfo not implemented for CapMem"); function setBoundsCombined = error("setBoundsCombined not implemented for CapMem"); function nullWithAddr = setAddrUnsafe(packCap(null_cap)); function almightyCap; @@ -1044,10 +1133,7 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); function getOffset = error("getOffset not implemented for CapReg"); function modifyOffset = error("modifyOffset not implemented for CapReg"); - function getBase = error("getBase not implemented for CapReg"); - function getTop = error("getTop not implemented for CapReg"); - function getLength = error("getLength not implemented for CapReg"); - function isInBounds = error("isInBounds not implemented for CapReg"); + function getBoundsInfo = error("getBoundsInfo not implemented for CapReg"); function setBoundsCombined(cap, length) = setBoundsFat(cap, length); @@ -1182,6 +1268,8 @@ instance CHERICap #(CapPipe, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); return Exact { exact: result.v, value: cap }; endfunction + function getBoundsInfo (cap) = getBoundsInfoFat (cap.capFat, cap.tempFields); + function getBase (cap) = getBotFat(cap.capFat, cap.tempFields); function getTop (cap) = getTopFat(cap.capFat, cap.tempFields); diff --git a/CHERICap.bsv b/CHERICap.bsv index 76632bf..a52fe5b 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -29,7 +29,17 @@ package CHERICap; -// CHERI public types +export SoftPerms; +export HardPerms; +export Kind; +export BoundsInfo; +export Exact; +export SetBoundsReturn; +export showCHERICap; +export CHERICap :: *; +export Cast; + +// CHERI capability types //////////////////////////////////////////////////////////////////////////////// // Permission bits @@ -64,15 +74,6 @@ instance Bitwise #(HardPerms); function lsb (x) = lsb(pack(x)); endinstance -// Helper type to return the result of an operation along with whether the -// operation was exact. In cases where no sensible inexact representation -// exists, the only guarantee is that the tag bit is not set. - -typedef struct { - Bool exact; - t value; -} Exact #(type t) deriving (Bits); - // Kind of a capability, that is whether it is "sealed with a given otype", or // if it is a "sentry" or simply "unsealed". @@ -84,6 +85,29 @@ typedef union tagged { Bit #(ot) SEALED_WITH_TYPE; } Kind #(numeric type ot) deriving (Bits, Eq, FShow); +// helper type for gathering bounds information on a capability + +typedef struct { + Bit#(n) base; + Bit#(TAdd#(n, 1)) top; + Bit#(TAdd#(n, 1)) length; + Bit#(n) repBase; + Bit#(TAdd#(n, 1)) repTop; + Bit#(TAdd#(n, 1)) repLength; +} BoundsInfo #(numeric type n) deriving (Bits, Eq, FShow); + +// helper types and functions +//////////////////////////////////////////////////////////////////////////////// + +// Helper type to return the result of an operation along with whether the +// operation was exact. In cases where no sensible inexact representation +// exists, the only guarantee is that the tag bit is not set. + +typedef struct { + Bool exact; + t value; +} Exact #(type t) deriving (Bits); + // Helper type for the return value of the 'setBoundsCombined' method typedef struct { @@ -93,143 +117,15 @@ typedef struct { Bit #(n) mask; } SetBoundsReturn #(type t, numeric type n) deriving (Bits, Eq, FShow); +// helper function to test belonging to a range +function Bool belongsToRange ( Bit #(n) x, Bit #(n) low, Bit #(n) high + , Bool highIncluded); + Bool notTooHigh = highIncluded ? x <= high : x < high; + Bool notTooLow = x >= low; + return notTooLow && notTooHigh; +endfunction -// CHERI capability typeclass -//////////////////////////////////////////////////////////////////////////////// - -typeclass CHERICap #( type t - , numeric type ot - , numeric type flg - , numeric type n - , numeric type mem_sz - , numeric type maskable_bits ) - dependencies (t determines (ot, flg, n, mem_sz, maskable_bits)); - - // Return whether the Capability is valid - function Bool isValidCap (t cap); - // Set the capability as valid. All fields left unchanged - function t setValidCap (t cap, Bool valid); - - // Get the flags field - function Bit#(flg) getFlags (t cap); - // Set the flags field - function t setFlags (t cap, Bit#(flg) flags); - - // Get the hardware permissions - function HardPerms getHardPerms (t cap); - // Set the hardware permissions - function t setHardPerms (t cap, HardPerms hardperms); - // Get the software permissions - function SoftPerms getSoftPerms (t cap); - // Set the software permissions - function t setSoftPerms (t cap, SoftPerms softperms); - // Get the architectural permissions - function Bit#(31) getPerms (t cap) = - zeroExtend({pack(getSoftPerms(cap)), 3'h0, pack(getHardPerms(cap))}); - // Set the architectural permissions - function t setPerms (t cap, Bit#(31) perms) = - setSoftPerms ( setHardPerms(cap, unpack(perms[11:0])) - , unpack(truncate(perms[30:15])) ); - - // Manipulate the kind of the capability, i.e. whether it is sealed, sentry, - // unsealed, ... - function Kind#(ot) getKind (t cap); - function t setKind (t cap, Kind#(ot) kind); - - // Get the in-memory architectural representation of the capability metadata - function Bit #(TSub #(mem_sz, n)) getMeta (t cap); - // Get the in-memory architectural representation of the capability address - function Bit #(n) getAddr (t cap); - - // Note that the following rule is expected to hold: - // fromMem (tuple2 (isValidCap (cap), {getMeta (cap), getAddr (cap)})) == cap - - // Set the address of the capability. Result invalid if unrepresentable - function Exact#(t) setAddr (t cap, Bit#(n) addr); - // Set the address of the capability. Result assumed to be representable - function t setAddrUnsafe (t cap, Bit#(n) addr); - // Add to the address of the capability. Result assumed to be representable - function t addAddrUnsafe (t cap, Bit#(maskable_bits) inc); - - // Get the offset of the capability - function Bit#(n) getOffset (t cap) = getAddr(cap) - getBase(cap); - // Modify the offset of the capability. Result invalid if unrepresentable - function Exact#(t) modifyOffset (t cap, Bit#(n) offset, Bool doInc); - // Set the offset of the capability. Result invalid if unrepresentable - function Exact#(t) setOffset (t cap, Bit#(n) offset) = - modifyOffset(cap, offset, False); - // Set the offset of the capability. Result invalid if unrepresentable - function Exact#(t) incOffset (t cap, Bit#(n) inc) = - modifyOffset(cap, inc, True); - - // Get the base - function Bit#(n) getBase (t cap); - // Get the top - function Bit#(TAdd#(n, 1)) getTop (t cap); - // Get the length - function Bit#(TAdd#(n, 1)) getLength (t cap); - - // Assertion that address is between base and top - function Bool isInBounds (t cap, Bool isTopIncluded); - Bool isNotTooHigh = isTopIncluded ? zeroExtend(getAddr(cap)) <= getTop(cap) - : zeroExtend(getAddr(cap)) < getTop(cap); - Bool isNotTooLow = getAddr(cap) >= getBase(cap); - return isNotTooLow && isNotTooHigh; - endfunction - - // Set the length of the capability. Inexact: result length may be different - // to requested - function Exact#(t) setBounds (t cap, Bit#(n) length); - let combinedResult = setBoundsCombined(cap, length); - return Exact {exact: combinedResult.exact, value: combinedResult.cap}; - endfunction - - function SetBoundsReturn#(t, n) setBoundsCombined (t cap, Bit#(n) length); - - // Returns a null cap with an address set to the argument - function t nullWithAddr (Bit#(n) addr); - - // Workaround to allow null cap to be derived in default implementations - function t nullCapFromDummy(t dummy); - - // Return the maximally permissive capability (initial register state) - function t almightyCap; - // Return the null capability - function t nullCap = nullCapFromDummy(?); - - // Check if a type is valid - function Bool validAsType (t dummy, Bit#(n) checkType); - - // Convert from and to bit memory representation - function t fromMem (Tuple2#(Bool, Bit#(mem_sz)) mem_cap); - function Tuple2#(Bool, Bit#(mem_sz)) toMem (t cap); - - // Functions that can be cheap by relying on current capability representation - - // Mask the least significant bits of capability address with a mask - // maskable_width should be small enough to make this - // safe with respect to representability - function t maskAddr (t cap, Bit#(maskable_bits) mask); - - // Check the alignment of the base, giving least significant 2 bits. - // This relies on the fact that internal exponents take up 2 bits of the - // base. - function Bit#(2) getBaseAlignment (t cap); - - // Get representable alignment mask - function Bit#(n) getRepresentableAlignmentMask ( t dummy - , Bit#(n) length_request) = - setBoundsCombined(nullCapFromDummy(dummy), length_request).mask; - - // Get representable length - function Bit#(n) getRepresentableLength (t dummy, Bit#(n) length_request) = - setBoundsCombined(nullCapFromDummy(dummy), length_request).length; - - // Assert that the encoding is valid - function Bool isDerivable (t cap); - -endtypeclass - +// XXX TODO augment with all architectural bounds/ repbounds ? function Fmt showCHERICap (t cap) provisos (CHERICap #(t , ot, flg, n, mem_sz, maskable_bits)); return $format( "Valid: 0x%0x", isValidCap(cap)) + @@ -251,4 +147,181 @@ instance Cast#(t, t); function cast = id; endinstance +// CHERI capability typeclass +//////////////////////////////////////////////////////////////////////////////// + +typeclass CHERICap #( type t + , numeric type ot + , numeric type flg + , numeric type n + , numeric type mem_sz + , numeric type maskable_bits ) + dependencies (t determines (ot, flg, n, mem_sz, maskable_bits)); + + // capability validity + ////////////////////////////////////////////////////////////////////////////// + + // Return whether the Capability is valid + function Bool isValidCap (t cap); + // Set the capability as valid. All fields left unchanged + function t setValidCap (t cap, Bool valid); + + // capability flags + ////////////////////////////////////////////////////////////////////////////// + + // Get the flags field + function Bit#(flg) getFlags (t cap); + // Set the flags field + function t setFlags (t cap, Bit#(flg) flags); + + // capability permissions + ////////////////////////////////////////////////////////////////////////////// + + // Get the hardware permissions + function HardPerms getHardPerms (t cap); + // Set the hardware permissions + function t setHardPerms (t cap, HardPerms hardperms); + // Get the software permissions + function SoftPerms getSoftPerms (t cap); + // Set the software permissions + function t setSoftPerms (t cap, SoftPerms softperms); + // Get the architectural permissions + function Bit#(31) getPerms (t cap) = + zeroExtend({pack(getSoftPerms(cap)), 3'h0, pack(getHardPerms(cap))}); + // Set the architectural permissions + function t setPerms (t cap, Bit#(31) perms) = + setSoftPerms ( setHardPerms(cap, unpack(perms[11:0])) + , unpack(truncate(perms[30:15])) ); + + // capability kind + ////////////////////////////////////////////////////////////////////////////// + // Manipulate the kind of the capability, i.e. whether it is sealed, sentry, + // unsealed, ... + + // get the kind of a capability + function Kind#(ot) getKind (t cap); + // set the kind of a capability + function t setKind (t cap, Kind#(ot) kind); + // XXX TODO Check if a type is valid + function Bool validAsType (t dummy, Bit#(n) checkType); + + // capability in-memory architectural representation + ////////////////////////////////////////////////////////////////////////////// + // Note that the following rule is expected to hold: + // fromMem (tuple2 (isValidCap (cap), {getMeta (cap), getAddr (cap)})) == cap + + // Get the in-memory architectural representation of the capability metadata + function Bit #(TSub #(mem_sz, n)) getMeta (t cap); + // Get the in-memory architectural representation of the capability address + function Bit #(n) getAddr (t cap); + // Convert from in-memory architectural bit representation to capability type + function t fromMem (Tuple2#(Bool, Bit#(mem_sz)) mem_cap); + // Convert from capability type to in-memory architectural bit representation + function Tuple2#(Bool, Bit#(mem_sz)) toMem (t cap); + + // capability address/offset manipulation + ////////////////////////////////////////////////////////////////////////////// + + // Set the address of the capability. Result invalid if unrepresentable + function Exact#(t) setAddr (t cap, Bit#(n) addr); + // Set the address of the capability. Result assumed to be representable + function t setAddrUnsafe (t cap, Bit#(n) addr); + // Add to the address of the capability. Result assumed to be representable + function t addAddrUnsafe (t cap, Bit#(maskable_bits) inc); + // Mask the least significant bits of capability address with a mask + // maskable_width should be small enough to make this + // safe with respect to representability + function t maskAddr (t cap, Bit#(maskable_bits) mask); + // Get the offset of the capability + function Bit#(n) getOffset (t cap) = getAddr(cap) - getBase(cap); + // Modify the offset of the capability. Result invalid if unrepresentable + function Exact#(t) modifyOffset (t cap, Bit#(n) offset, Bool doInc); + // Set the offset of the capability. Result invalid if unrepresentable + function Exact#(t) setOffset (t cap, Bit#(n) offset) = + modifyOffset(cap, offset, False); + // Set the offset of the capability. Result invalid if unrepresentable + function Exact#(t) incOffset (t cap, Bit#(n) inc) = + modifyOffset(cap, inc, True); + + // capability architectural bounds queries + ////////////////////////////////////////////////////////////////////////////// + // Note that the following rules are expected to hold: + // getBase (cap) + getLength (cap) == getLength (cap) + // getRepBase (cap) + getRepLength (cap) == getRepLength (cap) + // isInRepBounds (cap) ==> isInRepBounds (cap) + + // Get all architectural bound information for a capability + function BoundsInfo#(n) getBoundsInfo (t cap); + // Get the base + function Bit#(n) getBase (t cap) = getBoundsInfo(cap).base; + // Get the top + function Bit#(TAdd#(n, 1)) getTop (t cap) = getBoundsInfo(cap).top; + // Get the length + function Bit#(TAdd#(n, 1)) getLength (t cap) = getBoundsInfo(cap).length; + // Assertion that the capability's address is between its base and top + function Bool isInBounds (t cap, Bool isTopIncluded) = + belongsToRange ( zeroExtend (getAddr (cap)) + , zeroExtend (getBase (cap)) + , getTop (cap) + , isTopIncluded ); + // Get the representable base + function Bit#(n) getRepBase (t cap) = getBoundsInfo(cap).repBase; + // Get the representable top + function Bit#(TAdd#(n, 1)) getRepTop (t cap) = getBoundsInfo(cap).repTop; + // Get the representable length + function Bit#(TAdd#(n, 1)) getRepLength (t cap) = + getBoundsInfo(cap).repLength; + // Assertion that the capability's address is between its representable + // base and top + function Bool isInRepBounds (t cap, Bool isRepTopIncluded) = + belongsToRange ( zeroExtend (getAddr (cap)) + , zeroExtend (getRepBase (cap)) + , getRepTop (cap) + , isRepTopIncluded ); + + // XXX TODO Check the alignment of the base, giving least significant 2 bits. + // This relies on the fact that internal exponents take up 2 bits of the + // base. + function Bit#(2) getBaseAlignment (t cap); + + // XXX TODO Get representable alignment mask + function Bit#(n) getRepresentableAlignmentMask ( t dummy + , Bit#(n) length_request) = + setBoundsCombined(nullCapFromDummy(dummy), length_request).mask; + + // XXX TODO Get representable length + function Bit#(n) getRepresentableLength (t dummy, Bit#(n) length_request) = + setBoundsCombined(nullCapFromDummy(dummy), length_request).length; + + // capability derivation (bounds set) + ////////////////////////////////////////////////////////////////////////////// + + // Set the length of the capability. Inexact: result length may be different + // to requested + function Exact#(t) setBounds (t cap, Bit#(n) length); + let combinedResult = setBoundsCombined(cap, length); + return Exact {exact: combinedResult.exact, value: combinedResult.cap}; + endfunction + // XXX TODO + function SetBoundsReturn#(t, n) setBoundsCombined (t cap, Bit#(n) length); + + // common capabilities + ////////////////////////////////////////////////////////////////////////////// + + // the null capability + function t nullCap = nullCapFromDummy(?); + // a null capability with a given address set + function t nullWithAddr (Bit#(n) addr); + // maximally permissive capability (initial register state) + function t almightyCap; + // XXX TODO Workaround to allow null cap to be derived in default + // implementations + function t nullCapFromDummy(t dummy); + + // Assert that the encoding is valid + ////////////////////////////////////////////////////////////////////////////// + function Bool isDerivable (t cap); + +endtypeclass + endpackage From e110284da78514c3492b44b594aeccbc242b1fcc Mon Sep 17 00:00:00 2001 From: gameboo Date: Fri, 24 Sep 2021 13:17:18 +0100 Subject: [PATCH 02/10] More refactor + first implementation for rep{Base,Top,Length} --- CHERICC_Fat.bsv | 68 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index e25f627..52bf929 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -258,9 +258,9 @@ typedef MetaInfo TempFields; // Interface functions //------------------------------------------------------------------------------ -function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf); - // XXX TODO base top length repBase repTop repLength - // XXX DONE base top length +function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) + provisos ( NumAlias #(upperW, TSub #(TAdd #(CapAddrW, 1), MW)) + , NumAlias #(lowerW, MW) ); // shared useful bindings and precomputed values ////////////////////////////////////////////////////////////////////////////// @@ -269,34 +269,46 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf); Exp exp = cap.bounds.exp; Bit #(MW) baseBits = cap.bounds.baseBits; Bit #(MW) topBits = cap.bounds.topBits; + // prepare representable bound bits + Bit #(MW) repBoundBits = {tf.repBoundTopBits, 0}; - // Get the top and base bits with the 2 correction bits prepended - Bit #(TAdd #(MW, 2)) correctBase = {pack(tf.baseCorrection), baseBits}; - Bit #(TAdd #(MW, 2)) correctTop = {pack(tf.topCorrection), topBits}; + // prepare typed "lower" MW zeroes for simpler concatenation + Bit #(lowerW) lowerZeroes = 0; - // Build a mask on the high bits of a full length value - Bit #(TSub #(CapAddrW, MW)) maskBase = ~0 << exp; - Bit #(TSub #(TAdd #(CapAddrW, 1), MW)) maskTop = ~0 << exp; + // prepare "upper" version for baseBits, topBits and repBoundBits + Bit #(upperW) baseBitsUpper = zeroExtend (baseBits) << exp; + Bit #(upperW) topBitsUpper = zeroExtend (topBits) << exp; + Bit #(upperW) repBoundBitsUpper = zeroExtend (repBoundBits) << exp; + + // shared +1 and -1/~0 shifted by exponent + Bit #(upperW) allOnesExpShifted = ~0 << exp; + let mask = allOnesExpShifted; + let minusOne = allOnesExpShifted; + Bit #(upperW) oneExpShifted = 1 << exp; + let plusOne = oneExpShifted; + + // Prepare "upper" address and its "hi" and "lo" region versions + Bit #(upperW) addrUpperBits = truncateLSB ({1'b0, cap.address}) & mask; + Bit #(upperW) addrUpperHi = addrUpperBits + (tf.addrHi ? 0 : plusOne); + Bit #(upperW) addrUpperLo = addrUpperBits + (tf.addrHi ? minusOne : 0); + function addrUpper (isHi) = isHi ? addrUpperHi : addrUpperLo; // compute base ////////////////////////////////////////////////////////////////////////////// - // First, construct a full length value with the base bits and the correction - // bits above, and shift that value to the appropriate spot. - CapAddr addBase = signExtend (correctBase) << exp; - // Extract the high bits of the address (and append the implied zeros at the - // bottom), and add with the previously prepared value. - CapAddr base = {truncateLSB (cap.address) & maskBase, 0} + addBase; + // Use the appropriate upper bits of the address based on whether the base is + // in the "hi" or the "lo" region, or in the base bits in place and append the + // implied zeros in the lower bits + CapAddr base = + {truncate (addrUpper (tf.baseHi) | baseBitsUpper), lowerZeroes}; // compute top ////////////////////////////////////////////////////////////////////////////// - // First, construct a full length value with the top bits and the correction - // bits above, and shift that value to the appropriate spot. - CapAddrPlus1 addTop = signExtend (correctTop) << exp; - // Extract the high bits of the address (and append the implied zeros at the - // bottom), and add with the previously prepared value. - CapAddrPlus1 top = {truncateLSB ({1'b0, cap.address}) & maskTop, 0} + addTop; + // Use the appropriate upper bits of the address based on whether the top is + // in the "hi" or the "lo" region, or in the top bits in place and append the + // implied zeros in the lower bits + CapAddrPlus1 top = {addrUpper (tf.topHi) | topBitsUpper, lowerZeroes}; // If the base and top are more than an address space away from eachother, // invert the 64th/32nd bit of Top. This corrects for errors that happen when // the representable space wraps the address space. @@ -319,6 +331,9 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf); // compute length ////////////////////////////////////////////////////////////////////////////// + // Get the top and base bits with the 2 correction bits prepended + Bit #(TAdd #(MW, 2)) correctBase = {pack (tf.baseCorrection), baseBits}; + Bit #(TAdd #(MW, 2)) correctTop = {pack (tf.topCorrection), topBits}; // Get the length by subtracting base from top and shifting appropriately, and // saturate in case of big exponent CapAddrPlus1 length = @@ -327,17 +342,22 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf); // compute repBase ////////////////////////////////////////////////////////////////////////////// - CapAddr repBase = error ("TODO implement CapFat repBase"); + // Use the "lo" region upper bits of the address, or in the representable + // bound bits in place and append the implied zeros in the lower bits + CapAddr repBase = + {truncate (addrUpperLo | repBoundBitsUpper), lowerZeroes}; // compute repTop ////////////////////////////////////////////////////////////////////////////// - CapAddrPlus1 repTop = error ("TODO implement CapFat repTop"); + // Use the "hi" region upper bits of the address, or in the representable + // bound bits in place and append the implied zeros in the lower bits + CapAddrPlus1 repTop = {addrUpperHi | repBoundBitsUpper, lowerZeroes}; // compute repLength ////////////////////////////////////////////////////////////////////////////// - CapAddrPlus1 repLength = error ("TODO implement CapFat repLength"); + CapAddrPlus1 repLength = {oneExpShifted, lowerZeroes}; // return populated BoundsInfo structure ////////////////////////////////////////////////////////////////////////////// From f8dd16550599f8c1205837ed7ad94f48a23974c7 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 00:08:38 +0100 Subject: [PATCH 03/10] Can't cleanly use export mechanism at the moment apparently... + typo in comments --- CHERICap.bsv | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/CHERICap.bsv b/CHERICap.bsv index a52fe5b..287259c 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -29,16 +29,6 @@ package CHERICap; -export SoftPerms; -export HardPerms; -export Kind; -export BoundsInfo; -export Exact; -export SetBoundsReturn; -export showCHERICap; -export CHERICap :: *; -export Cast; - // CHERI capability types //////////////////////////////////////////////////////////////////////////////// @@ -208,6 +198,7 @@ typeclass CHERICap #( type t // capability in-memory architectural representation ////////////////////////////////////////////////////////////////////////////// // Note that the following rule is expected to hold: + // fromMem (toMem (cap)) == cap // fromMem (tuple2 (isValidCap (cap), {getMeta (cap), getAddr (cap)})) == cap // Get the in-memory architectural representation of the capability metadata @@ -246,9 +237,9 @@ typeclass CHERICap #( type t // capability architectural bounds queries ////////////////////////////////////////////////////////////////////////////// // Note that the following rules are expected to hold: - // getBase (cap) + getLength (cap) == getLength (cap) - // getRepBase (cap) + getRepLength (cap) == getRepLength (cap) - // isInRepBounds (cap) ==> isInRepBounds (cap) + // getBase (cap) + getLength (cap) == getTop (cap) + // getRepBase (cap) + getRepLength (cap) == getRepTop (cap) + // isInBounds (cap) ==> isInRepBounds (cap) // Get all architectural bound information for a capability function BoundsInfo#(n) getBoundsInfo (t cap); From 76d4dea31ecf9b0d3b78f2ff2e50d4db93148ac5 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 00:30:51 +0100 Subject: [PATCH 04/10] Minor renames and cosmetic changes --- CHERICC_Fat.bsv | 3 - CHERICap.bsv | 158 +++++++++++++++++++++++++----------------------- 2 files changed, 83 insertions(+), 78 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index 52bf929..c0ee28f 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -37,9 +37,6 @@ export CapMem; export CapReg; export CapPipe; -// ----- -// Auxiliary requried imports. TODO find a way around this? - export CapFat; export MW; export OTypeW; diff --git a/CHERICap.bsv b/CHERICap.bsv index 287259c..61b5268 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -72,19 +72,19 @@ typedef union tagged { void SENTRY; void RES0; void RES1; - Bit #(ot) SEALED_WITH_TYPE; -} Kind #(numeric type ot) deriving (Bits, Eq, FShow); + Bit #(otypeW) SEALED_WITH_TYPE; +} Kind #(numeric type otypeW) deriving (Bits, Eq, FShow); // helper type for gathering bounds information on a capability typedef struct { - Bit#(n) base; - Bit#(TAdd#(n, 1)) top; - Bit#(TAdd#(n, 1)) length; - Bit#(n) repBase; - Bit#(TAdd#(n, 1)) repTop; - Bit#(TAdd#(n, 1)) repLength; -} BoundsInfo #(numeric type n) deriving (Bits, Eq, FShow); + Bit #(addrW) base; + Bit #(TAdd #(addrW, 1)) top; + Bit #(TAdd #(addrW, 1)) length; + Bit #(addrW) repBase; + Bit #(TAdd #(addrW, 1)) repTop; + Bit #(TAdd #(addrW, 1)) repLength; +} BoundsInfo #(numeric type addrW) deriving (Bits, Eq, FShow); // helper types and functions //////////////////////////////////////////////////////////////////////////////// @@ -101,11 +101,11 @@ typedef struct { // Helper type for the return value of the 'setBoundsCombined' method typedef struct { - t cap; + capT cap; Bool exact; - Bit #(n) length; - Bit #(n) mask; -} SetBoundsReturn #(type t, numeric type n) deriving (Bits, Eq, FShow); + Bit #(addrW) length; + Bit #(addrW) mask; +} SetBoundsReturn #(type capT, numeric type addrW) deriving (Bits, Eq, FShow); // helper function to test belonging to a range function Bool belongsToRange ( Bit #(n) x, Bit #(n) low, Bit #(n) high @@ -116,8 +116,8 @@ function Bool belongsToRange ( Bit #(n) x, Bit #(n) low, Bit #(n) high endfunction // XXX TODO augment with all architectural bounds/ repbounds ? -function Fmt showCHERICap (t cap) - provisos (CHERICap #(t , ot, flg, n, mem_sz, maskable_bits)); +function Fmt showCHERICap (capT cap) + provisos (CHERICap #(capT , otypeW, flgW, addrW, inMemW, maskableW)); return $format( "Valid: 0x%0x", isValidCap(cap)) + $format(" Perms: 0x%0x", getPerms(cap)) + $format(" Kind: ", fshow(getKind(cap))) + @@ -129,59 +129,60 @@ endfunction // Cast typeclass to convert from one type to another. Helpful for converting // a capability format to another. -typeclass Cast#(type src, type dest); +typeclass Cast #(type src, type dest); function dest cast (src x); endtypeclass -instance Cast#(t, t); +instance Cast #(capT, capT); function cast = id; endinstance // CHERI capability typeclass //////////////////////////////////////////////////////////////////////////////// -typeclass CHERICap #( type t - , numeric type ot - , numeric type flg - , numeric type n - , numeric type mem_sz - , numeric type maskable_bits ) - dependencies (t determines (ot, flg, n, mem_sz, maskable_bits)); +typeclass CHERICap #( type capT // type of the CHERICap capability + , numeric type otypeW // width of the object type + , numeric type flgW // width of the flags field + , numeric type addrW // width of the address + , numeric type inMemW // width of the capability in mem + , numeric type maskableW // width of maskable bits + ) + dependencies (capT determines (otypeW, flgW, addrW, inMemW, maskableW)); // capability validity ////////////////////////////////////////////////////////////////////////////// // Return whether the Capability is valid - function Bool isValidCap (t cap); + function Bool isValidCap (capT cap); // Set the capability as valid. All fields left unchanged - function t setValidCap (t cap, Bool valid); + function capT setValidCap (capT cap, Bool valid); // capability flags ////////////////////////////////////////////////////////////////////////////// // Get the flags field - function Bit#(flg) getFlags (t cap); + function Bit #(flgW) getFlags (capT cap); // Set the flags field - function t setFlags (t cap, Bit#(flg) flags); + function capT setFlags (capT cap, Bit #(flgW) flags); // capability permissions ////////////////////////////////////////////////////////////////////////////// // Get the hardware permissions - function HardPerms getHardPerms (t cap); + function HardPerms getHardPerms (capT cap); // Set the hardware permissions - function t setHardPerms (t cap, HardPerms hardperms); + function capT setHardPerms (capT cap, HardPerms hardperms); // Get the software permissions - function SoftPerms getSoftPerms (t cap); + function SoftPerms getSoftPerms (capT cap); // Set the software permissions - function t setSoftPerms (t cap, SoftPerms softperms); + function capT setSoftPerms (capT cap, SoftPerms softperms); // Get the architectural permissions - function Bit#(31) getPerms (t cap) = - zeroExtend({pack(getSoftPerms(cap)), 3'h0, pack(getHardPerms(cap))}); + function Bit #(31) getPerms (capT cap) = + zeroExtend ({pack (getSoftPerms (cap)), 3'h0, pack (getHardPerms (cap))}); // Set the architectural permissions - function t setPerms (t cap, Bit#(31) perms) = - setSoftPerms ( setHardPerms(cap, unpack(perms[11:0])) - , unpack(truncate(perms[30:15])) ); + function capT setPerms (capT cap, Bit #(31) perms) = + setSoftPerms ( setHardPerms (cap, unpack (perms[11:0])) + , unpack (truncate (perms[30:15])) ); // capability kind ////////////////////////////////////////////////////////////////////////////// @@ -189,11 +190,11 @@ typeclass CHERICap #( type t // unsealed, ... // get the kind of a capability - function Kind#(ot) getKind (t cap); + function Kind #(otypeW) getKind (capT cap); // set the kind of a capability - function t setKind (t cap, Kind#(ot) kind); + function capT setKind (capT cap, Kind #(otypeW) kind); // XXX TODO Check if a type is valid - function Bool validAsType (t dummy, Bit#(n) checkType); + function Bool validAsType (capT dummy, Bit #(addrW) checkType); // capability in-memory architectural representation ////////////////////////////////////////////////////////////////////////////// @@ -202,36 +203,38 @@ typeclass CHERICap #( type t // fromMem (tuple2 (isValidCap (cap), {getMeta (cap), getAddr (cap)})) == cap // Get the in-memory architectural representation of the capability metadata - function Bit #(TSub #(mem_sz, n)) getMeta (t cap); + function Bit #(TSub #(inMemW, addrW)) getMeta (capT cap); // Get the in-memory architectural representation of the capability address - function Bit #(n) getAddr (t cap); + function Bit #(addrW) getAddr (capT cap); // Convert from in-memory architectural bit representation to capability type - function t fromMem (Tuple2#(Bool, Bit#(mem_sz)) mem_cap); + function capT fromMem (Tuple2 #(Bool, Bit #(inMemW)) mem_cap); // Convert from capability type to in-memory architectural bit representation - function Tuple2#(Bool, Bit#(mem_sz)) toMem (t cap); + function Tuple2 #(Bool, Bit #(inMemW)) toMem (capT cap); // capability address/offset manipulation ////////////////////////////////////////////////////////////////////////////// // Set the address of the capability. Result invalid if unrepresentable - function Exact#(t) setAddr (t cap, Bit#(n) addr); + function Exact #(capT) setAddr (capT cap, Bit #(addrW) addr); // Set the address of the capability. Result assumed to be representable - function t setAddrUnsafe (t cap, Bit#(n) addr); + function capT setAddrUnsafe (capT cap, Bit #(addrW) addr); // Add to the address of the capability. Result assumed to be representable - function t addAddrUnsafe (t cap, Bit#(maskable_bits) inc); + function capT addAddrUnsafe (capT cap, Bit #(maskableW) inc); // Mask the least significant bits of capability address with a mask // maskable_width should be small enough to make this // safe with respect to representability - function t maskAddr (t cap, Bit#(maskable_bits) mask); + function capT maskAddr (capT cap, Bit #(maskableW) mask); // Get the offset of the capability - function Bit#(n) getOffset (t cap) = getAddr(cap) - getBase(cap); + function Bit #(addrW) getOffset (capT cap) = getAddr(cap) - getBase(cap); // Modify the offset of the capability. Result invalid if unrepresentable - function Exact#(t) modifyOffset (t cap, Bit#(n) offset, Bool doInc); + function Exact #(capT) modifyOffset ( capT cap + , Bit #(addrW) offset + , Bool doInc); // Set the offset of the capability. Result invalid if unrepresentable - function Exact#(t) setOffset (t cap, Bit#(n) offset) = + function Exact #(capT) setOffset (capT cap, Bit #(addrW) offset) = modifyOffset(cap, offset, False); // Set the offset of the capability. Result invalid if unrepresentable - function Exact#(t) incOffset (t cap, Bit#(n) inc) = + function Exact #(capT) incOffset (capT cap, Bit #(addrW) inc) = modifyOffset(cap, inc, True); // capability architectural bounds queries @@ -242,29 +245,31 @@ typeclass CHERICap #( type t // isInBounds (cap) ==> isInRepBounds (cap) // Get all architectural bound information for a capability - function BoundsInfo#(n) getBoundsInfo (t cap); + function BoundsInfo #(addrW) getBoundsInfo (capT cap); // Get the base - function Bit#(n) getBase (t cap) = getBoundsInfo(cap).base; + function Bit #(addrW) getBase (capT cap) = getBoundsInfo(cap).base; // Get the top - function Bit#(TAdd#(n, 1)) getTop (t cap) = getBoundsInfo(cap).top; + function Bit #(TAdd #(addrW, 1)) getTop (capT cap) = getBoundsInfo(cap).top; // Get the length - function Bit#(TAdd#(n, 1)) getLength (t cap) = getBoundsInfo(cap).length; + function Bit #(TAdd #(addrW, 1)) getLength (capT cap) = + getBoundsInfo(cap).length; // Assertion that the capability's address is between its base and top - function Bool isInBounds (t cap, Bool isTopIncluded) = + function Bool isInBounds (capT cap, Bool isTopIncluded) = belongsToRange ( zeroExtend (getAddr (cap)) , zeroExtend (getBase (cap)) , getTop (cap) , isTopIncluded ); // Get the representable base - function Bit#(n) getRepBase (t cap) = getBoundsInfo(cap).repBase; + function Bit #(addrW) getRepBase (capT cap) = getBoundsInfo(cap).repBase; // Get the representable top - function Bit#(TAdd#(n, 1)) getRepTop (t cap) = getBoundsInfo(cap).repTop; + function Bit #(TAdd #(addrW, 1)) getRepTop (capT cap) = + getBoundsInfo(cap).repTop; // Get the representable length - function Bit#(TAdd#(n, 1)) getRepLength (t cap) = + function Bit #(TAdd #(addrW, 1)) getRepLength (capT cap) = getBoundsInfo(cap).repLength; // Assertion that the capability's address is between its representable // base and top - function Bool isInRepBounds (t cap, Bool isRepTopIncluded) = + function Bool isInRepBounds (capT cap, Bool isRepTopIncluded) = belongsToRange ( zeroExtend (getAddr (cap)) , zeroExtend (getRepBase (cap)) , getRepTop (cap) @@ -273,45 +278,48 @@ typeclass CHERICap #( type t // XXX TODO Check the alignment of the base, giving least significant 2 bits. // This relies on the fact that internal exponents take up 2 bits of the // base. - function Bit#(2) getBaseAlignment (t cap); + function Bit #(2) getBaseAlignment (capT cap); // XXX TODO Get representable alignment mask - function Bit#(n) getRepresentableAlignmentMask ( t dummy - , Bit#(n) length_request) = - setBoundsCombined(nullCapFromDummy(dummy), length_request).mask; + function Bit #(addrW) getRepresentableAlignmentMask ( capT dummy + , Bit #(addrW) lenReq) = + setBoundsCombined (nullCapFromDummy (dummy), lenReq).mask; // XXX TODO Get representable length - function Bit#(n) getRepresentableLength (t dummy, Bit#(n) length_request) = - setBoundsCombined(nullCapFromDummy(dummy), length_request).length; + function Bit #(addrW) getRepresentableLength ( capT dummy + , Bit #(addrW) lenReq) = + setBoundsCombined (nullCapFromDummy (dummy), lenReq).length; // capability derivation (bounds set) ////////////////////////////////////////////////////////////////////////////// // Set the length of the capability. Inexact: result length may be different // to requested - function Exact#(t) setBounds (t cap, Bit#(n) length); - let combinedResult = setBoundsCombined(cap, length); + function Exact #(capT) setBounds (capT cap, Bit #(addrW) length); + let combinedResult = setBoundsCombined (cap, length); return Exact {exact: combinedResult.exact, value: combinedResult.cap}; endfunction // XXX TODO - function SetBoundsReturn#(t, n) setBoundsCombined (t cap, Bit#(n) length); + function SetBoundsReturn #(capT, addrW) + setBoundsCombined (capT cap, Bit #(addrW) length); // common capabilities ////////////////////////////////////////////////////////////////////////////// // the null capability - function t nullCap = nullCapFromDummy(?); + function capT nullCap = nullCapFromDummy(?); // a null capability with a given address set - function t nullWithAddr (Bit#(n) addr); + function capT nullWithAddr (Bit #(addrW) addr); // maximally permissive capability (initial register state) - function t almightyCap; + function capT almightyCap; // XXX TODO Workaround to allow null cap to be derived in default // implementations - function t nullCapFromDummy(t dummy); + function capT nullCapFromDummy (capT dummy); // Assert that the encoding is valid ////////////////////////////////////////////////////////////////////////////// - function Bool isDerivable (t cap); + + function Bool isDerivable (capT cap); endtypeclass From 321409df6a6857d09e72cbeb721ead096b11b4f1 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 00:52:44 +0100 Subject: [PATCH 05/10] Cosmetics for CapMem CHERICap instance --- CHERICC_Fat.bsv | 133 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 40 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index c0ee28f..c627217 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -945,9 +945,6 @@ function MetaInfo getMetaInfo (CapFat cap); , baseCorrection : baseCorrection }; endfunction -// =============================================================================== -// Typeclass instance for interface - typedef Bit#(TAdd#(1, CapW)) CapMem; typedef CapFat CapReg; @@ -957,27 +954,41 @@ typedef struct { TempFields tempFields; } CapPipe deriving (Bits); +// CapMem CHERICap instance +//////////////////////////////////////////////////////////////////////////////// +// Note: commented out methods have a provided default implementation in the +// CHERICap typeclass definition + instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); + + // capability validity + ////////////////////////////////////////////////////////////////////////////// function isValidCap (capMem); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); return cap.isCapability; endfunction function setValidCap (capMem, v); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); cap.isCapability = v; - return pack(cap); + return pack (cap); endfunction + + // capability flags + ////////////////////////////////////////////////////////////////////////////// function getFlags (capMem); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); return cap.flags; endfunction function setFlags (capMem, f); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); cap.flags = f; - return pack(cap); + return pack (cap); endfunction + + // capability permissions + ////////////////////////////////////////////////////////////////////////////// function getHardPerms (capMem); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); return HardPerms { permitSetCID: cap.perms.hard.permit_set_CID , accessSysRegs: cap.perms.hard.access_sys_regs @@ -992,51 +1003,93 @@ instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); , permitExecute: cap.perms.hard.permit_execute , global: cap.perms.hard.non_ephemeral }; endfunction - function setHardPerms = error("setHardPerms not implemented for CapMem"); - function getSoftPerms = error("getSoftPerms not implemented for CapMem"); - function setSoftPerms = error("setSoftPerms not implemented for CapMem"); - function getKind = error("getKind not implemented for CapMem"); - function setKind = error("setKind not implemented for CapMem"); - function getMeta(capMem); - CapabilityInMemory cap = unpack(capMem); + function setHardPerms = error ("setHardPerms not implemented for CapMem"); + function getSoftPerms = error ("getSoftPerms not implemented for CapMem"); + function setSoftPerms = error ("setSoftPerms not implemented for CapMem"); + //function getPerms = error ("getPerms not implemented for CapMem"); + //function setPerms = error ("setPerms not implemented for CapMem"); + + // capability kind + ////////////////////////////////////////////////////////////////////////////// + function getKind = error ("getKind not implemented for CapMem"); + function setKind = error ("setKind not implemented for CapMem"); + function validAsType (dummy, checkType); + UInt #(CapAddrW) checkTypeUnsigned = unpack (checkType); + UInt #(CapAddrW) otypeMaxUnsigned = unpack (zeroExtend (otype_max)); + return checkTypeUnsigned <= otypeMaxUnsigned; + endfunction + + // capability in-memory architectural representation + ////////////////////////////////////////////////////////////////////////////// + function getMeta (capMem); + CapabilityInMemory cap = unpack (capMem); return { pack (cap.perms) , pack (cap.reserved) , pack (cap.flags) , pack (cap.otype) , pack (cap.bounds) }; endfunction - function getAddr(capMem); - CapabilityInMemory cap = unpack(capMem); + function getAddr (capMem); + CapabilityInMemory cap = unpack (capMem); return pack (cap.address); endfunction - function setAddr = error("setAddr not implemented for CapMem"); + function fromMem = error ("fromMem not implemented for CapMem"); + function toMem = error ("toMem not implemented for CapMem"); + + // capability address/offset manipulation + ////////////////////////////////////////////////////////////////////////////// + function setAddr = error ("setAddr not implemented for CapMem"); function setAddrUnsafe (capMem, address); - CapabilityInMemory cap = unpack(capMem); + CapabilityInMemory cap = unpack (capMem); cap.address = address; - return pack(cap); + return pack (cap); endfunction function addAddrUnsafe (capMem, inc) = - setAddrUnsafe(capMem, getAddr(capMem) + signExtend(inc)); - function getOffset = error("getOffset not implemented for CapMem"); - function modifyOffset = error("modifyOffset not implemented for CapMem"); - function getBoundsInfo = error("getBoundsInfo not implemented for CapMem"); - function setBoundsCombined = error("setBoundsCombined not implemented for CapMem"); - function nullWithAddr = setAddrUnsafe(packCap(null_cap)); + setAddrUnsafe (capMem, getAddr (capMem) + signExtend (inc)); + function maskAddr = error ("maskAddr not implemented for CapMem"); + //function getOffset = error ("getOffset not implemented for CapMem"); + function modifyOffset = error ("modifyOffset not implemented for CapMem"); + //function setOffset = error ("setOffset not implemented for CapMem"); + //function incOffset = error ("incOffset not implemented for CapMem"); + + // capability architectural bounds queries + ////////////////////////////////////////////////////////////////////////////// + function getBoundsInfo = error ("getBoundsInfo not implemented for CapMem"); + //function getBase = error ("getBase not implemented for CapMem"); + //function getTop = error ("getTop not implemented for CapMem"); + //function getLength = error ("getLength not implemented for CapMem"); + //function isInBounds = error ("isInBounds not implemented for CapMem"); + //function getRepBase = error ("getRepBase not implemented for CapMem"); + //function getRepTop = error ("getRepTop not implemented for CapMem"); + //function getRepLength = error ("getRepLength not implemented for CapMem"); + //function isInRepBounds = error ("isInRepBounds not implemented for CapMem"); + function getBaseAlignment = + error ("getBaseAlignment not implemented for CapMem"); + //function getRepresentableAlignmentMask = + // error ("getRepresentableAlignmentMask not implemented for CapMem"); + //function getRepresentableLength = + // error ("getRepresentableLength not implemented for CapMem"); + + // capability derivation (bounds set) + ////////////////////////////////////////////////////////////////////////////// + //function setBounds = error ("setBounds not implemented for CapMem"); + function setBoundsCombined = + error ("setBoundsCombined not implemented for CapMem"); + + // common capabilities + ////////////////////////////////////////////////////////////////////////////// + //function nullCap = error ("nullCap not implemented for CapMem"); + function nullWithAddr = setAddrUnsafe (packCap (null_cap)); function almightyCap; CapReg res = almightyCap; - return cast(res); + return cast (res); endfunction - function nullCapFromDummy (dummy) = packCap(null_cap); - function validAsType (dummy, checkType); - UInt#(CapAddrW) checkTypeUnsigned = unpack(checkType); - UInt#(CapAddrW) otypeMaxUnsigned = unpack(zeroExtend(otype_max)); - return checkTypeUnsigned <= otypeMaxUnsigned; - endfunction - function fromMem = error("fromMem not implemented for CapMem"); - function toMem = error("toMem not implemented for CapMem"); - function maskAddr = error("maskAddr not implemented for CapMem"); - function getBaseAlignment = error("getBaseAlignment not implemented for CapMem"); - function isDerivable = error("isDerivable not implemented for CapMem"); + function nullCapFromDummy (dummy) = packCap (null_cap); + + // Assert that the encoding is valid + ////////////////////////////////////////////////////////////////////////////// + function isDerivable = error ("isDerivable not implemented for CapMem"); + endinstance instance FShow #(CapPipe); From e55c65556a96840526b63269e40b4f0de63ef8d3 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 00:56:59 +0100 Subject: [PATCH 06/10] Comment about orphan instance for CapMem --- CHERICC_Fat.bsv | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index c627217..4cb7dea 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -945,7 +945,13 @@ function MetaInfo getMetaInfo (CapFat cap); , baseCorrection : baseCorrection }; endfunction -typedef Bit#(TAdd#(1, CapW)) CapMem; +// XXX TODO +// to avoid an orphan instance here, we should make CapMem a "newtype", +// basically: +// typedef struct { +// Bit #(TAdd #(1, CapW)) cap; +// } CapMem; +typedef Bit #(TAdd #(1, CapW)) CapMem; typedef CapFat CapReg; From 5bb91d9d99f5f3d2611eee1d28b07ba8b13a8978 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 01:30:19 +0100 Subject: [PATCH 07/10] Cosmetics for CapReg CHERICap instance --- CHERICC_Fat.bsv | 129 +++++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 50 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index 4cb7dea..824b4fa 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -1120,22 +1120,31 @@ instance Eq #(CapReg); // function Bool \/= (CapPipe x, CapPipe y); endinstance +// CapReg CHERICap instance +//////////////////////////////////////////////////////////////////////////////// +// Note: commented out methods have a provided default implementation in the +// CHERICap typeclass definition + instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); + // capability validity + ////////////////////////////////////////////////////////////////////////////// function isValidCap (x) = x.isCapability; - function setValidCap (cap, tag); cap.isCapability = tag; return cap; endfunction + // capability flags + ////////////////////////////////////////////////////////////////////////////// function getFlags (cap) = cap.flags; - function setFlags (cap, flags); cap.flags = flags; return cap; endfunction + // capability permissions + ////////////////////////////////////////////////////////////////////////////// function getHardPerms (cap) = HardPerms { permitSetCID: cap.perms.hard.permit_set_CID , accessSysRegs: cap.perms.hard.access_sys_regs @@ -1149,7 +1158,6 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); , permitLoad: cap.perms.hard.permit_load , permitExecute: cap.perms.hard.permit_execute , global: cap.perms.hard.non_ephemeral }; - function setHardPerms (cap, perms); cap.perms.hard = HPerms { permit_set_CID: perms.permitSetCID @@ -1166,14 +1174,16 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); , non_ephemeral: perms.global }; return cap; endfunction - - function getSoftPerms (cap) = zeroExtend(cap.perms.soft); - + function getSoftPerms (cap) = zeroExtend (cap.perms.soft); function setSoftPerms (cap, perms); - cap.perms.soft = truncate(perms); + cap.perms.soft = truncate (perms); return cap; endfunction + //function getPerms = error ("getPerms not implemented for CapReg"); + //function setPerms = error ("setPerms not implemented for CapReg"); + // capability kind + ////////////////////////////////////////////////////////////////////////////// function getKind (cap) = case (cap.otype) otype_unsealed: UNSEALED; otype_sentry: SENTRY; @@ -1181,68 +1191,87 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); otype_res1: RES1; default: SEALED_WITH_TYPE (cap.otype); endcase; - function setKind (cap, kind) = case (kind) matches - tagged UNSEALED: unseal(cap, ?); - tagged SENTRY: seal(cap, ?, VnD {v: True, d:otype_sentry}); - tagged RES0: seal(cap, ?, VnD {v: True, d:otype_res0}); - tagged RES1: seal(cap, ?, VnD {v: True, d:otype_res1}); - tagged SEALED_WITH_TYPE .ot: seal(cap, ?, VnD {v: True, d:ot}); + tagged UNSEALED: unseal (cap, ?); + tagged SENTRY: seal (cap, ?, VnD {v: True, d:otype_sentry}); + tagged RES0: seal (cap, ?, VnD {v: True, d:otype_res0}); + tagged RES1: seal (cap, ?, VnD {v: True, d:otype_res1}); + tagged SEALED_WITH_TYPE .ot: seal (cap, ?, VnD {v: True, d:ot}); endcase; + function validAsType (dummy, checkType); + CapMem nullC = nullCap; + return validAsType (nullC, checkType); + endfunction - function getMeta(capReg); + // capability in-memory architectural representation + ////////////////////////////////////////////////////////////////////////////// + function getMeta (capReg); CapMem cap = unpack (pack (toMem (capReg))); return getMeta (cap); endfunction - function getAddr (capReg); CapMem cap = unpack (pack (toMem (capReg))); return getAddr (cap); endfunction + function fromMem (x) = cast (pack (x)); + function toMem (x) = unpack (cast (x)); - function setAddr = error("setAddr not implemented for CapReg"); - - function setAddrUnsafe (cap, address) = setCapPointer(cap, address); - + // capability address/offset manipulation + ////////////////////////////////////////////////////////////////////////////// + function setAddr = error ("setAddr not implemented for CapReg"); + function setAddrUnsafe (cap, address) = setCapPointer (cap, address); function addAddrUnsafe (cap, inc) = - setAddrUnsafe(cap, getAddr(cap) + signExtend(inc)); + setAddrUnsafe (cap, getAddr (cap) + signExtend (inc)); + function maskAddr (cap, mask) = setCapPointer (cap, cap.address & {~0, mask}); + function getOffset = error ("getOffset not implemented for CapReg"); + function modifyOffset = error ("modifyOffset not implemented for CapReg"); + //function setOffset = error ("setOffset not implemented for CapReg"); + //function incOffset = error ("incOffset not implemented for CapReg"); - function getOffset = error("getOffset not implemented for CapReg"); - function modifyOffset = error("modifyOffset not implemented for CapReg"); - function getBoundsInfo = error("getBoundsInfo not implemented for CapReg"); + // capability architectural bounds queries + ////////////////////////////////////////////////////////////////////////////// + function getBoundsInfo = error ("getBoundsInfo not implemented for CapReg"); + //function getBase = error ("getBase not implemented for CapReg"); + //function getTop = error ("getTop not implemented for CapReg"); + //function getLength = error ("getLength not implemented for CapReg"); + //function isInBounds = error ("isInBounds not implemented for CapReg"); + //function getRepBase = error ("getRepBase not implemented for CapReg"); + //function getRepTop = error ("getRepTop not implemented for CapReg"); + //function getRepLength = error ("getRepLength not implemented for CapReg"); + //function isInRepBounds = error ("isInRepBounds not implemented for CapReg"); + function getBaseAlignment (cap) = + // If cap exp is non-zero, we have internal exponent, so the least + // significant two bits of the base are implicitly zero. Otherwise, we + // have a zero exponent, so the least significant two bits of the base are + // the least significant bits of the encoded base + (cap.bounds.exp == 0) ? cap.bounds.baseBits[1:0] : 2'b0; + //function getRepresentableAlignmentMask = + // error ("getRepresentableAlignmentMask not implemented for CapReg"); + //function getRepresentableLength = + // error ("getRepresentableLength not implemented for CapReg"); - function setBoundsCombined(cap, length) = setBoundsFat(cap, length); - - function nullWithAddr (addr) = setAddrUnsafe(null_cap, addr); + // capability derivation (bounds set) + ////////////////////////////////////////////////////////////////////////////// + //function setBounds = error ("setBounds not implemented for CapReg"); + function setBoundsCombined (cap, length) = setBoundsFat (cap, length); + // common capabilities + ////////////////////////////////////////////////////////////////////////////// + //function nullCap = error ("nullCap not implemented for CapReg"); + function nullWithAddr (addr) = setAddrUnsafe (null_cap, addr); function almightyCap = defaultCapFat; - function nullCapFromDummy (x) = null_cap; - function fromMem (x) = cast(pack(x)); - - function toMem (x) = unpack(cast(x)); - - function maskAddr (cap, mask) = setCapPointer(cap, cap.address & {~0,mask}); - - function validAsType (dummy, checkType); - CapMem nullC = nullCap; - return validAsType(nullC, checkType); - endfunction - - function getBaseAlignment (cap) = - // If cap exp is non-zero, we have internal exponent, so the least significant - // two bits of the base are implicitly zero. - // Otherwise, we have a zero exponent, so the least significant two bits - // of the base are the least significant bits of the encoded base - (cap.bounds.exp == 0) ? cap.bounds.baseBits[1:0] : 2'b0; - + // Assert that the encoding is valid + ////////////////////////////////////////////////////////////////////////////// function isDerivable (cap) = - cap.bounds.exp <= resetExp && - !(cap.bounds.exp == resetExp && ((truncateLSB(cap.bounds.topBits) != 1'b0) || - (truncateLSB(cap.bounds.baseBits) != 2'b0))) && - !(cap.bounds.exp == resetExp-1 && (truncateLSB(cap.bounds.baseBits) != 1'b0)) && - (cap.reserved == 0); + (cap.bounds.exp <= resetExp) + && !( (cap.bounds.exp == resetExp) + && ( (truncateLSB (cap.bounds.topBits) != 1'b0) + || (truncateLSB (cap.bounds.baseBits) != 2'b0) )) + && !( (cap.bounds.exp == resetExp-1) + && (truncateLSB (cap.bounds.baseBits) != 1'b0)) + && (cap.reserved == 0); endinstance From 6e20d177dc67d9abfb46bb6b9d63389fe29ce79d Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 12:05:35 +0100 Subject: [PATCH 08/10] Fixup base/top/repBase/repTop implementation --- CHERICC_Fat.bsv | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index 824b4fa..a9a4ed9 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -256,7 +256,8 @@ typedef MetaInfo TempFields; // Interface functions //------------------------------------------------------------------------------ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) - provisos ( NumAlias #(upperW, TSub #(TAdd #(CapAddrW, 1), MW)) + provisos ( NumAlias #(fullW, TAdd #(CapAddrW, 1)) + , NumAlias #(upperW, TSub #(fullW, MW)) , NumAlias #(lowerW, MW) ); // shared useful bindings and precomputed values @@ -272,10 +273,10 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) // prepare typed "lower" MW zeroes for simpler concatenation Bit #(lowerW) lowerZeroes = 0; - // prepare "upper" version for baseBits, topBits and repBoundBits - Bit #(upperW) baseBitsUpper = zeroExtend (baseBits) << exp; - Bit #(upperW) topBitsUpper = zeroExtend (topBits) << exp; - Bit #(upperW) repBoundBitsUpper = zeroExtend (repBoundBits) << exp; + // prepare "full" version for baseBits, topBits and repBoundBits + Bit #(fullW) baseBitsFull = zeroExtend (baseBits) << exp; + Bit #(fullW) topBitsFull = zeroExtend (topBits) << exp; + Bit #(fullW) repBoundBitsFull = zeroExtend (repBoundBits) << exp; // shared +1 and -1/~0 shifted by exponent Bit #(upperW) allOnesExpShifted = ~0 << exp; @@ -294,18 +295,18 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) ////////////////////////////////////////////////////////////////////////////// // Use the appropriate upper bits of the address based on whether the base is - // in the "hi" or the "lo" region, or in the base bits in place and append the - // implied zeros in the lower bits + // in the "hi" or the "lo" region, append implied zeroes in the lower bits, + // and or in the base bits CapAddr base = - {truncate (addrUpper (tf.baseHi) | baseBitsUpper), lowerZeroes}; + truncate ({addrUpper (tf.baseHi), lowerZeroes} | baseBitsFull); // compute top ////////////////////////////////////////////////////////////////////////////// // Use the appropriate upper bits of the address based on whether the top is - // in the "hi" or the "lo" region, or in the top bits in place and append the - // implied zeros in the lower bits - CapAddrPlus1 top = {addrUpper (tf.topHi) | topBitsUpper, lowerZeroes}; + // in the "hi" or the "lo" region, append implied zeroes in the lower bits, + // and or in the top bits + CapAddrPlus1 top = {addrUpper (tf.topHi), lowerZeroes} | topBitsFull; // If the base and top are more than an address space away from eachother, // invert the 64th/32nd bit of Top. This corrects for errors that happen when // the representable space wraps the address space. @@ -339,17 +340,17 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) // compute repBase ////////////////////////////////////////////////////////////////////////////// - // Use the "lo" region upper bits of the address, or in the representable - // bound bits in place and append the implied zeros in the lower bits + // Use the "lo" region upper bits of the address, append implied zeroes in the + // lower bits, and or in the representable bound bits CapAddr repBase = - {truncate (addrUpperLo | repBoundBitsUpper), lowerZeroes}; + truncate ({addrUpperLo, lowerZeroes} | repBoundBitsFull); // compute repTop ////////////////////////////////////////////////////////////////////////////// - // Use the "hi" region upper bits of the address, or in the representable - // bound bits in place and append the implied zeros in the lower bits - CapAddrPlus1 repTop = {addrUpperHi | repBoundBitsUpper, lowerZeroes}; + // Use the "hi" region upper bits of the address, append implied zeroes in the + // lower bits, and or in the representable bound bits + CapAddrPlus1 repTop = {addrUpperHi, lowerZeroes} | repBoundBitsFull; // compute repLength ////////////////////////////////////////////////////////////////////////////// From aa0a8fe224f995a5e65614d38b241ecf0b95c4e0 Mon Sep 17 00:00:00 2001 From: gameboo Date: Tue, 28 Sep 2021 12:42:17 +0100 Subject: [PATCH 09/10] Fold in some comments from jdw57 and pdr32 --- CHERICC_Fat.bsv | 16 ++++++---------- CHERICap.bsv | 41 +++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index a9a4ed9..ace1807 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -1072,16 +1072,14 @@ instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); //function isInRepBounds = error ("isInRepBounds not implemented for CapMem"); function getBaseAlignment = error ("getBaseAlignment not implemented for CapMem"); - //function getRepresentableAlignmentMask = - // error ("getRepresentableAlignmentMask not implemented for CapMem"); - //function getRepresentableLength = - // error ("getRepresentableLength not implemented for CapMem"); // capability derivation (bounds set) ////////////////////////////////////////////////////////////////////////////// - //function setBounds = error ("setBounds not implemented for CapMem"); function setBoundsCombined = error ("setBoundsCombined not implemented for CapMem"); + //function setBounds = error ("setBounds not implemented for CapMem"); + //function roundLength = error ("roundLength not implemented for CapMem"); + //function alignmentMask = error ("alignmentMask not implemented for CapMem"); // common capabilities ////////////////////////////////////////////////////////////////////////////// @@ -1246,15 +1244,13 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); // have a zero exponent, so the least significant two bits of the base are // the least significant bits of the encoded base (cap.bounds.exp == 0) ? cap.bounds.baseBits[1:0] : 2'b0; - //function getRepresentableAlignmentMask = - // error ("getRepresentableAlignmentMask not implemented for CapReg"); - //function getRepresentableLength = - // error ("getRepresentableLength not implemented for CapReg"); // capability derivation (bounds set) ////////////////////////////////////////////////////////////////////////////// - //function setBounds = error ("setBounds not implemented for CapReg"); function setBoundsCombined (cap, length) = setBoundsFat (cap, length); + //function setBounds = error ("setBounds not implemented for CapReg"); + //function roundLength = error ("roundLength not implemented for CapReg"); + //function alignmentMask = error ("alignmentMask not implemented for CapReg"); // common capabilities ////////////////////////////////////////////////////////////////////////////// diff --git a/CHERICap.bsv b/CHERICap.bsv index 61b5268..684b34f 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -139,6 +139,11 @@ endinstance // CHERI capability typeclass //////////////////////////////////////////////////////////////////////////////// +// Note: Some class methods receive a "dummy" capability as a type proxy +// argument. This is useful for methods to know which capability format is +// being operated on without requiring a specific capability value. +// (A more elegant way to achieve this would be to use something along the +// lines of haskell's "@type" type application mechanism) typeclass CHERICap #( type capT // type of the CHERICap capability , numeric type otypeW // width of the object type @@ -193,7 +198,7 @@ typeclass CHERICap #( type capT // type of the CHERICap capability function Kind #(otypeW) getKind (capT cap); // set the kind of a capability function capT setKind (capT cap, Kind #(otypeW) kind); - // XXX TODO Check if a type is valid + // Check if a type is valid (requires a dummy proxy) function Bool validAsType (capT dummy, Bit #(addrW) checkType); // capability in-memory architectural representation @@ -274,46 +279,38 @@ typeclass CHERICap #( type capT // type of the CHERICap capability , zeroExtend (getRepBase (cap)) , getRepTop (cap) , isRepTopIncluded ); - - // XXX TODO Check the alignment of the base, giving least significant 2 bits. - // This relies on the fact that internal exponents take up 2 bits of the - // base. - function Bit #(2) getBaseAlignment (capT cap); - - // XXX TODO Get representable alignment mask - function Bit #(addrW) getRepresentableAlignmentMask ( capT dummy - , Bit #(addrW) lenReq) = - setBoundsCombined (nullCapFromDummy (dummy), lenReq).mask; - - // XXX TODO Get representable length - function Bit #(addrW) getRepresentableLength ( capT dummy - , Bit #(addrW) lenReq) = - setBoundsCombined (nullCapFromDummy (dummy), lenReq).length; + // Check the alignment of the base, giving least significant 2 bits. + function Bit #(2) getBaseAlignment (capT cap) = getBoundsInfo (cap).base[1:0]; // capability derivation (bounds set) ////////////////////////////////////////////////////////////////////////////// + // Set the length of the capability + function SetBoundsReturn #(capT, addrW) + setBoundsCombined (capT cap, Bit #(addrW) length); // Set the length of the capability. Inexact: result length may be different // to requested function Exact #(capT) setBounds (capT cap, Bit #(addrW) length); let combinedResult = setBoundsCombined (cap, length); return Exact {exact: combinedResult.exact, value: combinedResult.cap}; endfunction - // XXX TODO - function SetBoundsReturn #(capT, addrW) - setBoundsCombined (capT cap, Bit #(addrW) length); + // Round a requested length (requires a dummy proxy) + function Bit #(addrW) roundLength (capT dummy, Bit #(addrW) reqLength) = + setBoundsCombined (nullCapFromDummy (dummy), reqLength).length; + // Get alignment mask for a requested length (requires a dummy proxy) + function Bit #(addrW) alignmentMask (capT dummy, Bit #(addrW) reqLength) = + setBoundsCombined (nullCapFromDummy (dummy), reqLength).mask; // common capabilities ////////////////////////////////////////////////////////////////////////////// // the null capability - function capT nullCap = nullCapFromDummy(?); + function capT nullCap = nullCapFromDummy (?); // a null capability with a given address set function capT nullWithAddr (Bit #(addrW) addr); // maximally permissive capability (initial register state) function capT almightyCap; - // XXX TODO Workaround to allow null cap to be derived in default - // implementations + // the null capability (requires a dummy proxy) function capT nullCapFromDummy (capT dummy); // Assert that the encoding is valid From bc727f9731763bef5450b9798004a48f53dd1ce9 Mon Sep 17 00:00:00 2001 From: gameboo Date: Thu, 7 Oct 2021 15:17:13 +0100 Subject: [PATCH 10/10] Fold in discussions with Jon and Matt regarding split representable regions --- CHERICC_Fat.bsv | 26 ++++++++++++++++++++++---- CHERICap.bsv | 16 +++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index ace1807..14ba193 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -278,6 +278,11 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) Bit #(fullW) topBitsFull = zeroExtend (topBits) << exp; Bit #(fullW) repBoundBitsFull = zeroExtend (repBoundBits) << exp; + // other helper values + CapAddr capAddr0 = 0; + CapAddrPlus1 addrSpaceTop = {1'b1, capAddr0}; + Bool alwaysRep = exp >= resetExp - 2; + // shared +1 and -1/~0 shifted by exponent Bit #(upperW) allOnesExpShifted = ~0 << exp; let mask = allOnesExpShifted; @@ -341,22 +346,34 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) ////////////////////////////////////////////////////////////////////////////// // Use the "lo" region upper bits of the address, append implied zeroes in the - // lower bits, and or in the representable bound bits + // lower bits, and or in the representable bound bit. + // Saturate to zero when in the "always representable" case, + // i.e. exp >= resetExp - 2. CapAddr repBase = - truncate ({addrUpperLo, lowerZeroes} | repBoundBitsFull); + alwaysRep ? capAddr0 + : truncate ({addrUpperLo, lowerZeroes} | repBoundBitsFull); // compute repTop ////////////////////////////////////////////////////////////////////////////// // Use the "hi" region upper bits of the address, append implied zeroes in the // lower bits, and or in the representable bound bits - CapAddrPlus1 repTop = {addrUpperHi, lowerZeroes} | repBoundBitsFull; + // Saturate to 1 and all zeroes when in the "always representable" case, + // i.e. exp >= resetExp - 2. + CapAddrPlus1 repTop = + alwaysRep ? addrSpaceTop + : {addrUpperHi, lowerZeroes} | repBoundBitsFull; // compute repLength ////////////////////////////////////////////////////////////////////////////// CapAddrPlus1 repLength = {oneExpShifted, lowerZeroes}; + // compute split of representable space + ////////////////////////////////////////////////////////////////////////////// + + Bool repSplit = alwaysRep ? False : ! unpack (reduceOr (addrUpperHi)); + // return populated BoundsInfo structure ////////////////////////////////////////////////////////////////////////////// @@ -365,7 +382,8 @@ function BoundsInfo#(CapAddrW) getBoundsInfoFat (CapFat cap, TempFields tf) , length: length , repBase: repBase , repTop: repTop - , repLength: repLength }; + , repLength: repLength + , repSplit: repSplit }; endfunction function CapAddr getBotFat(CapFat cap, TempFields tf); diff --git a/CHERICap.bsv b/CHERICap.bsv index 684b34f..791060a 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -84,6 +84,7 @@ typedef struct { Bit #(addrW) repBase; Bit #(TAdd #(addrW, 1)) repTop; Bit #(TAdd #(addrW, 1)) repLength; + Bool repSplit; } BoundsInfo #(numeric type addrW) deriving (Bits, Eq, FShow); // helper types and functions @@ -272,13 +273,18 @@ typeclass CHERICap #( type capT // type of the CHERICap capability // Get the representable length function Bit #(TAdd #(addrW, 1)) getRepLength (capT cap) = getBoundsInfo(cap).repLength; + // Check if the capapbility's representable region is split (i.e. wrapping the + // address space) + function Bool isRepSplit (capT cap) = getBoundsInfo(cap).repSplit; // Assertion that the capability's address is between its representable // base and top - function Bool isInRepBounds (capT cap, Bool isRepTopIncluded) = - belongsToRange ( zeroExtend (getAddr (cap)) - , zeroExtend (getRepBase (cap)) - , getRepTop (cap) - , isRepTopIncluded ); + function Bool isInRepBounds (capT cap); + let addr = getAddr (cap); + let bInfo = getBoundsInfo (cap); + let okLo = addr >= bInfo.repBase; + let okHi = zeroExtend (addr) < bInfo.repTop; + return (okLo && okHi) || (bInfo.repSplit && (okLo != okHi)); + endfunction // Check the alignment of the base, giving least significant 2 bits. function Bit #(2) getBaseAlignment (capT cap) = getBoundsInfo (cap).base[1:0];