diff --git a/CHERICC.bsv b/CHERICC.bsv new file mode 100644 index 0000000..af818f6 --- /dev/null +++ b/CHERICC.bsv @@ -0,0 +1,452 @@ +/*- + * Copyright (c) 2018-2019 Alexandre Joannou + * All rights reserved. + * + * 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. + * + * @BERI_LICENSE_HEADER_START@ + * + * Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. BERI licenses this + * file to you under the BERI Hardware-Software License, Version 1.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.beri-open-systems.org/legal/license-1-0.txt + * + * Unless required by applicable law or agreed to in writing, Work distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * @BERI_LICENSE_HEADER_END@ + */ + +package CHERICC; + +import CHERICap :: *; + +export CHERICCCap; +export CHERICCBounds; + +`define div2(x) TDiv#(x, 2) +`define sub2(x) TSub#(x, 2) +`define i(x) valueOf(x) + +// CHERICCBounds Bounds type +//////////////////////////////////////////////////////////////////////////////// +// CHERICC compressed bounds type +typedef union tagged { + struct { + Bit#(1) lenMSB; + Bit#(`sub2(base_)) top; + Bit#(base_) base; + } Exp0; + struct { + Bit#(TSub#(`sub2(base_), `div2(e_))) top; + Bit#(TSub#(base_, `div2(e_))) base; + Bit#(e_) e; + } EmbeddedExp; + struct { + Bit#(TSub#(`sub2(base_), TAdd#(`div2(t_), `div2(e_)))) top; + Bit#(TSub#(base_, TAdd#(`div2(t_), `div2(e_)))) base; + Bit#(t_) otype; + Bit#(e_) e; + } Sealed; +} CHERICCBounds#(numeric type base_, numeric type e_, numeric type t_); + +instance Bits#(CHERICCBounds#(b_, e_, t_), TMul#(b_, 2)) provisos( + // in pack + Add#(TDiv#(e_, 2), a__, e_), // truncates on e + Add#(TDiv#(t_, 2), b__, t_), // truncates on t + Add#(2, c__, b_), // 2 bits stolen from top + // in unpack + Add#(d__, TDiv#(e_, 2), TMul#(b_, 2)), // truncates raw into e + Add#(e__, TDiv#(t_, 2), TMul#(b_, 2)), // truncates raw into t + Add#(2, f__, TSub#( + TSub#( + TAdd#(b_, + TAdd#( + TDiv#(t_, 2), + TDiv#(e_, 2))), + TDiv#(e_, 2)), + TDiv#(t_, 2))) + ); + function pack(ccbounds) = + case (ccbounds) matches + tagged Exp0 .x: return {{{1'b0, x.lenMSB}, x.top}, x.base}; + tagged EmbeddedExp .x: begin + Bit#(`div2(e_)) eHi = truncateLSB(x.e); + Bit#(`div2(e_)) eLo = truncate(x.e); + return {{2'b10, x.top, eHi}, {x.base, eLo}}; + end + tagged Sealed .x: begin + Bit#(`div2(t_)) tHi = truncateLSB(x.otype); + Bit#(`div2(t_)) tLo = truncate(x.otype); + Bit#(`div2(e_)) eHi = truncateLSB(x.e); + Bit#(`div2(e_)) eLo = truncate(x.e); + return {{2'b11, x.top, tHi, eHi}, {x.base, tLo, eLo}}; + /* + Bit#(TMul#(b_, 2)) acc = 0; + acc = acc | zeroExtend(2'b11); + acc = (acc << `i(b_)-2-`i(t_)/2-`i(e_)/2) | zeroExtend(x.top); + acc = (acc << `i(t_)/2) | zeroExtend(tHi); + acc = (acc << `i(e_)/2) | zeroExtend(eHi); + acc = (acc << `i(b_)-`i(t_)/2-`i(e_)/2) | zeroExtend(x.base); + acc = (acc << `i(t_)/2) | zeroExtend(tLo); + acc = (acc << `i(e_)/2) | zeroExtend(eLo); + return acc; + */ + end + endcase; + function unpack(raw); + if (raw[2*`i(b_)-1] == 0) return Exp0 { + lenMSB: raw[2*`i(b_)-2], + top: raw[2*`i(b_)-3:`i(b_)], + base: raw[`i(b_)-1:0] + }; + else if (raw[2*`i(b_)-2] == 0) begin + Bit#(`div2(e_)) eHi = truncate(raw >> `i(b_)); + Bit#(`div2(e_)) eLo = truncate(raw); + // XXX Bit#(e_) new_e = {eHi, eLo}; XXX simpler provisos with equiv line below + Bit#(e_) new_e = zeroExtend(eLo) | zeroExtend(eHi) << `i(e_)/2; + return EmbeddedExp { + top: raw[2*`i(b_)-3:`i(b_)+`i(e_)/2], + base: raw[`i(b_)-1:`i(e_)/2], + e: new_e + }; + end else begin + Bit#(`div2(t_)) tHi = truncate(raw >> (`i(b_)+(`i(e_)/2))); + Bit#(`div2(t_)) tLo = truncate(raw >> (`i(e_)/2)); + // XXX Bit#(t_) new_t = {tHi, tLo}; XXX simpler provisos with equiv line below + Bit#(t_) new_t = zeroExtend(tLo) | zeroExtend(tHi) << `i(t_)/2; + Bit#(`div2(e_)) eHi = truncate(raw >> `i(b_)); + Bit#(`div2(e_)) eLo = truncate(raw); + // XXX Bit#(e_) new_e = {eHi, eLo}; XXX simpler provisos with equiv line below + Bit#(e_) new_e = zeroExtend(eLo) | zeroExtend(eHi) << `i(e_)/2; + return Sealed { + top: raw[2*`i(b_)-3:`i(b_)+`i(e_)/2+`i(t_)/2], + base: raw[`i(b_)-1:`i(e_)/2+`i(t_)/2], + otype: new_t, + e: new_e + }; + end + endfunction +endinstance + +// CHERICC capability type +//////////////////////////////////////////////////////////////////////////////// + +`define CCSoftPerms Bit#(4) +`define AllPermsSz TAdd#(SizeOf#(`CCSoftPerms), SizeOf#(HardPerms)) + +typedef struct { + Bool isCap; + `CCSoftPerms softperms; + HardPerms hardperms; + Bit#(TSub#(addr_, TAdd#(bounds_, `AllPermsSz))) res; // 15 permission bits and bounds_ bits to deduct + CHERICCBounds#(`div2(bounds_), e_, t_) bounds; + Bit#(addr_) addr; +} CHERICCCap#(numeric type addr_, numeric type bounds_, numeric type e_, numeric type t_); + +instance Bits#(CHERICCCap#(addr_, bounds_, e_, t_), + TAdd#(1, TAdd#(addr_, TAdd#(bounds_, TAdd#(res_, `AllPermsSz))))) provisos( + Bits#(CHERICCBounds#(TDiv#(bounds_, 2), e_, t_), bounds_), + Add#(TAdd#(bounds_, `AllPermsSz), res_, addr_) + ); + function pack(cap); + Bit#(1) isCap = pack(cap.isCap); + Bit#(SizeOf#(`CCSoftPerms)) softperms = cap.softperms; + Bit#(SizeOf#(HardPerms)) hardperms = pack(cap.hardperms); + Bit#(res_) res = cap.res; + Bit#(bounds_) bounds = pack(cap.bounds); + Bit#(addr_) addr = cap.addr; + return {isCap, softperms, hardperms, res, bounds, addr}; + endfunction + //function pack(cap) = {cap.softperms, pack(cap.perms), cap.res, pack(cap.bounds), cap.addr}; + function unpack(raw) = CHERICCCap { + isCap: unpack(msb(raw)), + softperms: raw[2*`i(addr_)-1:2*`i(addr_)-`i(SizeOf#(`CCSoftPerms))], + hardperms: unpack(raw[2*`i(addr_)-5:2*`i(addr_)-`i(`AllPermsSz)]), + res: raw[2*`i(addr_)-`i(`AllPermsSz)-1:`i(addr_)+`i(bounds_)], + bounds: unpack(raw[`i(addr_)+`i(bounds_)-1:`i(addr_)]), + addr: raw[`i(addr_)-1:0] + }; +endinstance + +`undef AllPermsSz +`undef CCSoftPerms + +// CHERICCCap inner helpers +//////////////////////////////////////////////////////////////////////////////// + +CHERICCCap#(addr_, bounds_, e_, t_) almightyCC = CHERICCCap { + isCap: True, + softperms: ~0, + hardperms: unpack(~0), + res: 0, + bounds: EmbeddedExp { + top: 0, // implied top bits of 01 + base: 0, + // position the 1 of top in the addr_'th bit + e: fromInteger(`i(addr_)-((`i(bounds_)/2)-2)) + }, + addr: 0 +}; + +CHERICCCap#(addr_, bounds_, e_, t_) nullCC = CHERICCCap { + isCap: False, + softperms: 0, + hardperms: unpack(0), + res: 0, + bounds: EmbeddedExp { + top: 0, // implied top bits of 01 + base: 0, + e: fromInteger(`i(addr_)-((`i(bounds_)/2)-2)) // position the 1 of top in the addr_'th bit + }, + addr: 0 +}; + +function Bit#(e_) getExpCC(CHERICCCap#(addr_, bounds_, e_, t_) cap); + case (cap.bounds) matches + tagged Exp0 .b: return 0; + tagged EmbeddedExp .b: return b.e; + tagged Sealed .b: return b.e; + endcase +endfunction + +function Bit#(3) getRepBoundCC(CHERICCCap#(addr_, bounds_, e_, t_) cap) + provisos (Add#(3, a__, `div2(bounds_))) = + truncateLSB(cap.bounds.Exp0.base) - 3'b001; // always 1/8th of representable space below object + +function Int#(2) getRegionCorrectionCC(Bit#(3) a, Bit#(3) b, Bit#(3) rep) = + ((b < rep) == (a < rep)) ? 0 : (((b < rep) && (a >= rep)) ? 1 : -1); + +function Bit#(`div2(bounds_)) + getTopFieldCC(CHERICCCap#(addr_, bounds_, e_, t_) cap); + Bit#(2) c_carry = 2'b00; + Bit#(2) c_len = 2'b01; + Bit#(`sub2(`div2(bounds_))) partialTop = 0; + case (cap.bounds) matches + tagged Exp0 .b: begin + if (zeroExtend(b.top) < b.base) c_carry = 2'b01; + c_len = {1'b0, b.lenMSB}; + partialTop = b.top; + end + tagged EmbeddedExp .b: begin + if (zeroExtend(b.top) < b.base) c_carry = 2'b01; + partialTop = {b.top, 0}; + end + tagged Sealed .b: begin + if (zeroExtend(b.top) < b.base) c_carry = 2'b01; + partialTop = {b.top, 0}; + end + endcase + return {truncateLSB(cap.bounds.Exp0.base) + c_carry + c_len, partialTop}; +endfunction + +function Bit#(`div2(bounds_)) + getBaseFieldCC(CHERICCCap#(addr_, bounds_, e_, t_) cap) = + case (cap.bounds) matches + tagged Exp0 .b: b.base; + tagged EmbeddedExp .b: {b.base, 0}; + tagged Sealed .b: {b.base, 0}; + endcase; + +// CHERICCCap CHERICap instance +//////////////////////////////////////////////////////////////////////////////// +instance CHERICap#(CHERICCCap#(addr_, bounds_, e_, t_), t_, addr_) provisos ( + Add#(3, a__, `div2(bounds_)), // 3 bits of bounds for 1/8th of rep space + Add#(3, b__, addr_), // same for addr + Add#(c__, TAdd#(2, `div2(bounds_)), addr_), // for base correction + Add#(d__, TAdd#(2, `div2(bounds_)), TAdd#(addr_, 1)), // for top 2 bits of Int#(2) correction + Add#(e__, `div2(bounds_), addr_), // slice addr into smaller bounds field + Add#(f__, `div2(bounds_), TAdd#(addr_, 1)), // same for addr+1 + Add#(g__, e_, TLog#(TAdd#(1, addr_))) // can fit result of countZerosMSB in e_ + ); + ////////////////////////////////////////////////////////////////////////////// + function isValidCap(cap) = cap.isCap; + ////////////////////////////////////////////////////////////////////////////// + function setValidCap(cap, v); + cap.isCap = v; + return cap; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getHardPerms(cap) = cap.hardperms; + ////////////////////////////////////////////////////////////////////////////// + function setHardPerms(cap, hardperms); + cap.hardperms = hardperms; + return cap; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getSoftPerms(cap) = zeroExtend(cap.softperms); + ////////////////////////////////////////////////////////////////////////////// + function setSoftPerms(cap, softperms); + cap.softperms = truncate(softperms); + return cap; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getKind(cap) = case (cap.bounds) matches + tagged Sealed ._: return SEALED_WITH_TYPE; + default: return UNSEALED; + endcase; + ////////////////////////////////////////////////////////////////////////////// + function getType(cap) = case (cap.bounds) matches + tagged Sealed .b: return zeroExtend(b.otype); + default: return -1; + endcase; + ////////////////////////////////////////////////////////////////////////////// + function setType(cap, otype); + let new_cap = cap; + let isExact = True; + case (cap.bounds) matches + tagged Sealed .b: if (otype == -1) begin + //Bit#(addr_) addrBits = cap.address >> b.e; + //let baseMid = addrBits[`sub1(TAdd#(`div2(t_), `div2(e))):`div2(e_)]; + //let baseLo = addrBits[`sub1(`div2(e_)):0]; + //let topMid = baseMid; + //let topLo = baseLo; + let baseHi = b.base; + let topHi = b.top; + if (b.e == 0) new_cap.bounds = Exp0 { + lenMSB: 1, + top: {topHi, 0}, + base: {baseHi, 0} + }; + else new_cap.bounds = EmbeddedExp { + top: {topHi, 0}, + base: {baseHi, 0}, + e: b.e + }; + end + default: if (otype != -1) begin + Bit#(e_) new_e = case (cap.bounds) matches + tagged EmbeddedExp .b: b.e; + default: 0; + endcase; + new_cap.bounds = Sealed { + top: truncateLSB(cap.bounds.Exp0.top), + base: truncateLSB(cap.bounds.Exp0.base), + otype: otype, + e: new_e + }; + Bit#(`div2(t_)) zero = 0; + isExact = cap.bounds.Exp0.top[`i(t_)/2-1:0] == zero && + cap.bounds.Exp0.base[`i(t_)/2-1:0] == zero; + end + endcase + return Exact{exact: isExact, value: new_cap}; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getAddr(cap) = cap.addr; + ////////////////////////////////////////////////////////////////////////////// + function setAddr(cap) = error("setAddr unimplemented"); + ////////////////////////////////////////////////////////////////////////////// + function getOffset(cap) = zeroExtend(getAddr(cap)) - getBase(cap); + ////////////////////////////////////////////////////////////////////////////// + function setOffset(cap, offset); + Bit#(`div2(bounds_)) e0m = ~(~0 << ((`i(t_)/2)+(`i(e_)/2))); + Bit#(TSub#(`div2(bounds_), `div2(e_))) eem = ~(~0 << (`i(t_)/2)); + // extract specific useful values + Bit#(e_) e = getExpCC(cap); + Bit#(e_) almighty_e = fromInteger(`i(addr_)-((`i(bounds_)/2)-2)); // position the 1 of top in the addr_'th bit + Bit#(addr_) i = offset - getOffset(cap); + Bit#(`div2(bounds_)) imid = truncate(i >> e); + Bit#(`div2(bounds_)) amid = truncate(cap.addr >> e); + Bit#(`div2(bounds_)) r = {getRepBoundCC(cap), 0}; + // perform inRange and inLimit tests + Bit#(addr_) mask = ~0 << (e + fromInteger(`i(bounds_)/2)); + Bool inRange = ((i & mask) == mask) || ((i & mask) == 0); + Bool inLimits = (i >= 0) ? imid < (r - amid - 1) : + imid >= (r - amid) && r != amid; + Bool isExact = ((inRange && inLimits) || e >= almighty_e); + // perform the offset update + let new_cap = cap; + new_cap.addr = truncate(getBase(cap) + offset); + return Exact{exact: isExact, value: new_cap}; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getBase(cap); + let baseCC = getBaseFieldCC(cap); + let e = getExpCC(cap); + let correction = getRegionCorrectionCC(truncateLSB(cap.addr), + truncateLSB(baseCC), + getRepBoundCC(cap)); + Bit#(addr_) mask = ~0 << (e + fromInteger(`i(bounds_)/2)); + Bit#(addr_) acc = cap.addr & mask; + return acc + (signExtend({pack(correction), baseCC}) << e); + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getTop(cap); + let topCC = getTopFieldCC(cap); + let e = getExpCC(cap); + let correction = getRegionCorrectionCC(truncateLSB(cap.addr), + truncateLSB(topCC), + getRepBoundCC(cap)); + Bit#(TAdd#(addr_, 1)) mask = ~0 << (e + fromInteger(`i(bounds_)/2)); + Bit#(TAdd#(addr_, 1)) acc = zeroExtend(cap.addr) & mask; + return acc + (signExtend({pack(correction), topCC}) << e); + endfunction + ////////////////////////////////////////////////////////////////////////////// + function getLength(cap) = getTop(cap) - zeroExtend(getBase(cap)); + ////////////////////////////////////////////////////////////////////////////// + function setBounds(cap, length); + let new_cap = cap; + let isExact = True; + // deriving new exponent + Bit#(TLog#(TAdd#(1, addr_))) e = + pack(fromInteger(`i(addr_)) + - countZerosMSB(length >> ((`i(bounds_)/2)-1))); + // deriving the new base + Bit#(`div2(bounds_)) newBase = truncate(cap.addr >> e); + // deriving the new top + Bit#(TAdd#(addr_, 1)) fullTop = zeroExtend(cap.addr) + zeroExtend(length); + Bit#(`div2(bounds_)) newTop = truncate(fullTop >> e); + // fold the derived values back in the new cap + if (e == 0) begin + new_cap.bounds = Exp0 { + lenMSB: length[(`i(bounds_)/2)-2], + top: truncate(newTop), + base: newBase + }; + end else begin + // slice the top and base values appropriately + Bit#(TSub#(`sub2(`div2(bounds_)), `div2(e_))) upperTop = truncateLSB(newTop); + Bit#(TSub#(`div2(bounds_), `div2(e_))) upperBase = truncateLSB(newBase); + // take care of loss of significant bits in the bits stolen/dropped from fullTop + Bit#(TAdd#(addr_, 1)) mask = ~(~0 << (e + fromInteger(`i(e_)/2))); + if ((fullTop & mask) != 0) upperTop = upperTop + 1; + new_cap.bounds = EmbeddedExp { + top: upperTop, + base: upperBase, + e: truncate(e) + }; + // check for exact or not + Bit#(addr_) exactMask = ~(~0 << (e - fromInteger(`i(bounds_)/2 - `i(e_)/2 - 1))); + if ((cap.addr & exactMask) != 0) isExact = False; + if ((length & exactMask) != 0) isExact = False; + end + return Exact{exact: isExact, value: new_cap}; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function nullWithAddr(x); + let cap = nullCap; + cap.addr = x; + return cap; + endfunction + ////////////////////////////////////////////////////////////////////////////// + function almightyCap = almightyCC; + ////////////////////////////////////////////////////////////////////////////// + function nullCap = nullCC; + ////////////////////////////////////////////////////////////////////////////// +endinstance + +`undef div2 +`undef sub2 +`undef i + +endpackage diff --git a/CHERICC128Cap.bsv b/CHERICC128Cap.bsv deleted file mode 100644 index c34c8c1..0000000 --- a/CHERICC128Cap.bsv +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2019 Peter Rugg - * All rights reserved. - * - * 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. - * - * @BERI_LICENSE_HEADER_START@ - * - * Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. BERI licenses this - * file to you under the BERI Hardware-Software License, Version 1.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.beri-open-systems.org/legal/license-1-0.txt - * - * Unless required by applicable law or agreed to in writing, Work distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * @BERI_LICENSE_HEADER_END@ - */ - -package CHERICC128Cap; - -import DefaultValue::*; -import Capability128ccLibs::*; -import CHERICap::*; - -export CapMem; -export CapReg; -export CapPipe; -export CHERICap::*; - - -// =============================================================================== -// Typeclass instance for interface - -typedef Bit#(129) CapMem; - -typedef CapFat CapReg; - -typedef Tuple2#(CapFat, TempFields) CapPipe; - -instance CHERICap #(CapMem, 18, 64); - function isValidCap (x) = error("feature not implemented for this cap type"); - function setValidCap (x) = error("feature not implemented for this cap type"); - function getHardPerms (x) = error("feature not implemented for this cap type"); - function setHardPerms (x) = error("feature not implemented for this cap type"); - function getSoftPerms (x) = error("feature not implemented for this cap type"); - function setSoftPerms (x) = error("feature not implemented for this cap type"); - function getKind (x) = error("feature not implemented for this cap type"); - function getType (x) = error("feature not implemented for this cap type"); - function setType (x) = error("feature not implemented for this cap type"); - function getAddr (x) = error("feature not implemented for this cap type"); - function setAddr (x) = error("feature not implemented for this cap type"); - function getOffset (x) = error("feature not implemented for this cap type"); - function setOffset (x) = error("feature not implemented for this cap type"); - function getBase (x) = error("feature not implemented for this cap type"); - function getTop (x) = error("feature not implemented for this cap type"); - function getLength (x) = error("feature not implemented for this cap type"); - function setBounds (x) = error("feature not implemented for this cap type"); - function nullWithAddr (x) = error("feature not implemented for this cap type"); - function almightyCap = error("feature not implemented for this cap type"); - function nullCap = error("feature not implemented for this cap type"); -endinstance - -instance CHERICap #(CapReg, 18, 64); - function isValidCap (x) = error("feature not implemented for this cap type"); - function setValidCap (x) = error("feature not implemented for this cap type"); - function getHardPerms (x) = error("feature not implemented for this cap type"); - function setHardPerms (x) = error("feature not implemented for this cap type"); - function getSoftPerms (x) = error("feature not implemented for this cap type"); - function setSoftPerms (x) = error("feature not implemented for this cap type"); - function getKind (x) = error("feature not implemented for this cap type"); - function getType (x) = error("feature not implemented for this cap type"); - function setType (x) = error("feature not implemented for this cap type"); - function getAddr (x) = error("feature not implemented for this cap type"); - function setAddr (x) = error("feature not implemented for this cap type"); - function getOffset (x) = error("feature not implemented for this cap type"); - function setOffset (x) = error("feature not implemented for this cap type"); - function getBase (x) = error("feature not implemented for this cap type"); - function getTop (x) = error("feature not implemented for this cap type"); - function getLength (x) = error("feature not implemented for this cap type"); - function setBounds (x) = error("feature not implemented for this cap type"); - function nullWithAddr (x) = error("feature not implemented for this cap type"); - function almightyCap = defaultCapFat; - function nullCap = Capability128ccLibs::nullCap; -endinstance - -instance CHERICap #(CapPipe, 18, 64); - - function isValidCap (x) = tpl_1(x).isCapability; - - function CapPipe setValidCap (CapPipe cap, Bool tag); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - capReg.isCapability = tag; - return tuple2(capReg, tempFields); - endfunction - - function HardPerms getHardPerms (CapPipe cap); - let capReg = tpl_1(cap); - return HardPerms { - accessSysRegs: capReg.perms.hard.acces_sys_regs, - permitUnseal: capReg.perms.hard.permit_unseal, - permitCCall: capReg.perms.hard.permit_ccall, - permitSeal: capReg.perms.hard.permit_seal, - permitStoreLocalCap: capReg.perms.hard.permit_store_ephemeral_cap, - permitStoreCap: capReg.perms.hard.permit_store_cap, - permitLoadCap: capReg.perms.hard.permit_load_cap, - permitStore: capReg.perms.hard.permit_store, - permitLoad: capReg.perms.hard.permit_load, - permitExecute: capReg.perms.hard.permit_execute, - global: capReg.perms.hard.non_ephemeral - }; - endfunction - - function CapPipe setHardPerms (CapPipe cap, HardPerms perms); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - capReg.perms.hard = HPerms { - reserved: ?, - acces_sys_regs: perms.accessSysRegs, - permit_unseal: perms.accessSysRegs, - permit_ccall: perms.accessSysRegs, - permit_seal: perms.accessSysRegs, - permit_store_ephemeral_cap: perms.accessSysRegs, - permit_store_cap: perms.accessSysRegs, - permit_load_cap: perms.accessSysRegs, - permit_store: perms.accessSysRegs, - permit_load: perms.accessSysRegs, - permit_execute: perms.accessSysRegs, - non_ephemeral: perms.accessSysRegs - }; - return tuple2(capReg, tempFields); - endfunction - - function SoftPerms getSoftPerms (CapPipe cap); - let capReg = tpl_1(cap); - return zeroExtend(capReg.perms.soft); - endfunction - - function CapPipe setSoftPerms (CapPipe cap, SoftPerms perms); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - capReg.perms.soft = truncate(perms); - return tuple2(capReg, tempFields); - endfunction - - function Kind getKind (CapPipe cap); - let capReg = tpl_1(cap); - case (capReg.otype) - otype_unsealed: return UNSEALED; - otype_sentry: return SENTRY; - default: return (capReg.otype <= otype_max) ? SEALED_WITH_TYPE : RES0; - endcase - endfunction - - function getType (x) = getType(tpl_1(x)).d; - - function Exact#(CapPipe) setType (CapPipe cap, Bit #(18) otype); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - if (otype == -1) begin - capReg = unseal(capReg, ?); - end else begin - capReg = seal(capReg, ?, VnD {v: True, d:otype}); - end - return Exact { - exact: True, - value: tuple2(capReg, tempFields) - }; - endfunction - - function getAddr (x) = truncate(getAddress(tpl_1(x))); - - function Exact#(CapPipe) setAddr (CapPipe cap, Bit#(64) address); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - capReg = setAddress(capReg, zeroExtend(address), tempFields); - return Exact {exact: capReg.isCapability, value: tuple2(capReg, getTempFields(capReg))}; - endfunction - - function getOffset (x) = getOffset(tpl_1(x)); - - function Exact#(CapPipe) setOffset (CapPipe cap, Bit#(64) offset); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - capReg = incOffset(capReg, ?, zeroExtend(offset), tempFields, True); //TODO split into separate incOffset and setOffset functions? - return Exact {exact: capReg.isCapability, value: tuple2(capReg, getTempFields(capReg))}; - endfunction - - function Bit#(64) getBase (CapPipe cap); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - return truncate(Capability128ccLibs::getBotFat(capReg, tempFields)); - endfunction - - function Bit#(65) getTop (CapPipe cap); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - return truncate(Capability128ccLibs::getTopFat(capReg, tempFields)); - endfunction - - function Bit#(65) getLength (CapPipe cap); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - return truncate(Capability128ccLibs::getLengthFat(capReg, tempFields)); - endfunction - - function Bool isInBounds (CapPipe cap, Bool inclusive); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - return capInBounds(capReg, tempFields, inclusive); - endfunction - - function Exact#(CapPipe) setBounds (CapPipe cap, Bit#(64) length); - let capReg = tpl_1(cap); - let tempFields = tpl_2(cap); - match {.result, .exact} = Capability128ccLibs::setBounds(capReg, length); - return Exact {exact: exact, value: tuple2(result, getTempFields(result))}; - endfunction - - function CapPipe nullWithAddr (Bit#(64) addr); - let res = setAddress (nullCap, zeroExtend(addr), getTempFields(nullCap)); - return tuple2(res, getTempFields(res)); - endfunction - - function almightyCap = tuple2(defaultCapFat, getTempFields(defaultCapFat)); - - function nullCap = tuple2(nullCap, getTempFields(nullCap)); - -endinstance - -instance Cast #(CapMem, CapReg); - function CapReg cast (CapMem thin); - return unpackCap(unpack(thin)); - endfunction -endinstance - -instance Cast #(CapReg, CapMem); - function CapMem cast (CapReg fat); - return pack(packCap(fat)); - endfunction -endinstance - -instance Cast #(CapReg, CapPipe); - function CapPipe cast (CapReg thin); - return tuple2(thin, getTempFields(thin)); - endfunction -endinstance - -instance Cast #(CapPipe, CapReg); - function CapReg cast (CapPipe fat); - return tpl_1(fat); - endfunction -endinstance - -endpackage diff --git a/Capability128ccLibs.bsv b/CHERICC_Fat.bsv similarity index 79% rename from Capability128ccLibs.bsv rename to CHERICC_Fat.bsv index 96f8dcc..28a4339 100644 --- a/Capability128ccLibs.bsv +++ b/CHERICC_Fat.bsv @@ -27,9 +27,10 @@ * @BERI_LICENSE_HEADER_END@ */ -package Capability128ccLibs; +package CHERICC_Fat; -import DefaultValue::*; +import DefaultValue :: *; +import CHERICap :: *; // =============================================================================== @@ -332,7 +333,7 @@ function Bit#(n) smearMSBRight(Bit#(n) x); return res; endfunction -function Tuple2#(CapFat, Bool) setBounds(CapFat cap, Address lengthFull); +function Tuple2#(CapFat, Bool) setBoundsFat(CapFat cap, Address lengthFull); CapFat ret = cap; // Find new exponent by finding the index of the most significant bit of the // length, or counting leading zeros in the high bits of the length, and @@ -637,7 +638,7 @@ instance DefaultValue #(CapFat); }; endinstance -CapFat nullCap = CapFat { +CapFat null_cap = CapFat { isCapability: False, perms : unpack(0), reserved : 0, @@ -767,4 +768,238 @@ function MetaInfo getMetaInfo (CapFat cap); baseCorrection : baseCorrection }; endfunction + +// =============================================================================== +// Typeclass instance for interface + +typedef Bit#(129) CapMem; + +typedef CapFat CapReg; + +typedef Tuple2#(CapFat, TempFields) CapPipe; + +instance CHERICap #(CapMem, 18, 64); + function isValidCap = error("feature not implemented for this cap type"); + function setValidCap = error("feature not implemented for this cap type"); + function getHardPerms = error("feature not implemented for this cap type"); + function setHardPerms = error("feature not implemented for this cap type"); + function getSoftPerms = error("feature not implemented for this cap type"); + function setSoftPerms = error("feature not implemented for this cap type"); + function getKind = error("feature not implemented for this cap type"); + function getType = error("feature not implemented for this cap type"); + function setType = error("feature not implemented for this cap type"); + function getAddr = error("feature not implemented for this cap type"); + function setAddr = error("feature not implemented for this cap type"); + function getOffset = error("feature not implemented for this cap type"); + function setOffset = error("feature not implemented for this cap type"); + function getBase = error("feature not implemented for this cap type"); + function getTop = error("feature not implemented for this cap type"); + function getLength = error("feature not implemented for this cap type"); + function isInBounds = error("feature not implemented for this cap type"); + function setBounds = error("feature not implemented for this cap type"); + function nullWithAddr = error("feature not implemented for this cap type"); + function almightyCap = error("feature not implemented for this cap type"); + function nullCap = error("feature not implemented for this cap type"); +endinstance + +instance CHERICap #(CapReg, 18, 64); + function isValidCap = error("feature not implemented for this cap type"); + function setValidCap = error("feature not implemented for this cap type"); + function getHardPerms = error("feature not implemented for this cap type"); + function setHardPerms = error("feature not implemented for this cap type"); + function getSoftPerms = error("feature not implemented for this cap type"); + function setSoftPerms = error("feature not implemented for this cap type"); + function getKind = error("feature not implemented for this cap type"); + function getType = error("feature not implemented for this cap type"); + function setType = error("feature not implemented for this cap type"); + function getAddr = error("feature not implemented for this cap type"); + function setAddr = error("feature not implemented for this cap type"); + function getOffset = error("feature not implemented for this cap type"); + function setOffset = error("feature not implemented for this cap type"); + function getBase = error("feature not implemented for this cap type"); + function getTop = error("feature not implemented for this cap type"); + function getLength = error("feature not implemented for this cap type"); + function isInBounds = error("feature not implemented for this cap type"); + function setBounds = error("feature not implemented for this cap type"); + function nullWithAddr = error("feature not implemented for this cap type"); + function almightyCap = defaultCapFat; + function nullCap = null_cap; +endinstance + +instance CHERICap #(CapPipe, 18, 64); + + function isValidCap (x) = tpl_1(x).isCapability; + + function CapPipe setValidCap (CapPipe cap, Bool tag); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + capReg.isCapability = tag; + return tuple2(capReg, tempFields); + endfunction + + function HardPerms getHardPerms (CapPipe cap); + let capReg = tpl_1(cap); + return HardPerms { + accessSysRegs: capReg.perms.hard.acces_sys_regs, + permitUnseal: capReg.perms.hard.permit_unseal, + permitCCall: capReg.perms.hard.permit_ccall, + permitSeal: capReg.perms.hard.permit_seal, + permitStoreLocalCap: capReg.perms.hard.permit_store_ephemeral_cap, + permitStoreCap: capReg.perms.hard.permit_store_cap, + permitLoadCap: capReg.perms.hard.permit_load_cap, + permitStore: capReg.perms.hard.permit_store, + permitLoad: capReg.perms.hard.permit_load, + permitExecute: capReg.perms.hard.permit_execute, + global: capReg.perms.hard.non_ephemeral + }; + endfunction + + function CapPipe setHardPerms (CapPipe cap, HardPerms perms); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + capReg.perms.hard = HPerms { + reserved: ?, + acces_sys_regs: perms.accessSysRegs, + permit_unseal: perms.accessSysRegs, + permit_ccall: perms.accessSysRegs, + permit_seal: perms.accessSysRegs, + permit_store_ephemeral_cap: perms.accessSysRegs, + permit_store_cap: perms.accessSysRegs, + permit_load_cap: perms.accessSysRegs, + permit_store: perms.accessSysRegs, + permit_load: perms.accessSysRegs, + permit_execute: perms.accessSysRegs, + non_ephemeral: perms.accessSysRegs + }; + return tuple2(capReg, tempFields); + endfunction + + function SoftPerms getSoftPerms (CapPipe cap); + let capReg = tpl_1(cap); + return zeroExtend(capReg.perms.soft); + endfunction + + function CapPipe setSoftPerms (CapPipe cap, SoftPerms perms); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + capReg.perms.soft = truncate(perms); + return tuple2(capReg, tempFields); + endfunction + + function Kind getKind (CapPipe cap); + let capReg = tpl_1(cap); + case (capReg.otype) + otype_unsealed: return UNSEALED; + otype_sentry: return SENTRY; + default: return (capReg.otype <= otype_max) ? SEALED_WITH_TYPE : RES0; + endcase + endfunction + + function getType (x) = getType(tpl_1(x)).d; + + function Exact#(CapPipe) setType (CapPipe cap, Bit #(18) otype); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + if (otype == -1) begin + capReg = unseal(capReg, ?); + end else begin + capReg = seal(capReg, ?, VnD {v: True, d:otype}); + end + return Exact { + exact: True, + value: tuple2(capReg, tempFields) + }; + endfunction + + function getAddr (x) = truncate(getAddress(tpl_1(x))); + + function Exact#(CapPipe) setAddr (CapPipe cap, Bit#(64) address); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + capReg = setAddress(capReg, zeroExtend(address), tempFields); + return Exact {exact: capReg.isCapability, value: tuple2(capReg, getTempFields(capReg))}; + endfunction + + function getOffset (x) = getOffsetFat(tpl_1(x), tpl_2(x)); + + function Exact#(CapPipe) setOffset (CapPipe cap, Bit#(64) offset); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + capReg = incOffset(capReg, ?, zeroExtend(offset), tempFields, True); //TODO split into separate incOffset and setOffset functions? + return Exact {exact: capReg.isCapability, value: tuple2(capReg, getTempFields(capReg))}; + endfunction + + function Bit#(64) getBase (CapPipe cap); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + return truncate(getBotFat(capReg, tempFields)); + endfunction + + function Bit#(65) getTop (CapPipe cap); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + return truncate(getTopFat(capReg, tempFields)); + endfunction + + function Bit#(65) getLength (CapPipe cap); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + return truncate(getLengthFat(capReg, tempFields)); + endfunction + + function Bool isInBounds (CapPipe cap, Bool inclusive); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + return capInBounds(capReg, tempFields, inclusive); + endfunction + + function Exact#(CapPipe) setBounds (CapPipe cap, Bit#(64) length); + let capReg = tpl_1(cap); + let tempFields = tpl_2(cap); + match {.result, .exact} = setBoundsFat(capReg, length); + return Exact {exact: exact, value: tuple2(result, getTempFields(result))}; + endfunction + + function CapPipe nullWithAddr (Bit#(64) addr); + let res = setAddress (nullCap, zeroExtend(addr), getTempFields(nullCap)); + return tuple2(res, getTempFields(res)); + endfunction + + function almightyCap = tuple2(defaultCapFat, getTempFields(defaultCapFat)); + + function nullCap = tuple2(nullCap, getTempFields(nullCap)); + +endinstance + +instance Cast#(CapMem, CapReg); + function CapReg cast (CapMem thin); + return unpackCap(thin); + endfunction +endinstance + +instance Cast#(CapReg, CapMem); + function CapMem cast (CapReg fat); + return pack(packCap(fat)); + endfunction +endinstance + +instance Cast#(CapReg, CapPipe); + function CapPipe cast (CapReg thin); + return tuple2(thin, getTempFields(thin)); + endfunction +endinstance + +instance Cast#(CapPipe, CapReg); + function CapReg cast (CapPipe fat); + return tpl_1(fat); + endfunction +endinstance + +instance Cast#(Bit#(129), CapPipe); + function cast(x); + CapReg fat = cast(x); + return tuple2(fat, getTempFields(fat)); + endfunction +endinstance + endpackage diff --git a/CHERICap.bsv b/CHERICap.bsv index f20d939..51fd8e2 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -129,7 +129,12 @@ typeclass CHERICap#(type t, numeric type ot, numeric type n) function Bit#(TAdd#(n, 1)) getLength (t cap); // Assertion that address is between base and top - function Bool isInBounds (t cap, Bool inclusive); + 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); @@ -154,12 +159,12 @@ function Fmt showCHERICap(t cap) provisos (CHERICap#(t, ot, n)); $format(" Length: 0x%0x", getLength(cap)); endfunction -typeclass Cast #(type src, type dest); +typeclass Cast#(type src, type dest); function dest cast (src x); endtypeclass -instance Cast #(t, t); - function t cast (t x) = x; +instance Cast#(t, t); + function cast = id; endinstance endpackage