Expand description
Support for processes granting memory from their allocations to the kernel.
Grant Overview
Grants allow capsules to dynamically allocate memory from a process to hold state on the process’s behalf.
Each capsule that wishes to do this needs to have a Grant
type. Grant
s
are created at boot, and each have a unique ID and a type T
. This type
only allows the capsule to allocate memory from a process in the future. It
does not initially represent any allocated memory.
When a capsule does wish to use its Grant
to allocate memory from a
process, it must “enter” the Grant
with a specific ProcessId
. Entering a
Grant
for a specific process instructs the core kernel to create an object
T
in the process’s memory space and provide the capsule with access to it.
If the Grant
has not previously been entered for that process, the memory
for object T
will be allocated from the “grant region” within the
kernel-accessible portion of the process’s memory.
If a Grant
has never been entered for a process, the object T
will not
be allocated in that process’s grant region, even if the Grant
has been
entered for other processes.
Upcalls and allowed buffer references are stored in the dynamically
allocated grant for a particular Driver as well. Upcalls and allowed buffer
references are stored outside of the T
object to enable the kernel to
manage them and ensure swapping guarantees are met.
The type T
of a Grant
is fixed in size and the number of upcalls and
allowed buffers associated with a grant is fixed. That is, when a Grant
is
entered for a process the resulting allocated object will be the size of
SizeOf<T>
plus the size for the structure to hold upcalls and allowed
buffer references. If capsules need additional process-specific memory for
their operation, they can use an Allocator
to request additional memory
from the process’s grant region.
┌──────────────────┐
│ │
│ Capsule │
│ │
└─┬────────────────┘
│ Capsules hold
│ references to
│ grants.
▼
┌──────────────────┐
│ Grant │
│ │
Process Memory │ Type: T │
┌────────────────────────┐ │ grant_num: 1 │
│ │ │ driver_num: 0x4 │
│ ... │ └───┬─────────────┬┘
├────────────────────────┤ │Each Grant │
│ Grant ptr 0 │ │has a pointer│
│ Pointers ptr 1 ───┐ │ ◄───┘per process. │
│ ... │ │ │
│ ptr N │ │ │
├──────────────────────┼─┤ │
│ ... │ │ │
├──────────────────────┼─┤ │
│ Grant Region │ │ When a Grant │
│ │ │ is allocated │
│ ┌─────────────────┐ │ │ for a process │
│ │ Allocated Grant │ │ │ ◄─────────────────┘
│ │ │ │ │ it uses memory
│ │ [ SizeOf<T> ] │ │ │ from the grant
│ │─────────────────│ │ │ region.
│ │ Padding │ │ │
│ │─────────────────│ │ │
│ │ GrantKernelData │ │ │
│ └─────────────────┘◄─┘ │
│ │
│ ┌─────────────────┐ │
│ │ Custom Grant │ │ ◄── Capsules can
│ │ │ │ allocate extra
│ └─────────────────┘ │ memory if needed.
│ │
├─kernel_brk─────────────┤
│ │
│ ... │
└────────────────────────┘
Grant Mechanisms and Types
Here is an overview of the types used by grant.rs to implement the Grant functionality in Tock:
┌──────────────────────────┐
│ struct Grant<T, ...> { │
│ driver_num: usize │
│ grant_num: usize │
│ } ├───┐
Entering a Grant for a └──┬───────────────────────┘ │
process causes the │ │
memory for T to be │ .enter(ProcessId) │ .enter(ProcessId, fn)
allocated. ▼ │
┌──────────────────────────┐ │ For convenience,
ProcessGrant represents │ struct ProcessGrant<T> { │ │ allocating and getting
a Grant allocated for a │ number: usize │ │ access to the T object
specific process. │ process: &Process │ │ is combined in one
│ } │ │ .enter() call.
A provided closure └──┬───────────────────────┘ │
is given access to │ │
the underlying memory │ .enter(fn) │
where the T is stored. ▼ │
┌────────────────────────────┐ │
GrantData wraps the │ struct GrantData<T> { │◄┘
type and provides │ data: &mut T │
mutable access. │ } │
GrantKernelData │ struct GrantKernelData { │
provides access to │ upcalls: [SavedUpcall] │
scheduling upcalls │ allow_ro: [SavedAllowRo] │
and process buffers. │ allow_rw: [SavedAllowRW] │
│ } │
└──┬─────────────────────────┘
The actual object T can │
only be accessed inside │ fn(mem: &GrantData, kernel_data: &GrantKernelData)
the closure. ▼
Structs
Grant
.ProcessGrant
s across processes.