mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-14 08:03:34 +00:00
kernel: get immutable borrows working
We can now pass memory immutably between processes Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
d6f985c141
commit
bedb499edb
5 changed files with 347 additions and 113 deletions
|
|
@ -1,16 +1,30 @@
|
|||
pub use crate::arch::ProcessContext;
|
||||
use core::{mem, slice};
|
||||
use xous::{CtxID, MemoryRange, MemorySize, PID, SID};
|
||||
use xous::{CtxID, MemoryAddress, MemoryRange, MemorySize, PID, SID, Message};
|
||||
|
||||
pub struct SenderID {
|
||||
pub sidx: usize,
|
||||
pub tidx: usize,
|
||||
}
|
||||
|
||||
impl SenderID {
|
||||
pub fn from_usize(src: usize) -> Result<SenderID, xous::Error> {
|
||||
Ok(SenderID {
|
||||
sidx: src >> 16,
|
||||
tidx: src & 0xffff,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal representation of a queued message for a server. This should be
|
||||
/// exactly 8 words / 32 bytes, yielding 128 queued messages per server
|
||||
#[repr(usize)]
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum QueuedMessage {
|
||||
Empty,
|
||||
ScalarMessage(
|
||||
usize, /* sender */
|
||||
usize, /* context */
|
||||
usize, /* sender PID/CtxID */
|
||||
usize, /* sender base address */
|
||||
usize, /* id */
|
||||
usize, /* arg1 */
|
||||
usize, /* arg2 */
|
||||
|
|
@ -18,8 +32,8 @@ enum QueuedMessage {
|
|||
usize, /* arg4 */
|
||||
),
|
||||
MemoryMessageSend(
|
||||
usize, /* sender */
|
||||
usize, /* context */
|
||||
usize, /* sender PID/CtxID */
|
||||
usize, /* reserved */
|
||||
usize, /* id */
|
||||
usize, /* buf */
|
||||
usize, /* buf_size */
|
||||
|
|
@ -27,8 +41,8 @@ enum QueuedMessage {
|
|||
usize, /* valid */
|
||||
),
|
||||
MemoryMessageROLend(
|
||||
usize, /* sender */
|
||||
usize, /* context */
|
||||
usize, /* sender PID/CtxID */
|
||||
usize, /* sender base address */
|
||||
usize, /* id */
|
||||
usize, /* buf */
|
||||
usize, /* buf_size */
|
||||
|
|
@ -36,14 +50,25 @@ enum QueuedMessage {
|
|||
usize, /* valid */
|
||||
),
|
||||
MemoryMessageRWLend(
|
||||
usize, /* sender */
|
||||
usize, /* context */
|
||||
usize, /* sender PID/CtxID */
|
||||
usize, /* sender base address */
|
||||
usize, /* id */
|
||||
usize, /* buf */
|
||||
usize, /* buf_size */
|
||||
usize, /* offset */
|
||||
usize, /* valid */
|
||||
),
|
||||
|
||||
/// When a message is taken that needs to be returned -- such as an ROLend
|
||||
/// or RWLend -- the slot is replaced with a WaitingResponse token and its
|
||||
/// index is returned as the message sender. This is used to unblock the
|
||||
/// sending process.
|
||||
WaitingResponse(
|
||||
usize, /* sender PID/CtxID */
|
||||
usize, /* Client base address */
|
||||
usize, /* Server base address */
|
||||
usize, /* Range size */
|
||||
),
|
||||
}
|
||||
|
||||
/// A pointer to resolve a server ID to a particular process
|
||||
|
|
@ -98,14 +123,60 @@ impl Server {
|
|||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_queue(&self) {
|
||||
println!(" Q Queue Head: {}", self.queue_head);
|
||||
println!(" Q Queue Tail: {}", self.queue_tail);
|
||||
for (_idx, _entry) in self.queue.iter().enumerate() {
|
||||
if _entry != &QueuedMessage::Empty {
|
||||
println!(" Q entry[{}]: {:?}", _idx, _entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `QueuedMesage::WaitingResponse` into `QueuedMessage::Empty`
|
||||
/// and return the pair. Advance the tail. Note that the `idx` could be
|
||||
/// somewhere other than the tail, but as long as it points to a valid
|
||||
/// message that's waiting a response, that's acceptable.
|
||||
pub fn take_waiting_message(
|
||||
&mut self,
|
||||
idx: usize,
|
||||
) -> Result<Option<(PID, CtxID, MemoryAddress, MemoryAddress, MemorySize)>, xous::Error> {
|
||||
if idx > self.queue.len() {
|
||||
return Err(xous::Error::BadAddress);
|
||||
}
|
||||
let (pid_ctx, server_addr, client_addr, len) = match self.queue[idx] {
|
||||
QueuedMessage::WaitingResponse(pid_ctx, server_addr, client_addr, len) => {
|
||||
(pid_ctx, server_addr, client_addr, len)
|
||||
}
|
||||
_ => return Err(xous::Error::BadAddress),
|
||||
};
|
||||
self.queue[idx] = QueuedMessage::Empty;
|
||||
self.queue_tail += 1;
|
||||
if self.queue_tail >= self.queue.len() {
|
||||
self.queue_tail = 0;
|
||||
}
|
||||
|
||||
let pid = ((pid_ctx >> 16) & 0xff) as PID;
|
||||
let ctx = (pid_ctx & 0xffff) as CtxID;
|
||||
let server_addr = match MemoryAddress::new(server_addr) {
|
||||
Some(o) => o,
|
||||
None => return Ok(None)
|
||||
};
|
||||
let client_addr = MemoryAddress::new(client_addr).expect("client memory address was 0, but server address was not");
|
||||
let len = MemorySize::new(len).expect("memory length was 0, but address was not None");
|
||||
Ok(Some((pid, ctx, server_addr, client_addr, len)))
|
||||
}
|
||||
|
||||
/// Remove a message from the server's queue and replace it with
|
||||
/// QueuedMessage::Empty. Advance the queue pointer while we're at it.
|
||||
pub fn take_next_message(&mut self) -> Option<(xous::MessageEnvelope, CtxID)> {
|
||||
/// QueuedMessage::WaitingResponse.
|
||||
pub fn take_next_message(&mut self, server_idx: usize) -> Option<xous::MessageEnvelope> {
|
||||
let result = match self.queue[self.queue_tail] {
|
||||
QueuedMessage::Empty => return None,
|
||||
QueuedMessage::WaitingResponse(_, _, _, _) => return None,
|
||||
QueuedMessage::MemoryMessageROLend(
|
||||
sender,
|
||||
context,
|
||||
pid_ctx,
|
||||
client_addr,
|
||||
id,
|
||||
buf,
|
||||
buf_size,
|
||||
|
|
@ -113,7 +184,7 @@ impl Server {
|
|||
valid,
|
||||
) => (
|
||||
xous::MessageEnvelope {
|
||||
sender: sender,
|
||||
sender: self.queue_tail | (server_idx << 16),
|
||||
message: xous::Message::ImmutableBorrow(xous::MemoryMessage {
|
||||
id,
|
||||
buf: MemoryRange::new(buf, buf_size),
|
||||
|
|
@ -121,11 +192,14 @@ impl Server {
|
|||
valid: MemorySize::new(valid),
|
||||
}),
|
||||
},
|
||||
context,
|
||||
pid_ctx,
|
||||
buf,
|
||||
client_addr,
|
||||
buf_size,
|
||||
),
|
||||
QueuedMessage::MemoryMessageRWLend(
|
||||
sender,
|
||||
context,
|
||||
pid_ctx,
|
||||
client_addr,
|
||||
id,
|
||||
buf,
|
||||
buf_size,
|
||||
|
|
@ -133,7 +207,7 @@ impl Server {
|
|||
valid,
|
||||
) => (
|
||||
xous::MessageEnvelope {
|
||||
sender: sender,
|
||||
sender: self.queue_tail | (server_idx << 16),
|
||||
message: xous::Message::MutableBorrow(xous::MemoryMessage {
|
||||
id,
|
||||
buf: MemoryRange::new(buf, buf_size),
|
||||
|
|
@ -141,25 +215,37 @@ impl Server {
|
|||
valid: MemorySize::new(valid),
|
||||
}),
|
||||
},
|
||||
context,
|
||||
pid_ctx,
|
||||
buf,
|
||||
client_addr,
|
||||
buf_size,
|
||||
),
|
||||
QueuedMessage::MemoryMessageSend(sender, context, id, buf, buf_size, offset, valid) => {
|
||||
(
|
||||
xous::MessageEnvelope {
|
||||
sender: sender,
|
||||
message: xous::Message::Move(xous::MemoryMessage {
|
||||
id,
|
||||
buf: MemoryRange::new(buf, buf_size),
|
||||
offset: MemorySize::new(offset),
|
||||
valid: MemorySize::new(valid),
|
||||
}),
|
||||
},
|
||||
context,
|
||||
)
|
||||
}
|
||||
QueuedMessage::ScalarMessage(sender, context, id, arg1, arg2, arg3, arg4) => (
|
||||
QueuedMessage::MemoryMessageSend(
|
||||
pid_ctx,
|
||||
_reserved,
|
||||
id,
|
||||
buf,
|
||||
buf_size,
|
||||
offset,
|
||||
valid,
|
||||
) => (
|
||||
xous::MessageEnvelope {
|
||||
sender: sender,
|
||||
sender: self.queue_tail | (server_idx << 16),
|
||||
message: xous::Message::Move(xous::MemoryMessage {
|
||||
id,
|
||||
buf: MemoryRange::new(buf, buf_size),
|
||||
offset: MemorySize::new(offset),
|
||||
valid: MemorySize::new(valid),
|
||||
}),
|
||||
},
|
||||
pid_ctx,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
QueuedMessage::ScalarMessage(pid_ctx, _reserved, id, arg1, arg2, arg3, arg4) => (
|
||||
xous::MessageEnvelope {
|
||||
sender: self.queue_tail | (server_idx << 16),
|
||||
message: xous::Message::Scalar(xous::ScalarMessage {
|
||||
id,
|
||||
arg1,
|
||||
|
|
@ -168,31 +254,37 @@ impl Server {
|
|||
arg4,
|
||||
}),
|
||||
},
|
||||
context,
|
||||
pid_ctx,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
};
|
||||
self.queue[self.queue_tail] = QueuedMessage::Empty;
|
||||
self.queue_tail += 1;
|
||||
if self.queue_tail >= self.queue.len() {
|
||||
self.queue_tail = 0;
|
||||
}
|
||||
Some(result)
|
||||
self.queue[self.queue_tail] =
|
||||
QueuedMessage::WaitingResponse(result.1, result.2, result.3, result.4);
|
||||
Some(result.0)
|
||||
}
|
||||
|
||||
/// Add the given message to this server's queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * **ServerQueueFull**: The server queue cannot accept any more messages
|
||||
pub fn queue_message(
|
||||
&mut self,
|
||||
context: usize,
|
||||
envelope: xous::MessageEnvelope,
|
||||
) -> core::result::Result<(), xous::Error> {
|
||||
pid: PID,
|
||||
context: CtxID,
|
||||
message: xous::Message,
|
||||
original_address: Option<MemoryAddress>,
|
||||
) -> core::result::Result<usize, xous::Error> {
|
||||
if self.queue[self.queue_head] != QueuedMessage::Empty {
|
||||
return Err(xous::Error::ServerQueueFull);
|
||||
}
|
||||
|
||||
self.queue[self.queue_head] = match envelope.message {
|
||||
self.queue[self.queue_head] = match message {
|
||||
xous::Message::Scalar(msg) => QueuedMessage::ScalarMessage(
|
||||
envelope.sender,
|
||||
context,
|
||||
pid as usize | (context << 16),
|
||||
original_address.map(|x| x.get()).unwrap_or(0),
|
||||
msg.id,
|
||||
msg.arg1,
|
||||
msg.arg2,
|
||||
|
|
@ -200,25 +292,72 @@ impl Server {
|
|||
msg.arg4,
|
||||
),
|
||||
xous::Message::Move(msg) => QueuedMessage::MemoryMessageSend(
|
||||
envelope.sender,
|
||||
context,
|
||||
pid as usize | (context << 16),
|
||||
original_address.map(|x| x.get()).unwrap_or(0),
|
||||
msg.id,
|
||||
msg.buf.addr.get(),
|
||||
msg.buf.size.get(),
|
||||
msg.offset.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
msg.valid.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
),
|
||||
xous::Message::MutableBorrow(msg) => QueuedMessage::MemoryMessageRWLend(
|
||||
pid as usize | (context << 16),
|
||||
original_address.map(|x| x.get()).unwrap_or(0),
|
||||
msg.id,
|
||||
msg.buf.addr.get(),
|
||||
msg.buf.size.get(),
|
||||
msg.offset.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
msg.valid.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
),
|
||||
xous::Message::ImmutableBorrow(msg) => QueuedMessage::MemoryMessageROLend(
|
||||
pid as usize | (context << 16),
|
||||
original_address.map(|x| x.get()).unwrap_or(0),
|
||||
msg.id,
|
||||
msg.buf.addr.get(),
|
||||
msg.buf.size.get(),
|
||||
msg.offset.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
msg.valid.map(|x| x.get()).unwrap_or(0) as usize,
|
||||
),
|
||||
xous::Message::MutableBorrow(_msg) => unimplemented!(),
|
||||
xous::Message::ImmutableBorrow(_msg) => unimplemented!(),
|
||||
};
|
||||
|
||||
let idx = self.queue_head;
|
||||
self.queue_head += 1;
|
||||
if self.queue_head >= self.queue.len() {
|
||||
self.queue_head = 0;
|
||||
}
|
||||
Ok(())
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
pub fn queue_address(
|
||||
&mut self,
|
||||
pid: PID,
|
||||
context: CtxID,
|
||||
message: &Message,
|
||||
client_address: Option<MemoryAddress>,
|
||||
) -> core::result::Result<usize, xous::Error> {
|
||||
if self.queue[self.queue_head] != QueuedMessage::Empty {
|
||||
return Err(xous::Error::ServerQueueFull);
|
||||
}
|
||||
let (server_address, len) = match message {
|
||||
xous::Message::Scalar(_) | xous::Message::Move(_) => (0, 0),
|
||||
xous::Message::MutableBorrow(msg) | xous::Message::ImmutableBorrow(msg) => {
|
||||
(msg.buf.addr.get(), msg.buf.size.get())
|
||||
}
|
||||
};
|
||||
|
||||
self.queue[self.queue_head] = QueuedMessage::WaitingResponse(
|
||||
pid as usize | (context << 16),
|
||||
server_address,
|
||||
client_address.map(|x| x.get()).unwrap_or(0),
|
||||
len,
|
||||
);
|
||||
let idx = self.queue_head;
|
||||
self.queue_head += 1;
|
||||
if self.queue_head >= self.queue.len() {
|
||||
self.queue_head = 0;
|
||||
}
|
||||
Ok(idx)
|
||||
}
|
||||
// assert!(
|
||||
// mem::size_of::<QueuedMessage>() == 32,
|
||||
// "QueuedMessage was supposed to be 32 bytes, but instead was {} bytes",
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use crate::args::KernelArguments;
|
|||
use crate::filled_array;
|
||||
use crate::mem::{MemoryManagerHandle, PAGE_SIZE};
|
||||
use crate::server::Server;
|
||||
use core::{mem, slice};
|
||||
use xous::{CtxID, MemoryFlags, MemoryType, MessageEnvelope, CID, PID, SID};
|
||||
use core::slice;
|
||||
use xous::{CtxID, MemoryAddress, MemoryFlags, MemoryType, Message, CID, PID, SID};
|
||||
|
||||
const MAX_PROCESS_COUNT: usize = 32;
|
||||
const MAX_SERVER_COUNT: usize = 32;
|
||||
|
|
@ -634,10 +634,10 @@ impl SystemServices {
|
|||
// Restore the previous context, if one exists.
|
||||
process.set_context_nr(new_context);
|
||||
self.processes[self.pid as usize - 1].current_context = new_context as u8;
|
||||
let ctx = process.current_context();
|
||||
let _ctx = process.current_context();
|
||||
println!(
|
||||
"Switched to PID {}, context {}, with sepc: {:08x}",
|
||||
new_pid, new_context, ctx.sepc
|
||||
new_pid, new_context, _ctx.sepc
|
||||
);
|
||||
|
||||
Ok(new_context)
|
||||
|
|
@ -664,6 +664,7 @@ impl SystemServices {
|
|||
&mut self,
|
||||
src_virt: *mut usize,
|
||||
dest_pid: PID,
|
||||
dest_virt: *mut usize,
|
||||
len: usize,
|
||||
writable: bool,
|
||||
_borrow: bool,
|
||||
|
|
@ -704,7 +705,7 @@ impl SystemServices {
|
|||
}
|
||||
let result = mm.map_range(
|
||||
phys as *mut usize,
|
||||
0 as *mut usize,
|
||||
dest_virt,
|
||||
len,
|
||||
dest_pid,
|
||||
flags,
|
||||
|
|
@ -775,7 +776,7 @@ impl SystemServices {
|
|||
/// server table is full, return an error.
|
||||
pub fn create_server(&mut self, name: usize) -> Result<SID, xous::Error> {
|
||||
println!("Looking through server list for free server");
|
||||
println!("Server entries are {} bytes long", mem::size_of::<Server>());
|
||||
println!("Server entries are {} bytes long", core::mem::size_of::<Server>());
|
||||
|
||||
for entry in self.servers.iter_mut() {
|
||||
if entry == &None {
|
||||
|
|
@ -863,12 +864,16 @@ impl SystemServices {
|
|||
}
|
||||
}
|
||||
|
||||
/// Switch to the server's memory space and add the message to its server
|
||||
/// queue
|
||||
pub fn queue_server_message(
|
||||
&mut self,
|
||||
sidx: usize,
|
||||
context: usize,
|
||||
envelope: MessageEnvelope,
|
||||
) -> Result<(), xous::Error> {
|
||||
pid: PID,
|
||||
context: CtxID,
|
||||
message: Message,
|
||||
original_address: Option<MemoryAddress>,
|
||||
) -> Result<usize, xous::Error> {
|
||||
let current_pid = self.current_pid();
|
||||
let result = {
|
||||
let server_pid = self
|
||||
|
|
@ -882,7 +887,9 @@ impl SystemServices {
|
|||
let server = self
|
||||
.server_from_sidx(sidx)
|
||||
.expect("couldn't re-discover server index");
|
||||
server.queue_message(context, envelope)
|
||||
let result = server.queue_message(pid, context, message, original_address);
|
||||
server.print_queue();
|
||||
result
|
||||
};
|
||||
let current_process = self
|
||||
.get_process(current_pid)
|
||||
|
|
@ -891,18 +898,51 @@ impl SystemServices {
|
|||
result
|
||||
}
|
||||
|
||||
/// Get a server based on a SID
|
||||
pub fn server_mut(&mut self, sid: SID) -> Option<&mut Server> {
|
||||
for server in self.servers.iter_mut() {
|
||||
/// Switch to the server's address space and add a "remember this address"
|
||||
/// entry to its server queue
|
||||
pub fn remember_server_message(
|
||||
&mut self,
|
||||
sidx: usize,
|
||||
pid: PID,
|
||||
context: CtxID,
|
||||
message: &Message,
|
||||
client_address: Option<MemoryAddress>,
|
||||
) -> Result<usize, xous::Error> {
|
||||
let current_pid = self.current_pid();
|
||||
let result = {
|
||||
let server_pid = self
|
||||
.server_from_sidx(sidx)
|
||||
.ok_or(xous::Error::ServerNotFound)?
|
||||
.pid;
|
||||
{
|
||||
let server_process = self.get_process(server_pid)?;
|
||||
server_process.mapping.activate();
|
||||
}
|
||||
let server = self
|
||||
.server_from_sidx(sidx)
|
||||
.expect("couldn't re-discover server index");
|
||||
let result = server.queue_address(pid, context, message, client_address);
|
||||
server.print_queue();
|
||||
result
|
||||
};
|
||||
let current_process = self
|
||||
.get_process(current_pid)
|
||||
.expect("couldn't restore previous process");
|
||||
current_process.mapping.activate();
|
||||
result
|
||||
}
|
||||
|
||||
/// Get a server index based on a SID
|
||||
pub fn server_sidx(&mut self, sid: SID) -> Option<usize> {
|
||||
for (idx, server) in self.servers.iter_mut().enumerate() {
|
||||
if let Some(active_server) = server {
|
||||
if active_server.sid == sid {
|
||||
return server.as_mut();
|
||||
return Some(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
/// How many people have checked out the handle object. This should be replaced
|
||||
/// by an AtomicUsize when we get multicore support. For now, we can get away
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::arch;
|
|||
use crate::arch::process::ProcessHandle;
|
||||
use crate::irq::interrupt_claim;
|
||||
use crate::mem::{MemoryManagerHandle, PAGE_SIZE};
|
||||
use crate::server::SenderID;
|
||||
use crate::services::SystemServicesHandle;
|
||||
use core::mem;
|
||||
use xous::*;
|
||||
|
|
@ -264,7 +265,11 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
let mut ss = SystemServicesHandle::get();
|
||||
let context_nr = ss.current_context_nr();
|
||||
// See if there is a pending message. If so, return immediately.
|
||||
let server = ss.server_mut(sid).ok_or(xous::Error::ServerNotFound)?;
|
||||
let sidx = ss.server_sidx(sid).ok_or(xous::Error::ServerNotFound)?;
|
||||
let server = ss
|
||||
.server_from_sidx(sidx)
|
||||
.ok_or(xous::Error::ServerNotFound)?;
|
||||
server.print_queue();
|
||||
|
||||
// Ensure the server is for this PID
|
||||
if server.pid != pid {
|
||||
|
|
@ -272,12 +277,16 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
}
|
||||
|
||||
// If there is a pending message, return it immediately.
|
||||
if let Some(msg) = server.take_next_message() {
|
||||
return Ok(xous::Result::Message(msg.0));
|
||||
if let Some(msg) = server.take_next_message(sidx) {
|
||||
println!("PID {} had a message ready -- returning it", pid);
|
||||
return Ok(xous::Result::Message(msg));
|
||||
}
|
||||
|
||||
// There is no pending message, so return control to the parent process
|
||||
// and mark ourselves as awaiting an event.
|
||||
// There is no pending message, so return control to the parent
|
||||
// process and mark ourselves as awaiting an event. When a message
|
||||
// arrives, our return value will already be set to the
|
||||
// MessageEnvelope of the incoming message.
|
||||
println!("PID {} did not have any waiting messages -- parking context", pid);
|
||||
server.park_context(context_nr);
|
||||
|
||||
let ppid = ss.get_process(pid).expect("Can't get current process").ppid;
|
||||
|
|
@ -309,6 +318,51 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
ss.connect_to_server(sid)
|
||||
.map(|x| xous::Result::ConnectionID(x))
|
||||
}
|
||||
SysCall::ReturnMemory(sender) => {
|
||||
let mut ss = SystemServicesHandle::get();
|
||||
let sender = SenderID::from_usize(sender)?;
|
||||
|
||||
let server = ss
|
||||
.server_from_sidx(sender.sidx)
|
||||
.ok_or(xous::Error::ServerNotFound)?;
|
||||
if server.pid != pid {
|
||||
return Err(xous::Error::ServerNotFound);
|
||||
}
|
||||
let result = server.take_waiting_message(sender.tidx)?;
|
||||
let (client_pid, client_ctx, server_addr, client_addr, len) = match result {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
println!("Tried to return memory to client, but address was bad. Assuming this is not memory that needs to be returned.");
|
||||
return Ok(xous::Result::Ok);
|
||||
}
|
||||
};
|
||||
println!(
|
||||
"Returning {} bytes from {:08x} in PID {} to {:08x} in PID {} in context {}",
|
||||
len,
|
||||
server_addr.get(),
|
||||
pid,
|
||||
client_addr.get(),
|
||||
client_pid,
|
||||
client_ctx
|
||||
);
|
||||
|
||||
// Return the memory to the other process
|
||||
// XXX This should keep the same previous write permissions as it used to have!
|
||||
ss.send_memory(
|
||||
server_addr.get() as *mut usize,
|
||||
client_pid,
|
||||
client_addr.get() as *mut usize,
|
||||
len.get(),
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
|
||||
// Unblock the client context to allow it to continue.
|
||||
println!("Unblocking PID {} CTX {}", client_pid, client_ctx);
|
||||
ss.ready_context(client_pid, client_ctx)?;
|
||||
ss.set_context_result(client_pid, client_ctx, xous::Result::Ok)?;
|
||||
Ok(xous::Result::Ok)
|
||||
}
|
||||
SysCall::SendMessage(cid, message) => {
|
||||
let mut ss = SystemServicesHandle::get();
|
||||
let context_nr = ss.current_context_nr();
|
||||
|
|
@ -319,19 +373,29 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
.expect("server couldn't be located")
|
||||
.pid;
|
||||
|
||||
// Remember the address the message came from, in case we need to
|
||||
// return it after the borrow is through.
|
||||
let client_address = match &message {
|
||||
Message::Scalar(_) => None,
|
||||
Message::Move(msg)
|
||||
| Message::MutableBorrow(msg)
|
||||
| Message::ImmutableBorrow(msg) => Some(msg.buf.addr),
|
||||
};
|
||||
|
||||
// Translate memory messages from the client process to the server
|
||||
// process. Additionally, determine whether the call is blocking.
|
||||
// If so, switch to the server context right away.
|
||||
// process. Additionally, determine whether the call is blocking. If
|
||||
// so, switch to the server context right away.
|
||||
let (message, blocking) = match message {
|
||||
Message::Scalar(_) => (message, false),
|
||||
Message::Move(msg) => {
|
||||
let new_virt = ss.send_memory(
|
||||
msg.buf.as_mut_ptr(),
|
||||
server_pid,
|
||||
msg.buf.len(),
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
msg.buf.as_mut_ptr(),
|
||||
server_pid,
|
||||
0 as *mut usize,
|
||||
msg.buf.len(),
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
(
|
||||
Message::Move(MemoryMessage {
|
||||
id: msg.id,
|
||||
|
|
@ -345,12 +409,13 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
Message::MutableBorrow(_) => unimplemented!(),
|
||||
Message::ImmutableBorrow(msg) => {
|
||||
let new_virt = ss.send_memory(
|
||||
msg.buf.as_mut_ptr(),
|
||||
server_pid,
|
||||
msg.buf.len(),
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
msg.buf.as_mut_ptr(),
|
||||
server_pid,
|
||||
0 as *mut usize,
|
||||
msg.buf.len(),
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
(
|
||||
Message::ImmutableBorrow(MemoryMessage {
|
||||
id: msg.id,
|
||||
|
|
@ -361,12 +426,6 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
true,
|
||||
)
|
||||
}
|
||||
,
|
||||
};
|
||||
|
||||
let envelope = MessageEnvelope {
|
||||
sender: (((pid as usize) << 16) & 0xffff0000) | ((context_nr << 0) & 0xffff),
|
||||
message,
|
||||
};
|
||||
|
||||
// If the server has an available context to receive the message,
|
||||
|
|
@ -380,6 +439,10 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
"There are contexts available to handle this message. Marking PID {} as Ready",
|
||||
server_pid
|
||||
);
|
||||
let sender =
|
||||
ss.remember_server_message(sidx, pid, context_nr, &message, client_address)?;
|
||||
let envelope = MessageEnvelope { sender, message };
|
||||
|
||||
ss.ready_context(server_pid, ctx_number)?;
|
||||
if blocking {
|
||||
println!("Activating Server context and switching away from Client");
|
||||
|
|
@ -399,10 +462,7 @@ pub fn handle(call: SysCall) -> core::result::Result<xous::Result, xous::Error>
|
|||
|
||||
// Add this message to the queue. If the queue is full, this
|
||||
// returns an error.
|
||||
// let server = ss
|
||||
// .server_from_sidx(sidx)
|
||||
// .ok_or(xous::Error::ServerNotFound)?;
|
||||
ss.queue_server_message(sidx, context_nr, envelope)?;
|
||||
ss.queue_server_message(sidx, pid, context_nr, message, client_address)?;
|
||||
|
||||
// Park this context if it's blocking. This is roughly
|
||||
// equivalent to a "Yield".
|
||||
|
|
|
|||
|
|
@ -109,15 +109,10 @@ pub struct MessageEnvelope {
|
|||
/// (in the case of a Borrow). Ignore Scalar messages.
|
||||
impl Drop for MessageEnvelope {
|
||||
fn drop(&mut self) {
|
||||
match &self.message {
|
||||
Message::MutableBorrow(msg) | Message::ImmutableBorrow(msg) => {
|
||||
crate::syscall::return_memory(self.sender, msg.buf).expect("couldn't return memory");
|
||||
}
|
||||
Message::Move(msg) => {
|
||||
crate::syscall::unmap_memory(msg.buf.addr, msg.buf.size)
|
||||
crate::syscall::return_memory(self.sender).expect("couldn't return memory");
|
||||
if let Message::Move(msg) = &self.message {
|
||||
crate::syscall::unmap_memory(msg.buf.addr, msg.buf.size)
|
||||
.expect("couldn't free memory message");
|
||||
}
|
||||
Message::Scalar(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ pub enum SysCall {
|
|||
SendMessage(CID, Message),
|
||||
|
||||
/// Return a Borrowed memory region to a sender
|
||||
ReturnMemory(MessageSender, MemoryRange),
|
||||
ReturnMemory(MessageSender),
|
||||
|
||||
/// Spawn a new thread
|
||||
SpawnThread(
|
||||
|
|
@ -499,8 +499,8 @@ impl SysCall {
|
|||
sc.arg4,
|
||||
],
|
||||
},
|
||||
SysCall::ReturnMemory(a1, a2) => [SysCallNumber::ReturnMemory as usize,
|
||||
*a1, a2.addr.get(), a2.addr.get(), 0, 0, 0, 0],
|
||||
SysCall::ReturnMemory(a1) => [SysCallNumber::ReturnMemory as usize,
|
||||
*a1, 0, 0, 0, 0, 0, 0],
|
||||
SysCall::SpawnThread(a1, a2, a3) => [
|
||||
SysCallNumber::SpawnThread as usize,
|
||||
*a1 as usize,
|
||||
|
|
@ -606,7 +606,7 @@ impl SysCall {
|
|||
),
|
||||
_ => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
|
||||
},
|
||||
Some(SysCallNumber::ReturnMemory) => SysCall::ReturnMemory(a1, MemoryRange::new(a2, a3)),
|
||||
Some(SysCallNumber::ReturnMemory) => SysCall::ReturnMemory(a1),
|
||||
Some(SysCallNumber::SpawnThread) => {
|
||||
SysCall::SpawnThread(a1 as *mut usize, a2 as *mut usize, a3 as *mut usize)
|
||||
}
|
||||
|
|
@ -711,8 +711,8 @@ pub fn unmap_memory(virt: MemoryAddress, size: MemorySize) -> core::result::Resu
|
|||
|
||||
/// Map the given physical address to the given virtual address.
|
||||
/// The `size` field must be page-aligned.
|
||||
pub fn return_memory(sender: MessageSender, range: MemoryRange) -> core::result::Result<(), Error> {
|
||||
let result = rsyscall(SysCall::ReturnMemory(sender, range))?;
|
||||
pub fn return_memory(sender: MessageSender) -> core::result::Result<(), Error> {
|
||||
let result = rsyscall(SysCall::ReturnMemory(sender))?;
|
||||
if let Result::Ok = result {
|
||||
Ok(())
|
||||
} else if let Result::Error(e) = result {
|
||||
|
|
|
|||
Loading…
Reference in a new issue