kernel/grant.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Support for processes granting memory from their allocations to the kernel.
6//!
7//! ## Grant Overview
8//!
9//! Grants allow capsules to dynamically allocate memory from a process to hold
10//! state on the process's behalf.
11//!
12//! Each capsule that wishes to do this needs to have a [`Grant`] type. Grants
13//! are created at boot, and each have a unique ID and a type `T`. This type
14//! only allows the capsule to allocate memory from a process in the future. It
15//! does not initially represent any allocated memory.
16//!
17//! When a capsule does wish to use its Grant to allocate memory from a process,
18//! it must "enter" the Grant with a specific [`ProcessId`]. Entering a Grant
19//! for a specific process instructs the core kernel to create an object `T` in
20//! the process's memory space and provide the capsule with access to it. If the
21//! Grant has not previously been entered for that process, the memory for
22//! object `T` will be allocated from the "grant region" within the
23//! kernel-accessible portion of the process's memory.
24//!
25//! If a Grant has never been entered for a process, the object `T` will _not_
26//! be allocated in that process's grant region, even if the `Grant` has been
27//! entered for other processes.
28//!
29//! Upcalls and allowed buffer references are stored in the dynamically
30//! allocated grant for a particular Driver as well. Upcalls and allowed buffer
31//! references are stored outside of the `T` object to enable the kernel to
32//! manage them and ensure swapping guarantees are met.
33//!
34//! The type `T` of a Grant is fixed in size and the number of upcalls and
35//! allowed buffers associated with a grant is fixed. That is, when a Grant is
36//! entered for a process the resulting allocated object will be the size of
37//! `SizeOf<T>` plus the size for the structure to hold upcalls and allowed
38//! buffer references. If capsules need additional process-specific memory for
39//! their operation, they can use an [`GrantRegionAllocator`] to request
40//! additional memory from the process's grant region.
41//!
42//! ```text,ignore
43//! ┌──────────────────┐
44//! │ │
45//! │ Capsule │
46//! │ │
47//! └─┬────────────────┘
48//! │ Capsules hold
49//! │ references to
50//! │ grants.
51//! ▼
52//! ┌──────────────────┐
53//! │ Grant │
54//! │ │
55//! Process Memory │ Type: T │
56//! ┌────────────────────────┐ │ grant_num: 1 │
57//! │ │ │ driver_num: 0x4 │
58//! │ ... │ └───┬─────────────┬┘
59//! ├────────────────────────┤ │Each Grant │
60//! │ Grant ptr 0 │ │has a pointer│
61//! │ Pointers ptr 1 ───┐ │ ◄───┘per process. │
62//! │ ... │ │ │
63//! │ ptr N │ │ │
64//! ├──────────────────────┼─┤ │
65//! │ ... │ │ │
66//! ├──────────────────────┼─┤ │
67//! │ Grant Region │ │ When a Grant │
68//! │ │ │ is allocated │
69//! │ ┌─────────────────┐ │ │ for a process │
70//! │ │ Allocated Grant │ │ │ ◄─────────────────┘
71//! │ │ │ │ │ it uses memory
72//! │ │ [ SizeOf<T> ] │ │ │ from the grant
73//! │ │─────────────────│ │ │ region.
74//! │ │ Padding │ │ │
75//! │ │─────────────────│ │ │
76//! │ │ GrantKernelData │ │ │
77//! │ └─────────────────┘◄─┘ │
78//! │ │
79//! │ ┌─────────────────┐ │
80//! │ │ Custom Grant │ │ ◄── Capsules can
81//! │ │ │ │ allocate extra
82//! │ └─────────────────┘ │ memory if needed.
83//! │ │
84//! ├─kernel_brk─────────────┤
85//! │ │
86//! │ ... │
87//! └────────────────────────┘
88//! ```
89//!
90//! ## Grant Mechanisms and Types
91//!
92//! Here is an overview of the types used by grant.rs to implement the Grant
93//! functionality in Tock:
94//!
95//! ```text,ignore
96//! ┌──────────────────────────┐
97//! │ struct Grant<T, ...> { │
98//! │ driver_num: usize │
99//! │ grant_num: usize │
100//! │ } ├───┐
101//! Entering a Grant for a └──┬───────────────────────┘ │
102//! process causes the │ │
103//! memory for T to be │ .enter(ProcessId) │ .enter(ProcessId, fn)
104//! allocated. ▼ │
105//! ┌──────────────────────────┐ │ For convenience,
106//! ProcessGrant represents │ struct ProcessGrant<T> { │ │ allocating and getting
107//! a Grant allocated for a │ number: usize │ │ access to the T object
108//! specific process. │ process: &Process │ │ is combined in one
109//! │ } │ │ .enter() call.
110//! A provided closure └──┬───────────────────────┘ │
111//! is given access to │ │
112//! the underlying memory │ .enter(fn) │
113//! where the T is stored. ▼ │
114//! ┌────────────────────────────┐ │
115//! GrantData wraps the │ struct GrantData<T> { │◄┘
116//! type and provides │ data: &mut T │
117//! mutable access. │ } │
118//! GrantKernelData │ struct GrantKernelData { │
119//! provides access to │ upcalls: [SavedUpcall] │
120//! scheduling upcalls │ allow_ro: [SavedAllowRo] │
121//! and process buffers. │ allow_rw: [SavedAllowRW] │
122//! │ } │
123//! └──┬─────────────────────────┘
124//! The actual object T can │
125//! only be accessed inside │ fn(mem: &GrantData, kernel_data: &GrantKernelData)
126//! the closure. ▼
127//! ```
128
129use core::cmp;
130use core::marker::PhantomData;
131use core::mem::{align_of, size_of};
132use core::ops::{Deref, DerefMut};
133use core::ptr::{write, NonNull};
134use core::slice;
135
136use crate::kernel::Kernel;
137use crate::process::{Error, Process, ProcessCustomGrantIdentifier, ProcessId};
138use crate::processbuffer::{ReadOnlyProcessBuffer, ReadWriteProcessBuffer};
139use crate::processbuffer::{ReadOnlyProcessBufferRef, ReadWriteProcessBufferRef};
140use crate::upcall::{Upcall, UpcallError, UpcallId};
141use crate::utilities::capability_ptr::CapabilityPtr;
142use crate::utilities::machine_register::MachineRegister;
143use crate::ErrorCode;
144
145/// Tracks how many upcalls a grant instance supports automatically.
146pub trait UpcallSize {
147 /// The number of upcalls the grant supports.
148 const COUNT: u8;
149}
150
151/// Specifies how many upcalls a grant instance supports automatically.
152pub struct UpcallCount<const NUM: u8>;
153impl<const NUM: u8> UpcallSize for UpcallCount<NUM> {
154 const COUNT: u8 = NUM;
155}
156
157/// Tracks how many read-only allows a grant instance supports automatically.
158pub trait AllowRoSize {
159 /// The number of read-only allows the grant supports.
160 const COUNT: u8;
161}
162
163/// Specifies how many read-only allows a grant instance supports automatically.
164pub struct AllowRoCount<const NUM: u8>;
165impl<const NUM: u8> AllowRoSize for AllowRoCount<NUM> {
166 const COUNT: u8 = NUM;
167}
168
169/// Tracks how many read-write allows a grant instance supports automatically.
170pub trait AllowRwSize {
171 /// The number of read-write allows the grant supports.
172 const COUNT: u8;
173}
174
175/// Specifies how many read-write allows a grant instance supports
176/// automatically.
177pub struct AllowRwCount<const NUM: u8>;
178impl<const NUM: u8> AllowRwSize for AllowRwCount<NUM> {
179 const COUNT: u8 = NUM;
180}
181
182/// Helper that calculated offsets within the kernel owned memory (i.e. the
183/// non-T part of grant).
184///
185/// Example layout of full grant belonging to a single app and driver:
186///
187/// ```text,ignore
188/// 0x003FFC8 ┌────────────────────────────────────┐
189/// │ T |
190/// 0x003FFxx ├ ───────────────────────── ┐ K |
191/// │ Padding (ensure T aligns)| e |
192/// 0x003FF44 ├ ───────────────────────── | r |
193/// │ SavedAllowRwN | n |
194/// │ ... | e | G
195/// │ SavedAllowRw1 | l | r
196/// │ SavedAllowRw0 | | a
197/// 0x003FF44 ├ ───────────────────────── | O | n
198/// │ SavedAllowRoN | w | t
199/// │ ... | n |
200/// │ SavedAllowRo1 | e | M
201/// │ SavedAllowRo0 | d | e
202/// 0x003FF30 ├ ───────────────────────── | | m
203/// │ SavedUpcallN | D | o
204/// │ ... | a | r
205/// │ SavedUpcall1 | t | y
206/// │ SavedUpcall0 | a |
207/// 0x003FF24 ├ ───────────────────────── | |
208/// │ Counters (usize) | |
209/// 0x003FF20 └────────────────────────────────────┘
210/// ```
211///
212/// The counters structure is composed as:
213///
214/// ```text,ignore
215/// 0 1 2 3 bytes
216/// |-------------|-------------|-------------|-------------|
217/// | # Upcalls | # RO Allows | # RW Allows | [unused] |
218/// |-------------|-------------|-------------|-------------|
219/// ```
220///
221/// This type is created whenever a grant is entered, and is responsible for
222/// ensuring that the grant is closed when it is no longer used. On `Drop`, we
223/// leave the grant. This protects against calling `grant.enter()` without
224/// calling the corresponding `grant.leave()`, perhaps due to accidentally using
225/// the `?` operator.
226struct EnteredGrantKernelManagedLayout<'a> {
227 /// Leaving a grant is handled through the process implementation, so must
228 /// keep a reference to the relevant process.
229 process: &'a dyn Process,
230 /// The grant number of the entered grant that we want to ensure we leave
231 /// properly.
232 grant_num: usize,
233
234 /// The location of the counters structure for the grant.
235 counters_ptr: *mut usize,
236 /// Pointer to the array of saved upcalls.
237 upcalls_array: *mut SavedUpcall,
238 /// Pointer to the array of saved read-only allows.
239 allow_ro_array: *mut SavedAllowRo,
240 /// Pointer to the array of saved read-write allows.
241 allow_rw_array: *mut SavedAllowRw,
242}
243
244/// Represents the number of the upcall elements in the kernel owned section of
245/// the grant.
246#[derive(Copy, Clone)]
247struct UpcallItems(u8);
248/// Represents the number of the read-only allow elements in the kernel owned
249/// section of the grant.
250#[derive(Copy, Clone)]
251struct AllowRoItems(u8);
252/// Represents the number of the read-write allow elements in the kernel owned
253/// section of the grant.
254#[derive(Copy, Clone)]
255struct AllowRwItems(u8);
256/// Represents the size data (in bytes) T within the grant.
257#[derive(Copy, Clone)]
258struct GrantDataSize(usize);
259/// Represents the alignment of data T within the grant.
260#[derive(Copy, Clone)]
261struct GrantDataAlign(usize);
262
263impl<'a> EnteredGrantKernelManagedLayout<'a> {
264 /// Reads the specified pointer as the base of the kernel owned grant region
265 /// that has previously been initialized.
266 ///
267 /// # Safety
268 ///
269 /// The incoming base pointer must be well aligned and already contain
270 /// initialized data in the expected form. There must not be any other
271 /// `EnteredGrantKernelManagedLayout` for the given `base_ptr` at the same
272 /// time, otherwise multiple mutable references to the same upcall/allow
273 /// slices could be created.
274 unsafe fn read_from_base(
275 base_ptr: NonNull<u8>,
276 process: &'a dyn Process,
277 grant_num: usize,
278 ) -> Self {
279 let counters_ptr = base_ptr.as_ptr() as *mut usize;
280 let counters_val = counters_ptr.read();
281
282 // Parse the counters field for each of the fields
283 let [_, _, allow_ro_num, upcalls_num] = u32::to_be_bytes(counters_val as u32);
284
285 // Skip over the counter usize, then the stored array of `SavedAllowRo`
286 // items and `SavedAllowRw` items.
287 let upcalls_array = counters_ptr.add(1) as *mut SavedUpcall;
288 let allow_ro_array = upcalls_array.add(upcalls_num as usize) as *mut SavedAllowRo;
289 let allow_rw_array = allow_ro_array.add(allow_ro_num as usize) as *mut SavedAllowRw;
290
291 Self {
292 process,
293 grant_num,
294 counters_ptr,
295 upcalls_array,
296 allow_ro_array,
297 allow_rw_array,
298 }
299 }
300
301 /// Creates a layout from the specified pointer and lengths of arrays and
302 /// initializes the kernel owned portion of the layout.
303 ///
304 /// # Safety
305 ///
306 /// The incoming base pointer must be well aligned and reference enough
307 /// memory to hold the entire kernel managed grant structure. There must
308 /// not be any other `EnteredGrantKernelManagedLayout` for
309 /// the given `base_ptr` at the same time, otherwise multiple mutable
310 /// references to the same upcall/allow slices could be created.
311 unsafe fn initialize_from_counts(
312 base_ptr: NonNull<u8>,
313 upcalls_num_val: UpcallItems,
314 allow_ro_num_val: AllowRoItems,
315 allow_rw_num_val: AllowRwItems,
316 process: &'a dyn Process,
317 grant_num: usize,
318 ) -> Self {
319 let counters_ptr = base_ptr.as_ptr() as *mut usize;
320
321 // Create the counters usize value by correctly packing the various
322 // counts into 8 bit fields.
323 let counter: usize =
324 u32::from_be_bytes([0, allow_rw_num_val.0, allow_ro_num_val.0, upcalls_num_val.0])
325 as usize;
326
327 let upcalls_array = counters_ptr.add(1) as *mut SavedUpcall;
328 let allow_ro_array = upcalls_array.add(upcalls_num_val.0.into()) as *mut SavedAllowRo;
329 let allow_rw_array = allow_ro_array.add(allow_ro_num_val.0.into()) as *mut SavedAllowRw;
330
331 counters_ptr.write(counter);
332 write_default_array(upcalls_array, upcalls_num_val.0.into());
333 write_default_array(allow_ro_array, allow_ro_num_val.0.into());
334 write_default_array(allow_rw_array, allow_rw_num_val.0.into());
335
336 Self {
337 process,
338 grant_num,
339 counters_ptr,
340 upcalls_array,
341 allow_ro_array,
342 allow_rw_array,
343 }
344 }
345
346 /// Returns the entire grant size including the kernel owned memory,
347 /// padding, and data for T. Requires that grant_t_align be a power of 2,
348 /// which is guaranteed from align_of rust calls.
349 fn grant_size(
350 upcalls_num: UpcallItems,
351 allow_ro_num: AllowRoItems,
352 allow_rw_num: AllowRwItems,
353 grant_t_size: GrantDataSize,
354 grant_t_align: GrantDataAlign,
355 ) -> usize {
356 let kernel_managed_size = size_of::<usize>()
357 + upcalls_num.0 as usize * size_of::<SavedUpcall>()
358 + allow_ro_num.0 as usize * size_of::<SavedAllowRo>()
359 + allow_rw_num.0 as usize * size_of::<SavedAllowRw>();
360 // We know that grant_t_align is a power of 2, so we can make a mask
361 // that will save only the remainder bits.
362 let grant_t_align_mask = grant_t_align.0 - 1;
363 // Determine padding to get to the next multiple of grant_t_align by
364 // taking the remainder and subtracting that from the alignment, then
365 // ensuring a full alignment value maps to 0.
366 let padding =
367 (grant_t_align.0 - (kernel_managed_size & grant_t_align_mask)) & grant_t_align_mask;
368 kernel_managed_size + padding + grant_t_size.0
369 }
370
371 /// Returns the alignment of the entire grant region based on the alignment
372 /// of data T.
373 fn grant_align(grant_t_align: GrantDataAlign) -> usize {
374 // The kernel owned memory all aligned to usize. We need to use the
375 // higher of the two alignment to ensure our padding calculations work
376 // for any alignment of T.
377 cmp::max(align_of::<usize>(), grant_t_align.0)
378 }
379
380 /// Returns the offset for the grant data t within the entire grant region.
381 ///
382 /// # Safety
383 ///
384 /// The caller must ensure that the specified base pointer is aligned to at
385 /// least the alignment of T and points to a grant that is of size
386 /// grant_size bytes.
387 unsafe fn offset_of_grant_data_t(
388 base_ptr: NonNull<u8>,
389 grant_size: usize,
390 grant_t_size: GrantDataSize,
391 ) -> NonNull<u8> {
392 // The location of the grant data T is the last element in the entire
393 // grant region. Caller must verify that memory is accessible and well
394 // aligned to T.
395 let grant_t_size_usize: usize = grant_t_size.0;
396 NonNull::new_unchecked(base_ptr.as_ptr().add(grant_size - grant_t_size_usize))
397 }
398
399 /// Read an 8 bit value from the counter field offset by the specified
400 /// number of bits. This is a helper function for reading the counter field.
401 fn get_counter_offset(&self, offset_bits: usize) -> usize {
402 // # Safety
403 //
404 // Creating a `EnteredGrantKernelManagedLayout` object requires that the
405 // pointers are well aligned and point to valid memory.
406 let counters_val = unsafe { self.counters_ptr.read() };
407 (counters_val >> offset_bits) & 0xFF
408 }
409
410 /// Return the number of upcalls stored by the core kernel for this grant.
411 fn get_upcalls_number(&self) -> usize {
412 self.get_counter_offset(0)
413 }
414
415 /// Return the number of read-only allow buffers stored by the core kernel
416 /// for this grant.
417 fn get_allow_ro_number(&self) -> usize {
418 self.get_counter_offset(8)
419 }
420
421 /// Return the number of read-write allow buffers stored by the core kernel
422 /// for this grant.
423 fn get_allow_rw_number(&self) -> usize {
424 self.get_counter_offset(16)
425 }
426
427 /// Return mutable access to the slice of stored upcalls for this grant.
428 /// This is necessary for storing a new upcall.
429 fn get_upcalls_slice(&mut self) -> &mut [SavedUpcall] {
430 // # Safety
431 //
432 // Creating a `EnteredGrantKernelManagedLayout` object ensures that the
433 // pointer to the upcall array is valid.
434 unsafe { slice::from_raw_parts_mut(self.upcalls_array, self.get_upcalls_number()) }
435 }
436
437 /// Return mutable access to the slice of stored read-only allow buffers for
438 /// this grant. This is necessary for storing a new read-only allow.
439 fn get_allow_ro_slice(&mut self) -> &mut [SavedAllowRo] {
440 // # Safety
441 //
442 // Creating a `EnteredGrantKernelManagedLayout` object ensures that the
443 // pointer to the RO allow array is valid.
444 unsafe { slice::from_raw_parts_mut(self.allow_ro_array, self.get_allow_ro_number()) }
445 }
446
447 /// Return mutable access to the slice of stored read-write allow buffers
448 /// for this grant. This is necessary for storing a new read-write allow.
449 fn get_allow_rw_slice(&mut self) -> &mut [SavedAllowRw] {
450 // # Safety
451 //
452 // Creating a `EnteredGrantKernelManagedLayout` object ensures that the
453 // pointer to the RW allow array is valid.
454 unsafe { slice::from_raw_parts_mut(self.allow_rw_array, self.get_allow_rw_number()) }
455 }
456
457 /// Return slices to the kernel managed upcalls and allow buffers. This
458 /// permits using upcalls and allow buffers when a capsule is accessing a
459 /// grant.
460 fn get_resource_slices(&self) -> (&[SavedUpcall], &[SavedAllowRo], &[SavedAllowRw]) {
461 // # Safety
462 //
463 // Creating a `EnteredGrantKernelManagedLayout` object ensures that the
464 // pointer to the upcall array is valid.
465 let upcall_slice =
466 unsafe { slice::from_raw_parts(self.upcalls_array, self.get_upcalls_number()) };
467
468 // # Safety
469 //
470 // Creating a `EnteredGrantKernelManagedLayout` object ensures that the
471 // pointer to the RO allow array is valid.
472 let allow_ro_slice =
473 unsafe { slice::from_raw_parts(self.allow_ro_array, self.get_allow_ro_number()) };
474
475 // # Safety
476 //
477 // Creating a `KernelManagedLayout` object ensures that the pointer to
478 // the RW allow array is valid.
479 let allow_rw_slice =
480 unsafe { slice::from_raw_parts(self.allow_rw_array, self.get_allow_rw_number()) };
481
482 (upcall_slice, allow_ro_slice, allow_rw_slice)
483 }
484}
485
486// Ensure that we leave the grant once this goes out of scope.
487impl Drop for EnteredGrantKernelManagedLayout<'_> {
488 fn drop(&mut self) {
489 // ### Safety
490 //
491 // To safely call this function we must ensure that no references will
492 // exist to the grant once `leave_grant()` returns. Because using a
493 // `EnteredGrantKernelManagedLayout` object is the only only way we
494 // access the actual memory of a grant, and we are calling
495 // `leave_grant()` from its `drop()` method, we are sure there will be
496 // no remaining references to the grant.
497 unsafe {
498 self.process.leave_grant(self.grant_num);
499 }
500 }
501}
502
503/// This [`GrantData`] object provides access to the memory allocated for a
504/// grant for a specific process.
505///
506/// The [`GrantData`] type is templated on `T`, the actual type of the object in
507/// the grant. [`GrantData'] holds a mutable reference to the type, allowing
508/// users access to the object in process memory.
509///
510/// Capsules gain access to a [`GrantData`] object by calling
511/// [`Grant::enter()`].
512pub struct GrantData<'a, T: 'a + ?Sized> {
513 /// The mutable reference to the actual object type stored in the grant.
514 data: &'a mut T,
515}
516
517impl<'a, T: 'a + ?Sized> GrantData<'a, T> {
518 /// Create a [`GrantData`] object to provide access to the actual object
519 /// allocated for a process.
520 ///
521 /// Only one can [`GrantData`] per underlying object can be created at a
522 /// time. Otherwise, there would be multiple mutable references to the same
523 /// object which is undefined behavior.
524 fn new(data: &'a mut T) -> GrantData<'a, T> {
525 GrantData { data }
526 }
527}
528
529impl<'a, T: 'a + ?Sized> Deref for GrantData<'a, T> {
530 type Target = T;
531 fn deref(&self) -> &T {
532 self.data
533 }
534}
535
536impl<'a, T: 'a + ?Sized> DerefMut for GrantData<'a, T> {
537 fn deref_mut(&mut self) -> &mut T {
538 self.data
539 }
540}
541
542/// This [`GrantKernelData`] object provides a handle to access upcalls and
543/// process buffers stored on behalf of a particular grant/driver.
544///
545/// Capsules gain access to a [`GrantKernelData`] object by calling
546/// [`Grant::enter()`]. From there, they can schedule upcalls or access process
547/// buffers.
548///
549/// It is expected that this type will only exist as a short-lived stack
550/// allocation, so its size is not a significant concern.
551pub struct GrantKernelData<'a> {
552 /// A reference to the actual upcall slice stored in the grant.
553 upcalls: &'a [SavedUpcall],
554
555 /// A reference to the actual read only allow slice stored in the grant.
556 allow_ro: &'a [SavedAllowRo],
557
558 /// A reference to the actual read write allow slice stored in the grant.
559 allow_rw: &'a [SavedAllowRw],
560
561 /// We need to keep track of the driver number so we can properly identify
562 /// the Upcall that is called. We need to keep track of its source so we can
563 /// remove it if the Upcall is unsubscribed.
564 driver_num: usize,
565
566 /// A reference to the process that these upcalls are for. This is used for
567 /// actually scheduling the upcalls.
568 process: &'a dyn Process,
569}
570
571impl<'a> GrantKernelData<'a> {
572 /// Create a [`GrantKernelData`] object to provide a handle for capsules to
573 /// call Upcalls.
574 fn new(
575 upcalls: &'a [SavedUpcall],
576 allow_ro: &'a [SavedAllowRo],
577 allow_rw: &'a [SavedAllowRw],
578 driver_num: usize,
579 process: &'a dyn Process,
580 ) -> GrantKernelData<'a> {
581 Self {
582 upcalls,
583 allow_ro,
584 allow_rw,
585 driver_num,
586 process,
587 }
588 }
589
590 /// Schedule the specified upcall for the process with r0, r1, r2 as
591 /// provided values.
592 ///
593 /// Capsules call this function to schedule upcalls, and upcalls are
594 /// identified by the `subscribe_num`, which must match the subscribe number
595 /// used when the upcall was originally subscribed by a process.
596 /// `subscribe_num`s are indexed starting at zero.
597 pub fn schedule_upcall(
598 &self,
599 subscribe_num: usize,
600 r: (usize, usize, usize),
601 ) -> Result<(), UpcallError> {
602 // Implement `self.upcalls[subscribe_num]` without a chance of a panic.
603 self.upcalls.get(subscribe_num).map_or(
604 Err(UpcallError::InvalidSubscribeNum),
605 |saved_upcall| {
606 // We can create an `Upcall` object based on what is stored in
607 // the process grant and use that to add the upcall to the
608 // pending array for the process.
609 let upcall = Upcall::new(
610 self.process.processid(),
611 UpcallId {
612 subscribe_num,
613 driver_num: self.driver_num,
614 },
615 saved_upcall.appdata,
616 saved_upcall.fn_ptr,
617 );
618 upcall.schedule(self.process, r.0, r.1, r.2)
619 },
620 )
621 }
622
623 /// Search the work queue for the first pending operation with the given
624 /// `subscribe_num` and if one exists remove it from the task queue.
625 ///
626 /// Returns the associated [`Task`](crate::process::Task) if one was found, otherwise returns
627 /// [`None`].
628 pub fn remove_upcall(&self, subscribe_num: usize) -> Option<crate::process::Task> {
629 self.process.remove_upcall(UpcallId {
630 subscribe_num,
631 driver_num: self.driver_num,
632 })
633 }
634
635 /// Remove all scheduled upcalls with the given `subscribe_num` from the
636 /// task queue.
637 ///
638 /// Returns the number of removed upcalls.
639 pub fn remove_pending_upcalls(&self, subscribe_num: usize) -> usize {
640 self.process.remove_pending_upcalls(UpcallId {
641 subscribe_num,
642 driver_num: self.driver_num,
643 })
644 }
645
646 /// Returns a lifetime limited reference to the requested
647 /// [`ReadOnlyProcessBuffer`].
648 ///
649 /// The len of the returned [`ReadOnlyProcessBuffer`] must be checked by the
650 /// caller to ensure that a buffer has in fact been allocated. An
651 /// unallocated buffer will be returned as a [`ReadOnlyProcessBuffer`] of
652 /// length 0.
653 ///
654 /// The [`ReadOnlyProcessBuffer`] is only valid for as long as this object
655 /// is valid, i.e. the lifetime of the app enter closure.
656 ///
657 /// If the specified allow number is invalid, then a
658 /// [`crate::process::Error::AddressOutOfBounds`] will be returned. This
659 /// returns a [`crate::process::Error`] to allow for easy chaining of this
660 /// function with the `ReadOnlyProcessBuffer::enter()` function with
661 /// `and_then`.
662 pub fn get_readonly_processbuffer(
663 &self,
664 allow_ro_num: usize,
665 ) -> Result<ReadOnlyProcessBufferRef, crate::process::Error> {
666 self.allow_ro.get(allow_ro_num).map_or(
667 Err(crate::process::Error::AddressOutOfBounds),
668 |saved_ro| {
669 // # Safety
670 //
671 // This is the saved process buffer data has been validated to
672 // be wholly contained within this process before it was stored.
673 // The lifetime of the ReadOnlyProcessBuffer is bound to the
674 // lifetime of self, which correctly limits dereferencing this
675 // saved pointer to only when it is valid.
676 unsafe {
677 Ok(ReadOnlyProcessBufferRef::new(
678 saved_ro.ptr,
679 saved_ro.len,
680 self.process.processid(),
681 ))
682 }
683 },
684 )
685 }
686
687 /// Returns a lifetime limited reference to the requested
688 /// [`ReadWriteProcessBuffer`].
689 ///
690 /// The length of the returned [`ReadWriteProcessBuffer`] must be checked by
691 /// the caller to ensure that a buffer has in fact been allocated. An
692 /// unallocated buffer will be returned as a [`ReadWriteProcessBuffer`] of
693 /// length 0.
694 ///
695 /// The [`ReadWriteProcessBuffer`] is only value for as long as this object
696 /// is valid, i.e. the lifetime of the app enter closure.
697 ///
698 /// If the specified allow number is invalid, then a
699 /// [`crate::process::Error::AddressOutOfBounds`] will be returned. This
700 /// returns a [`crate::process::Error`] to allow for easy chaining of this
701 /// function with the `ReadWriteProcessBuffer::enter()` function with
702 /// `and_then`.
703 pub fn get_readwrite_processbuffer(
704 &self,
705 allow_rw_num: usize,
706 ) -> Result<ReadWriteProcessBufferRef, crate::process::Error> {
707 self.allow_rw.get(allow_rw_num).map_or(
708 Err(crate::process::Error::AddressOutOfBounds),
709 |saved_rw| {
710 // # Safety
711 //
712 // This is the saved process buffer data has been validated to
713 // be wholly contained within this process before it was stored.
714 // The lifetime of the ReadWriteProcessBuffer is bound to the
715 // lifetime of self, which correctly limits dereferencing this
716 // saved pointer to only when it is valid.
717 unsafe {
718 Ok(ReadWriteProcessBufferRef::new(
719 saved_rw.ptr,
720 saved_rw.len,
721 self.process.processid(),
722 ))
723 }
724 },
725 )
726 }
727}
728
729/// A minimal representation of an upcall, used for storing an upcall in a
730/// process' grant table without wasting memory duplicating information such as
731/// process ID.
732#[repr(C)]
733#[derive(Default)]
734struct SavedUpcall {
735 appdata: MachineRegister,
736 fn_ptr: CapabilityPtr,
737}
738
739/// A minimal representation of a read-only allow from app, used for storing a
740/// read-only allow in a process' kernel managed grant space without wasting
741/// memory duplicating information such as process ID.
742#[repr(C)]
743struct SavedAllowRo {
744 ptr: *const u8,
745 len: usize,
746}
747
748impl Default for SavedAllowRo {
749 fn default() -> Self {
750 Self {
751 ptr: core::ptr::null(),
752 len: 0,
753 }
754 }
755}
756
757/// A minimal representation of a read-write allow from app, used for storing a
758/// read-write allow in a process' kernel managed grant space without wasting
759/// memory duplicating information such as process ID.
760#[repr(C)]
761struct SavedAllowRw {
762 ptr: *mut u8,
763 len: usize,
764}
765
766impl Default for SavedAllowRw {
767 fn default() -> Self {
768 Self {
769 ptr: core::ptr::null_mut(),
770 len: 0,
771 }
772 }
773}
774
775/// Write the default value of T to every element of the array.
776///
777/// # Safety
778///
779/// The pointer must be well aligned and point to allocated memory that is
780/// writable for `size_of::<T> * num` bytes. No Rust references may exist to
781/// memory in the address range spanned by `base..base+num` at the time this
782/// function is called. The memory does not need to be initialized yet. If it
783/// already does contain initialized memory, then those contents will be
784/// overwritten without being `Drop`ed first.
785unsafe fn write_default_array<T: Default>(base: *mut T, num: usize) {
786 for i in 0..num {
787 base.add(i).write(T::default());
788 }
789}
790
791/// Enters the grant for the specified process. Caller must hold on to the grant
792/// lifetime guard while they accessing the memory in the layout (second
793/// element).
794fn enter_grant_kernel_managed(
795 process: &dyn Process,
796 driver_num: usize,
797) -> Result<EnteredGrantKernelManagedLayout, ErrorCode> {
798 let grant_num = process.lookup_grant_from_driver_num(driver_num)?;
799
800 // Check if the grant has been allocated, and if not we cannot enter this
801 // grant.
802 match process.grant_is_allocated(grant_num) {
803 Some(true) => { /* Allocated, nothing to do */ }
804 Some(false) => return Err(ErrorCode::NOMEM),
805 None => return Err(ErrorCode::FAIL),
806 }
807
808 // Return early if no grant.
809 let grant_base_ptr = process.enter_grant(grant_num).or(Err(ErrorCode::NOMEM))?;
810 // # Safety
811 //
812 // We know that this pointer is well aligned and initialized with meaningful
813 // data when the grant region was allocated.
814 let layout = unsafe {
815 EnteredGrantKernelManagedLayout::read_from_base(grant_base_ptr, process, grant_num)
816 };
817 Ok(layout)
818}
819
820/// Subscribe to an upcall by saving the upcall in the grant region for the
821/// process and returning the existing upcall for the same UpcallId.
822pub(crate) fn subscribe(
823 process: &dyn Process,
824 upcall: Upcall,
825) -> Result<Upcall, (Upcall, ErrorCode)> {
826 // Enter grant and keep it open until _grant_open goes out of scope.
827 let mut layout = match enter_grant_kernel_managed(process, upcall.upcall_id.driver_num) {
828 Ok(val) => val,
829 Err(e) => return Err((upcall, e)),
830 };
831
832 // Create the saved upcalls slice from the grant memory.
833 //
834 // # Safety
835 //
836 // This is safe because of how the grant was initially allocated and that
837 // because we were able to enter the grant the grant region must be valid
838 // and initialized. We are also holding the grant open until `_grant_open`
839 // goes out of scope.
840 let saved_upcalls_slice = layout.get_upcalls_slice();
841
842 // Index into the saved upcall slice to get the old upcall. Use .get in case
843 // userspace passed us a bad subscribe number.
844 match saved_upcalls_slice.get_mut(upcall.upcall_id.subscribe_num) {
845 Some(saved_upcall) => {
846 // Create an `Upcall` object with the old saved upcall.
847 let old_upcall = Upcall::new(
848 process.processid(),
849 upcall.upcall_id,
850 saved_upcall.appdata,
851 saved_upcall.fn_ptr,
852 );
853
854 // Overwrite the saved upcall with the new upcall.
855 saved_upcall.appdata = upcall.appdata;
856 saved_upcall.fn_ptr = upcall.fn_ptr;
857
858 // Success!
859 Ok(old_upcall)
860 }
861 None => Err((upcall, ErrorCode::NOSUPPORT)),
862 }
863}
864
865/// Stores the specified read-only process buffer in the kernel managed grant
866/// region for this process and driver. The previous read-only process buffer
867/// stored at the same allow_num id is returned.
868pub(crate) fn allow_ro(
869 process: &dyn Process,
870 driver_num: usize,
871 allow_num: usize,
872 buffer: ReadOnlyProcessBuffer,
873) -> Result<ReadOnlyProcessBuffer, (ReadOnlyProcessBuffer, ErrorCode)> {
874 // Enter grant and keep it open until `_grant_open` goes out of scope.
875 let mut layout = match enter_grant_kernel_managed(process, driver_num) {
876 Ok(val) => val,
877 Err(e) => return Err((buffer, e)),
878 };
879
880 // Create the saved allow ro slice from the grant memory.
881 //
882 // # Safety
883 //
884 // This is safe because of how the grant was initially allocated and that
885 // because we were able to enter the grant the grant region must be valid
886 // and initialized. We are also holding the grant open until _grant_open
887 // goes out of scope.
888 let saved_allow_ro_slice = layout.get_allow_ro_slice();
889
890 // Index into the saved slice to get the old value. Use .get in case
891 // userspace passed us a bad allow number.
892 match saved_allow_ro_slice.get_mut(allow_num) {
893 Some(saved) => {
894 // # Safety
895 //
896 // The pointer has already been validated to be within application
897 // memory before storing the values in the saved slice.
898 let old_allow =
899 unsafe { ReadOnlyProcessBuffer::new(saved.ptr, saved.len, process.processid()) };
900
901 // Replace old values with current buffer.
902 let (ptr, len) = buffer.consume();
903 saved.ptr = ptr;
904 saved.len = len;
905
906 // Success!
907 Ok(old_allow)
908 }
909 None => Err((buffer, ErrorCode::NOSUPPORT)),
910 }
911}
912
913/// Stores the specified read-write process buffer in the kernel managed grant
914/// region for this process and driver. The previous read-write process buffer
915/// stored at the same allow_num id is returned.
916pub(crate) fn allow_rw(
917 process: &dyn Process,
918 driver_num: usize,
919 allow_num: usize,
920 buffer: ReadWriteProcessBuffer,
921) -> Result<ReadWriteProcessBuffer, (ReadWriteProcessBuffer, ErrorCode)> {
922 // Enter grant and keep it open until `_grant_open` goes out of scope.
923 let mut layout = match enter_grant_kernel_managed(process, driver_num) {
924 Ok(val) => val,
925 Err(e) => return Err((buffer, e)),
926 };
927
928 // Create the saved allow rw slice from the grant memory.
929 //
930 // # Safety
931 //
932 // This is safe because of how the grant was initially allocated and that
933 // because we were able to enter the grant the grant region must be valid
934 // and initialized. We are also holding the grant open until `_grant_open`
935 // goes out of scope.
936 let saved_allow_rw_slice = layout.get_allow_rw_slice();
937
938 // Index into the saved slice to get the old value. Use .get in case
939 // userspace passed us a bad allow number.
940 match saved_allow_rw_slice.get_mut(allow_num) {
941 Some(saved) => {
942 // # Safety
943 //
944 // The pointer has already been validated to be within application
945 // memory before storing the values in the saved slice.
946 let old_allow =
947 unsafe { ReadWriteProcessBuffer::new(saved.ptr, saved.len, process.processid()) };
948
949 // Replace old values with current buffer.
950 let (ptr, len) = buffer.consume();
951 saved.ptr = ptr;
952 saved.len = len;
953
954 // Success!
955 Ok(old_allow)
956 }
957 None => Err((buffer, ErrorCode::NOSUPPORT)),
958 }
959}
960
961/// An instance of a grant allocated for a particular process.
962///
963/// [`ProcessGrant`] is a handle to an instance of a grant that has been
964/// allocated in a specific process's grant region. A [`ProcessGrant`]
965/// guarantees that the memory for the grant has been allocated in the process's
966/// memory.
967///
968/// This is created from a [`Grant`] when that grant is entered for a specific
969/// process.
970pub struct ProcessGrant<
971 'a,
972 T: 'a,
973 Upcalls: UpcallSize,
974 AllowROs: AllowRoSize,
975 AllowRWs: AllowRwSize,
976> {
977 /// The process the grant is applied to.
978 ///
979 /// We use a reference here because instances of [`ProcessGrant`] are very
980 /// short lived. They only exist while a [`Grant`] is being entered, so we
981 /// can be sure the process still exists while a `ProcessGrant` exists. No
982 /// [`ProcessGrant`] can be stored.
983 process: &'a dyn Process,
984
985 /// The syscall driver number this grant is associated with.
986 driver_num: usize,
987
988 /// The identifier of the Grant this is applied for.
989 grant_num: usize,
990
991 /// Used to store Rust types for grant.
992 _phantom: PhantomData<(T, Upcalls, AllowROs, AllowRWs)>,
993}
994
995impl<'a, T: Default, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize>
996 ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>
997{
998 /// Create a [`ProcessGrant`] for the given Grant in the given Process's
999 /// grant region.
1000 ///
1001 /// If the grant in this process has not been setup before this will attempt
1002 /// to allocate the memory from the process's grant region.
1003 ///
1004 /// # Return
1005 ///
1006 /// If the grant is already allocated or could be allocated, and the process
1007 /// is valid, this returns `Ok(ProcessGrant)`. Otherwise it returns a
1008 /// relevant error.
1009 fn new(
1010 grant: &Grant<T, Upcalls, AllowROs, AllowRWs>,
1011 processid: ProcessId,
1012 ) -> Result<Self, Error> {
1013 // Moves non-generic code from new() into non-generic function to reduce
1014 // code bloat from the generic function being monomorphized, as it is
1015 // common to have over 50 copies of Grant::enter() in a Tock kernel (and
1016 // thus 50+ copies of this function). The returned Option indicates if
1017 // the returned pointer still needs to be initialized (in the case where
1018 // the grant was only just allocated).
1019 fn new_inner<'a>(
1020 grant_num: usize,
1021 driver_num: usize,
1022 grant_t_size: GrantDataSize,
1023 grant_t_align: GrantDataAlign,
1024 num_upcalls: UpcallItems,
1025 num_allow_ros: AllowRoItems,
1026 num_allow_rws: AllowRwItems,
1027 processid: ProcessId,
1028 ) -> Result<(Option<NonNull<u8>>, &'a dyn Process), Error> {
1029 // Here is an example of how the grants are laid out in the grant
1030 // region of process's memory:
1031 //
1032 // Mem. Addr.
1033 // 0x0040000 ┌────────────────────────────────────
1034 // │ DriverNumN [0x1]
1035 // │ GrantPointerN [0x003FFC8]
1036 // │ ...
1037 // │ DriverNum1 [0x60000]
1038 // │ GrantPointer1 [0x003FFC0]
1039 // │ DriverNum0
1040 // │ GrantPointer0 [0x0000000 (NULL)]
1041 // ├────────────────────────────────────
1042 // │ Process Control Block
1043 // 0x003FFE0 ├──────────────────────────────────── Grant Region ┐
1044 // │ GrantDataN │
1045 // 0x003FFC8 ├──────────────────────────────────── │
1046 // │ GrantData1 ▼
1047 // 0x003FF20 ├────────────────────────────────────
1048 // │
1049 // │ --unallocated--
1050 // │
1051 // └────────────────────────────────────
1052 //
1053 // An array of pointers (one per possible grant region) point to
1054 // where the actual grant memory is allocated inside of the process.
1055 // The grant memory is not allocated until the actual grant region
1056 // is actually used.
1057
1058 let process = processid
1059 .kernel
1060 .get_process(processid)
1061 .ok_or(Error::NoSuchApp)?;
1062
1063 // Check if the grant is allocated. If not, we allocate it process
1064 // memory first. We then create an `ProcessGrant` object for this
1065 // grant.
1066 if let Some(is_allocated) = process.grant_is_allocated(grant_num) {
1067 if !is_allocated {
1068 // Calculate the alignment and size for entire grant region.
1069 let alloc_align = EnteredGrantKernelManagedLayout::grant_align(grant_t_align);
1070 let alloc_size = EnteredGrantKernelManagedLayout::grant_size(
1071 num_upcalls,
1072 num_allow_ros,
1073 num_allow_rws,
1074 grant_t_size,
1075 grant_t_align,
1076 );
1077
1078 // Allocate grant, the memory is still uninitialized though.
1079 if process
1080 .allocate_grant(grant_num, driver_num, alloc_size, alloc_align)
1081 .is_err()
1082 {
1083 return Err(Error::OutOfMemory);
1084 }
1085
1086 let grant_ptr = process.enter_grant(grant_num)?;
1087
1088 // Create a layout from the counts we have and initialize
1089 // all memory so it is valid in the future to read as a
1090 // reference.
1091 //
1092 // # Safety
1093 //
1094 // - The grant base pointer is well aligned, yet does not
1095 // have initialized data.
1096 // - The pointer points to a large enough space to correctly
1097 // write to is guaranteed by alloc of size
1098 // `EnteredGrantKernelManagedLayout::grant_size`.
1099 // - There are no proper rust references that map to these
1100 // addresses.
1101 unsafe {
1102 let _layout = EnteredGrantKernelManagedLayout::initialize_from_counts(
1103 grant_ptr,
1104 num_upcalls,
1105 num_allow_ros,
1106 num_allow_rws,
1107 process,
1108 grant_num,
1109 );
1110 }
1111
1112 // # Safety
1113 //
1114 // The grant pointer points to an alloc that is alloc_size
1115 // large and is at least as aligned as grant_t_align.
1116 unsafe {
1117 Ok((
1118 Some(EnteredGrantKernelManagedLayout::offset_of_grant_data_t(
1119 grant_ptr,
1120 alloc_size,
1121 grant_t_size,
1122 )),
1123 process,
1124 ))
1125 }
1126 } else {
1127 // T was already allocated, outer function should not
1128 // initialize T.
1129 Ok((None, process))
1130 }
1131 } else {
1132 // Cannot use the grant region in any way if the process is
1133 // inactive.
1134 Err(Error::InactiveApp)
1135 }
1136 }
1137
1138 // Handle the bulk of the work in a function which is not templated.
1139 let (opt_raw_grant_ptr_nn, process) = new_inner(
1140 grant.grant_num,
1141 grant.driver_num,
1142 GrantDataSize(size_of::<T>()),
1143 GrantDataAlign(align_of::<T>()),
1144 UpcallItems(Upcalls::COUNT),
1145 AllowRoItems(AllowROs::COUNT),
1146 AllowRwItems(AllowRWs::COUNT),
1147 processid,
1148 )?;
1149
1150 // We can now do the initialization of T object if necessary.
1151 if let Some(allocated_ptr) = opt_raw_grant_ptr_nn {
1152 // Grant type T
1153 //
1154 // # Safety
1155 //
1156 // This is safe because:
1157 //
1158 // 1. The pointer address is valid. The pointer is allocated
1159 // statically in process memory, and will exist for as long
1160 // as the process does. The grant is only accessible while
1161 // the process is still valid.
1162 //
1163 // 2. The pointer is correctly aligned. The newly allocated
1164 // grant is aligned for type T, and there is padding inserted
1165 // between the upcall array and the T object such that the T
1166 // object starts a multiple of `align_of<T>` from the
1167 // beginning of the allocation.
1168 unsafe {
1169 // Convert untyped `*mut u8` allocation to allocated type.
1170 let new_region = NonNull::cast::<T>(allocated_ptr);
1171 // We use `ptr::write` to avoid `Drop`ping the uninitialized
1172 // memory in case `T` implements the `Drop` trait.
1173 write(new_region.as_ptr(), T::default());
1174 }
1175 }
1176
1177 // We have ensured the grant is already allocated or was just allocated,
1178 // so we can create and return the `ProcessGrant` type.
1179 Ok(ProcessGrant {
1180 process,
1181 driver_num: grant.driver_num,
1182 grant_num: grant.grant_num,
1183 _phantom: PhantomData,
1184 })
1185 }
1186
1187 /// Return a [`ProcessGrant`] for a grant in a process if the process is
1188 /// valid and that process grant has already been allocated, or `None`
1189 /// otherwise.
1190 fn new_if_allocated(
1191 grant: &Grant<T, Upcalls, AllowROs, AllowRWs>,
1192 process: &'a dyn Process,
1193 ) -> Option<Self> {
1194 if let Some(is_allocated) = process.grant_is_allocated(grant.grant_num) {
1195 if is_allocated {
1196 Some(ProcessGrant {
1197 process,
1198 driver_num: grant.driver_num,
1199 grant_num: grant.grant_num,
1200 _phantom: PhantomData,
1201 })
1202 } else {
1203 // Grant has not been allocated.
1204 None
1205 }
1206 } else {
1207 // Process is invalid.
1208 None
1209 }
1210 }
1211
1212 /// Return the [`ProcessId`] of the process this [`ProcessGrant`] is
1213 /// associated with.
1214 pub fn processid(&self) -> ProcessId {
1215 self.process.processid()
1216 }
1217
1218 /// Run a function with access to the memory in the related process for the
1219 /// related Grant. This also provides access to any associated Upcalls and
1220 /// allowed buffers stored with the grant.
1221 ///
1222 /// This is "entering" the grant region, and the _only_ time when the
1223 /// contents of a grant region can be accessed.
1224 ///
1225 /// Note, a grant can only be entered once at a time. Attempting to call
1226 /// `.enter()` on a grant while it is already entered will result in a
1227 /// `panic!()`. See the comment in `access_grant()` for more information.
1228 pub fn enter<F, R>(self, fun: F) -> R
1229 where
1230 F: FnOnce(&mut GrantData<T>, &GrantKernelData) -> R,
1231 {
1232 // # `unwrap()` Safety
1233 //
1234 // `access_grant()` can only return `None` if the grant is already
1235 // entered. Since we are asking for a panic!() if the grant is entered,
1236 // `access_grant()` function will never return `None`.
1237 self.access_grant(fun, true).unwrap()
1238 }
1239
1240 /// Run a function with access to the data in the related process for the
1241 /// related Grant only if that grant region is not already entered. If the
1242 /// grant is already entered silently skip it. Also provide access to
1243 /// associated Upcalls.
1244 ///
1245 /// **You almost certainly should use `.enter()` rather than
1246 /// `.try_enter()`.**
1247 ///
1248 /// While the `.enter()` version can panic, that panic likely indicates a
1249 /// bug in the code and not a condition that should be handled. For example,
1250 /// this benign looking code is wrong:
1251 ///
1252 /// ```ignore
1253 /// self.apps.enter(thisapp, |app_grant, _| {
1254 /// // Update state in the grant region of `thisapp`. Also, mark that
1255 /// // `thisapp` needs to run again.
1256 /// app_grant.runnable = true;
1257 ///
1258 /// // Now, check all apps to see if any are ready to run.
1259 /// let mut work_left_to_do = false;
1260 /// self.apps.iter().each(|other_app| {
1261 /// other_app.enter(|other_app_grant, _| { // ERROR! This leads to a
1262 /// if other_app_grant.runnable { // grant being entered
1263 /// work_left_to_do = true; // twice!
1264 /// }
1265 /// })
1266 /// })
1267 /// })
1268 /// ```
1269 ///
1270 /// The example is wrong because it tries to iterate across all grant
1271 /// regions while one of them is already entered. This will lead to a grant
1272 /// region being entered twice which violates Rust's memory restrictions and
1273 /// is undefined behavior.
1274 ///
1275 /// However, since the example uses `.enter()` on the iteration, Tock will
1276 /// panic when the grant is entered for the second time, notifying the
1277 /// developer that something is wrong. The fix is to exit out of the first
1278 /// `.enter()` before attempting to iterate over the grant for all
1279 /// processes.
1280 ///
1281 /// However, if the example used `.try_enter()` in the iter loop, there
1282 /// would be no panic, but the already entered grant would be silently
1283 /// skipped. This can hide subtle bugs if the skipped grant is only relevant
1284 /// in certain cases.
1285 ///
1286 /// Therefore, only use `try_enter()` if you are sure you want to skip the
1287 /// already entered grant. Cases for this are rare.
1288 ///
1289 /// ## Return
1290 ///
1291 /// Returns `None` if the grant is already entered. Otherwise returns
1292 /// `Some(fun())`.
1293 pub fn try_enter<F, R>(self, fun: F) -> Option<R>
1294 where
1295 F: FnOnce(&mut GrantData<T>, &GrantKernelData) -> R,
1296 {
1297 self.access_grant(fun, false)
1298 }
1299
1300 /// Run a function with access to the memory in the related process for the
1301 /// related Grant. Also provide this function with access to any associated
1302 /// Upcalls and an allocator for allocating additional memory in the
1303 /// process's grant region.
1304 ///
1305 /// This is "entering" the grant region, and the _only_ time when the
1306 /// contents of a grant region can be accessed.
1307 ///
1308 /// Note, a grant can only be entered once at a time. Attempting to call
1309 /// `.enter()` on a grant while it is already entered will result in a
1310 /// panic!()`. See the comment in `access_grant()` for more information.
1311 pub fn enter_with_allocator<F, R>(self, fun: F) -> R
1312 where
1313 F: FnOnce(&mut GrantData<T>, &GrantKernelData, &mut GrantRegionAllocator) -> R,
1314 {
1315 // # `unwrap()` Safety
1316 //
1317 // `access_grant()` can only return `None` if the grant is already
1318 // entered. Since we are asking for a panic!() if the grant is entered,
1319 // `access_grant()` function will never return `None`.
1320 self.access_grant_with_allocator(fun, true).unwrap()
1321 }
1322
1323 /// Access the [`ProcessGrant`] memory and run a closure on the process's
1324 /// grant memory.
1325 ///
1326 /// If `panic_on_reenter` is `true`, this will panic if the grant region is
1327 /// already currently entered. If `panic_on_reenter` is `false`, this will
1328 /// return `None` if the grant region is entered and do nothing.
1329 fn access_grant<F, R>(self, fun: F, panic_on_reenter: bool) -> Option<R>
1330 where
1331 F: FnOnce(&mut GrantData<T>, &GrantKernelData) -> R,
1332 {
1333 self.access_grant_with_allocator(
1334 |grant_data, kernel_data, _allocator| fun(grant_data, kernel_data),
1335 panic_on_reenter,
1336 )
1337 }
1338
1339 /// Access the [`ProcessGrant`] memory and run a closure on the process's
1340 /// grant memory.
1341 ///
1342 /// If `panic_on_reenter` is `true`, this will panic if the grant region is
1343 /// already currently entered. If `panic_on_reenter` is `false`, this will
1344 /// return `None` if the grant region is entered and do nothing.
1345 fn access_grant_with_allocator<F, R>(self, fun: F, panic_on_reenter: bool) -> Option<R>
1346 where
1347 F: FnOnce(&mut GrantData<T>, &GrantKernelData, &mut GrantRegionAllocator) -> R,
1348 {
1349 // Access the grant that is in process memory. This can only fail if
1350 // the grant is already entered.
1351 let grant_ptr = self
1352 .process
1353 .enter_grant(self.grant_num)
1354 .map_err(|_err| {
1355 // If we get an error it is because the grant is already
1356 // entered. `process.enter_grant()` can fail for several
1357 // reasons, but only the double enter case can happen once a
1358 // grant has been applied. The other errors would be detected
1359 // earlier (i.e. before the grant can be applied).
1360
1361 // If `panic_on_reenter` is false, we skip this error and do
1362 // nothing with this grant.
1363 if !panic_on_reenter {
1364 return;
1365 }
1366
1367 // If `enter_grant` fails, we panic!() to notify the developer
1368 // that they tried to enter the same grant twice which is
1369 // prohibited because it would result in two mutable references
1370 // existing for the same memory. This preserves type correctness
1371 // (but does crash the system).
1372 //
1373 // ## Explanation and Rationale
1374 //
1375 // This panic represents a tradeoff. While it is undesirable to
1376 // have the potential for a runtime crash in this grant region
1377 // code, it balances usability with type correctness. The
1378 // challenge is that calling `self.apps.iter()` is a common
1379 // pattern in capsules to access the grant region of every app
1380 // that is using the capsule, and sometimes it is intuitive to
1381 // call that inside of a `self.apps.enter(processid, |app| {...})`
1382 // closure. However, `.enter()` means that app's grant region is
1383 // entered, and then a naive `.iter()` would re-enter the grant
1384 // region and cause undefined behavior. We considered different
1385 // options to resolve this.
1386 //
1387 // 1. Have `.iter()` only iterate over grant regions which are
1388 // not entered. This avoids the bug, but could lead to
1389 // unexpected behavior, as `self.apps.iter()` will do
1390 // different things depending on where in a capsule it is
1391 // called.
1392 // 2. Have the compiler detect when `.iter()` is called when a
1393 // grant region has already been entered. We don't know of a
1394 // viable way to implement this.
1395 // 3. Panic if `.iter()` is called when a grant is already
1396 // entered.
1397 //
1398 // We decided on option 3 because it balances minimizing
1399 // surprises (`self.apps.iter()` will always iterate all grants)
1400 // while also protecting against the bug. We expect that any
1401 // code that attempts to call `self.apps.iter()` after calling
1402 // `.enter()` will immediately encounter this `panic!()` and
1403 // have to be refactored before any tests will be successful.
1404 // Therefore, this `panic!()` should only occur at
1405 // development/testing time.
1406 //
1407 // ## How to fix this error
1408 //
1409 // If you are seeing this panic, you need to refactor your
1410 // capsule to not call `.iter()` or `.each()` from inside a
1411 // `.enter()` closure. That is, you need to close the grant
1412 // region you are currently in before trying to iterate over all
1413 // grant regions.
1414 panic!("Attempted to re-enter a grant region.");
1415 })
1416 .ok()?;
1417 let grant_t_align = GrantDataAlign(align_of::<T>());
1418 let grant_t_size = GrantDataSize(size_of::<T>());
1419
1420 let alloc_size = EnteredGrantKernelManagedLayout::grant_size(
1421 UpcallItems(Upcalls::COUNT),
1422 AllowRoItems(AllowROs::COUNT),
1423 AllowRwItems(AllowRWs::COUNT),
1424 grant_t_size,
1425 grant_t_align,
1426 );
1427
1428 // Parse layout of entire grant allocation using the known base pointer.
1429 //
1430 // # Safety
1431 //
1432 // Grant pointer is well aligned and points to initialized data.
1433 let layout = unsafe {
1434 EnteredGrantKernelManagedLayout::read_from_base(grant_ptr, self.process, self.grant_num)
1435 };
1436
1437 // Get references to all of the saved upcall data.
1438 //
1439 // # Safety
1440 //
1441 // - Pointer is well aligned and initialized with data from Self::new()
1442 // call.
1443 // - Data will not be modified externally while this immutable reference
1444 // is alive.
1445 // - Data is accessible for the entire duration of this immutable
1446 // reference.
1447 // - No other mutable reference to this memory exists concurrently.
1448 // Mutable reference to this memory are only created through the
1449 // kernel in the syscall interface which is serialized in time with
1450 // this call.
1451 let (saved_upcalls_slice, saved_allow_ro_slice, saved_allow_rw_slice) =
1452 layout.get_resource_slices();
1453 let grant_data = unsafe {
1454 EnteredGrantKernelManagedLayout::offset_of_grant_data_t(
1455 grant_ptr,
1456 alloc_size,
1457 grant_t_size,
1458 )
1459 .cast()
1460 .as_mut()
1461 };
1462
1463 // Create a wrapped objects that are passed to functor.
1464 let mut grant_data = GrantData::new(grant_data);
1465 let kernel_data = GrantKernelData::new(
1466 saved_upcalls_slice,
1467 saved_allow_ro_slice,
1468 saved_allow_rw_slice,
1469 self.driver_num,
1470 self.process,
1471 );
1472 // Setup an allocator in case the capsule needs additional memory in the
1473 // grant space.
1474 let mut allocator = GrantRegionAllocator {
1475 processid: self.process.processid(),
1476 };
1477
1478 // Call functor and pass back value.
1479 Some(fun(&mut grant_data, &kernel_data, &mut allocator))
1480 }
1481}
1482
1483/// Grant which was allocated from the kernel-owned grant region in a specific
1484/// process's memory, separately from a normal `Grant`.
1485///
1486/// A [`CustomGrant`] allows a capsule to allocate additional memory on behalf
1487/// of a process.
1488pub struct CustomGrant<T> {
1489 /// An identifier for this custom grant within a process's grant region.
1490 ///
1491 /// Here, this is an opaque reference that Process uses to access the
1492 /// custom grant allocation. This setup ensures that Process owns the grant
1493 /// memory.
1494 identifier: ProcessCustomGrantIdentifier,
1495
1496 /// Identifier for the process where this custom grant is allocated.
1497 processid: ProcessId,
1498
1499 /// Used to keep the Rust type of the grant.
1500 _phantom: PhantomData<T>,
1501}
1502
1503impl<T> CustomGrant<T> {
1504 /// Creates a new [`CustomGrant`].
1505 fn new(identifier: ProcessCustomGrantIdentifier, processid: ProcessId) -> Self {
1506 CustomGrant {
1507 identifier,
1508 processid,
1509 _phantom: PhantomData,
1510 }
1511 }
1512
1513 /// Helper function to get the [`ProcessId`] from the custom grant.
1514 pub fn processid(&self) -> ProcessId {
1515 self.processid
1516 }
1517
1518 /// Gives access to inner data within the given closure.
1519 ///
1520 /// If the process has since been restarted or crashed, or the memory is
1521 /// otherwise no longer present, then this function will not call the given
1522 /// closure, and will instead directly return `Err(Error::NoSuchApp)`.
1523 ///
1524 /// Because this function requires `&mut self`, it should be impossible to
1525 /// access the inner data of a given `CustomGrant` reentrantly. Thus the
1526 /// reentrance detection we use for non-custom grants is not needed here.
1527 pub fn enter<F, R>(&self, fun: F) -> Result<R, Error>
1528 where
1529 F: FnOnce(GrantData<'_, T>) -> R,
1530 {
1531 // Verify that the process this CustomGrant was allocated within still
1532 // exists.
1533 self.processid
1534 .kernel
1535 .process_map_or(Err(Error::NoSuchApp), self.processid, |process| {
1536 // App is valid.
1537
1538 // Now try to access the custom grant memory.
1539 let grant_ptr = process.enter_custom_grant(self.identifier)?;
1540
1541 // # Safety
1542 //
1543 // `grant_ptr` must be a valid pointer and there must not exist
1544 // any other references to the same memory. We verify the
1545 // pointer is valid and aligned when the memory is allocated and
1546 // `CustomGrant` is created. We are sure that there are no
1547 // other references because the only way to create a reference
1548 // is using this `enter()` function, and it can only be called
1549 // once (because of the `&mut self` requirement).
1550 let custom_grant = unsafe { &mut *(grant_ptr as *mut T) };
1551 let borrowed = GrantData::new(custom_grant);
1552 Ok(fun(borrowed))
1553 })
1554 }
1555}
1556
1557/// Tool for allocating additional memory regions in a process's grant region.
1558///
1559/// This is optionally provided along with a grant so that if a capsule needs
1560/// per-process dynamic allocation it can allocate additional memory.
1561pub struct GrantRegionAllocator {
1562 /// The process the allocator will allocate memory from.
1563 processid: ProcessId,
1564}
1565
1566impl GrantRegionAllocator {
1567 /// Allocates a new [`CustomGrant`] initialized using the given closure.
1568 ///
1569 /// The closure will be called exactly once, and the result will be used to
1570 /// initialize the owned value.
1571 ///
1572 /// This interface was chosen instead of a simple `alloc(val)` as it's
1573 /// much more likely to optimize out all stack intermediates. This
1574 /// helps to prevent stack overflows when allocating large values.
1575 ///
1576 /// # Panic Safety
1577 ///
1578 /// If `init` panics, the freshly allocated memory may leak.
1579 pub fn alloc_with<T, F>(&self, init: F) -> Result<CustomGrant<T>, Error>
1580 where
1581 F: FnOnce() -> T,
1582 {
1583 let (custom_grant_identifier, typed_ptr) = self.alloc_raw::<T>()?;
1584
1585 // # Safety
1586 //
1587 // Writing to this pointer is safe as long as the pointer is valid
1588 // and aligned. `alloc_raw()` guarantees these constraints are met.
1589 unsafe {
1590 // We use `ptr::write` to avoid `Drop`ping the uninitialized memory
1591 // in case `T` implements the `Drop` trait.
1592 write(typed_ptr.as_ptr(), init());
1593 }
1594
1595 Ok(CustomGrant::new(custom_grant_identifier, self.processid))
1596 }
1597
1598 /// Allocates a slice of n instances of a given type. Each instance is
1599 /// initialized using the provided function.
1600 ///
1601 /// The provided function will be called exactly `n` times, and will be
1602 /// passed the index it's initializing, from `0` through `NUM_ITEMS - 1`.
1603 ///
1604 /// # Panic Safety
1605 ///
1606 /// If `val_func` panics, the freshly allocated memory and any values
1607 /// already written will be leaked.
1608 pub fn alloc_n_with<T, F, const NUM_ITEMS: usize>(
1609 &self,
1610 mut init: F,
1611 ) -> Result<CustomGrant<[T; NUM_ITEMS]>, Error>
1612 where
1613 F: FnMut(usize) -> T,
1614 {
1615 let (custom_grant_identifier, typed_ptr) = self.alloc_n_raw::<T>(NUM_ITEMS)?;
1616
1617 for i in 0..NUM_ITEMS {
1618 // # Safety
1619 //
1620 // The allocate function guarantees that `ptr` points to memory
1621 // large enough to allocate `num_items` copies of the object.
1622 unsafe {
1623 write(typed_ptr.as_ptr().add(i), init(i));
1624 }
1625 }
1626
1627 Ok(CustomGrant::new(custom_grant_identifier, self.processid))
1628 }
1629
1630 /// Allocates uninitialized grant memory appropriate to store a `T`.
1631 ///
1632 /// The caller must initialize the memory.
1633 ///
1634 /// Also returns a ProcessCustomGrantIdentifier to access the memory later.
1635 fn alloc_raw<T>(&self) -> Result<(ProcessCustomGrantIdentifier, NonNull<T>), Error> {
1636 self.alloc_n_raw::<T>(1)
1637 }
1638
1639 /// Allocates space for a dynamic number of items.
1640 ///
1641 /// The caller is responsible for initializing the returned memory.
1642 ///
1643 /// Returns memory appropriate for storing `num_items` contiguous instances
1644 /// of `T` and a ProcessCustomGrantIdentifier to access the memory later.
1645 fn alloc_n_raw<T>(
1646 &self,
1647 num_items: usize,
1648 ) -> Result<(ProcessCustomGrantIdentifier, NonNull<T>), Error> {
1649 let (custom_grant_identifier, raw_ptr) =
1650 self.alloc_n_raw_inner(num_items, size_of::<T>(), align_of::<T>())?;
1651 let typed_ptr = NonNull::cast::<T>(raw_ptr);
1652
1653 Ok((custom_grant_identifier, typed_ptr))
1654 }
1655
1656 /// Helper to reduce code bloat by avoiding monomorphization.
1657 fn alloc_n_raw_inner(
1658 &self,
1659 num_items: usize,
1660 single_alloc_size: usize,
1661 alloc_align: usize,
1662 ) -> Result<(ProcessCustomGrantIdentifier, NonNull<u8>), Error> {
1663 let alloc_size = single_alloc_size
1664 .checked_mul(num_items)
1665 .ok_or(Error::OutOfMemory)?;
1666 self.processid
1667 .kernel
1668 .process_map_or(Err(Error::NoSuchApp), self.processid, |process| {
1669 process
1670 .allocate_custom_grant(alloc_size, alloc_align)
1671 .map_or(
1672 Err(Error::OutOfMemory),
1673 |(custom_grant_identifier, raw_ptr)| Ok((custom_grant_identifier, raw_ptr)),
1674 )
1675 })
1676 }
1677}
1678
1679/// Type for storing an object of type T in process memory that is only
1680/// accessible by the kernel.
1681///
1682/// A single [`Grant`] can allocate space for one object of type T for each
1683/// process on the board. Each allocated object will reside in the grant region
1684/// belonging to the process that the object is allocated for. The [`Grant`]
1685/// type is used to get access to [`ProcessGrant`]s, which are tied to a
1686/// specific process and provide access to the memory object allocated for that
1687/// process.
1688pub struct Grant<T: Default, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize> {
1689 /// Hold a reference to the core kernel so we can iterate processes.
1690 pub(crate) kernel: &'static Kernel,
1691
1692 /// Keep track of the syscall driver number assigned to the capsule that is
1693 /// using this grant. This allows us to uniquely identify upcalls stored in
1694 /// this grant.
1695 driver_num: usize,
1696
1697 /// The identifier for this grant. Having an identifier allows the Process
1698 /// implementation to lookup the memory for this grant in the specific
1699 /// process.
1700 grant_num: usize,
1701
1702 /// Used to store the Rust types for grant.
1703 ptr: PhantomData<(T, Upcalls, AllowROs, AllowRWs)>,
1704}
1705
1706impl<T: Default, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize>
1707 Grant<T, Upcalls, AllowROs, AllowRWs>
1708{
1709 /// Create a new [`Grant`] type which allows a capsule to store
1710 /// process-specific data for each process in the process's memory region.
1711 ///
1712 /// This must only be called from the main kernel so that it can ensure that
1713 /// `grant_index` is a valid index.
1714 pub(crate) fn new(kernel: &'static Kernel, driver_num: usize, grant_index: usize) -> Self {
1715 Self {
1716 kernel,
1717 driver_num,
1718 grant_num: grant_index,
1719 ptr: PhantomData,
1720 }
1721 }
1722
1723 /// Enter the grant for a specific process.
1724 ///
1725 /// This creates a [`ProcessGrant`] which is a handle for a grant allocated
1726 /// for a specific process. Then, that [`ProcessGrant`] is entered and the
1727 /// provided closure is run with access to the memory in the grant region.
1728 pub fn enter<F, R>(&self, processid: ProcessId, fun: F) -> Result<R, Error>
1729 where
1730 F: FnOnce(&mut GrantData<T>, &GrantKernelData) -> R,
1731 {
1732 let pg = ProcessGrant::new(self, processid)?;
1733
1734 // If we have managed to create an `ProcessGrant`, all we need
1735 // to do is actually access the memory and run the
1736 // capsule-provided closure. This can only fail if the grant is
1737 // already entered, at which point the kernel will panic.
1738 Ok(pg.enter(fun))
1739 }
1740
1741 /// Enter the grant for a specific process with access to an allocator.
1742 ///
1743 /// This creates an [`ProcessGrant`] which is a handle for a grant allocated
1744 /// for a specific process. Then, that [`ProcessGrant`] is entered and the
1745 /// provided closure is run with access to the memory in the grant region.
1746 ///
1747 /// The allocator allows the caller to dynamically allocate additional
1748 /// memory in the process's grant region.
1749 pub fn enter_with_allocator<F, R>(&self, processid: ProcessId, fun: F) -> Result<R, Error>
1750 where
1751 F: FnOnce(&mut GrantData<T>, &GrantKernelData, &mut GrantRegionAllocator) -> R,
1752 {
1753 // Get the `ProcessGrant` for the process, possibly needing to
1754 // actually allocate the memory in the process's grant region to
1755 // do so. This can fail for a variety of reasons, and if so we
1756 // return the error to the capsule.
1757 let pg = ProcessGrant::new(self, processid)?;
1758
1759 // If we have managed to create an `ProcessGrant`, all we need
1760 // to do is actually access the memory and run the
1761 // capsule-provided closure. This can only fail if the grant is
1762 // already entered, at which point the kernel will panic.
1763 Ok(pg.enter_with_allocator(fun))
1764 }
1765
1766 /// Run a function on the grant for each active process if the grant has
1767 /// been allocated for that process.
1768 ///
1769 /// This will silently skip any process where the grant has not previously
1770 /// been allocated. This will also silently skip any invalid processes.
1771 ///
1772 /// Calling this function when an [`ProcessGrant`] for a process is
1773 /// currently entered will result in a panic.
1774 pub fn each<F>(&self, mut fun: F)
1775 where
1776 F: FnMut(ProcessId, &mut GrantData<T>, &GrantKernelData),
1777 {
1778 // Create a the iterator across `ProcessGrant`s for each process.
1779 for pg in self.iter() {
1780 let processid = pg.processid();
1781 // Since we iterating, there is no return value we need to worry
1782 // about.
1783 pg.enter(|data, upcalls| fun(processid, data, upcalls));
1784 }
1785 }
1786
1787 /// Get an iterator over all processes and their active grant regions for
1788 /// this particular grant.
1789 ///
1790 /// Calling this function when an [`ProcessGrant`] for a process is
1791 /// currently entered will result in a panic.
1792 pub fn iter(&self) -> Iter<T, Upcalls, AllowROs, AllowRWs> {
1793 Iter {
1794 grant: self,
1795 subiter: self.kernel.get_process_iter(),
1796 }
1797 }
1798}
1799
1800/// Type to iterate [`ProcessGrant`]s across processes.
1801pub struct Iter<
1802 'a,
1803 T: 'a + Default,
1804 Upcalls: UpcallSize,
1805 AllowROs: AllowRoSize,
1806 AllowRWs: AllowRwSize,
1807> {
1808 /// The grant type to use.
1809 grant: &'a Grant<T, Upcalls, AllowROs, AllowRWs>,
1810
1811 /// Iterator over valid processes.
1812 subiter: core::iter::FilterMap<
1813 core::slice::Iter<'a, Option<&'static dyn Process>>,
1814 fn(&Option<&'static dyn Process>) -> Option<&'static dyn Process>,
1815 >,
1816}
1817
1818impl<'a, T: Default, Upcalls: UpcallSize, AllowROs: AllowRoSize, AllowRWs: AllowRwSize> Iterator
1819 for Iter<'a, T, Upcalls, AllowROs, AllowRWs>
1820{
1821 type Item = ProcessGrant<'a, T, Upcalls, AllowROs, AllowRWs>;
1822
1823 fn next(&mut self) -> Option<Self::Item> {
1824 let grant = self.grant;
1825 // Get the next `ProcessId` from the kernel processes array that is
1826 // setup to use this grant. Since the iterator itself is saved calling
1827 // this function again will start where we left off.
1828 self.subiter
1829 .find_map(|process| ProcessGrant::new_if_allocated(grant, process))
1830 }
1831}