obkrnl/context/
x86_64.rs

1use super::Base;
2use crate::arch::{ArchConfig, wrmsr};
3use core::arch::asm;
4use core::marker::PhantomPinned;
5use core::mem::offset_of;
6use core::pin::Pin;
7
8pub const fn current_trap_rsp_offset() -> usize {
9    offset_of!(Context, trap_rsp)
10}
11
12pub const fn current_user_rsp_offset() -> usize {
13    offset_of!(Context, user_rsp)
14}
15
16/// Extended [Base] for x86-64.
17#[repr(C)]
18pub(super) struct Context {
19    pub base: Base,        // Must be first field.
20    pub trap_rsp: *mut u8, // pc_rsp0
21    pub user_rsp: usize,   // pc_scratch_rsp
22    phantom: PhantomPinned,
23}
24
25impl Context {
26    pub fn new(base: Base, arch: &ArchConfig) -> Self {
27        Self {
28            base,
29            trap_rsp: arch.trap_rsp as *mut u8,
30            user_rsp: 0,
31            phantom: PhantomPinned,
32        }
33    }
34
35    /// Set kernel `GS` segment register to `self`.
36    ///
37    /// At a glance this may looks incorrect due to `0xc0000102` is `KERNEL_GS_BAS` according to the
38    /// docs. The problem is the CPU always use the value from `0xc0000101` regardless the current
39    /// privilege level. That means `KERNEL_GS_BAS` is the name when the CPU currently on the user
40    /// space.
41    ///
42    /// This also set user-mode `FS` and `GS` to null.
43    pub unsafe fn activate(self: Pin<&mut Self>) {
44        // Set GS for kernel mode.
45        unsafe { wrmsr(0xc0000101, self.get_unchecked_mut() as *mut Self as usize) };
46
47        // Clear FS and GS for user mode.
48        unsafe { wrmsr(0xc0000100, 0) };
49        unsafe { wrmsr(0xc0000102, 0) };
50    }
51
52    pub(super) unsafe fn store_ptr<const O: usize, T>(v: *const T) {
53        unsafe {
54            asm!("mov gs:[{o}], {v}", o = const O, v = in(reg) v, options(preserves_flags, nostack))
55        };
56    }
57
58    pub unsafe fn load_static_ptr<const O: usize, T>() -> *const T {
59        let mut v;
60
61        unsafe {
62            asm!(
63                "mov {out}, gs:[{off}]",
64                off = const O,
65                out = out(reg) v,
66                options(pure, nomem, preserves_flags, nostack)
67            )
68        };
69
70        v
71    }
72
73    pub unsafe fn load_ptr<const O: usize, T>() -> *const T {
74        let mut v;
75
76        unsafe {
77            asm!(
78                "mov {out}, gs:[{off}]",
79                off = const O,
80                out = out(reg) v,
81                options(pure, readonly, preserves_flags, nostack)
82            )
83        };
84
85        v
86    }
87
88    pub unsafe fn load_volatile_usize<const O: usize>() -> usize {
89        let mut v;
90
91        unsafe {
92            asm!(
93                "mov {out}, gs:[{off}]",
94                off = const O,
95                out = out(reg) v,
96                options(preserves_flags, nostack)
97            )
98        };
99
100        v
101    }
102}