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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use crate::arch::x86_64::kernel::BOOT_INFO;
use crate::collections::CachePadded;
use crate::scheduler::{CoreId, PerCoreScheduler};
use crate::x86::bits64::task::TaskStateSegment;
use crate::x86::msr::*;
use core::ptr;
pub static mut PERCORE: PerCoreVariables = CachePadded::new(PerCoreInnerVariables::new(0));
pub type PerCoreVariables = CachePadded<PerCoreInnerVariables>;
pub struct PerCoreInnerVariables {
core_id: PerCoreVariable<CoreId>,
scheduler: PerCoreVariable<*mut PerCoreScheduler>,
pub tss: PerCoreVariable<*mut TaskStateSegment>,
pub kernel_stack: PerCoreVariable<u64>,
}
impl PerCoreInnerVariables {
pub const fn new(core_id: CoreId) -> Self {
Self {
core_id: PerCoreVariable::new(core_id),
scheduler: PerCoreVariable::new(ptr::null_mut() as *mut PerCoreScheduler),
tss: PerCoreVariable::new(ptr::null_mut() as *mut TaskStateSegment),
kernel_stack: PerCoreVariable::new(0),
}
}
}
#[repr(C)]
pub struct PerCoreVariable<T> {
data: T,
}
pub trait PerCoreVariableMethods<T> {
unsafe fn get(&self) -> T;
unsafe fn set(&self, value: T);
}
impl<T> PerCoreVariable<T> {
const fn new(value: T) -> Self {
Self { data: value }
}
#[inline]
unsafe fn offset(&self) -> usize {
let base = &PERCORE as *const _ as usize;
let field = self as *const _ as usize;
field - base
}
}
impl<T> PerCoreVariableMethods<T> for PerCoreVariable<T> {
#[inline]
default unsafe fn get(&self) -> T {
let value: T;
llvm_asm!("movq %gs:($1), $0" : "=r"(value) : "r"(self.offset()) :: "volatile");
value
}
#[inline]
default unsafe fn set(&self, value: T) {
llvm_asm!("movq $0, %gs:($1)" :: "r"(value), "r"(self.offset()) :: "volatile");
}
}
pub trait Is32BitVariable {}
impl Is32BitVariable for u32 {}
impl<T: Is32BitVariable> PerCoreVariableMethods<T> for PerCoreVariable<T> {
#[inline]
unsafe fn get(&self) -> T {
let value: T;
llvm_asm!("movl %gs:($1), $0" : "=r"(value) : "r"(self.offset()) :: "volatile");
value
}
#[inline]
unsafe fn set(&self, value: T) {
llvm_asm!("movl $0, %gs:($1)" :: "r"(value), "r"(self.offset()) :: "volatile");
}
}
#[cfg(not(test))]
#[inline]
pub fn core_id() -> CoreId {
unsafe { PERCORE.core_id.get() }
}
#[cfg(test)]
pub fn core_id() -> CoreId {
0
}
#[inline(always)]
pub fn get_kernel_stack() -> u64 {
unsafe { PERCORE.kernel_stack.get() }
}
#[inline]
pub fn set_kernel_stack(addr: u64) {
unsafe { PERCORE.kernel_stack.set(addr) }
}
#[inline]
pub fn core_scheduler() -> &'static mut PerCoreScheduler {
unsafe { &mut *PERCORE.scheduler.get() }
}
#[inline]
pub fn set_core_scheduler(scheduler: *mut PerCoreScheduler) {
unsafe {
PERCORE.scheduler.set(scheduler);
}
}
pub fn init() {
unsafe {
let address = core::ptr::read_volatile(&(*BOOT_INFO).current_percore_address);
if address == 0 {
wrmsr(IA32_GS_BASE, &PERCORE as *const _ as u64);
} else {
wrmsr(IA32_GS_BASE, address as u64);
}
}
}