Skip to content

Commit fad9594

Browse files
committed
kernel: move token registration into Thread
1 parent bfa8204 commit fad9594

File tree

7 files changed

+334
-261
lines changed

7 files changed

+334
-261
lines changed

oro-kernel/src/iface/kernel/mem_token_v0.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use oro::{key, syscall::Error as SysError};
1818

1919
use super::KernelInterface;
2020
use crate::{
21-
arch::Arch, instance::TokenMapError, syscall::InterfaceResponse, tab::Tab, thread::Thread,
21+
arch::Arch,
22+
syscall::InterfaceResponse,
23+
tab::Tab,
24+
thread::{Thread, TokenMapError},
2225
token::Token,
2326
};
2427

@@ -42,8 +45,7 @@ impl KernelInterface for MemTokenV0 {
4245
const TYPE_ID: u64 = oro::id::iface::KERNEL_MEM_TOKEN_V0;
4346

4447
fn get<A: Arch>(thread: &Tab<Thread<A>>, index: u64, key: u64) -> InterfaceResponse {
45-
let instance = thread.with(|t| t.instance().clone());
46-
let Some(token) = instance.with(|i| i.token(index)) else {
48+
let Some(token) = thread.with(|t| t.token(index)) else {
4749
return InterfaceResponse::immediate(SysError::BadIndex, 0);
4850
};
4951

@@ -77,16 +79,14 @@ impl KernelInterface for MemTokenV0 {
7779
) -> InterfaceResponse {
7880
match key {
7981
key!("forget") => {
80-
let instance = thread.with(|t| t.instance().clone());
81-
instance.with_mut(|i| i.forget_token(index)).map_or_else(
82+
thread.with_mut(|t| t.forget_token(index)).map_or_else(
8283
|| InterfaceResponse::immediate(SysError::BadIndex, 0),
8384
|_| InterfaceResponse::ok(0),
8485
)
8586
}
8687
key!("base") => {
87-
let instance = thread.with(|t| t.instance().clone());
88-
instance.with_mut(|i| {
89-
let Some(token) = i.token(index) else {
88+
thread.with_mut(|t| {
89+
let Some(token) = t.token(index) else {
9090
return InterfaceResponse::immediate(SysError::BadIndex, 0);
9191
};
9292

@@ -97,7 +97,7 @@ impl KernelInterface for MemTokenV0 {
9797
);
9898
};
9999

100-
i.try_map_token_at(&token, virt).map_or_else(
100+
t.try_map_token_at(&token, virt).map_or_else(
101101
|err| {
102102
InterfaceResponse::immediate(
103103
SysError::InterfaceError,

oro-kernel/src/iface/kernel/page_alloc_v0.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,7 @@ impl KernelInterface for PageAllocV0 {
6363
)
6464
},
6565
|tab| {
66-
InterfaceResponse::ok(
67-
thread
68-
.with(|t| t.instance().clone())
69-
.with_mut(|i| i.insert_token(tab)),
70-
)
66+
InterfaceResponse::ok(thread.with_mut(|t| t.insert_token(tab)))
7167
},
7268
)
7369
},

oro-kernel/src/iface/root_ring/test_ports.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,13 @@ impl<A: Arch> Interface<A> for RootTestPorts<A> {
5050
key!("prodtkn") => {
5151
// Mark it owned by the current thread's instead.
5252
let tkn = self.0.with(|p| p.producer());
53-
let instance = thread.with(|t| t.instance().clone());
54-
instance.with_mut(|i| i.insert_token(tkn.clone()));
53+
thread.with_mut(|t| t.insert_token(tkn.clone()));
5554
InterfaceResponse::ok(tkn.id())
5655
}
5756
key!("cnsmtkn") => {
5857
// Mark it owned by the current thread's instead.
5958
let tkn = self.0.with(|p| p.consumer());
60-
let instance = thread.with(|t| t.instance().clone());
61-
instance.with_mut(|i| i.insert_token(tkn.clone()));
59+
thread.with_mut(|t| t.insert_token(tkn.clone()));
6260
InterfaceResponse::ok(tkn.id())
6361
}
6462
_ => InterfaceResponse::immediate(SysError::BadKey, 0),

oro-kernel/src/instance.rs

+10-236
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
//! Module instance types and functionality.
22
3-
use oro_mem::{
4-
mapper::{AddressSegment, AddressSpace as _, MapError},
5-
phys::PhysAddr,
6-
};
3+
use oro_mem::mapper::{AddressSegment, AddressSpace as _, MapError};
74

85
use crate::{
96
AddressSpace, Kernel, UserHandle,
@@ -63,16 +60,23 @@ pub struct Instance<A: Arch> {
6360
data: TypeTable,
6461
/// Memory tokens owned by this instance.
6562
///
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+
///
6666
/// If a token is here, the instance is allowed to map it
6767
/// into its address space.
68-
tokens: Table<Tab<Token>>,
68+
pub(super) tokens: Table<Tab<Token>>,
6969
/// 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+
///
7074
/// Values are `(token, page_id)` pairs.
7175
// TODO(qix-): This assumes a 4096 byte page size, and is also
7276
// TODO(qix-): not a very efficient data structure. It will be
7377
// TODO(qix-): replaced with a more efficient data structure
7478
// TODO(qix-): in the future.
75-
token_vmap: Table<(Tab<Token>, usize)>,
79+
pub(super) token_vmap: Table<(Tab<Token>, usize)>,
7680
}
7781

7882
impl<A: Arch> Instance<A> {
@@ -132,202 +136,6 @@ impl<A: Arch> Instance<A> {
132136
&self.threads
133137
}
134138

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-
331139
/// Returns the instance's address space handle.
332140
#[inline]
333141
#[must_use]
@@ -347,37 +155,3 @@ impl<A: Arch> Instance<A> {
347155
&mut self.data
348156
}
349157
}
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

Comments
 (0)