From 1741ce43ddcc0a16bfe0ee49afc5de509ad587f2 Mon Sep 17 00:00:00 2001 From: gameboo Date: Wed, 15 Sep 2021 17:57:01 +0100 Subject: [PATCH] Introduced a getMeta method as a counterpart to getAddr for getting all bits of in-memory architectural capability representation --- CHERICC_Fat.bsv | 33 ++++++++++++---- CHERICap.bsv | 100 +++++++++++++++++++++++++++++++----------------- 2 files changed, 91 insertions(+), 42 deletions(-) diff --git a/CHERICC_Fat.bsv b/CHERICC_Fat.bsv index 49fda6b..f8b2c08 100644 --- a/CHERICC_Fat.bsv +++ b/CHERICC_Fat.bsv @@ -92,6 +92,7 @@ typedef `FLAGSW FlagsW; typedef 64 CapAddrW; typedef 128 CapW; `endif + // The Address type is used to represent the full sized address returned to the // consuming pipeline. In cases where fewer than CapAddrW bits are stored to // represent a memory address (and remaining bits are usable for storing extra @@ -145,7 +146,7 @@ typedef struct { Bit#(OTypeW) otype; CBounds bounds; CapAddr address; -} CapabilityInMemory deriving(Bits, Eq, FShow); // CapW + 1 (tag bit) +} CapabilityInMemory deriving (Bits, Eq, FShow); // CapW + 1 (tag bit) // The full capability structure as Bits, including the "tag" bit. typedef Bit#(TAdd#(CapW,1)) Capability; // not including the tag bit @@ -180,7 +181,7 @@ typedef struct { Bit#(OTypeW) otype; Format format; Bounds bounds; -} CapFat deriving(Bits); +} CapFat deriving (Bits); // "Architectural FShow" function Fmt showArchitectural(CapFat cap) = @@ -847,7 +848,7 @@ typedef struct { TempFields tempFields; } CapPipe deriving (Bits); -instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); +instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); function isValidCap (capMem); CapabilityInMemory cap = unpack(capMem); return cap.isCapability; @@ -887,9 +888,17 @@ instance CHERICap #(CapMem, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); 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); + return { pack (cap.perms) + , pack (cap.reserved) + , pack (cap.flags) + , pack (cap.otype) + , pack (cap.bounds) }; + endfunction function getAddr(capMem); CapabilityInMemory cap = unpack(capMem); - return cap.address; + return pack (cap.address); endfunction function setAddr = error("setAddr not implemented for CapMem"); function setAddrUnsafe (capMem, address); @@ -946,7 +955,7 @@ instance Eq #(CapReg); // function Bool \/= (CapPipe x, CapPipe y); endinstance -instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); +instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub #(MW, 3)); function isValidCap (x) = x.isCapability; @@ -1016,7 +1025,15 @@ instance CHERICap #(CapReg, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); tagged SEALED_WITH_TYPE .ot: seal(cap, ?, VnD {v: True, d:ot}); endcase; - function getAddr (cap) = cap.address; + 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 setAddr = error("setAddr not implemented for CapReg"); @@ -1091,7 +1108,9 @@ instance CHERICap #(CapPipe, OTypeW, FlagsW, CapAddrW, CapW, TSub#(MW, 3)); function setKind (cap, kind) = CapPipe { capFat:setKind(cap.capFat,kind) , tempFields: cap.tempFields }; - function getAddr (cap) = getAddr(cap.capFat); + + function getMeta (cap) = getMeta (cap.capFat); + function getAddr (cap) = getAddr (cap.capFat); function maskAddr (cap, mask) = CapPipe { capFat: maskAddr(cap.capFat, mask) , tempFields: cap.tempFields }; diff --git a/CHERICap.bsv b/CHERICap.bsv index 499f376..76632bf 100644 --- a/CHERICap.bsv +++ b/CHERICap.bsv @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2019 Alexandre Joannou + * Copyright (c) 2018-2021 Alexandre Joannou * Copyright (c) 2019 Peter Rugg * All rights reserved. * @@ -29,27 +29,29 @@ package CHERICap; -// CHERI capability typeclass +// CHERI public types //////////////////////////////////////////////////////////////////////////////// + // Permission bits -typedef Bit#(16) SoftPerms; +typedef Bit #(16) SoftPerms; + typedef struct { - Bool permitSetCID; - Bool accessSysRegs; - Bool permitUnseal; - Bool permitCCall; - Bool permitSeal; - Bool permitStoreLocalCap; - Bool permitStoreCap; - Bool permitLoadCap; - Bool permitStore; - Bool permitLoad; - Bool permitExecute; - Bool global; + Bool permitSetCID; + Bool accessSysRegs; + Bool permitUnseal; + Bool permitCCall; + Bool permitSeal; + Bool permitStoreLocalCap; + Bool permitStoreCap; + Bool permitLoadCap; + Bool permitStore; + Bool permitLoad; + Bool permitExecute; + Bool global; } HardPerms deriving(Bits, Eq, FShow); -instance Bitwise#(HardPerms); +instance Bitwise #(HardPerms); function \& (x1, x2) = unpack(pack(x1) & pack(x2)); function \| (x1, x2) = unpack(pack(x1) | pack(x2)); function \^ (x1, x2) = unpack(pack(x1) ^ pack(x2)); @@ -62,31 +64,45 @@ instance Bitwise#(HardPerms); function lsb (x) = lsb(pack(x)); endinstance -// 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. +// 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". + typedef union tagged { void UNSEALED; void SENTRY; void RES0; void RES1; - Bit#(ot) SEALED_WITH_TYPE; -} Kind#(numeric type ot) deriving (Bits, Eq, FShow); + Bit #(ot) SEALED_WITH_TYPE; +} Kind #(numeric type ot) deriving (Bits, Eq, FShow); -typedef struct -{ +// Helper type for the return value of the 'setBoundsCombined' method + +typedef struct { t cap; Bool exact; - Bit#(n) length; - Bit#(n) mask; -} SetBoundsReturn#(type t, numeric type n) deriving (Bits, Eq, FShow); + Bit #(n) length; + Bit #(n) mask; +} SetBoundsReturn #(type t, numeric type n) deriving (Bits, Eq, FShow); -typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, numeric type mem_sz, numeric type maskable_bits) + +// 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 @@ -112,14 +128,22 @@ typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, n 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]))); + 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, ... + // 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 address pointed to by the capability - function Bit#(n) getAddr (t 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); + + // 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 @@ -153,7 +177,8 @@ typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, n return isNotTooLow && isNotTooHigh; endfunction - // Set the length of the capability. Inexact: result length may be different to requested + // 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}; @@ -175,7 +200,7 @@ typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, n // Check if a type is valid function Bool validAsType (t dummy, Bit#(n) checkType); - // convert from and to bit memory representation + // 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); @@ -192,7 +217,8 @@ typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, n function Bit#(2) getBaseAlignment (t cap); // Get representable alignment mask - function Bit#(n) getRepresentableAlignmentMask (t dummy, Bit#(n) length_request) = + function Bit#(n) getRepresentableAlignmentMask ( t dummy + , Bit#(n) length_request) = setBoundsCombined(nullCapFromDummy(dummy), length_request).mask; // Get representable length @@ -204,7 +230,8 @@ typeclass CHERICap#(type t, numeric type ot, numeric type flg, numeric type n, n endtypeclass -function Fmt showCHERICap(t cap) provisos (CHERICap#(t, ot, flg, n, mem_sz, maskable_bits)); +function Fmt showCHERICap (t cap) + provisos (CHERICap #(t , ot, flg, n, mem_sz, maskable_bits)); return $format( "Valid: 0x%0x", isValidCap(cap)) + $format(" Perms: 0x%0x", getPerms(cap)) + $format(" Kind: ", fshow(getKind(cap))) + @@ -213,6 +240,9 @@ function Fmt showCHERICap(t cap) provisos (CHERICap#(t, ot, flg, n, mem_sz, mask $format(" Length: 0x%0x", getLength(cap)); endfunction +// Cast typeclass to convert from one type to another. Helpful for converting +// a capability format to another. + typeclass Cast#(type src, type dest); function dest cast (src x); endtypeclass