-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathuspace.rs
More file actions
109 lines (96 loc) · 3.14 KB
/
Copy pathuspace.rs
File metadata and controls
109 lines (96 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Structures and functions for user space.
use memory_addr::VirtAddr;
use crate::TrapFrame;
/// Context to enter user space.
pub struct UspaceContext(TrapFrame);
impl UspaceContext {
/// Creates an empty context with all registers set to zero.
pub const fn empty() -> Self {
unsafe { core::mem::MaybeUninit::zeroed().assume_init() }
}
/// Creates a new context with the given entry point, user stack pointer,
/// and the argument.
pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
use x86_64::registers::rflags::RFlags;
use crate::GdtStruct;
Self(TrapFrame {
rdi: arg0 as _,
rip: entry as _,
cs: GdtStruct::UCODE64_SELECTOR.0 as _,
rflags: RFlags::INTERRUPT_FLAG.bits(), // IOPL = 0, IF = 1
rsp: ustack_top.as_usize() as _,
ss: GdtStruct::UDATA_SELECTOR.0 as _,
..Default::default()
})
}
/// Creates a new context from the given [`TrapFrame`].
///
/// It copies almost all registers except `CS` and `SS` which need to be
/// set to the user segment selectors.
pub const fn from(tf: &TrapFrame) -> Self {
use crate::GdtStruct;
let mut tf = *tf;
tf.cs = GdtStruct::UCODE64_SELECTOR.0 as _;
tf.ss = GdtStruct::UDATA_SELECTOR.0 as _;
Self(tf)
}
/// Gets the instruction pointer.
pub const fn get_ip(&self) -> usize {
self.0.rip as _
}
/// Gets the stack pointer.
pub const fn get_sp(&self) -> usize {
self.0.rsp as _
}
/// Sets the instruction pointer.
pub const fn set_ip(&mut self, rip: usize) {
self.0.rip = rip as _;
}
/// Sets the stack pointer.
pub const fn set_sp(&mut self, rsp: usize) {
self.0.rsp = rsp as _;
}
/// Sets the return value register.
pub const fn set_retval(&mut self, rax: usize) {
self.0.rax = rax as _;
}
/// Enters user space.
///
/// It restores the user registers and jumps to the user entry point
/// (saved in `rip`).
/// When an exception or syscall occurs, the kernel stack pointer is
/// switched to `kstack_top`.
///
/// # Safety
///
/// This function is unsafe because it changes processor mode and the stack.
pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! {
crate::asm::disable_irqs();
assert_eq!(super::gdt::read_tss_rsp0(), kstack_top);
unsafe {
core::arch::asm!("
mov rsp, {tf}
pop rax
pop rcx
pop rdx
pop rbx
pop rbp
pop rsi
pop rdi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
add rsp, 16 // skip vector, error_code
swapgs
iretq",
tf = in(reg) &self.0,
options(noreturn),
)
}
}
}