Skip to main content

ostd/
user.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! User mode.
4
5use crate::{
6    arch::{cpu::context::UserContext, trap::TrapFrame},
7    irq::DisabledLocalIrqGuard,
8};
9
10/// The internal interface that every CPU architecture-specific [`UserContext`] implements.
11///
12/// This should only used in [`UserMode`]. It is only visible in `ostd`.
13pub(crate) trait UserContextApiInternal {
14    /// Starts executing in the user mode.
15    fn execute<T: UserModeHooks>(&mut self, hooks: &T) -> ReturnReason;
16
17    /// Uses the information inside CpuContext to build a trapframe
18    fn as_trap_frame(&self) -> TrapFrame;
19}
20
21/// The common interface that every CPU architecture-specific [`UserContext`] implements.
22pub trait UserContextApi {
23    /// Sets the instruction pointer
24    fn set_instruction_pointer(&mut self, ip: usize);
25
26    /// Gets the instruction pointer
27    fn instruction_pointer(&self) -> usize;
28
29    /// Sets the stack pointer
30    fn set_stack_pointer(&mut self, sp: usize);
31
32    /// Gets the stack pointer
33    fn stack_pointer(&self) -> usize;
34}
35
36/// Code execution in the user mode.
37///
38/// This type enables executing the code in user space from a task in the kernel
39/// space safely.
40///
41/// Here is a sample code on how to use `UserMode`.
42///
43/// ```no_run
44/// # fn handle_return(_reason: crate::user::ReturnReason) {}
45/// #
46/// use crate::{
47///     arch::cpu::context::UserContext,
48///     user::{DummyUserHooks, UserMode},
49/// };
50///
51/// let user_ctx = UserContext::default();
52/// let mut user_mode = UserMode::new(user_ctx);
53///
54/// // Note: Users should activate a suitable `VmSpace` before to support
55/// // user-mode execution.
56///
57/// loop {
58///     // Execute in the user space until some interesting events occur.
59///     let return_reason = user_mode.execute(&DummyUserHooks);
60///     // Handle the event, e.g., a system call.
61///     handle_return(return_reason);
62/// }
63/// ```
64pub struct UserMode {
65    context: UserContext,
66}
67
68// An instance of `UserMode` is bound to the current task. So it must not be sent to other tasks.
69impl !Send for UserMode {}
70// Note that implementing `!Sync` is unnecessary
71// because entering the user space via `UserMode` requires taking a mutable reference.
72
73impl UserMode {
74    /// Creates a new `UserMode`.
75    pub fn new(context: UserContext) -> Self {
76        Self { context }
77    }
78
79    /// Starts executing in the user mode. Make sure current task is the task in `UserMode`.
80    ///
81    /// The method returns for one of three possible reasons indicated by [`ReturnReason`].
82    /// 1. A system call is issued by the user space;
83    /// 2. A CPU exception is triggered by the user space;
84    /// 3. A kernel event is pending, as indicated by the given closure.
85    ///
86    /// After handling whatever user or kernel events that
87    /// cause the method to return
88    /// and updating the user-mode CPU context,
89    /// this method can be invoked again to go back to the user space.
90    #[track_caller]
91    pub fn execute<T: UserModeHooks>(&mut self, hooks: &T) -> ReturnReason {
92        crate::task::atomic_mode::might_sleep();
93        self.context.execute(hooks)
94    }
95
96    /// Returns an immutable reference the user-mode CPU context.
97    pub fn context(&self) -> &UserContext {
98        &self.context
99    }
100
101    /// Returns a mutable reference the user-mode CPU context.
102    pub fn context_mut(&mut self) -> &mut UserContext {
103        &mut self.context
104    }
105}
106
107/// A reason as to why the control of the CPU is returned from
108/// the user space to the kernel.
109#[derive(Debug, Eq, PartialEq)]
110pub enum ReturnReason {
111    /// A system call is issued by the user space.
112    UserSyscall,
113    /// A CPU exception is triggered by the user space.
114    UserException,
115    /// A kernel event is pending
116    KernelEvent,
117}
118
119/// Hooks that will be called during [`UserMode::execute`].
120pub trait UserModeHooks {
121    /// Checks whether a kernel event is pending.
122    ///
123    /// This method will be called after user space is interrupted
124    /// by external interrupts. If the result is `true`,
125    /// [`UserMode::execute`] will return with [`ReturnReason::KernelEvent`].
126    fn has_kernel_event(&self) -> bool {
127        false
128    }
129
130    /// Prepares user space execution.
131    ///
132    /// This method will be called just before entering user space.
133    /// Local IRQs are disabled and will only be enabled after entering user space.
134    fn pre_user_run(&self, _guard: &DisabledLocalIrqGuard) {}
135}
136
137/// A struct that provides dummy (no-op) user mode hooks.
138pub struct DummyUserHooks;
139
140impl UserModeHooks for DummyUserHooks {}