CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Toggle main menu visibility
Loading...
Searching...
No Matches
sdk
include
ds
pointer.h
Go to the documentation of this file.
1
// Copyright Microsoft and CHERIoT Contributors.
2
// SPDX-License-Identifier: MIT
3
4
/**
5
* @file
6
* Pointer utilities
7
*/
8
9
#pragma once
10
11
#include <
cheri.hh
>
12
#include <concepts>
13
14
namespace
ds::pointer
15
{
16
17
/**
18
* Offset a pointer by a number of bytes. The return type must be
19
* explicitly specified by the caller. The type of the displacement offset
20
* (Offset) is templated so that we can accept both signed and unsigned
21
* offsets.
22
*/
23
template
<
typename
T,
typename
U>
24
static
inline
__always_inline T *
offset
(U *base, std::integral
auto
offset
)
25
{
26
CHERI::Capability
c{base};
27
c.
address
() +=
offset
;
28
return
c.template cast<void>().template cast<T>();
29
}
30
31
/**
32
* Compute the unsigned difference in bytes between two pointers' target
33
* addresses. To be standards-compliant, cursor must be part of the same
34
* allocation as base and at a higher address.
35
*/
36
static
inline
__always_inline
size_t
diff
(
const
void
*base,
37
const
void
*cursor)
38
{
39
return
static_cast<
size_t
>
(
reinterpret_cast<
const
char
*
>
(cursor) -
40
reinterpret_cast<
const
char
*
>
(base));
41
}
42
43
namespace
proxy
44
{
45
46
/**
47
* Proxies<P,T> if P is a proxy object for T*-s.
48
*/
49
template
<
typename
P,
typename
T>
50
concept
Proxies
= std::same_as<T, typename P::Type> &&
51
requires
(P &proxy, P &proxy2, T *ptr) {
52
/* Probe for operator=(T*) */
53
{ proxy = ptr } -> std::same_as<P &>;
54
55
/* Probe for operator T*() */
56
{ ptr == proxy } -> std::same_as<bool>;
57
58
/* TODO: How to probe for operator-> ? */
59
60
/* Probe for operator==(T*) */
61
{ proxy == ptr } -> std::same_as<bool>;
62
63
/* Probe for operator==(P&) */
64
{ proxy == proxy2 } -> std::same_as<bool>;
65
66
/* Probe for operator<=>(T*) */
67
{
68
proxy <=> ptr
69
} -> std::same_as<std::strong_ordering>;
70
71
/* Probe for operator<=>(P) */
72
{
73
proxy <=> proxy2
74
} -> std::same_as<std::strong_ordering>;
75
};
76
77
/**
78
* Pointer references are pointer proxies, shockingly enough.
79
*/
80
template
<
typename
T>
81
class
Pointer
82
{
83
T *&ref;
84
85
public
:
86
using
Type = T;
87
88
__always_inline Pointer(T *&r) : ref(r) {}
89
90
__always_inline
operator
T *()
91
{
92
return
ref;
93
}
94
95
__always_inline T *operator->()
96
{
97
return
*
this
;
98
}
99
100
__always_inline Pointer<T> &operator=(T *t)
101
{
102
ref = t;
103
return
*
this
;
104
}
105
106
__always_inline Pointer<T> &operator=(Pointer
const
&p)
107
{
108
ref =
static_cast<
T *
>
(p.ref);
109
return
*
this
;
110
}
111
112
__always_inline
bool
operator==(Pointer &p)
113
{
114
return
this->ref == p.ref;
115
}
116
117
__always_inline
auto
operator<=>(Pointer &p)
118
{
119
return
this->ref <=> p.ref;
120
}
121
};
122
static_assert
(
Proxies<Pointer<void>
,
void
>);
123
124
/**
125
* Equipped with a context for bounds, an address reference can be a
126
* proxy for a pointer.
127
*/
128
template
<
typename
T>
129
class
PtrAddr
130
{
131
CHERI::Capability<void>
ctx;
132
ptraddr_t &ref;
133
134
public
:
135
using
Type = T;
136
137
__always_inline PtrAddr(
void
*c, ptraddr_t &r) : ctx(c), ref(r) {}
138
139
__always_inline
operator
T *()
140
{
141
auto
c = ctx;
142
c.address() = ref;
143
return
c.cast<T>().get();
144
}
145
146
__always_inline T *operator->()
147
{
148
return
*
this
;
149
}
150
151
__always_inline PtrAddr &operator=(T *p)
152
{
153
ref =
CHERI::Capability
{p}.
address
();
154
return
*
this
;
155
}
156
157
__always_inline PtrAddr &operator=(PtrAddr
const
&p)
158
{
159
ref = p.ref;
160
return
*
this
;
161
}
162
163
/*
164
* Since the context is used only for bounds, don't bother
165
* implicitly converting both proxies up to T*
166
*/
167
168
__always_inline
bool
operator==(PtrAddr &p)
169
{
170
return
ref == p.ref;
171
}
172
173
__always_inline
auto
operator<=>(PtrAddr &p)
174
{
175
return
ref <=> p.ref;
176
}
177
};
178
static_assert
(
Proxies<PtrAddr<void>
,
void
>);
179
180
/**
181
* Deduction gude for the common enough case where the context
182
* type and the represented type are equal.
183
*/
184
template
<
typename
T>
185
PtrAddr
(T *, ptraddr_t) ->
PtrAddr<T>
;
186
187
/**
188
* Like the above, but with a constant offset on the interpretation of
189
* its addresss fields. This is useful for building points-to-container
190
* data structures (rather than points-to-member as with the above two).
191
* The container_of and address-taking operations that move back and
192
* forth between container and link member should fuse away with the
193
* offsetting operations herein. You may prefer this if your common or
194
* fast-paths involve lots of container_of operations.
195
*/
196
template
<ptrdiff_t Offset,
typename
T>
197
class
OffsetPtrAddr
198
{
199
CHERI::Capability<void>
ctx;
200
ptraddr_t &ref;
201
202
public
:
203
using
Type = T;
204
205
__always_inline OffsetPtrAddr(
void
*c, ptraddr_t &r)
206
: ctx(c), ref(r)
207
{
208
}
209
210
__always_inline
operator
T *()
211
{
212
auto
c = ctx;
213
c.address() = ref + Offset;
214
return
c.cast<T>().get();
215
}
216
217
__always_inline T *operator->()
218
{
219
return
*
this
;
220
}
221
222
__always_inline OffsetPtrAddr &operator=(T *p)
223
{
224
ref =
CHERI::Capability
{p}.
address
() - Offset;
225
return
*
this
;
226
}
227
228
__always_inline OffsetPtrAddr &operator=(OffsetPtrAddr
const
&p)
229
{
230
ref = p.ref;
231
return
*
this
;
232
}
233
234
/*
235
* Since the context is used only for bounds, don't bother
236
* implicitly converting both proxies up to T*. This also probably
237
* saves the optimizer the effort of cancelling the Offset
238
* arithmetic on either side of the comparison.
239
*/
240
241
__always_inline
bool
operator==(OffsetPtrAddr &p)
242
{
243
return
ref == p.ref;
244
}
245
246
__always_inline
auto
operator<=>(OffsetPtrAddr &p)
247
{
248
return
ref <=> p.ref;
249
}
250
};
251
static_assert
(
Proxies<OffsetPtrAddr<8, void>
,
void
>);
252
253
}
// namespace proxy
254
255
}
// namespace ds::pointer
cheri.hh
C++ helpers for operating on capabilities.
CHERI::Capability
Helper class for accessing capability properties on pointers.
Definition
cheri.hh:482
CHERI::Capability::address
AddressProxy address()
Access the address of the capability.
Definition
cheri.hh:851
ds::pointer::proxy::PtrAddr
Equipped with a context for bounds, an address reference can be a proxy for a pointer.
Definition
pointer.h:130
ds::pointer::proxy::Proxies
Proxies<P,T> if P is a proxy object for T*-s.
Definition
pointer.h:50
ds::pointer::diff
static size_t diff(const void *base, const void *cursor)
Compute the unsigned difference in bytes between two pointers' target addresses.
Definition
pointer.h:36
ds::pointer::offset
static T * offset(U *base, std::integral auto offset)
Offset a pointer by a number of bytes.
Definition
pointer.h:24
Generated by
1.18.0