CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
allocator.h
Go to the documentation of this file.
1// Copyright Microsoft and CHERIoT Contributors.
2// SPDX-License-Identifier: MIT
3
4/**
5 * \file
6 * \brief CHERIoT RTOS heap allocator interface
7 */
8
9#pragma once
10
11#include <cdefs.h>
12#include <riscvreg.h>
13#include <stddef.h>
14#include <timeout.h>
15#include <token.h>
16
17// Forward declarations from stdlib.h
19typedef CHERI_SEALED(struct AllocatorCapabilityState *) AllocatorCapability;
20
21__BEGIN_DECLS
22
23/**
24 * Permission bits for allocator capabilities.
25 * Permission to free is implicit, and cannot be restricted.
26 */
27enum [[clang::flag_enum]] AllocatorPermission
28{
29 /**
30 * This allocator capability is fully de-permissioned. Note that this
31 * capability can still be used to free.
32 */
34 /**
35 * This allocator capability may be used to perform allocations and make
36 * claims using its quota.
37 */
39 /**
40 * This allocator capability may be used to free all allocations made
41 * using its quota via `heap_free_all`.
42 */
44 /**
45 * Unused permissions bit.
46 */
48 /**
49 * This allocator capability is fully permissioned. It can be used to
50 * allocate and free all.
51 */
54};
55
56/**
57 * Returns the permissions held by this allocator capability. This is a
58 * bitmask of `AllocatorPermission` values.
59 */
60static inline int allocator_permissions(AllocatorCapability heapCapability)
61{
62 return token_permissions_get(heapCapability);
63}
64
65/**
66 * Returns a copy of `heapCapability` with a subset of permissions. The
67 * `permissions` argument is a bitmask of `AllocatorPermission` values. The
68 * returned allocator capability has only the permissions that are both already
69 * present on `heapCapability` and enumerated in `permissions`.
70 */
71static inline AllocatorCapability
72allocator_permissions_and(AllocatorCapability heapCapability, int permissions)
73{
74 return token_permissions_and(heapCapability, permissions);
75}
76
77/**
78 * Add a claim to an allocation. The object will be counted against the quota
79 * provided by the first argument until a corresponding call to `heap_free`.
80 * Note that this can be used with interior pointers.
81 *
82 * This will return the size of the allocation claimed on success (which may be
83 * larger than the size requested in the original `heap_allocate` call; see its
84 * documentation for more information).
85 *
86 * Returns `-EPERM` if `heapCapability` does not have permission to perform this
87 * claim, `-ENOMEM` if the provided quota is too small to accomodate the claim,
88 * and `-EINVAL` if `pointer` is not a valid pointer into a live heap
89 * allocation.
90 *
91 * Similarly to `heap_allocate`, `-ENOTENOUGHSTACK` may be returned if the
92 * stack is insufficiently large to run the function. See `heap_allocate`.
93 */
94ssize_t __cheri_compartment("allocator")
95 heap_claim(AllocatorCapability heapCapability, void *pointer);
96
97/**
98 * Interface to the ephemeral claims mechanism. This claims two pointers using
99 * the hazard-pointer-inspired lightweight claims mechanism. If this function
100 * returns zero then the heap pointers are guaranteed not to become invalid
101 * until either the next cross-compartment call or the next call to this
102 * function.
103 *
104 * A null pointer can be used as a not-present value. This function will treat
105 * operations on null pointers as unconditionally successful. It returns
106 * `-ETIMEDOUT` if it failed to claim before the timeout expired, or `-EINVAL`
107 * if one or more of the arguments is neither null nor a valid pointer at the
108 * end.
109 *
110 * In the case of failure, neither pointer will have been claimed.
111 *
112 * This function is provided by the `compartment_helpers` library, which must be
113 * linked for it to be available.
114 */
115int __cheri_libcall heap_claim_ephemeral(TimeoutArgument timeout,
116 const void *ptr,
117 const void *ptr2 __if_cxx(= nullptr));
118
119__attribute__((deprecated("heap_claim_fast was a bad name. This function has "
120 "been renamed heap_claim_ephemeral")))
121__always_inline static int
122heap_claim_fast(TimeoutArgument timeout,
123 const void *ptr,
124 const void *ptr2 __if_cxx(= nullptr))
125{
126 return heap_claim_ephemeral(timeout, ptr, ptr2);
127}
128
129/**
130 * Free all allocations owned by this capability.
131 *
132 * Returns the number of bytes freed, `-EPERM` if this heap capability does not
133 * have permission to perform this action, or `-ENOTENOUGHSTACK` if the stack
134 * size is insufficiently large to safely run the function.
135 */
136ssize_t __cheri_compartment("allocator")
137 heap_free_all(AllocatorCapability heapCapability);
138
139/**
140 * Returns 0 if the allocation can be freed with the given capability,
141 * `-EPERM` if `heapCapability` is not valid or it cannot free the provided
142 * allocation (such as when `heapCapability` does not own the allocation,
143 * and holds no claim on it), and `-EINVAL` if `ptr` is not a valid pointer
144 * into a live heap allocation.
145 */
146int __cheri_compartment("allocator")
147 heap_can_free(AllocatorCapability heapCapability, void *ptr);
148
149/**
150 * Returns the space available in the given quota. This will return `-EPERM` if
151 * `heapCapability` is not valid or `-ENOTENOUGHSTACK` if the stack is
152 * insufficient to run the function.
153 */
154ssize_t __cheri_compartment("allocator")
155 heap_quota_remaining(AllocatorCapability heapCapability);
156
157/**
158 * Try to empty the quarantine and defragment the heap.
159 *
160 * This will (finish and then) run a revocation sweep and try to empty the
161 * quarantine. In normal operation, the allocator will remove a small number of
162 * allocations from quarantine on each allocation. Allocations are not
163 * coalesced until they are moved from quarantine, so this can cause
164 * fragmentation. If you have just freed a lot of memory (for example, after
165 * resetting a compartment and calling `heap_free_all`), especially if you have
166 * freed a lot of small allocations, then calling this function will likely
167 * reduce fragmentation.
168 *
169 * Calling this function will ensure that all objects freed before the call are
170 * out of quarantine (unless a timeout occurs). Objects freed concurrently (by
171 * another thread) may remain in quarantine, so this does not guarantee that
172 * the quarantine is empty, only that everything freed by this thread is
173 * removed from quarantine.
174 *
175 * Returns 0 on success, a compartment invocation failure indication
176 * (`-ENOTENOUGHSTACK`, `-ENOTENOUGHTRUSTEDSTACK`) if it cannot be invoked, or
177 * possibly `-ECOMPARTMENTFAIL` if the allocator compartment is damaged.
178 *
179 * Returns `-ETIMEDOUT` if the timeout expires or `-EINVAL` if the timeout is
180 * not valid.
181 */
182__attribute__((overloadable)) int __cheri_compartment("allocator")
183 heap_quarantine_flush(TimeoutArgument timeout);
184
185/**
186 * Run `heap_quarantine_flush` with unlimited timeout.
187 *
188 * This is guaranteed to terminate (barring bugs), but, as with most
189 * unlimited-timeout operation, should be confined to debug or test code.
190 */
195
196/**
197 * Dump a textual rendering of the heap's structure to the debug console.
198 *
199 * If the RTOS is not built with --allocator-rendering=y, this is a no-op.
200 *
201 * Returns zero on success, non-zero on error (e.g. compartment call failure).
202 */
203int __cheri_compartment("allocator") heap_render();
204
205/**
206 * Returns the total available space in the heap. This counts free space but
207 * does not account for quota restrictions.
208 */
209size_t __cheri_compartment("allocator") heap_available(void);
210
211__END_DECLS
int heap_quarantine_flush(TimeoutArgument timeout)
Try to empty the quarantine and defragment the heap.
static int heap_quarantine_empty()
Run heap_quarantine_flush with unlimited timeout.
Definition allocator.h:191
static AllocatorCapability allocator_permissions_and(AllocatorCapability heapCapability, int permissions)
Returns a copy of heapCapability with a subset of permissions.
Definition allocator.h:72
size_t heap_available(void)
Returns the total available space in the heap.
ssize_t heap_free_all(AllocatorCapability heapCapability)
Free all allocations owned by this capability.
AllocatorPermission
Permission bits for allocator capabilities.
Definition allocator.h:28
@ AllocatorPermitUnused
Unused permissions bit.
Definition allocator.h:47
@ AllocatorPermitFreeAll
This allocator capability may be used to free all allocations made using its quota via heap_free_all.
Definition allocator.h:43
@ AllocatorPermitAllocate
This allocator capability may be used to perform allocations and make claims using its quota.
Definition allocator.h:38
@ AllocatorPermitFull
This allocator capability is fully permissioned.
Definition allocator.h:52
@ AllocatorPermitNone
This allocator capability is fully de-permissioned.
Definition allocator.h:33
int heap_render()
Dump a textual rendering of the heap's structure to the debug console.
static int allocator_permissions(AllocatorCapability heapCapability)
Returns the permissions held by this allocator capability.
Definition allocator.h:60
ssize_t heap_quota_remaining(AllocatorCapability heapCapability)
Returns the space available in the given quota.
ssize_t heap_claim(AllocatorCapability heapCapability, void *pointer)
Add a claim to an allocation.
int __cheri_libcall heap_claim_ephemeral(TimeoutArgument timeout, const void *ptr, const void *ptr2)
Interface to the ephemeral claims mechanism.
int heap_can_free(AllocatorCapability heapCapability, void *ptr)
Returns 0 if the allocation can be freed with the given capability, -EPERM if heapCapability is not v...
The public view of state represented by a capability that is used to authorise heap allocations.
Definition stdlib.h:35
This file contains the types used for timeouts across scheduler APIs.
static const AbsoluteMonotonicTimeout TimeoutWaitForever
Timeout value for unlimited blocking.
Definition timeout.h:31
APIs for dealing with type-safe opaque handles (sealed objects).
static int token_permissions_get(CHERI_SEALED(void *) object)
Returns the user permissions bitmap for the sealed object.
Definition token.h:160
token_permissions_and(CHERI_SEALED(T *) object, int permissions)
Mask the user permissions of a sealed object.
Definition token.h:148