Skip to main content

kernel/arch/x86_64/cpu/
gs_info.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Per-CPU GS info struct used by the kernel for things like finding the kernel stack on syscall entry
3//!
4//! Authors: MarioS271
5
6use crate::lib::addr::VirtAddr;
7use core::mem::offset_of;
8use core::sync::atomic::{AtomicU64, Ordering};
9use x86_64::registers::model_specific::{GsBase, KernelGsBase};
10
11/// A per-CPU struct which each CPU's GS kernel reg points to in order to handle syscall entry
12#[repr(C, align(64))]
13pub struct GsInfo {
14    self_ptr: AtomicU64,
15    kernel_stack_top: AtomicU64,
16    user_rsp: AtomicU64
17}
18
19pub const GS_INFO_SELF_PTR: usize = offset_of!(GsInfo, self_ptr);
20pub const GS_INFO_KERNEL_STACK_TOP: usize = offset_of!(GsInfo, kernel_stack_top);
21pub const GS_INFO_USER_RSP: usize = offset_of!(GsInfo, user_rsp);
22
23impl GsInfo {
24    /// Construct a new zeroed instance of [`GsInfo`]
25    pub const fn new() -> Self {
26        Self {
27            self_ptr: AtomicU64::new(0),
28            kernel_stack_top: AtomicU64::new(0),
29            user_rsp: AtomicU64::new(0)
30        }
31    }
32
33    /// Initialize the given [`GsInfo`]
34    ///
35    /// # Safety
36    /// The caller must guarantee the following:
37    /// - This method is called exactly once on the CPU which owns the given [`GsInfo`]
38    /// - This method is called before the first jump to userspace on the CPU which owns the
39    ///   given [`GsInfo`]
40    pub unsafe fn init(&'static self) {
41        let self_ptr = VirtAddr::from_ptr(self as *const Self);
42
43        self.self_ptr.store(self_ptr.as_u64(), Ordering::Relaxed);
44        self.kernel_stack_top.store(0u64, Ordering::Relaxed);
45
46        KernelGsBase::write(self_ptr.as_x86_64());
47        GsBase::write(VirtAddr::null().as_x86_64());
48    }
49
50    /// Set the kernel stack top of the given [`GsInfo`]
51    ///
52    /// # Safety
53    /// The caller must ensure that `kernel_stack_top` is a valid pointer to a valid, mapped
54    /// kernel stack
55    pub unsafe fn set_kernel_stack_top(&self, kernel_stack_top: VirtAddr) {
56        self.kernel_stack_top.store(kernel_stack_top.as_u64(), Ordering::Relaxed);
57    }
58
59    /// Getter for `GsInfo::self_ptr`
60    pub fn self_ptr(&self) -> u64 {
61        self.self_ptr.load(Ordering::Relaxed)
62    }
63
64    /// Getter for `GsInfo::kernel_stack_top`
65    pub fn kernel_stack_top(&self) -> u64 {
66        self.kernel_stack_top.load(Ordering::Relaxed)
67    }
68
69    /// Getter for `GsInfo::user_rsp`
70    pub fn user_rsp(&self) -> u64 {
71        self.user_rsp.load(Ordering::Relaxed)
72    }
73}