feat: add SavedContext::with_entry_and_stack, wire SpawnThread to preserve entry point and stack
This commit is contained in:
@@ -31,10 +31,31 @@ pub struct SavedContext {
|
|||||||
registers: [usize; 32],
|
registers: [usize; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const PC_REGISTER: usize = 0;
|
||||||
|
pub const SP_REGISTER: usize = 1;
|
||||||
|
|
||||||
impl SavedContext {
|
impl SavedContext {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self { registers: [0; 32] }
|
Self { registers: [0; 32] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_entry_and_stack(
|
||||||
|
entry: types::address::EntryPoint,
|
||||||
|
stack: types::address::StackPointer,
|
||||||
|
) -> Self {
|
||||||
|
let mut ctx = Self::empty();
|
||||||
|
ctx.registers[PC_REGISTER] = entry.raw();
|
||||||
|
ctx.registers[SP_REGISTER] = stack.raw();
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program_counter(&self) -> usize {
|
||||||
|
self.registers[PC_REGISTER]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack_pointer(&self) -> usize {
|
||||||
|
self.registers[SP_REGISTER]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlockReason {
|
pub enum BlockReason {
|
||||||
@@ -63,6 +84,29 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_context(
|
||||||
|
id: ThreadId,
|
||||||
|
process: ProcessId,
|
||||||
|
priority: Priority,
|
||||||
|
time_slice: TimeSlice,
|
||||||
|
core_affinity: Option<CoreId>,
|
||||||
|
context: SavedContext,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
process,
|
||||||
|
state: ThreadState::Ready,
|
||||||
|
saved_context: context,
|
||||||
|
priority,
|
||||||
|
time_slice,
|
||||||
|
core_affinity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn saved_context(&self) -> &SavedContext {
|
||||||
|
&self.saved_context
|
||||||
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> ThreadId {
|
pub fn id(&self) -> ThreadId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
@@ -173,6 +217,25 @@ impl ThreadTable {
|
|||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn_with_context(
|
||||||
|
&mut self,
|
||||||
|
process: ProcessId,
|
||||||
|
priority: Priority,
|
||||||
|
time_slice: TimeSlice,
|
||||||
|
core_affinity: Option<CoreId>,
|
||||||
|
context: SavedContext,
|
||||||
|
) -> Result<ThreadId, KernelError> {
|
||||||
|
let idx = self
|
||||||
|
.threads
|
||||||
|
.iter()
|
||||||
|
.position(|s| s.is_none())
|
||||||
|
.ok_or(KernelError::TooManyThreads)?;
|
||||||
|
|
||||||
|
let id = ThreadId::from_raw(idx as u16);
|
||||||
|
self.threads[idx] = Some(Thread::with_context(id, process, priority, time_slice, core_affinity, context));
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: ThreadId) -> Result<&Thread, KernelError> {
|
pub fn get(&self, id: ThreadId) -> Result<&Thread, KernelError> {
|
||||||
let idx = id.raw() as usize;
|
let idx = id.raw() as usize;
|
||||||
self.threads
|
self.threads
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ impl<P: Platform> Kernel<P> {
|
|||||||
pub(crate) fn handle_spawn_thread(
|
pub(crate) fn handle_spawn_thread(
|
||||||
&mut self,
|
&mut self,
|
||||||
pid: types::id::ProcessId,
|
pid: types::id::ProcessId,
|
||||||
_entry: types::address::EntryPoint,
|
entry: types::address::EntryPoint,
|
||||||
_stack: types::address::StackPointer,
|
stack: types::address::StackPointer,
|
||||||
) -> SyscallOutcome {
|
) -> SyscallOutcome {
|
||||||
use domain::scheduler::Scheduler;
|
use domain::scheduler::Scheduler;
|
||||||
|
use domain::thread::SavedContext;
|
||||||
|
|
||||||
let priority = types::bounded::Priority::new(16)
|
let priority = types::bounded::Priority::new(16)
|
||||||
.unwrap_or_else(|| unreachable!());
|
.unwrap_or_else(|| unreachable!());
|
||||||
let time_slice = types::time::TimeSlice::new(100);
|
let time_slice = types::time::TimeSlice::new(100);
|
||||||
|
let context = SavedContext::with_entry_and_stack(entry, stack);
|
||||||
|
|
||||||
let tid = match self.threads.spawn(pid, priority, time_slice, None) {
|
let tid = match self.threads.spawn_with_context(pid, priority, time_slice, None, context) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)),
|
Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,4 +97,8 @@ impl Kernel<MockPlatform> {
|
|||||||
) -> CapSlot {
|
) -> CapSlot {
|
||||||
self.grant_cap(pid, resource, permissions).expect("grant cap")
|
self.grant_cap(pid, resource, permissions).expect("grant cap")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn thread_context(&self, tid: ThreadId) -> &domain::thread::SavedContext {
|
||||||
|
self.threads.get(tid).expect("thread").saved_context()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use crate::{SyscallOutcome, SyscallResult};
|
|||||||
use domain::syscall::Syscall;
|
use domain::syscall::Syscall;
|
||||||
use types::address::{DataRef, EntryPoint, StackPointer};
|
use types::address::{DataRef, EntryPoint, StackPointer};
|
||||||
use types::bounded::CapSlot;
|
use types::bounded::CapSlot;
|
||||||
|
use types::id::ThreadId;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn spawn_thread_creates_ready_thread() {
|
fn spawn_thread_creates_ready_thread() {
|
||||||
@@ -17,6 +18,21 @@ fn spawn_thread_creates_ready_thread() {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spawn_thread_preserves_entry_and_stack() {
|
||||||
|
let (mut k, _) = kernel_with_process();
|
||||||
|
let tid = match k.handle_syscall(Syscall::SpawnThread {
|
||||||
|
entry: EntryPoint::from_raw(0xDEAD),
|
||||||
|
stack: StackPointer::from_raw(0xBEEF),
|
||||||
|
}) {
|
||||||
|
SyscallOutcome::Complete(SyscallResult::Value(v)) => ThreadId::from_raw(v as u16),
|
||||||
|
_ => panic!("expected Value"),
|
||||||
|
};
|
||||||
|
let ctx = k.thread_context(tid);
|
||||||
|
assert_eq!(ctx.program_counter(), 0xDEAD);
|
||||||
|
assert_eq!(ctx.stack_pointer(), 0xBEEF);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_process_with_cap_succeeds() {
|
fn create_process_with_cap_succeeds() {
|
||||||
let (mut k, _) = kernel_with_process();
|
let (mut k, _) = kernel_with_process();
|
||||||
|
|||||||
Reference in New Issue
Block a user