@@ -35,7 +35,6 @@ pub struct FixedCpuLocal {
35
35
}
36
36
// NOTE: These fields must be kept in sync with `cpu_local::FixedCpuLocal`.
37
37
impl FixedCpuLocal {
38
- const SELF_PTR_OFFSET : usize = 0 ;
39
38
pub const CPU_ID : Self = Self { offset : 8 , size : 4 , align : 4 } ;
40
39
pub const PREEMPTION_COUNT : Self = Self { offset : 12 , size : 1 , align : 1 } ;
41
40
pub const TASK_SWITCH_PREEMPTION_GUARD : Self = Self { offset : 16 , size : 8 , align : 4 } ;
@@ -120,7 +119,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
120
119
unsafe {
121
120
#[ cfg( target_arch = "x86_64" ) ]
122
121
asm ! (
123
- concat! ( "mov {}, gs:[0]" ) , // the SELF_PTR_OFFSET is 0
122
+ "mov {}, gs:[0]" , // the SELF_PTR_OFFSET is 0
124
123
lateout( reg) self_ptr,
125
124
options( nostack, preserves_flags, readonly, pure)
126
125
) ;
@@ -135,7 +134,7 @@ impl<const OFFSET: usize, T> CpuLocal<OFFSET, T> {
135
134
impl < const OFFSET : usize , T : Copy > CpuLocal < OFFSET , T > {
136
135
/// Returns a copy of this `CpuLocal`'s inner value of type `T`.
137
136
///
138
- /// This is a convenience functiononly available for types where `T: Copy`.
137
+ /// This is a convenience function only available for types where `T: Copy`.
139
138
pub fn get ( & self ) -> T {
140
139
self . with ( |v| * v)
141
140
}
@@ -144,67 +143,66 @@ impl<const OFFSET: usize, T: Copy> CpuLocal<OFFSET, T> {
144
143
145
144
/// The underlying memory region for each CPU's per-CPU data.
146
145
#[ derive( Debug ) ]
147
- struct CpuLocalDataImage ( MappedPages ) ;
148
- impl CpuLocalDataImage {
149
- /// This function does 3 main things:
150
- /// 1. Allocates a new CPU-local data image for this CPU.
151
- /// 2. Sets the self pointer value such that it can be properly accessed.
152
- /// 3. Sets this CPU's base register (e.g., GsBase on x86_64) to the address
153
- /// of this new data image, making it "currently active" and accessible.
154
- fn new ( ) -> Result < CpuLocalDataImage , & ' static str > {
155
- // 1. Allocate a single page to store each CPU's local data.
156
- let mut mp = memory:: create_mapping ( 1 , PteFlags :: new ( ) . writable ( true ) . valid ( true ) ) ?;
157
-
158
- // 2. Set up the self pointer for the new data image.
159
- let self_ptr_value = mp. start_address ( ) . value ( ) ;
160
- let self_ptr_dest = mp. as_type_mut :: < usize > ( 0 ) ?;
161
- * self_ptr_dest = self_ptr_value;
146
+ struct CpuLocalDataRegion ( MappedPages ) ;
147
+ impl CpuLocalDataRegion {
148
+ /// Allocates a new CPU-local data image.
149
+ fn new ( size_of_per_cpu_data : usize ) -> Result < CpuLocalDataRegion , & ' static str > {
150
+ let mp = memory:: create_mapping (
151
+ size_of_per_cpu_data,
152
+ PteFlags :: new ( ) . writable ( true ) . valid ( true ) ,
153
+ ) ?;
154
+ Ok ( CpuLocalDataRegion ( mp) )
155
+ }
162
156
163
- // 3. Set the base register used for CPU-local data.
164
- {
165
- #[ cfg( target_arch = "x86_64" ) ] {
166
- let gsbase_val = VirtAddr :: new_truncate ( self_ptr_value as u64 ) ;
167
- log:: warn!( "Writing value {:#X} to GSBASE" , gsbase_val) ;
168
- GsBase :: write ( gsbase_val) ;
169
- }
157
+ /// Sets this CPU's base register (e.g., GsBase on x86_64) to the address
158
+ /// of this CPU-local data image, making it "currently active" and accessible.
159
+ fn set_as_current_cpu_local_base ( & self ) {
160
+ let self_ptr_value = self . 0 . start_address ( ) . value ( ) ;
170
161
171
- #[ cfg( not( target_arch = "x86_64" ) ) ]
172
- todo ! ( "CPU-local variable access is not yet implemented on this architecture" )
162
+ #[ cfg( target_arch = "x86_64" ) ] {
163
+ let gsbase_val = VirtAddr :: new_truncate ( self_ptr_value as u64 ) ;
164
+ log:: warn!( "Writing value {:#X} to GSBASE" , gsbase_val) ;
165
+ GsBase :: write ( gsbase_val) ;
173
166
}
174
167
175
- Ok ( CpuLocalDataImage ( mp) )
168
+ #[ cfg( not( target_arch = "x86_64" ) ) ]
169
+ todo ! ( "CPU-local variable access is not yet implemented on this architecture" )
176
170
}
177
171
}
178
172
179
173
180
- /// Initializes the CPU-local data image for this CPU.
174
+ /// Initializes the CPU-local data region for this CPU.
181
175
///
182
176
/// Note: this is invoked by the `per_cpu` crate;
183
177
/// other crates do not need to invoke this.
184
178
pub fn init < P > (
185
179
cpu_id : u32 ,
180
+ size_of_per_cpu_data : usize ,
186
181
per_cpu_data_initializer : impl FnOnce ( usize ) -> P
187
182
) -> Result < ( ) , & ' static str > {
188
183
/// The global set of all per-CPU data regions.
189
- static CPU_LOCAL_DATA_REGIONS : Mutex < BTreeMap < u32 , CpuLocalDataImage > > = Mutex :: new ( BTreeMap :: new ( ) ) ;
184
+ static CPU_LOCAL_DATA_REGIONS : Mutex < BTreeMap < u32 , CpuLocalDataRegion > > = Mutex :: new ( BTreeMap :: new ( ) ) ;
190
185
191
186
let mut regions = CPU_LOCAL_DATA_REGIONS . lock ( ) ;
192
187
let entry = regions. entry ( cpu_id) ;
193
- let data_image = match entry {
194
- Entry :: Vacant ( v) => v. insert ( CpuLocalDataImage :: new ( ) ?) ,
188
+ let data_region = match entry {
189
+ Entry :: Vacant ( v) => v. insert ( CpuLocalDataRegion :: new ( size_of_per_cpu_data ) ?) ,
195
190
Entry :: Occupied ( _) => return Err ( "BUG: cannot init CPU-local data more than once" ) ,
196
191
} ;
197
- let self_ptr = data_image. 0 . start_address ( ) . value ( ) ;
198
192
199
- // Run the given initializer function on the per-CPU data.
200
- let new_data_image = CpuLocal :: < { FixedCpuLocal :: SELF_PTR_OFFSET } , P > ( PhantomData ) ;
201
- new_data_image . with_mut ( |per_cpu_data_mut| {
193
+ // Run the given initializer function to initialize the per-CPU data region .
194
+ {
195
+ let self_ptr = data_region . 0 . start_address ( ) . value ( ) ;
202
196
let initial_value = per_cpu_data_initializer ( self_ptr) ;
203
- let existing_junk = core:: mem:: replace ( per_cpu_data_mut, initial_value) ;
204
- // The memory contents we just replaced was random junk, so it'd be invalid
205
- // to run any destructors on it. Thus, we must forget it here.
206
- core:: mem:: forget ( existing_junk) ;
207
- } ) ;
197
+ // SAFETY:
198
+ // ✅ We just allocated memory for the self ptr above, it is only accessible by us.
199
+ // ✅ That memory is mutable (writable) and is aligned to a page boundary.
200
+ // ✅ The memory is at least as large as `size_of::<P>()`.
201
+ unsafe { core:: ptr:: write ( self_ptr as * mut P , initial_value) } ;
202
+ }
203
+
204
+ // Set the new CPU-local data region as active and ready to be used on this CPU.
205
+ data_region. set_as_current_cpu_local_base ( ) ;
208
206
209
207
// TODO Remove, temp tests
210
208
if true {
0 commit comments