-
Notifications
You must be signed in to change notification settings - Fork 9
/
CHERICap.bsv
330 lines (286 loc) · 13.4 KB
/
CHERICap.bsv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*-
* Copyright (c) 2018-2021 Alexandre Joannou
* 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 CHERICap;
// CHERI capability types
////////////////////////////////////////////////////////////////////////////////
// Permission bits
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;
} HardPerms deriving(Bits, Eq, FShow);
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));
function \~^ (x1, x2) = unpack(pack(x1) ~^ pack(x2));
function \^~ (x1, x2) = unpack(pack(x1) ^~ pack(x2));
function invert (x) = unpack(invert (pack(x))); //XXX Bluespec ref guide uses x1 here but simply x for other single arg methods...
function \<< (x1, x2) = unpack(pack(x1) << x2);
function \>> (x1, x2) = unpack(pack(x1) >> x2);
function msb (x) = msb(pack(x));
function lsb (x) = lsb(pack(x));
endinstance
// 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 #(otypeW) SEALED_WITH_TYPE;
} Kind #(numeric type otypeW) deriving (Bits, Eq, FShow);
// helper type for gathering bounds information on a capability
typedef struct {
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;
Bool repSplit;
} BoundsInfo #(numeric type addrW) 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 {
capT cap;
Bool exact;
Bool inBounds;
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
, Bool highIncluded);
Bool notTooHigh = highIncluded ? x <= high : x < high;
Bool notTooLow = x >= low;
return notTooLow && notTooHigh;
endfunction
// XXX TODO augment with all architectural bounds/ repbounds ?
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))) +
$format(" Addr: 0x%0x", getAddr(cap)) +
$format(" Base: 0x%0x", getBase(cap)) +
$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
instance Cast #(capT, capT);
function cast = id;
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
, 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 (capT cap);
// Set the capability as valid. All fields left unchanged
function capT setValidCap (capT cap, Bool valid);
// capability flags
//////////////////////////////////////////////////////////////////////////////
// Get the flags field
function Bit #(flgW) getFlags (capT cap);
// Set the flags field
function capT setFlags (capT cap, Bit #(flgW) flags);
// capability permissions
//////////////////////////////////////////////////////////////////////////////
// Get the hardware permissions
function HardPerms getHardPerms (capT cap);
// Set the hardware permissions
function capT setHardPerms (capT cap, HardPerms hardperms);
// Get the software permissions
function SoftPerms getSoftPerms (capT cap);
// Set the software permissions
function capT setSoftPerms (capT cap, SoftPerms softperms);
// Get the architectural permissions
function Bit #(31) getPerms (capT cap) =
zeroExtend ({pack (getSoftPerms (cap)), 3'h0, pack (getHardPerms (cap))});
// Set the architectural permissions
function capT setPerms (capT 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 #(otypeW) getKind (capT cap);
// set the kind of a capability
function capT setKind (capT cap, Kind #(otypeW) kind);
// Check if a type is valid (requires a dummy proxy)
function Bool validAsType (capT dummy, Bit #(addrW) checkType);
// 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
function Bit #(TSub #(inMemW, addrW)) getMeta (capT cap);
// Get the in-memory architectural representation of the capability address
function Bit #(addrW) getAddr (capT cap);
// Convert from in-memory architectural bit representation to capability type
function capT fromMem (Tuple2 #(Bool, Bit #(inMemW)) mem_cap);
// Convert from capability type to in-memory architectural bit representation
function Tuple2 #(Bool, Bit #(inMemW)) toMem (capT cap);
// capability address/offset manipulation
//////////////////////////////////////////////////////////////////////////////
// Set the address of the capability. Result invalid if unrepresentable
function Exact #(capT) setAddr (capT cap, Bit #(addrW) addr);
// Set the address of the capability. Result assumed to be representable
function capT setAddrUnsafe (capT cap, Bit #(addrW) addr);
// Add to the address of the capability. Result assumed to be representable
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 capT maskAddr (capT cap, Bit #(maskableW) mask);
// Get the offset of the capability
function Bit #(addrW) getOffset (capT cap) = getAddr(cap) - getBase(cap);
// Modify the offset of the capability. Result invalid if unrepresentable
function Exact #(capT) modifyOffset ( capT cap
, Bit #(addrW) offset
, Bool doInc);
// Set the offset of the capability. Result invalid if unrepresentable
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 #(capT) incOffset (capT cap, Bit #(addrW) inc) =
modifyOffset(cap, inc, True);
// capability architectural bounds queries
//////////////////////////////////////////////////////////////////////////////
// Note that the following rules are expected to hold:
// 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 #(addrW) getBoundsInfo (capT cap);
// Get the base
function Bit #(addrW) getBase (capT cap) = getBoundsInfo(cap).base;
// Get the top
function Bit #(TAdd #(addrW, 1)) getTop (capT cap) = getBoundsInfo(cap).top;
// Get the 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 (capT cap, Bool isTopIncluded) =
belongsToRange ( zeroExtend (getAddr (cap))
, zeroExtend (getBase (cap))
, getTop (cap)
, isTopIncluded );
// Get the representable base
function Bit #(addrW) getRepBase (capT cap) = getBoundsInfo(cap).repBase;
// Get the representable top
function Bit #(TAdd #(addrW, 1)) getRepTop (capT cap) =
getBoundsInfo(cap).repTop;
// 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);
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];
// 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
// 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 (?);
// a null capability with a given address set
function capT nullWithAddr (Bit #(addrW) addr);
// maximally permissive capability (initial register state)
function capT almightyCap;
// the null capability (requires a dummy proxy)
function capT nullCapFromDummy (capT dummy);
// Assert that the encoding is valid
//////////////////////////////////////////////////////////////////////////////
function Bool isDerivable (capT cap);
endtypeclass
endpackage