moto_sys/
shared_mem.rs

1use core::sync::atomic::AtomicU64;
2
3// Custom userspace region (1TB): the kernel will never allocate a vaddr in a userspace
4// address space in this region, so it can be used by userspace to map things like
5// stdio (stdin/stdout/stderr), env, and args.
6pub const CUSTOM_USERSPACE_REGION_START: u64 = (1_u64 << 45) + (1_u64 << 40);
7pub const CUSTOM_USERSPACE_REGION_END: u64 = CUSTOM_USERSPACE_REGION_START + (1_u64 << 40);
8
9// Describes a global static page populated by the kernel and mapped
10// into the address space of each user process (read-only).
11// Readonly in the userspace.
12#[repr(C)]
13pub struct KernelStaticPage {
14    pub version: u64,
15
16    // Fields for tsc time conversion from KVM struct pvclock_vcpu_time_info.
17    // See https://www.kernel.org/doc/Documentation/virt/kvm/msr.rst
18    pub tsc_shift: i8,
19    pub tsc_mul: u32,
20    pub tsc_in_sec: u64,
21    pub tsc_ts: u64,
22    pub system_time: u64,
23
24    // Wallclock base from struct pvclock_wall_clock.
25    // See https://www.kernel.org/doc/Documentation/virt/kvm/msr.rst
26    pub base_nsec: u64, // Add this to system_time.
27
28    // The kernel's view of system start time.
29    pub system_start_time_tsc: u64,
30
31    pub num_cpus: u32,
32}
33
34impl KernelStaticPage {
35    pub const PAGE_SIZE: u64 = 4096;
36    pub const VADDR: u64 = 0x3F7FFFE00000; // See STATIC_SHARED_PAGE_USER_VADDR in virt.rs in the kernel.
37
38    #[cfg(feature = "userspace")]
39    pub fn get() -> &'static Self {
40        // Safety: the OS is supposed to have taken care of this.
41        unsafe {
42            (Self::VADDR as usize as *const KernelStaticPage)
43                .as_ref()
44                .unwrap_unchecked()
45        }
46    }
47}
48const _: () =
49    assert!(core::mem::size_of::<KernelStaticPage>() as u64 <= KernelStaticPage::PAGE_SIZE);
50
51// Describes a per-process page shared between the kernel and the process.
52// Readonly in the userspace.
53#[derive(Debug)]
54#[repr(C)]
55pub struct ProcessStaticPage {
56    pub version: u64,
57
58    // The capabilities of the process.
59    pub capabilities: u64,
60
61    // How much memory the process can use.
62    // The number cannot change for now, but...
63    pub max_memory: AtomicU64,
64
65    pub kernel_memory_used: AtomicU64,
66    pub user_memory_used: AtomicU64,
67}
68
69impl ProcessStaticPage {
70    pub const PAGE_SIZE: u64 = 4096;
71    pub const VADDR: u64 = (1_u64 << 46) - (2 * super::syscalls::SysMem::PAGE_SIZE_MID); // x64.
72
73    #[cfg(feature = "userspace")]
74    pub fn get() -> &'static Self {
75        // Safety: the OS is supposed to have taken care of this.
76        unsafe {
77            (Self::VADDR as usize as *const ProcessStaticPage)
78                .as_ref()
79                .unwrap_unchecked()
80        }
81    }
82}
83const _: () =
84    assert!(core::mem::size_of::<ProcessStaticPage>() as u64 <= ProcessStaticPage::PAGE_SIZE);
85
86// Describes a static per-thread page shared between the kernel and the thread.
87// Usually resides at the top of the stack and is pointed at by FS register on x64.
88// Writable by the userspace.
89#[derive(Debug)]
90#[repr(C)]
91pub struct UserThreadControlBlock {
92    pub guard: u64,          // For kernel use.
93    pub kernel_version: u32, // The kernel tells the user the version of the struct.
94    pub user_version: u32,   // The userspace tells the kernel the version of the struct.
95    pub self_handle: u64,    // Could be re-used.
96    pub tls: usize,          // TLS. For userspace use.
97    pub current_cpu: u32,
98    pub reserved0: u32,
99}
100
101impl UserThreadControlBlock {
102    #[cfg(feature = "userspace")]
103    pub fn get_mut() -> &'static mut Self {
104        // Safety: the OS is supposed to have taken care of this.
105        // The userspace MUST NOT write to FS register.
106        unsafe {
107            let mut fsbase: u64;
108            core::arch::asm!("rdfsbase {}", out(reg) fsbase, options(nostack, preserves_flags));
109            (fsbase as usize as *mut Self).as_mut().unwrap()
110        }
111    }
112
113    #[cfg(feature = "userspace")]
114    pub fn get() -> &'static Self {
115        Self::get_mut()
116    }
117
118    // A "user friendly thread ID.".
119    #[cfg(feature = "userspace")]
120    pub fn __utid() -> u64 {
121        u64::MAX - Self::get().self_handle
122    }
123}