Skip to content

Commit b0ce230

Browse files
committed
Enum API
Signed-off-by: Klim Tsoutsman <[email protected]>
1 parent 0bbb4f8 commit b0ce230

File tree

2 files changed

+121
-55
lines changed

2 files changed

+121
-55
lines changed

kernel/cpu_local/src/lib.rs

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,64 @@ pub struct FixedCpuLocal {
3636
pub size: usize,
3737
pub align: usize,
3838
}
39+
3940
// NOTE: These fields must be kept in sync with `cpu_local::FixedCpuLocal`.
40-
impl FixedCpuLocal {
41-
pub const CPU_ID: Self = Self { offset: 8, size: 4, align: 4 };
42-
pub const PREEMPTION_COUNT: Self = Self { offset: 12, size: 1, align: 1 };
43-
pub const TASK_SWITCH_PREEMPTION_GUARD: Self = Self { offset: 16, size: 8, align: 4 };
44-
pub const DROP_AFTER_TASK_SWITCH: Self = Self { offset: 24, size: 8, align: 8 };
41+
pub enum CpuLocalField {
42+
CpuId,
43+
PreemptionCount,
44+
TaskSwitchPreemptionGuard,
45+
DropAfterTaskSwitch,
46+
}
47+
48+
impl CpuLocalField {
49+
pub const fn offset(&self) -> usize {
50+
match self {
51+
Self::CpuId => 8,
52+
Self::PreemptionCount => 12,
53+
Self::TaskSwitchPreemptionGuard => 16,
54+
Self::DropAfterTaskSwitch => 24,
55+
}
56+
}
57+
58+
// TODO: Do we even need to know the size and alignment?
59+
60+
// pub const fn size(&self) -> usize {
61+
// match self {
62+
// Self::CpuId => 4,
63+
// Self::PreemptionCount => 1,
64+
// Self::TaskSwitchPreemptionGuard => 8,
65+
// Self::DropAfterTaskSwitch => 8,
66+
// }
67+
// }
68+
69+
// pub const fn align(&self) -> usize {
70+
// match self {
71+
// Self::CpuId => 4,
72+
// Self::PreemptionCount => 1,
73+
// Self::TaskSwitchPreemptionGuard => 4,
74+
// Self::DropAfterTaskSwitch => 8,
75+
// }
76+
// }
77+
}
78+
79+
// TODO: Could come up with a more imaginative name.
80+
pub unsafe trait Field: Sized {
81+
const FIELD: CpuLocalField;
82+
83+
// const SIZE_CHECK: () = assert!(Self::FIELD.size() == size_of::<Self>());
84+
// const ALIGN_CHECK: () = assert!(Self::FIELD.align() == align_of::<Self>());
4585
}
4686

4787
/// A reference to a CPU-local variable.
4888
///
4989
/// Note that this struct doesn't contain an instance of the type `T`,
5090
/// and dropping it has no effect.
51-
pub struct CpuLocal<const OFFSET: usize, T>(PhantomData<*mut T>);
52-
impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
91+
pub struct CpuLocal<T: Field>(PhantomData<*mut T>);
92+
93+
impl<T> CpuLocal<T>
94+
where
95+
T: Field,
96+
{
5397
/// Creates a new reference to a predefined CPU-local variable.
5498
///
5599
/// # Arguments
@@ -63,12 +107,8 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
63107
///
64108
/// Thus, the caller must guarantee that the type `T` is correct for the
65109
/// given `FixedCpuLocal`.
66-
pub const unsafe fn new_fixed(
67-
fixed: FixedCpuLocal,
68-
) -> Self {
69-
assert!(OFFSET == fixed.offset);
70-
assert!(size_of::<T>() == fixed.size);
71-
assert!(align_of::<T>() == fixed.align);
110+
pub const unsafe fn new_fixed() -> Self {
111+
// FIXME: Should this still be unsafe?
72112
Self(PhantomData)
73113
}
74114

@@ -97,7 +137,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
97137
where
98138
F: FnOnce(&T) -> R,
99139
{
100-
let ptr_to_cpu_local = self.self_ptr() + OFFSET;
140+
let ptr_to_cpu_local = self.self_ptr() + T::FIELD.offset();
101141
let local_ref = unsafe { &*(ptr_to_cpu_local as *const T) };
102142
func(local_ref)
103143
}
@@ -111,7 +151,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
111151
F: FnOnce(&mut T) -> R,
112152
{
113153
let _held_interrupts = irq_safety::hold_interrupts();
114-
let ptr_to_cpu_local = self.self_ptr() + OFFSET;
154+
let ptr_to_cpu_local = self.self_ptr() + T::FIELD.offset();
115155
let local_ref_mut = unsafe { &mut *(ptr_to_cpu_local as *mut T) };
116156
func(local_ref_mut)
117157
}
@@ -134,7 +174,10 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
134174
}
135175
}
136176

137-
impl<const OFFSET: usize, T: Copy> CpuLocal<OFFSET, T> {
177+
impl<T> CpuLocal<T>
178+
where
179+
T: Copy + Field,
180+
{
138181
/// Returns a copy of this `CpuLocal`'s inner value of type `T`.
139182
///
140183
/// This is a convenience function only available for types where `T: Copy`.
@@ -209,18 +252,23 @@ pub fn init<P>(
209252

210253
// TODO Remove, temp tests
211254
if true {
212-
let test_value = CpuLocal::<32, u64>(PhantomData);
213-
test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
214-
log::warn!("Setting test_value to 0x12345678...");
215-
test_value.with_mut(|tv| { *tv = 0x12345678; });
216-
test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
217-
218-
let test_string = CpuLocal::<40, alloc::string::String>(PhantomData);
219-
test_string.with(|s| log::warn!("Got test_string: {:?}", s));
220-
let new_str = ", world!";
221-
log::warn!("Appending {:?} to test_string...", new_str);
222-
test_string.with_mut(|s| s.push_str(new_str));
223-
test_string.with(|s| log::warn!("Got test_string: {:?}", s));
255+
// NOTE: The fact that this previously compiled in `cpu_local` is
256+
// indicative of an unsafe API, as the offsets (and types) are
257+
// completely arbitrary. There's nothing stopping us from trying to
258+
// access CpuLocal::<16, String> which would be undefined behaviour.
259+
260+
// let test_value = CpuLocal::<32, u64>(PhantomData);
261+
// test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
262+
// log::warn!("Setting test_value to 0x12345678...");
263+
// test_value.with_mut(|tv| { *tv = 0x12345678; });
264+
// test_value.with(|tv| log::warn!("Got test_value: {:#X}", *tv));
265+
266+
// let test_string = CpuLocal::<40, alloc::string::String>(PhantomData);
267+
// test_string.with(|s| log::warn!("Got test_string: {:?}", s));
268+
// let new_str = ", world!";
269+
// log::warn!("Appending {:?} to test_string...", new_str);
270+
// test_string.with_mut(|s| s.push_str(new_str));
271+
// test_string.with(|s| log::warn!("Got test_string: {:?}", s));
224272
}
225273
Ok(())
226274
}

kernel/per_cpu/src/lib.rs

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535

3636
extern crate alloc; // TODO temp remove this
3737

38-
use cpu::CpuId;
39-
use preemption::{PreemptionCount, PreemptionGuard};
38+
use cpu_local::{CpuLocalField, Field};
39+
use preemption::PreemptionGuard;
4040
use task::TaskRef;
4141

4242
/// The data stored on a per-CPU basis in Theseus.
@@ -71,35 +71,64 @@ pub struct PerCpuData {
7171
/// A preemption guard used during task switching to ensure that one task switch
7272
/// cannot interrupt (preempt) another task switch already in progress.
7373
// task_switch_preemption_guard: Option<TestU32>, // TODO temp remove this
74-
task_switch_preemption_guard: Option<PreemptionGuard>,
74+
task_switch_preemption_guard: TaskSwitchPreemptionGuard,
7575
/// Data that should be dropped after switching away from a task that has exited.
7676
/// Currently, this contains the previous task's `TaskRef` that was removed
7777
/// from its TLS area during the last task switch away from it.
78-
drop_after_task_switch: Option<TaskRef>,
78+
drop_after_task_switch: DropAfterTaskSwitch,
7979
test_value: u64,
8080
test_string: alloc::string::String,
8181
}
82+
8283
impl PerCpuData {
8384
/// Defines the initial values of each per-CPU state.
84-
fn new(self_ptr: usize, cpu_id: CpuId) -> Self {
85+
fn new(self_ptr: usize, cpu_id: cpu::CpuId) -> Self {
8586
Self {
8687
self_ptr,
87-
cpu_id,
88-
preemption_count: PreemptionCount::new(),
89-
task_switch_preemption_guard: None,
90-
drop_after_task_switch: None,
88+
cpu_id: CpuId(cpu_id),
89+
preemption_count: PreemptionCount(preemption::PreemptionCount::new()),
90+
task_switch_preemption_guard: TaskSwitchPreemptionGuard(None),
91+
drop_after_task_switch: DropAfterTaskSwitch(None),
9192
test_value: 0xDEADBEEF,
9293
test_string: alloc::string::String::from("test_string hello"),
9394

9495
}
9596
}
9697
}
9798

99+
#[repr(transparent)]
100+
pub struct CpuId(pub cpu::CpuId);
101+
102+
unsafe impl Field for CpuId {
103+
const FIELD: CpuLocalField = CpuLocalField::CpuId;
104+
}
105+
106+
#[repr(transparent)]
107+
pub struct PreemptionCount(pub preemption::PreemptionCount);
108+
109+
unsafe impl Field for PreemptionCount {
110+
const FIELD: CpuLocalField = CpuLocalField::PreemptionCount;
111+
}
112+
113+
#[repr(transparent)]
114+
pub struct TaskSwitchPreemptionGuard(pub Option<PreemptionGuard>);
115+
116+
unsafe impl Field for TaskSwitchPreemptionGuard {
117+
const FIELD: CpuLocalField = CpuLocalField::TaskSwitchPreemptionGuard;
118+
}
119+
120+
#[repr(transparent)]
121+
pub struct DropAfterTaskSwitch(pub Option<TaskRef>);
122+
123+
unsafe impl Field for DropAfterTaskSwitch {
124+
const FIELD: CpuLocalField = CpuLocalField::DropAfterTaskSwitch;
125+
}
126+
98127
/// Initializes the current CPU's `PerCpuData`.
99128
///
100129
/// This must be invoked from (run on) the actual CPU with the given `cpu_id`;
101130
/// the main bootstrap CPU cannot run this for all CPUs itself.
102-
pub fn init(cpu_id: CpuId) -> Result<(), &'static str> {
131+
pub fn init(cpu_id: cpu::CpuId) -> Result<(), &'static str> {
103132
cpu_local::init(
104133
cpu_id.value(),
105134
core::mem::size_of::<PerCpuData>(),
@@ -109,27 +138,16 @@ pub fn init(cpu_id: CpuId) -> Result<(), &'static str> {
109138

110139
mod const_assertions {
111140
use core::mem::{align_of, size_of};
112-
use cpu_local::FixedCpuLocal;
141+
use cpu_local::CpuLocalField;
113142
use memoffset::offset_of;
114143
use super::*;
115144

116-
const _: () = assert!(0 == offset_of!(PerCpuData, self_ptr));
117145
const _: () = assert!(8 == size_of::<usize>());
118146
const _: () = assert!(8 == align_of::<usize>());
119147

120-
const _: () = assert!(FixedCpuLocal::CPU_ID.offset == offset_of!(PerCpuData, cpu_id));
121-
const _: () = assert!(FixedCpuLocal::CPU_ID.size == size_of::<CpuId>());
122-
const _: () = assert!(FixedCpuLocal::CPU_ID.align == align_of::<CpuId>());
123-
124-
const _: () = assert!(FixedCpuLocal::PREEMPTION_COUNT.offset == offset_of!(PerCpuData, preemption_count));
125-
const _: () = assert!(FixedCpuLocal::PREEMPTION_COUNT.size == size_of::<PreemptionCount>());
126-
const _: () = assert!(FixedCpuLocal::PREEMPTION_COUNT.align == align_of::<PreemptionCount>());
127-
128-
const _: () = assert!(FixedCpuLocal::TASK_SWITCH_PREEMPTION_GUARD.offset == offset_of!(PerCpuData, task_switch_preemption_guard));
129-
const _: () = assert!(FixedCpuLocal::TASK_SWITCH_PREEMPTION_GUARD.size == size_of::<Option<PreemptionGuard>>());
130-
const _: () = assert!(FixedCpuLocal::TASK_SWITCH_PREEMPTION_GUARD.align == align_of::<Option<PreemptionGuard>>());
131-
132-
const _: () = assert!(FixedCpuLocal::DROP_AFTER_TASK_SWITCH.offset == offset_of!(PerCpuData, drop_after_task_switch));
133-
const _: () = assert!(FixedCpuLocal::DROP_AFTER_TASK_SWITCH.size == size_of::<Option<TaskRef>>());
134-
const _: () = assert!(FixedCpuLocal::DROP_AFTER_TASK_SWITCH.align == align_of::<Option<TaskRef >>());
148+
const _: () = assert!(0 == offset_of!(PerCpuData, self_ptr));
149+
const _: () = assert!(CpuLocalField::CpuId.offset() == offset_of!(PerCpuData, cpu_id));
150+
const _: () = assert!(CpuLocalField::PreemptionCount.offset() == offset_of!(PerCpuData, preemption_count));
151+
const _: () = assert!(CpuLocalField::TaskSwitchPreemptionGuard.offset() == offset_of!(PerCpuData, task_switch_preemption_guard));
152+
const _: () = assert!(CpuLocalField::DropAfterTaskSwitch.offset() == offset_of!(PerCpuData, drop_after_task_switch));
135153
}

0 commit comments

Comments
 (0)