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 {}