diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 1a7244d3b2..7d2a33aeb4 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -4,10 +4,67 @@ //! Mechanisms for handling and defining system calls. //! -//! This includes: -//! - syscall class -//! - error types -//! - interface trait for context switches +//! # System Call Overview +//! +//! Tock supports six system calls. The `allow_readonly`, `allow_readwrite`, +//! `subscribe`, `yield`, and `memop` system calls are handled by the core +//! kernel, while `command` is implemented by drivers. The main system calls: +//! +//! - `subscribe` passes a upcall to the driver which it can invoke on the +//! process later, when an event has occurred or data of interest is +//! available. +//! - `command` tells the driver to do something immediately. +//! - `allow_readwrite` provides the driver read-write access to an application +//! buffer. +//! - `allow_userspace_readable` provides the driver read-write access to an +//! application buffer that is still shared with the app. +//! - `allow_readonly` provides the driver read-only access to an application +//! buffer. +//! +//! ## Mapping system-calls to drivers +//! +//! Each of these three system calls takes at least two parameters. The first is +//! a _driver identifier_ and tells the scheduler which driver to forward the +//! system call to. The second parameters is a __syscall number_ and is used by +//! the driver to differentiate instances of the call with different +//! driver-specific meanings (e.g. `subscribe` for "data received" vs +//! `subscribe` for "send completed"). The mapping between _driver identifiers_ +//! and drivers is determined by a particular platform, while the _syscall +//! number_ is driver-specific. +//! +//! One convention in Tock is that _driver minor number_ 0 for the `command` +//! syscall can always be used to determine if the driver is supported by the +//! running kernel by checking the return code. If the return value is greater +//! than or equal to zero then the driver is present. Typically this is +//! implemented by a null command that only returns 0, but in some cases the +//! command can also return more information, like the number of supported +//! devices (useful for things like the number of LEDs). +//! +//! # The `yield` system call class +//! +//! While drivers do not handle `yield` system calls, it is important to +//! understand them and how they interact with `subscribe`, which registers +//! upcall functions with the kernel. When a process calls a `yield` system +//! call, the kernel checks if there are any pending upcalls for the process. If +//! there are pending upcalls, it pushes one upcall onto the process stack. If +//! there are no pending upcalls, `yield-wait` will cause the process to sleep +//! until a upcall is triggered, while `yield-no-wait` returns immediately. +//! +//! # Method result types +//! +//! Each driver method has a limited set of valid return types. Every method has +//! a single return type corresponding to success and a single return type +//! corresponding to failure. For the `subscribe` and `allow` system calls, +//! these return types are the same for every instance of those calls. Each +//! instance of the `command` system call, however, has its own specified return +//! types. A command that requests a timestamp, for example, might return a +//! 32-bit number on success and an error code on failure, while a command that +//! requests time of day in microsecond granularity might return a 64-bit number +//! and a 32-bit timezone encoding on success, and an error code on failure. +//! +//! These result types are represented as safe Rust types. The core kernel (the +//! scheduler and syscall dispatcher) is responsible for encoding these types +//! into the Tock system call ABI specification. use core::fmt::Write; @@ -16,10 +73,9 @@ use crate::process; pub use crate::syscall_driver::{CommandReturn, SyscallDriver}; -/// Helper function to split a u64 into a higher and lower u32. +/// Helper function to split a [`u64`] into a higher and lower [`u32`]. /// -/// Used in encoding 64-bit wide system call return values on 32-bit -/// platforms. +/// Used in encoding 64-bit wide system call return values on 32-bit platforms. #[inline] fn u64_to_be_u32s(src: u64) -> (u32, u32) { let src_bytes = src.to_be_bytes(); @@ -31,11 +87,11 @@ fn u64_to_be_u32s(src: u64) -> (u32, u32) { // ---------- SYSTEMCALL ARGUMENT DECODING ---------- -/// Enumeration of the system call classes based on the identifiers -/// specified in the Tock ABI. +/// Enumeration of the system call classes based on the identifiers specified in +/// the Tock ABI. /// -/// These are encoded as 8 bit values as on some architectures the value can -/// be encoded in the instruction itself. +/// These are encoded as 8 bit values as on some architectures the value can be +/// encoded in the instruction itself. #[repr(u8)] #[derive(Copy, Clone, Debug)] pub enum SyscallClass { @@ -73,7 +129,7 @@ impl TryFrom for YieldCall { // Required as long as no solution to // https://github.com/rust-lang/rfcs/issues/2783 is integrated into -// the standard library +// the standard library. impl TryFrom for SyscallClass { type Error = u8; @@ -92,11 +148,12 @@ impl TryFrom for SyscallClass { } } -/// Decoded system calls as defined in TRD 104. +/// Decoded system calls as defined in TRD104. #[derive(Copy, Clone, Debug, PartialEq)] pub enum Syscall { - /// Structure representing an invocation of the Yield system call class. - /// `which` is the Yield identifier value and `address` is the no wait field. + /// Structure representing an invocation of the [`SyscallClass::Yield`] + /// system call class. `which` is the Yield identifier value and `address` + /// is the no wait field. Yield { which: usize, param_a: usize, @@ -104,98 +161,99 @@ pub enum Syscall { }, /// Structure representing an invocation of the Subscribe system call class. - /// - /// - `driver_number`: the driver identifier - /// - `subdriver_number`: the subscribe identifier - /// - `upcall_ptr`: upcall pointer to the upcall function - /// - `appdata`: userspace application data Subscribe { + /// The driver identifier. driver_number: usize, + /// The subscribe identifier. subdriver_number: usize, + /// Upcall pointer to the upcall function. upcall_ptr: *mut (), + /// Userspace application data. appdata: usize, }, /// Structure representing an invocation of the Command system call class. - /// - /// - `driver_number`: the driver identifier - /// - `subdriver_number`: the command identifier - /// - `arg0`: value passed to the `Command` implementation - /// - `arg1`: value passed to the `Command` implementation Command { + /// The driver identifier. driver_number: usize, + /// The command identifier. subdriver_number: usize, + /// Value passed to the `Command` implementation. arg0: usize, + /// Value passed to the `Command` implementation. arg1: usize, }, /// Structure representing an invocation of the ReadWriteAllow system call /// class. - /// - /// - `driver_number`: the driver identifier - /// - `subdriver_number`: the buffer identifier - /// - `allow_address`: the address where the buffer starts - /// - `allow_size`: the size of the buffer in bytes ReadWriteAllow { + /// The driver identifier. driver_number: usize, + /// The buffer identifier. subdriver_number: usize, + /// The address where the buffer starts. allow_address: *mut u8, + /// The size of the buffer in bytes. allow_size: usize, }, - /// Structure representing an invocation of the ReadWriteAllow system call - /// class, but with shared kernel and app access. + /// Structure representing an invocation of the UserspaceReadableAllow + /// system call class that allows shared kernel and app access. /// /// - `driver_number`: the driver identifier /// - `subdriver_number`: the buffer identifier /// - `allow_address`: the address where the buffer starts /// - `allow_size`: the size of the buffer in bytes UserspaceReadableAllow { + /// driver_number: usize, + /// subdriver_number: usize, + /// allow_address: *mut u8, + /// allow_size: usize, }, /// Structure representing an invocation of the ReadOnlyAllow system call /// class. - /// - /// - `driver_number`: the driver identifier - /// - `subdriver_number`: the buffer identifier - /// - `allow_address`: the address where the buffer starts - /// - `allow_size`: the size of the buffer in bytes ReadOnlyAllow { + /// The driver identifier. driver_number: usize, + /// The buffer identifier. subdriver_number: usize, + /// The address where the buffer starts. allow_address: *const u8, + /// The size of the buffer in bytes. allow_size: usize, }, /// Structure representing an invocation of the Memop system call class. - /// - /// - `operand`: the operation - /// - `arg0`: the operation argument - Memop { operand: usize, arg0: usize }, + Memop { + /// The operation. + operand: usize, + /// The operation argument. + arg0: usize, + }, /// Structure representing an invocation of the Exit system call class. - /// - /// - `which`: the exit identifier - /// - `completion_code`: the completion code passed into the kernel Exit { + /// The exit identifier. which: usize, + /// The completion code passed into the kernel. completion_code: usize, }, } impl Syscall { - /// Helper function for converting raw values passed back from an application - /// into a `Syscall` type in Tock, representing an typed version of a system - /// call invocation. The method returns None if the values do not specify - /// a valid system call. + /// Helper function for converting raw values passed back from an + /// application into a `Syscall` type in Tock, representing an typed version + /// of a system call invocation. The method returns None if the values do + /// not specify a valid system call. /// /// Different architectures have different ABIs for a process and the kernel - /// to exchange data. The 32-bit ABI for CortexM and RISCV microcontrollers is - /// specified in TRD104. + /// to exchange data. The 32-bit ABI for CortexM and RISCV microcontrollers + /// is specified in TRD104. pub fn from_register_arguments( syscall_number: u8, r0: usize, @@ -332,8 +390,8 @@ impl Syscall { /// Enumeration of the system call return type variant identifiers described /// in TRD104. /// -/// Each variant is associated with the respective variant identifier -/// that would be passed along with the return value to userspace. +/// Each variant is associated with the respective variant identifier that would +/// be passed along with the return value to userspace. #[repr(u32)] #[derive(Copy, Clone, Debug)] pub enum SyscallReturnVariant { @@ -349,22 +407,18 @@ pub enum SyscallReturnVariant { SuccessU32U64 = 133, } -/// Enumeration of the possible system call return variants specified -/// in TRD104. +/// Enumeration of the possible system call return variants specified in TRD104. /// -/// This struct operates over primitive types such as integers of -/// fixed length and pointers. It is constructed by the scheduler and -/// passed down to the architecture to be encoded into registers, -/// using the provided -/// [`encode_syscall_return`](SyscallReturn::encode_syscall_return) -/// method. +/// This struct operates over primitive types such as integers of fixed length +/// and pointers. It is constructed by the scheduler and passed down to the +/// architecture to be encoded into registers, using the provided +/// [`encode_syscall_return`](SyscallReturn::encode_syscall_return) method. /// -/// Capsules do not use this struct. Capsules use higher level Rust -/// types -/// (e.g. [`ReadWriteProcessBuffer`](crate::processbuffer::ReadWriteProcessBuffer) -/// and `GrantKernelData`) or wrappers around this struct -/// ([`CommandReturn`]) which limit the -/// available constructors to safely constructable variants. +/// Capsules do not use this struct. Capsules use higher level Rust types (e.g. +/// [`ReadWriteProcessBuffer`](crate::processbuffer::ReadWriteProcessBuffer) and +/// [`GrantKernelData`](crate::grant::GrantKernelData)) or wrappers around this +/// struct ([`CommandReturn`]) which limit the available constructors to safely +/// constructable variants. #[derive(Copy, Clone, Debug)] pub enum SyscallReturn { /// Generic error case @@ -385,68 +439,67 @@ pub enum SyscallReturn { SuccessU32U32U32(u32, u32, u32), /// Generic success case, with an additional 64-bit data field SuccessU64(u64), - /// Generic success case, with an additional 32-bit and 64-bit - /// data field + /// Generic success case, with an additional 32-bit and 64-bit data field SuccessU32U64(u32, u64), - // These following types are used by the scheduler so that it can - // return values to userspace in an architecture (pointer-width) - // independent way. The kernel passes these types (rather than - // ProcessBuffer or Upcall) for two reasons. First, since the - // kernel/scheduler makes promises about the lifetime and safety - // of these types, it does not want to leak them to other - // code. Second, if subscribe or allow calls pass invalid values + // These following types are used by the scheduler so that it can return + // values to userspace in an architecture (pointer-width) independent way. + // The kernel passes these types (rather than ProcessBuffer or Upcall) for + // two reasons. First, since the kernel/scheduler makes promises about the + // lifetime and safety of these types, it does not want to leak them to + // other code. Second, if subscribe or allow calls pass invalid values // (pointers out of valid memory), the kernel cannot construct an - // ProcessBuffer or Upcall type but needs to be able to return a - // failure. -pal 11/24/20 - /// Read/Write allow success case, returns the previous allowed - /// buffer and size to the process. + // ProcessBuffer or Upcall type but needs to be able to return a failure. + // -pal 11/24/20 + /// Read/Write allow success case, returns the previous allowed buffer and + /// size to the process. AllowReadWriteSuccess(*mut u8, usize), - /// Read/Write allow failure case, returns the passed allowed - /// buffer and size to the process. + /// Read/Write allow failure case, returns the passed allowed buffer and + /// size to the process. AllowReadWriteFailure(ErrorCode, *mut u8, usize), /// Shared Read/Write allow success case, returns the previous allowed /// buffer and size to the process. UserspaceReadableAllowSuccess(*mut u8, usize), - /// Shared Read/Write allow failure case, returns the passed allowed - /// buffer and size to the process. + /// Shared Read/Write allow failure case, returns the passed allowed buffer + /// and size to the process. UserspaceReadableAllowFailure(ErrorCode, *mut u8, usize), - /// Read only allow success case, returns the previous allowed - /// buffer and size to the process. + /// Read only allow success case, returns the previous allowed buffer and + /// size to the process. AllowReadOnlySuccess(*const u8, usize), - /// Read only allow failure case, returns the passed allowed - /// buffer and size to the process. + /// Read only allow failure case, returns the passed allowed buffer and size + /// to the process. AllowReadOnlyFailure(ErrorCode, *const u8, usize), - /// Subscribe success case, returns the previous upcall function - /// pointer and application data. + /// Subscribe success case, returns the previous upcall function pointer and + /// application data. SubscribeSuccess(*const (), usize), - /// Subscribe failure case, returns the passed upcall function - /// pointer and application data. + /// Subscribe failure case, returns the passed upcall function pointer and + /// application data. SubscribeFailure(ErrorCode, *const (), usize), - /// YieldWaitFor return value. These arguments match the arguments to an + /// Yield-WaitFor return value. These arguments match the arguments to an /// upcall, where the kernel does not define an error field. Therefore this /// does not have success/failure versions because the kernel cannot know if - /// the upcall (i.e. YieldWaitFor return value) represents success or + /// the upcall (i.e. Yield-WaitFor return value) represents success or /// failure. YieldWaitFor(usize, usize, usize), } impl SyscallReturn { - /// Transforms a CommandReturn, which is wrapper around a subset of - /// SyscallReturn, into a SyscallReturn. + /// Transforms a [`CommandReturn`], which is wrapper around a subset of + /// [`SyscallReturn`], into a [`SyscallReturn`]. /// - /// This allows CommandReturn to include only the variants of SyscallReturn - /// that can be returned from a Command, while having an inexpensive way to - /// handle it as a SyscallReturn for more generic code paths. + /// This allows [`CommandReturn`] to include only the variants of + /// [`SyscallReturn`] that can be returned from a Command, while having an + /// inexpensive way to handle it as a [`SyscallReturn`] for more generic + /// code paths. pub(crate) fn from_command_return(res: CommandReturn) -> Self { res.into_inner() } - /// Returns true if the `SyscallReturn` is any success type. + /// Returns true if the [`SyscallReturn`] is any success type. pub(crate) fn is_success(&self) -> bool { match self { SyscallReturn::Success => true, @@ -471,9 +524,9 @@ impl SyscallReturn { } } - /// Encode the system call return value into 4 registers, following - /// the encoding specified in TRD104. Architectures which do not follow - /// TRD104 are free to define their own encoding. + /// Encode the system call return value into 4 registers, following the + /// encoding specified in TRD104. Architectures which do not follow TRD104 + /// are free to define their own encoding. pub fn encode_syscall_return(&self, a0: &mut u32, a1: &mut u32, a2: &mut u32, a3: &mut u32) { match *self { SyscallReturn::Failure(e) => { @@ -586,42 +639,42 @@ impl SyscallReturn { // ---------- USERSPACE KERNEL BOUNDARY ---------- -/// `ContentSwitchReason` specifies why the process stopped executing and +/// [`ContextSwitchReason`] specifies why the process stopped executing and /// execution returned to the kernel. #[derive(PartialEq, Copy, Clone)] pub enum ContextSwitchReason { /// Process called a syscall. Also returns the syscall and relevant values. SyscallFired { syscall: Syscall }, - /// Process triggered the hardfault handler. - /// The implementation should still save registers in the event that the - /// `Platform` can handle the fault and allow the app to continue running. - /// For more details on this see `Platform::process_fault_hook()`. + /// Process triggered the hardfault handler. The implementation should still + /// save registers in the event that the platform can handle the fault and + /// allow the app to continue running. For more details on this see + /// [`ProcessFault`](crate::platform::ProcessFault). Fault, - /// Process interrupted (e.g. by a hardware event) + /// Process was interrupted (e.g. by a hardware event). Interrupted, } -/// The `UserspaceKernelBoundary` trait is implemented by the -/// architectural component of the chip implementation of Tock. This -/// trait allows the kernel to switch to and from processes -/// in an architecture-independent manner. +/// The [`UserspaceKernelBoundary`] trait is implemented by the architectural +/// component of the chip implementation of Tock. This trait allows the kernel +/// to switch to and from processes in an architecture-independent manner. /// -/// Exactly how upcalls and return values are passed between -/// kernelspace and userspace is architecture specific. The -/// architecture may use process memory to store state when -/// switching. Therefore, functions in this trait are passed the -/// bounds of process-accessible memory so that the architecture -/// implementation can verify it is reading and writing memory that -/// the process has valid access to. These bounds are passed through +/// Exactly how upcalls and return values are passed between kernelspace and +/// userspace is architecture specific. The architecture may use process memory +/// to store state when switching. Therefore, functions in this trait are passed +/// the bounds of process-accessible memory so that the architecture +/// implementation can verify it is reading and writing memory that the process +/// has valid access to. These bounds are passed through /// `accessible_memory_start` and `app_brk` pointers. pub trait UserspaceKernelBoundary { /// Some architecture-specific struct containing per-process state that must /// be kept while the process is not running. For example, for keeping CPU /// registers that aren't stored on the stack. /// - /// Implementations should **not** rely on the `Default` constructor (custom - /// or derived) for any initialization of a process's stored state. The - /// initialization must happen in the `initialize_process()` function. + /// Implementations should **not** rely on the [`Default`] constructor + /// (custom or derived) for any initialization of a process's stored state. + /// The initialization must happen in the + /// [`initialize_process()`](UserspaceKernelBoundary::initialize_process()) + /// function. type StoredState: Default; /// Called by the kernel during process creation to inform the kernel of the @@ -743,8 +796,8 @@ pub trait UserspaceKernelBoundary { /// /// This returns two values in a tuple. /// - /// 1. A `ContextSwitchReason` indicating why the process stopped executing - /// and switched back to the kernel. + /// 1. A [`ContextSwitchReason`] indicating why the process stopped + /// executing and switched back to the kernel. /// 2. Optionally, the current stack pointer used by the process. This is /// optional because it is only for debugging in process.rs. By sharing /// the process's stack pointer with process.rs users can inspect the diff --git a/kernel/src/syscall_driver.rs b/kernel/src/syscall_driver.rs index 758da28ea1..e37f3f239b 100644 --- a/kernel/src/syscall_driver.rs +++ b/kernel/src/syscall_driver.rs @@ -5,77 +5,6 @@ //! System call interface for userspace processes implemented by capsules. //! //! Drivers implement these interfaces to expose operations to processes. -//! -//! # System-call Overview -//! -//! Tock supports six system calls. The `allow_readonly`, `allow_readwrite`, -//! `subscribe`, `yield`, and `memop` system calls are handled by the core -//! kernel, while `command` is implemented by drivers. The main system calls: -//! -//! * `subscribe` passes a upcall to the driver which it can -//! invoke on the process later, when an event has occurred or data -//! of interest is available. -//! -//! * `command` tells the driver to do something immediately. -//! -//! * `allow_readwrite` provides the driver read-write access to an -//! application buffer. -//! -//! * `allow_userspace_readable` provides the driver read-write access to an -//! application buffer that is still shared with the app. -//! -//! * `allow_readonly` provides the driver read-only access to an -//! application buffer. -//! -//! ## Mapping system-calls to drivers -//! -//! Each of these three system calls takes at least two -//! parameters. The first is a _driver identifier_ and tells the -//! scheduler which driver to forward the system call to. The second -//! parameters is a __syscall number_ and is used by the driver to -//! differentiate instances of the call with different driver-specific -//! meanings (e.g. `subscribe` for "data received" vs `subscribe` for -//! "send completed"). The mapping between _driver identifiers_ and -//! drivers is determined by a particular platform, while the _syscall -//! number_ is driver-specific. -//! -//! One convention in Tock is that _driver minor number_ 0 for the `command` -//! syscall can always be used to determine if the driver is supported by -//! the running kernel by checking the return code. If the return value is -//! greater than or equal to zero then the driver is present. Typically this is -//! implemented by a null command that only returns 0, but in some cases the -//! command can also return more information, like the number of supported -//! devices (useful for things like the number of LEDs). -//! -//! # The `yield` system call class -//! -//! While drivers do not handle `yield` system calls, it is important -//! to understand them and how they interact with `subscribe`, which -//! registers upcall functions with the kernel. When a process calls -//! a `yield` system call, the kernel checks if there are any pending -//! upcalls for the process. If there are pending upcalls, it -//! pushes one upcall onto the process stack. If there are no -//! pending upcalls, `yield-wait` will cause the process to sleep -//! until a upcall is triggered, while `yield-no-wait` returns -//! immediately. -//! -//! # Method result types -//! -//! Each driver method has a limited set of valid return types. Every -//! method has a single return type corresponding to success and a -//! single return type corresponding to failure. For the `subscribe` -//! and `allow` system calls, these return types are the same for -//! every instance of those calls. Each instance of the `command` -//! system call, however, has its own specified return types. A -//! command that requests a timestamp, for example, might return a -//! 32-bit number on success and an error code on failure, while a -//! command that requests time of day in microsecond granularity might -//! return a 64-bit number and a 32-bit timezone encoding on success, -//! and an error code on failure. -//! -//! These result types are represented as safe Rust types. The core -//! kernel (the scheduler and syscall dispatcher) is responsible for -//! encoding these types into the Tock system call ABI specification. use crate::errorcode::ErrorCode; use crate::process; @@ -83,22 +12,18 @@ use crate::process::ProcessId; use crate::processbuffer::UserspaceReadableProcessBuffer; use crate::syscall::SyscallReturn; -/// Possible return values of a `command` driver method, as specified -/// in TRD104. +/// Possible return values of a `command` driver method, as specified in TRD104. /// -/// This is just a wrapper around -/// [`SyscallReturn`](SyscallReturn) since a -/// `command` driver method may only return primitive integer types as -/// payload. +/// This is just a wrapper around [`SyscallReturn`] since a `command` driver +/// method may only return primitive integer types as payload. /// -/// It is important for this wrapper to only be constructable over -/// variants of -/// [`SyscallReturn`](SyscallReturn) that are -/// deemed safe for a capsule to construct and return to an -/// application (e.g. not -/// [`SubscribeSuccess`](crate::syscall::SyscallReturn::SubscribeSuccess)). -/// This means that the inner value **must** remain private. +/// It is important for this wrapper to only be constructable over variants of +/// [`SyscallReturn`] that are deemed safe for a capsule to construct and return +/// to an application (e.g. not +/// [`SubscribeSuccess`](crate::syscall::SyscallReturn::SubscribeSuccess)). This +/// means that the inner value **must** remain private. pub struct CommandReturn(SyscallReturn); + impl CommandReturn { pub(crate) fn into_inner(self) -> SyscallReturn { self.0 @@ -170,28 +95,25 @@ impl From for CommandReturn { } } -/// Trait for capsules implementing peripheral driver system calls -/// specified in TRD104. The kernel translates the values passed from -/// userspace into Rust types and includes which process is making the -/// call. All of these system calls perform very little synchronous work; -/// long running computations or I/O should be split-phase, with an upcall -/// indicating their completion. +/// Trait for capsules implementing peripheral driver system calls specified in +/// TRD104. The kernel translates the values passed from userspace into Rust +/// types and includes which process is making the call. All of these system +/// calls perform very little synchronous work; long running computations or I/O +/// should be split-phase, with an upcall indicating their completion. /// /// The exact instances of each of these methods (which identifiers are valid -/// and what they represents) are specific to the peripheral system call -/// driver. +/// and what they represents) are specific to the peripheral system call driver. /// -/// Note about **subscribe**, **read-only allow**, and *read-write allow** -/// syscalls: -/// those are handled entirely by the core kernel, and there is no -/// corresponding function for capsules to implement. +/// Note about `subscribe`, `read-only allow`, and `read-write allow` syscalls: +/// those are handled entirely by the core kernel, and there is no corresponding +/// function for capsules to implement. #[allow(unused_variables)] pub trait SyscallDriver { - /// System call for a process to perform a short synchronous operation - /// or start a long-running split-phase operation (whose completion - /// is signaled with an upcall). Command 0 is a reserved command to - /// detect if a peripheral system call driver is installed and must - /// always return a CommandReturn::Success. + /// System call for a process to perform a short synchronous operation or + /// start a long-running split-phase operation (whose completion is signaled + /// with an upcall). Command 0 is a reserved command to detect if a + /// peripheral system call driver is installed and must always return a + /// [`CommandReturn::success`]. fn command( &self, command_num: usize, @@ -203,15 +125,15 @@ pub trait SyscallDriver { } /// System call for a process to pass a buffer (a - /// `UserspaceReadableProcessBuffer`) to the kernel that the kernel can + /// [`UserspaceReadableProcessBuffer`]) to the kernel that the kernel can /// either read or write. The kernel calls this method only after it checks /// that the entire buffer is within memory the process can both read and /// write. /// - /// This is different to `allow_readwrite()` in that the app is allowed - /// to read the buffer once it has been passed to the kernel. - /// For more details on how this can be done safely see the userspace - /// readable allow syscalls TRDXXX. + /// This is different to `allow_readwrite` in that the app is allowed to + /// read the buffer once it has been passed to the kernel. For more details + /// on how this can be done safely see the userspace readable allow syscalls + /// TRDXXX. fn allow_userspace_readable( &self, app: ProcessId, @@ -226,7 +148,7 @@ pub trait SyscallDriver { /// The core kernel uses this function to instruct a capsule to ensure its /// grant (if it has one) is allocated for a specific process. The core /// kernel needs the capsule to initiate the allocation because only the - /// capsule knows the type T (and therefore the size of T) that will be + /// capsule knows the type `T` (and therefore the size of `T`) that will be /// stored in the grant. /// /// The typical implementation will look like: @@ -240,7 +162,7 @@ pub trait SyscallDriver { /// forgetting to implement this function. /// /// If a capsule fails to successfully implement this function, subscribe - /// calls from userspace for the Driver may fail. + /// calls from userspace for the [`SyscallDriver`] may fail. // // The inclusion of this function originates from the method for ensuring // correct upcall swapping semantics in the kernel starting with Tock 2.0. @@ -306,10 +228,10 @@ pub trait SyscallDriver { // together. // // Based on the available options, the Tock developers decided go with - // option 4 and add the `allocate_grant` method to the `Driver` trait. This - // mechanism may find more uses in the future if the kernel needs to store - // additional state on a per-driver basis and therefore needs a mechanism to - // force a grant allocation. + // option 4 and add the `allocate_grant` method to the `SyscallDriver` + // trait. This mechanism may find more uses in the future if the kernel + // needs to store additional state on a per-driver basis and therefore needs + // a mechanism to force a grant allocation. // // This same mechanism was later extended to handle allow calls as well. // Capsules that do not need upcalls but do use process buffers must also