mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-14 08:03:34 +00:00
xous: fix memory messages in hosted environment
This fixes passing memory between clients and servers when running n a hosted environment. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
ca32e4f9c1
commit
7aab01c95d
3 changed files with 173 additions and 70 deletions
|
|
@ -445,6 +445,7 @@ pub fn _xous_syscall(
|
|||
if *ret != Result::WouldBlock {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
@ -506,7 +507,10 @@ fn _xous_syscall_result(
|
|||
// This thread_id doesn't exist in the mailbox, so read additional data.
|
||||
let mut pkt = [0usize; 8];
|
||||
let mut raw_bytes = [0u8; size_of::<usize>() * 9];
|
||||
stream.read_exact(&mut raw_bytes).expect("Server shut down");
|
||||
if let Err(e) = stream.read_exact(&mut raw_bytes) {
|
||||
eprintln!("Server shut down: {}", e);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let mut raw_bytes_chunks = raw_bytes.chunks(size_of::<usize>());
|
||||
|
||||
|
|
@ -518,66 +522,71 @@ fn _xous_syscall_result(
|
|||
*pkt_word = usize::from_le_bytes(word.try_into().unwrap());
|
||||
}
|
||||
|
||||
let response = Result::from_args(pkt);
|
||||
let mut response = Result::from_args(pkt);
|
||||
|
||||
// println!(" Response: {:?}", response);
|
||||
// println!(" Response to {:?}: {:?}", call, response);
|
||||
if Result::BlockedProcess == response {
|
||||
// println!(" Waiting again");
|
||||
continue;
|
||||
}
|
||||
match &call {
|
||||
crate::SysCall::SendMessage(_, msg) | crate::SysCall::TrySendMessage(_, msg) => {
|
||||
match msg {
|
||||
crate::Message::MutableBorrow(crate::MemoryMessage {
|
||||
id: _id,
|
||||
buf,
|
||||
offset: _offset,
|
||||
valid: _valid,
|
||||
}) => {
|
||||
// Read the buffer back from the remote host.
|
||||
use core::slice;
|
||||
let mut data = unsafe {
|
||||
slice::from_raw_parts_mut(buf.addr.get() as _, buf.size.get())
|
||||
};
|
||||
stream.read_exact(&mut data).expect("Server shut down");
|
||||
// pkt.extend_from_slice(data);
|
||||
}
|
||||
|
||||
crate::Message::Borrow(crate::MemoryMessage {
|
||||
id: _id,
|
||||
buf,
|
||||
offset: _offset,
|
||||
valid: _valid,
|
||||
}) => {
|
||||
// Read the buffer back from the remote host and ensure it's the same
|
||||
use core::slice;
|
||||
let mut check_data = Vec::new();
|
||||
check_data.resize(buf.len(), 0);
|
||||
let data =
|
||||
unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) };
|
||||
stream
|
||||
.read_exact(&mut check_data)
|
||||
.expect("Server shut down");
|
||||
|
||||
assert_eq!(data, check_data.as_slice());
|
||||
// If the client is passing us memory, remap the array to our own space.
|
||||
if let Result::Message(msg) = &mut response {
|
||||
match &mut msg.body {
|
||||
crate::Message::Move(ref mut memory_message)
|
||||
| crate::Message::Borrow(ref mut memory_message)
|
||||
| crate::Message::MutableBorrow(ref mut memory_message) => {
|
||||
let data = vec![0u8; memory_message.buf.len()];
|
||||
let mut data = std::mem::ManuallyDrop::new(data);
|
||||
// println!("KERNEL: Reading {} bytes of data from network", data.len());
|
||||
if let Err(e) = stream.read_exact(&mut data) {
|
||||
eprintln!("Server shut down: {}", e);
|
||||
std::process::exit(0);
|
||||
}
|
||||
let len = data.len();
|
||||
let addr = data.as_mut_ptr();
|
||||
|
||||
crate::Message::Move(crate::MemoryMessage {
|
||||
id: _id,
|
||||
buf,
|
||||
offset: _offset,
|
||||
valid: _valid,
|
||||
}) => {
|
||||
// In a hosted environment, the message contents are leaked when
|
||||
// it gets converted into a MemoryMessage. Now that the call is
|
||||
// complete, free the memory.
|
||||
mem::unmap_memory_post(*buf).unwrap();
|
||||
}
|
||||
// Nothing to do for Immutable borrow, since the memory can't change
|
||||
crate::Message::Scalar(_) | crate::Message::BlockingScalar(_) => (),
|
||||
memory_message.buf.addr = crate::MemoryAddress::new(addr as _).unwrap();
|
||||
memory_message.buf.size = crate::MemorySize::new(len).unwrap();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// If the original call contained memory, then ensure the memory we get back is correct.
|
||||
if let Some(mem) = call.memory() {
|
||||
if call.is_borrow() || call.is_mutableborrow() {
|
||||
// Read the buffer back from the remote host.
|
||||
use core::slice;
|
||||
let mut data =
|
||||
unsafe { slice::from_raw_parts_mut(mem.addr.get() as _, mem.size.get()) };
|
||||
let previous_data = if call.is_borrow() {
|
||||
Some(data.to_vec())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Err(e) = stream.read_exact(&mut data) {
|
||||
eprintln!("Server shut down: {}", e);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// If it is an immutable borrow, verify the contents haven't changed somehow
|
||||
if let Some(previous_data) = previous_data {
|
||||
assert_eq!(data, previous_data.as_slice());
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
||||
if call.is_move() {
|
||||
// In a hosted environment, the message contents are leaked when
|
||||
// it gets converted into a MemoryMessage. Now that the call is
|
||||
// complete, free the memory.
|
||||
mem::unmap_memory_post(mem).unwrap();
|
||||
}
|
||||
|
||||
if call.is_return_memory() {
|
||||
let rebuilt = unsafe { Vec::from_raw_parts(mem.as_mut_ptr(), mem.len(), mem.len()) };
|
||||
drop(rebuilt);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have the Stream mutex, temporarily take the Mailbox mutex to see if
|
||||
|
|
@ -622,22 +631,16 @@ fn _xous_syscall_to(
|
|||
for word in &[nr, a1, a2, a3, a4, a5, a6, a7] {
|
||||
pkt.extend_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
match call {
|
||||
crate::SysCall::SendMessage(_, ref msg) | crate::SysCall::TrySendMessage(_, ref msg) => {
|
||||
match msg {
|
||||
crate::Message::MutableBorrow(m)
|
||||
| crate::Message::Borrow(m)
|
||||
| crate::Message::Move(m) => {
|
||||
use core::slice;
|
||||
let data: &[u8] =
|
||||
unsafe { slice::from_raw_parts(m.buf.addr.get() as _, m.buf.size.get()) };
|
||||
pkt.extend_from_slice(data);
|
||||
}
|
||||
crate::Message::Scalar(_) | crate::Message::BlockingScalar(_) => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
||||
// Also send memory, if it's present.
|
||||
if let Some(memory) = call.memory() {
|
||||
use core::slice;
|
||||
let data: &[u8] = unsafe { slice::from_raw_parts(memory.addr.get() as _, memory.size.get()) };
|
||||
pkt.extend_from_slice(data);
|
||||
}
|
||||
|
||||
xsc.write_all(&pkt).expect("Server shut down");
|
||||
if let Err(e) = xsc.write_all(&pkt) {
|
||||
eprintln!("Server shut down: {}", e);
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -369,6 +369,10 @@ impl MemoryRange {
|
|||
addr != 0,
|
||||
"tried to construct a memory range with a null pointer"
|
||||
);
|
||||
assert!(
|
||||
size != 0,
|
||||
"tried to construct a zero-length memory range"
|
||||
);
|
||||
Ok(MemoryRange {
|
||||
addr: MemoryAddress::new(addr).ok_or(Error::BadAddress)?,
|
||||
size: MemorySize::new(size).ok_or(Error::BadAddress)?,
|
||||
|
|
@ -575,6 +579,20 @@ impl Result {
|
|||
_ => Result::UnknownResult(src[0], src[1], src[2], src[3], src[4], src[5], src[6]),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// If the Result has memory attached to it, return the memory
|
||||
pub fn memory(&self) -> Option<MemoryRange> {
|
||||
match self {
|
||||
Result::Message(msg) => match &msg.body {
|
||||
Message::Move(memory_message)
|
||||
| Message::Borrow(memory_message)
|
||||
| Message::MutableBorrow(memory_message) => Some(memory_message.buf),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for Result {
|
||||
|
|
|
|||
|
|
@ -580,8 +580,26 @@ impl SysCall {
|
|||
sc.arg4,
|
||||
],
|
||||
},
|
||||
SysCall::ReturnScalar1(sender, arg1) => [SysCallNumber::ReturnScalar1 as usize, *sender, *arg1, 0, 0, 0, 0, 0],
|
||||
SysCall::ReturnScalar2(sender, arg1, arg2) => [SysCallNumber::ReturnScalar2 as usize, *sender, *arg1, *arg2, 0, 0, 0, 0],
|
||||
SysCall::ReturnScalar1(sender, arg1) => [
|
||||
SysCallNumber::ReturnScalar1 as usize,
|
||||
*sender,
|
||||
*arg1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
SysCall::ReturnScalar2(sender, arg1, arg2) => [
|
||||
SysCallNumber::ReturnScalar2 as usize,
|
||||
*sender,
|
||||
*arg1,
|
||||
*arg2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7) => [
|
||||
SysCallNumber::Invalid as usize,
|
||||
*a1,
|
||||
|
|
@ -769,6 +787,66 @@ impl SysCall {
|
|||
SysCallNumber::Invalid => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if the associated syscall is a message that has memory attached to it
|
||||
pub fn has_memory(&self) -> bool {
|
||||
match self {
|
||||
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
|
||||
matches!(msg, Message::Move(_) | Message::Borrow(_) | Message::MutableBorrow(_))
|
||||
}
|
||||
SysCall::ReturnMemory(_, _) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the associated syscall is a message that is a Move
|
||||
pub fn is_move(&self) -> bool {
|
||||
match self {
|
||||
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
|
||||
matches!(msg, Message::Move(_))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the associated syscall is a message that is a Borrow
|
||||
pub fn is_borrow(&self) -> bool {
|
||||
match self {
|
||||
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
|
||||
matches!(msg, Message::Borrow(_))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the associated syscall is a message that is a MutableBorrow
|
||||
pub fn is_mutableborrow(&self) -> bool {
|
||||
match self {
|
||||
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
|
||||
matches!(msg, Message::MutableBorrow(_))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the associated syscall is returning memory
|
||||
pub fn is_return_memory(&self) -> bool {
|
||||
matches!(self, SysCall::ReturnMemory(_, _))
|
||||
}
|
||||
|
||||
/// If the syscall has memory attached to it, return the memory
|
||||
pub fn memory(&self) -> Option<MemoryRange> {
|
||||
match self {
|
||||
SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => match msg {
|
||||
Message::Move(memory_message)
|
||||
| Message::Borrow(memory_message)
|
||||
| Message::MutableBorrow(memory_message) => Some(memory_message.buf),
|
||||
_ => None,
|
||||
},
|
||||
SysCall::ReturnMemory(_, range) => Some(*range),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
|
|
@ -865,7 +943,11 @@ pub fn return_scalar(sender: MessageSender, val: usize) -> core::result::Result<
|
|||
|
||||
/// Map the given physical address to the given virtual address.
|
||||
/// The `size` field must be page-aligned.
|
||||
pub fn return_scalar2(sender: MessageSender, val1: usize, val2: usize) -> core::result::Result<(), Error> {
|
||||
pub fn return_scalar2(
|
||||
sender: MessageSender,
|
||||
val1: usize,
|
||||
val2: usize,
|
||||
) -> core::result::Result<(), Error> {
|
||||
let result = rsyscall(SysCall::ReturnScalar2(sender, val1, val2))?;
|
||||
if let crate::Result::Ok = result {
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Reference in a new issue