@@ -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}
0 commit comments