mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
Merge remote-tracking branch 'origin/master' into ticktimer
This commit is contained in:
commit
5cf8e9e3bc
8 changed files with 139 additions and 54 deletions
|
|
@ -68,6 +68,10 @@ fn generate_pid_key() -> [u8; 16] {
|
|||
process_key
|
||||
}
|
||||
|
||||
pub fn current_pid() -> PID {
|
||||
crate::arch::process::current_pid()
|
||||
}
|
||||
|
||||
/// Each client gets its own connection and its own thread, which is handled here.
|
||||
fn handle_connection(
|
||||
conn: TcpStream,
|
||||
|
|
|
|||
|
|
@ -171,6 +171,19 @@ impl Process {
|
|||
})
|
||||
}
|
||||
|
||||
/// Calls the provided function with the current inner process state.
|
||||
pub fn with_current_mut<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Process) -> R,
|
||||
{
|
||||
let mut process = Self::current();
|
||||
f(&mut process)
|
||||
}
|
||||
|
||||
pub fn current_tid(&self) -> TID {
|
||||
1
|
||||
}
|
||||
|
||||
fn setup_thread_inner(thread: TID, process_table: &mut ProcessTable) {
|
||||
let current_pid_idx = process_table.current.get() as usize - 1;
|
||||
let process = &mut process_table.table[current_pid_idx].as_mut().unwrap();
|
||||
|
|
@ -179,6 +192,10 @@ impl Process {
|
|||
process.threads[thread - 1].allocated = true;
|
||||
}
|
||||
|
||||
pub fn retry_instruction(&mut self, _tid: TID) -> Result<(), xous_kernel::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup_process(pid: PID, setup: ThreadInit) -> Result<(), xous_kernel::Error> {
|
||||
let mut tmp = Process { pid };
|
||||
tmp.setup_thread(INITIAL_TID, setup)
|
||||
|
|
|
|||
|
|
@ -235,6 +235,15 @@ impl Process {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn retry_instruction(&mut self, tid: TID) -> Result<(), xous_kernel::Error> {
|
||||
let process = unsafe { &mut *PROCESS };
|
||||
let mut thread = &mut process.threads[tid];
|
||||
if thread.sepc >= 4 {
|
||||
thread.sepc -= 4;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize this process thread with the given entrypoint and stack
|
||||
/// addresses.
|
||||
pub fn setup_process(pid: PID, thread_init: ThreadInit) -> Result<(), xous_kernel::Error> {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ mod syscall;
|
|||
|
||||
use services::SystemServices;
|
||||
use xous_kernel::*;
|
||||
|
||||
#[cfg(baremetal)]
|
||||
use utralib::generated::*;
|
||||
|
||||
#[cfg(baremetal)]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,25 @@ use xous_kernel::*;
|
|||
/// This is the context that called SwitchTo
|
||||
static mut SWITCHTO_CALLER: Option<(PID, TID)> = None;
|
||||
|
||||
fn do_yield(_pid: PID, tid: TID) -> SysCallResult {
|
||||
// If we're not running on bare metal, treat this as a no-op.
|
||||
if !cfg!(baremetal) {
|
||||
return Ok(xous_kernel::Result::Ok);
|
||||
}
|
||||
|
||||
let (parent_pid, parent_ctx) = unsafe {
|
||||
SWITCHTO_CALLER
|
||||
.take()
|
||||
.expect("yielded when no parent context was present")
|
||||
};
|
||||
SystemServices::with_mut(|ss| {
|
||||
// TODO: Advance thread
|
||||
ss.activate_process_thread(tid, parent_pid, parent_ctx, true)
|
||||
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
|
||||
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
|
||||
})
|
||||
}
|
||||
|
||||
fn send_message(pid: PID, thread: TID, cid: CID, message: Message) -> SysCallResult {
|
||||
SystemServices::with_mut(|ss| {
|
||||
let sidx = ss
|
||||
|
|
@ -279,7 +298,12 @@ fn return_memory(pid: PID, tid: TID, sender: MessageSender, buf: MemoryRange) ->
|
|||
})
|
||||
}
|
||||
|
||||
fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysCallResult {
|
||||
fn return_scalar(
|
||||
server_pid: PID,
|
||||
server_tid: TID,
|
||||
sender: MessageSender,
|
||||
arg: usize,
|
||||
) -> SysCallResult {
|
||||
SystemServices::with_mut(|ss| {
|
||||
let sender = SenderID::from(sender);
|
||||
|
||||
|
|
@ -289,7 +313,7 @@ fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysC
|
|||
let server = ss
|
||||
.server_from_sidx_mut(sidx)
|
||||
.ok_or(xous_kernel::Error::ServerNotFound)?;
|
||||
if server.pid != pid {
|
||||
if server.pid != server_pid {
|
||||
return Err(xous_kernel::Error::ServerNotFound);
|
||||
}
|
||||
let result = server.take_waiting_message(sender.idx, None)?;
|
||||
|
|
@ -318,10 +342,27 @@ fn return_scalar(pid: PID, _tid: TID, sender: MessageSender, arg: usize) -> SysC
|
|||
return Err(xous_kernel::Error::ProcessNotFound);
|
||||
}
|
||||
};
|
||||
ss.ready_thread(client_pid, client_tid)?;
|
||||
ss.switch_to_thread(client_pid, Some(client_tid))?;
|
||||
ss.set_thread_result(client_pid, client_tid, xous_kernel::Result::Scalar1(arg))?;
|
||||
Ok(xous_kernel::Result::Scalar1(arg))
|
||||
|
||||
if !cfg!(baremetal) {
|
||||
// In a hosted environment, `switch_to_thread()` doesn't continue
|
||||
// execution from the new thread. Instead it continues in the old
|
||||
// thread. Therefore, we need to instruct the client to resume, and
|
||||
// return to the server.
|
||||
// In a baremetal environment, the opposite is true -- we instruct
|
||||
// the server to resume and return to the client.
|
||||
ss.set_thread_result(client_pid, client_tid, xous_kernel::Result::Scalar1(arg))?;
|
||||
Ok(xous_kernel::Result::Ok)
|
||||
} else {
|
||||
// Switch away from the server, but leave it as Runnable
|
||||
ss.switch_from_thread(server_pid, server_tid)?;
|
||||
ss.ready_thread(server_pid, server_tid)?;
|
||||
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
|
||||
|
||||
// Switch to the client
|
||||
ss.ready_thread(client_pid, client_tid)?;
|
||||
ss.switch_to_thread(client_pid, Some(client_tid))?;
|
||||
Ok(xous_kernel::Result::Scalar1(arg))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -368,22 +409,31 @@ fn return_scalar2(
|
|||
return Err(xous_kernel::Error::ProcessNotFound);
|
||||
}
|
||||
};
|
||||
ss.ready_thread(client_pid, client_tid)?;
|
||||
ss.ready_thread(server_pid, server_tid)?;
|
||||
|
||||
/*
|
||||
ss.activate_process_thread(server_tid, client_pid, client_tid, false)
|
||||
.map(|_| Ok(xous_kernel::Result::Scalar2(arg1, arg2)))
|
||||
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))?;*/
|
||||
//ss.switch_from_thread(server_pid, server_tid)?;
|
||||
if !cfg!(baremetal) {
|
||||
// In a hosted environment, `switch_to_thread()` doesn't continue
|
||||
// execution from the new thread. Instead it continues in the old
|
||||
// thread. Therefore, we need to instruct the client to resume, and
|
||||
// return to the server.
|
||||
// In a baremetal environment, the opposite is true -- we instruct
|
||||
// the server to resume and return to the client.
|
||||
ss.set_thread_result(
|
||||
client_pid,
|
||||
client_tid,
|
||||
xous_kernel::Result::Scalar2(arg1, arg2),
|
||||
)?;
|
||||
Ok(xous_kernel::Result::Ok)
|
||||
} else {
|
||||
// Switch away from the server, but leave it as Runnable
|
||||
ss.switch_from_thread(server_pid, server_tid)?;
|
||||
ss.ready_thread(server_pid, server_tid)?;
|
||||
ss.set_thread_result(server_pid, server_tid, xous_kernel::Result::Ok)?;
|
||||
|
||||
ss.switch_to_thread(client_pid, Some(client_tid))?;
|
||||
ss.set_thread_result(
|
||||
client_pid,
|
||||
client_tid,
|
||||
xous_kernel::Result::Scalar2(arg1, arg2),
|
||||
)?;
|
||||
Ok(xous_kernel::Result::Scalar2(arg1, arg2))
|
||||
// Switch to the client
|
||||
ss.ready_thread(client_pid, client_tid)?;
|
||||
ss.switch_to_thread(client_pid, Some(client_tid))?;
|
||||
Ok(xous_kernel::Result::Scalar2(arg1, arg2))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +496,12 @@ pub fn handle(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
|
|||
print!("KERNEL({}:{}): Syscall {:x?}", pid, tid, call);
|
||||
let result = handle_inner(pid, tid, call);
|
||||
#[cfg(feature = "debug-print")]
|
||||
println!(" -> {:x?}", result);
|
||||
println!(
|
||||
" -> ({}:{}) {:?}",
|
||||
crate::arch::current_pid(),
|
||||
crate::arch::process::Process::current().current_tid(),
|
||||
result
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -598,24 +653,7 @@ pub fn handle_inner(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
|
|||
interrupt_claim(no, pid as definitions::PID, callback, arg)
|
||||
.map(|_| xous_kernel::Result::Ok)
|
||||
}
|
||||
SysCall::Yield => {
|
||||
// If we're not running on bare metal, treat this as a no-op.
|
||||
if !cfg!(baremetal) {
|
||||
return Ok(xous_kernel::Result::Ok);
|
||||
}
|
||||
|
||||
let (parent_pid, parent_ctx) = unsafe {
|
||||
SWITCHTO_CALLER
|
||||
.take()
|
||||
.expect("yielded when no parent context was present")
|
||||
};
|
||||
SystemServices::with_mut(|ss| {
|
||||
// TODO: Advance thread
|
||||
ss.activate_process_thread(tid, parent_pid, parent_ctx, true)
|
||||
.map(|_| Ok(xous_kernel::Result::ResumeProcess))
|
||||
.unwrap_or(Err(xous_kernel::Error::ProcessNotFound))
|
||||
})
|
||||
}
|
||||
SysCall::Yield => do_yield(pid, tid),
|
||||
SysCall::ReturnToParentI(_pid, _cpuid) => {
|
||||
unsafe {
|
||||
// let (_current_pid, _current_ctx) = crate::arch::irq::take_isr_return_pair()
|
||||
|
|
@ -679,7 +717,17 @@ pub fn handle_inner(pid: PID, tid: TID, call: SysCall) -> SysCallResult {
|
|||
// SysCall::Connect(sid) => {
|
||||
// SystemServices::with_mut(|ss| ss.connect_to_server(sid).map(xous_kernel::Result::ConnectionID))
|
||||
// }
|
||||
// SysCall::SendMessage(cid, message) => send_message(pid, tid, cid, message),
|
||||
SysCall::SendMessage(cid, message) => {
|
||||
let result = send_message(pid, tid, cid, message);
|
||||
match result {
|
||||
Ok(o) => Ok(o),
|
||||
Err(xous_kernel::Error::ServerQueueFull) => {
|
||||
arch::process::Process::with_current_mut(|p| p.retry_instruction(tid))?;
|
||||
do_yield(pid, tid)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
_ => panic!("Unhandled Syscall: {:?}", call), //Err(xous_kernel::Error::UnhandledSyscall),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,24 +3,24 @@
|
|||
pub mod api;
|
||||
pub use api::{Point, Color};
|
||||
|
||||
use xous::{try_send_message, CID};
|
||||
use xous::{send_message, CID};
|
||||
|
||||
pub fn draw_line(cid: CID, start: Point, end: Point) -> Result<(), xous::Error> {
|
||||
try_send_message(cid, api::Opcode::Line(start, end).into()).map(|_| ())
|
||||
send_message(cid, api::Opcode::Line(start, end).into()).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn draw_circle(cid: CID, center: Point, radius: u32) -> Result<(), xous::Error> {
|
||||
try_send_message(cid, api::Opcode::Circle(center, radius).into()).map(|_| ())
|
||||
send_message(cid, api::Opcode::Circle(center, radius).into()).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn draw_rectangle(cid: CID, start: Point, end: Point) -> Result<(), xous::Error> {
|
||||
try_send_message(cid, api::Opcode::Rectangle(start, end).into()).map(|_| ())
|
||||
send_message(cid, api::Opcode::Rectangle(start, end).into()).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn set_style(cid: CID, width: u32, stroke: Color, fill: Color) -> Result<(), xous::Error> {
|
||||
try_send_message(cid, api::Opcode::Style(width, stroke, fill).into()).map(|_| ())
|
||||
send_message(cid, api::Opcode::Style(width, stroke, fill).into()).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn flush(cid: CID) -> Result<(), xous::Error> {
|
||||
try_send_message(cid, api::Opcode::Flush.into()).map(|_| ())
|
||||
send_message(cid, api::Opcode::Flush.into()).map(|_| ())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -981,21 +981,26 @@ pub fn try_send_message(connection: CID, message: Message) -> core::result::Resu
|
|||
}
|
||||
}
|
||||
|
||||
/// Send a message to a server, but keep trying if the server queue is full.
|
||||
/// Send a message to a server. Depending on the mesage type (move or borrow), it
|
||||
/// will either block (borrow) or return immediately (move).
|
||||
/// If the message type is `borrow`, then the memory addresses pointed to will be
|
||||
/// unavailable to this process until this function returns.
|
||||
///
|
||||
/// If the server queue is full, this will block.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * **ServerNotFound**: The server does not exist so the connection is now invalid
|
||||
/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
|
||||
/// * **Timeout**: The timeout limit has been reached
|
||||
pub fn send_message(connection: CID, message: Message) -> core::result::Result<(), Error> {
|
||||
pub fn send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
|
||||
let result = rsyscall(SysCall::SendMessage(connection, message));
|
||||
if let Ok(Result::Ok) = result {
|
||||
Ok(())
|
||||
} else if let Err(e) = result {
|
||||
Err(e)
|
||||
} else {
|
||||
panic!("Unexpected return value: {:?}", result);
|
||||
match result {
|
||||
Ok(Result::Ok) => Ok(Result::Ok),
|
||||
Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
|
||||
Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
|
||||
Err(e) => Err(e),
|
||||
v => panic!("Unexpected return value: {:?}", v),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue