1
1
//! Module instance types and functionality.
2
2
3
- use oro_mem:: {
4
- mapper:: { AddressSegment , AddressSpace as _, MapError } ,
5
- phys:: PhysAddr ,
6
- } ;
3
+ use oro_mem:: mapper:: { AddressSegment , AddressSpace as _, MapError } ;
7
4
8
5
use crate :: {
9
6
AddressSpace , Kernel , UserHandle ,
@@ -63,16 +60,23 @@ pub struct Instance<A: Arch> {
63
60
data : TypeTable ,
64
61
/// Memory tokens owned by this instance.
65
62
///
63
+ /// DOES cover thread-local mappings. This is managed exclusively
64
+ /// by [`Thread`]s; tokens here are shared between all threads in the instance.
65
+ ///
66
66
/// If a token is here, the instance is allowed to map it
67
67
/// into its address space.
68
- tokens : Table < Tab < Token > > ,
68
+ pub ( super ) tokens : Table < Tab < Token > > ,
69
69
/// The virtual memory mappings of virtual addresses to tokens.
70
+ ///
71
+ /// Does NOT cover thread-local mappings. This is managed exclusively
72
+ /// by [`Thread`]s; tokens here are shared between all threads in the instance.
73
+ ///
70
74
/// Values are `(token, page_id)` pairs.
71
75
// TODO(qix-): This assumes a 4096 byte page size, and is also
72
76
// TODO(qix-): not a very efficient data structure. It will be
73
77
// TODO(qix-): replaced with a more efficient data structure
74
78
// TODO(qix-): in the future.
75
- token_vmap : Table < ( Tab < Token > , usize ) > ,
79
+ pub ( super ) token_vmap : Table < ( Tab < Token > , usize ) > ,
76
80
}
77
81
78
82
impl < A : Arch > Instance < A > {
@@ -132,202 +136,6 @@ impl<A: Arch> Instance<A> {
132
136
& self . threads
133
137
}
134
138
135
- /// Attempts to return a [`Token`] from the instance's token list.
136
- ///
137
- /// Returns `None` if the token is not present.
138
- #[ inline]
139
- #[ must_use]
140
- pub fn token ( & self , id : u64 ) -> Option < Tab < Token > > {
141
- self . tokens . get ( id) . cloned ( )
142
- }
143
-
144
- /// "Forgets" a [`Token`] from the instance's token list.
145
- ///
146
- /// Returns the forgotten token, or `None` if the token is not present.
147
- #[ inline]
148
- pub fn forget_token ( & mut self , id : u64 ) -> Option < Tab < Token > > {
149
- self . tokens . remove ( id)
150
- }
151
-
152
- /// Inserts a [`Token`] into the instance's token list.
153
- ///
154
- /// Returns the ID of the token.
155
- #[ inline]
156
- pub fn insert_token ( & mut self , token : Tab < Token > ) -> u64 {
157
- self . tokens . insert_tab ( token)
158
- }
159
-
160
- /// Maps (sets the base of and reserves) a [`Token`] into the instance's address space.
161
- ///
162
- /// **This does not immediately map in any memory.** It only marks the range
163
- /// in the _internal kernel_ address space as reserved for the token, to be
164
- /// committed later (typically via a page fault calling [`Instance::try_commit_token_at`]).
165
- pub fn try_map_token_at (
166
- & mut self ,
167
- token : & Tab < Token > ,
168
- virt : usize ,
169
- ) -> Result < ( ) , TokenMapError > {
170
- if !self . tokens . contains ( token. id ( ) ) {
171
- return Err ( TokenMapError :: BadToken ) ;
172
- }
173
-
174
- token. with ( |t| {
175
- match t {
176
- Token :: Normal ( t) => {
177
- debug_assert ! (
178
- t. page_size( ) == 4096 ,
179
- "page size != 4096 is not implemented"
180
- ) ;
181
- debug_assert ! (
182
- t. page_size( ) . is_power_of_two( ) ,
183
- "page size is not a power of 2"
184
- ) ;
185
-
186
- if ( virt & ( t. page_size ( ) - 1 ) ) != 0 {
187
- return Err ( TokenMapError :: VirtNotAligned ) ;
188
- }
189
-
190
- let segment = AddressSpace :: < A > :: user_data ( ) ;
191
-
192
- // Make sure that none of the tokens exist in the vmap.
193
- for page_idx in 0 ..t. page_count ( ) {
194
- let page_base = virt + ( page_idx * t. page_size ( ) ) ;
195
-
196
- if !virt_resides_within :: < A > ( & segment, page_base)
197
- || !virt_resides_within :: < A > ( & segment, page_base + t. page_size ( ) - 1 )
198
- {
199
- return Err ( TokenMapError :: VirtOutOfRange ) ;
200
- }
201
-
202
- if self . token_vmap . contains (
203
- u64:: try_from ( page_base) . map_err ( |_| TokenMapError :: VirtOutOfRange ) ?,
204
- ) {
205
- return Err ( TokenMapError :: Conflict ) ;
206
- }
207
- }
208
-
209
- // Everything's okay, map them into the vmap now.
210
- for page_idx in 0 ..t. page_count ( ) {
211
- let page_base = virt + ( page_idx * t. page_size ( ) ) ;
212
- // NOTE(qix-): We can use `as` here since we already check the page base above.
213
- self . token_vmap
214
- . insert ( page_base as u64 , ( token. clone ( ) , page_idx) ) ;
215
- }
216
-
217
- Ok ( ( ) )
218
- }
219
- Token :: SlotMap ( t) => {
220
- debug_assert ! (
221
- t. page_size( ) == 4096 ,
222
- "page size != 4096 is not implemented"
223
- ) ;
224
- debug_assert ! (
225
- t. page_size( ) . is_power_of_two( ) ,
226
- "page size is not a power of 2"
227
- ) ;
228
- debug_assert ! (
229
- t. page_count( ) == 1 ,
230
- "slot map tokens must be exactly one page"
231
- ) ;
232
-
233
- if ( virt & ( t. page_size ( ) - 1 ) ) != 0 {
234
- return Err ( TokenMapError :: VirtNotAligned ) ;
235
- }
236
-
237
- let segment = AddressSpace :: < A > :: user_thread_local_data ( ) ;
238
-
239
- // Make sure that no other token exists in the vmap.
240
- if !virt_resides_within :: < A > ( & segment, virt)
241
- || !virt_resides_within :: < A > ( & segment, virt + t. page_size ( ) - 1 )
242
- {
243
- return Err ( TokenMapError :: VirtOutOfRange ) ;
244
- }
245
-
246
- if self
247
- . token_vmap
248
- . contains ( u64:: try_from ( virt) . map_err ( |_| TokenMapError :: VirtOutOfRange ) ?)
249
- {
250
- return Err ( TokenMapError :: Conflict ) ;
251
- }
252
-
253
- // Everything's okay, map them into the vmap now.
254
- // NOTE(qix-): We can use `as` here since we already check the page base above.
255
- self . token_vmap . insert ( virt as u64 , ( token. clone ( ) , 0 ) ) ;
256
-
257
- Ok ( ( ) )
258
- }
259
- }
260
- } )
261
- }
262
-
263
- /// Commits a [`Token`] into the instance's address space at
264
- /// the specified virtual address. Returns a mapping error
265
- /// if the mapping could not be completed.
266
- ///
267
- /// **The `maybe_unaligned_virt` parameter is not guaranteed to be aligned
268
- /// to any page boundary.** In most cases, it is coming directly from a
269
- /// userspace application (typically via a fault).
270
- ///
271
- /// The `Token` must have been previously mapped via [`Instance::try_map_token_at`],
272
- /// or else this method will fail.
273
- pub fn try_commit_token_at ( & self , maybe_unaligned_virt : usize ) -> Result < ( ) , TryCommitError > {
274
- // TODO(qix-): We always assume a 4096 page boundary. This will change in the future.
275
- let virt = maybe_unaligned_virt & !0xFFF ;
276
-
277
- if let Some ( ( token, page_idx) ) = u64:: try_from ( virt)
278
- . ok ( )
279
- . and_then ( |virt| self . token_vmap . get ( virt) )
280
- {
281
- token. with_mut ( |t| {
282
- match t {
283
- Token :: Normal ( t) => {
284
- debug_assert ! ( * page_idx < t. page_count( ) ) ;
285
- debug_assert ! (
286
- t. page_size( ) == 4096 ,
287
- "page size != 4096 is not implemented"
288
- ) ;
289
- let page_base = virt + ( * page_idx * t. page_size ( ) ) ;
290
- let segment = AddressSpace :: < A > :: user_data ( ) ;
291
- let phys = t
292
- . get_or_allocate ( * page_idx)
293
- . ok_or ( TryCommitError :: MapError ( MapError :: OutOfMemory ) ) ?;
294
- segment
295
- . map ( self . handle . mapper ( ) , page_base, phys. address_u64 ( ) )
296
- . map_err ( TryCommitError :: MapError ) ?;
297
- Ok ( ( ) )
298
- }
299
- Token :: SlotMap ( t) => {
300
- debug_assert ! (
301
- * page_idx == 0 ,
302
- "slot map tokens must be exactly one page; attempt was made to commit \
303
- page index >0"
304
- ) ;
305
- debug_assert ! (
306
- t. page_size( ) == 4096 ,
307
- "page size != 4096 is not implemented"
308
- ) ;
309
- debug_assert ! (
310
- t. page_count( ) == 1 ,
311
- "slot map tokens must be exactly one page"
312
- ) ;
313
- let segment = AddressSpace :: < A > :: user_thread_local_data ( ) ;
314
- let phys = t
315
- . get_or_allocate ( 0 )
316
- // NOTE(qix-): Should never happen as we don't allocate on the fly, but enforce
317
- // NOTE(qix-): that the token is already allocated.
318
- . ok_or ( TryCommitError :: MapError ( MapError :: OutOfMemory ) ) ?;
319
- segment
320
- . map ( self . handle . mapper ( ) , virt, phys. address_u64 ( ) )
321
- . map_err ( TryCommitError :: MapError ) ?;
322
- Ok ( ( ) )
323
- }
324
- }
325
- } )
326
- } else {
327
- Err ( TryCommitError :: BadVirt )
328
- }
329
- }
330
-
331
139
/// Returns the instance's address space handle.
332
140
#[ inline]
333
141
#[ must_use]
@@ -347,37 +155,3 @@ impl<A: Arch> Instance<A> {
347
155
& mut self . data
348
156
}
349
157
}
350
-
351
- /// An error returned by [`Instance::try_map_token_at`].
352
- #[ derive( Debug , Clone , Copy ) ]
353
- pub enum TokenMapError {
354
- /// The virtual address is not aligned.
355
- VirtNotAligned ,
356
- /// The virtual address is out of range for the
357
- /// thread's address space.
358
- VirtOutOfRange ,
359
- /// The token was not found for the instance.
360
- BadToken ,
361
- /// The mapping conflicts (overlaps) with another mapping.
362
- Conflict ,
363
- }
364
-
365
- /// Checks if the given virtual address resides within the given address segment.
366
- #[ inline]
367
- fn virt_resides_within < A : Arch > (
368
- segment : & <AddressSpace < A > as :: oro_mem:: mapper:: AddressSpace >:: UserSegment ,
369
- virt : usize ,
370
- ) -> bool {
371
- // NOTE(qix-): Range is *inclusive*.
372
- let ( first, last) = segment. range ( ) ;
373
- virt >= first && virt <= last
374
- }
375
-
376
- /// An error returned by [`Instance::try_commit_token_at`].
377
- #[ derive( Debug , Clone , Copy ) ]
378
- pub enum TryCommitError {
379
- /// The virtual address was not found in the virtual map.
380
- BadVirt ,
381
- /// Mapping the token failed.
382
- MapError ( MapError ) ,
383
- }
0 commit comments