more tests passing
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
abef5b7db3
commit
36d4c143f1
254
src/xous.rs
254
src/xous.rs
@ -1,8 +1,10 @@
|
||||
use riscv_cpu::{cpu::Memory as OtherMemory, mmu::SyscallResult};
|
||||
use riscv_cpu::cpu::Memory as OtherMemory;
|
||||
mod definitions;
|
||||
mod services;
|
||||
mod syscalls;
|
||||
|
||||
use definitions::{Syscall, SyscallNumber, SyscallResultNumber};
|
||||
pub use riscv_cpu::mmu::SyscallResult;
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
sync::{
|
||||
@ -12,8 +14,6 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::xous::definitions::SyscallErrorNumber;
|
||||
|
||||
const MEMORY_BASE: u32 = 0x8000_0000;
|
||||
const ALLOCATION_START: u32 = 0x4000_0000;
|
||||
const ALLOCATION_END: u32 = ALLOCATION_START + 5 * 1024 * 1024;
|
||||
@ -364,6 +364,7 @@ impl Memory {
|
||||
}
|
||||
|
||||
fn ensure_page(&mut self, virt: u32) -> Option<bool> {
|
||||
assert!(virt != 0);
|
||||
let mut allocated = false;
|
||||
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||
let vpn0 = ((virt >> 12) & ((1 << 10) - 1)) as usize * 4;
|
||||
@ -635,249 +636,18 @@ impl riscv_cpu::cpu::Memory for Memory {
|
||||
|
||||
// println!("Syscall {:?}", SyscallNumber::from(args[0]));
|
||||
match syscall {
|
||||
Syscall::IncreaseHeap(bytes, _flags) => {
|
||||
// println!("IncreaseHeap({} bytes, flags: {:02x})", bytes, _flags);
|
||||
let increase_bytes = bytes as u32;
|
||||
let heap_address = self.heap_start + self.heap_size;
|
||||
if self.heap_size.wrapping_add(increase_bytes) > HEAP_END {
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
SyscallErrorNumber::OutOfMemory as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
for new_address in (heap_address..(heap_address + increase_bytes)).step_by(4096)
|
||||
{
|
||||
self.ensure_page(new_address);
|
||||
}
|
||||
self.heap_size += increase_bytes;
|
||||
[
|
||||
SyscallResultNumber::MemoryRange as i64,
|
||||
heap_address as i64,
|
||||
bytes,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
Syscall::IncreaseHeap(bytes, flags) => syscalls::increase_heap(self, bytes, flags),
|
||||
|
||||
Syscall::MapMemory(phys, virt, size, _flags) => {
|
||||
// print!(
|
||||
// "MapMemory(phys: {:08x}, virt: {:08x}, bytes: {}, flags: {:02x})",
|
||||
// phys, virt, size, _flags
|
||||
// );
|
||||
if virt != 0 {
|
||||
unimplemented!("Non-zero virt address");
|
||||
}
|
||||
if phys != 0 {
|
||||
unimplemented!("Non-zero phys address");
|
||||
}
|
||||
if let Some(region) = self.allocate_virt_region(size as usize) {
|
||||
[
|
||||
SyscallResultNumber::MemoryRange as i64,
|
||||
region as i64,
|
||||
size,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
// self.print_mmu();
|
||||
println!(
|
||||
"Couldn't find a free spot to allocate {} bytes of virtual memory, or out of memory",
|
||||
size as usize
|
||||
);
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
SyscallErrorNumber::OutOfMemory as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
Syscall::Connect(id) => {
|
||||
// println!(
|
||||
// "Connect([0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}])",
|
||||
// id[0], id[1], id[2], id[3]
|
||||
// );
|
||||
if let Some(service) = services::get_service(&id) {
|
||||
let connection_id = self.connections.len() as u32 + 1;
|
||||
self.connections.insert(connection_id, service);
|
||||
[
|
||||
SyscallResultNumber::ConnectionId as i64,
|
||||
connection_id as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
[
|
||||
SyscallResultNumber::ConnectionId as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
Syscall::MapMemory(phys, virt, size, flags) => {
|
||||
syscalls::map_memory(self, phys, virt, size, flags)
|
||||
}
|
||||
Syscall::Connect(id) => syscalls::connect(self, id),
|
||||
Syscall::TryConnect(id) => syscalls::try_connect(self, id),
|
||||
Syscall::SendMessage(connection_id, kind, opcode, args) => {
|
||||
// println!(
|
||||
// "SendMessage({}, {}, {}: {:x?})",
|
||||
// connection_id, kind, opcode, args
|
||||
// );
|
||||
let memory_region = if kind == 1 || kind == 2 || kind == 3 {
|
||||
let mut memory_region = vec![0; args[1] as usize];
|
||||
for (offset, value) in memory_region.iter_mut().enumerate() {
|
||||
*value = self.read_u8(
|
||||
self.virt_to_phys(args[0] + offset as u32)
|
||||
.expect("invalid memory address")
|
||||
as u64,
|
||||
);
|
||||
}
|
||||
Some(memory_region)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let Some(service) = self.connections.get_mut(&connection_id) else {
|
||||
println!("Unhandled connection ID {}", connection_id);
|
||||
return [
|
||||
SyscallResultNumber::Error as i64,
|
||||
9, /* ServerNotFound */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into();
|
||||
};
|
||||
match kind {
|
||||
1..=3 => {
|
||||
let mut memory_region = memory_region.unwrap();
|
||||
let extra = [args[2], args[3]];
|
||||
match kind {
|
||||
1 => match service.lend_mut(0, opcode, &mut memory_region, extra) {
|
||||
services::LendResult::WaitForResponse(msg) => msg.into(),
|
||||
services::LendResult::MemoryReturned(result) => {
|
||||
for (offset, value) in memory_region.into_iter().enumerate() {
|
||||
self.write_u8(args[0] as u64 + offset as u64, value);
|
||||
}
|
||||
[
|
||||
SyscallResultNumber::MemoryReturned as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
},
|
||||
2 => match service.lend(0, opcode, &memory_region, extra) {
|
||||
services::LendResult::WaitForResponse(msg) => msg.into(),
|
||||
services::LendResult::MemoryReturned(result) => [
|
||||
SyscallResultNumber::MemoryReturned as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
},
|
||||
3 => {
|
||||
service.send(0, opcode, &memory_region, extra);
|
||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
service.scalar(0, opcode, args);
|
||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||
}
|
||||
5 => match service.blocking_scalar(0, opcode, args) {
|
||||
services::ScalarResult::Scalar1(result) => [
|
||||
SyscallResultNumber::Scalar1 as i64,
|
||||
result as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::Scalar2(result) => [
|
||||
SyscallResultNumber::Scalar2 as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::Scalar5(result) => [
|
||||
SyscallResultNumber::Scalar5 as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
result[2] as i64,
|
||||
result[3] as i64,
|
||||
result[4] as i64,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::WaitForResponse(msg) => msg.into(),
|
||||
},
|
||||
_ => {
|
||||
println!("Unknown message kind {}", kind);
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
9, /* ServerNotFound */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
syscalls::send_message(self, connection_id, kind, opcode, args)
|
||||
}
|
||||
Syscall::TrySendMessage(connection_id, kind, opcode, args) => {
|
||||
syscalls::try_send_message(self, connection_id, kind, opcode, args)
|
||||
}
|
||||
Syscall::UpdateMemoryFlags(address, range, value) => {
|
||||
for addr in address..(address + range) {
|
||||
|
@ -73,12 +73,19 @@ pub enum Syscall {
|
||||
i64, /* name */
|
||||
),
|
||||
Connect([u32; 4] /* Server ID */),
|
||||
TryConnect([u32; 4] /* Server ID */),
|
||||
SendMessage(
|
||||
u32, /* Connection ID */
|
||||
u32, /* message kind */
|
||||
u32, /* opcode */
|
||||
[u32; 4], /* descriptor */
|
||||
),
|
||||
TrySendMessage(
|
||||
u32, /* Connection ID */
|
||||
u32, /* message kind */
|
||||
u32, /* opcode */
|
||||
[u32; 4], /* descriptor */
|
||||
),
|
||||
UpdateMemoryFlags(
|
||||
i64, /* address */
|
||||
i64, /* range */
|
||||
@ -131,6 +138,12 @@ impl From<[i64; 8]> for Syscall {
|
||||
value[3] as u32,
|
||||
value[4] as u32,
|
||||
]),
|
||||
SyscallNumber::TryConnect => Syscall::TryConnect([
|
||||
value[1] as u32,
|
||||
value[2] as u32,
|
||||
value[3] as u32,
|
||||
value[4] as u32,
|
||||
]),
|
||||
SyscallNumber::SendMessage => Syscall::SendMessage(
|
||||
value[1] as u32,
|
||||
value[2] as u32,
|
||||
@ -142,6 +155,17 @@ impl From<[i64; 8]> for Syscall {
|
||||
value[7] as u32,
|
||||
],
|
||||
),
|
||||
SyscallNumber::TrySendMessage => Syscall::TrySendMessage(
|
||||
value[1] as u32,
|
||||
value[2] as u32,
|
||||
value[3] as u32,
|
||||
[
|
||||
value[4] as u32,
|
||||
value[5] as u32,
|
||||
value[6] as u32,
|
||||
value[7] as u32,
|
||||
],
|
||||
),
|
||||
SyscallNumber::UpdateMemoryFlags => {
|
||||
Syscall::UpdateMemoryFlags(value[1], value[2], value[3])
|
||||
}
|
||||
|
246
src/xous/definitions/memoryflags.rs
Normal file
246
src/xous/definitions/memoryflags.rs
Normal file
@ -0,0 +1,246 @@
|
||||
/// Flags to be passed to the MapMemory struct.
|
||||
/// Note that it is an error to have memory be
|
||||
/// writable and not readable.
|
||||
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct MemoryFlags {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl MemoryFlags {
|
||||
/// Free this memory
|
||||
pub const FREE: Self = Self { bits: 0b0000_0000 };
|
||||
|
||||
/// Immediately allocate this memory. Otherwise it will
|
||||
/// be demand-paged. This is implicitly set when `phys`
|
||||
/// is not 0.
|
||||
pub const VALID: Self = Self { bits: 0b0000_0001 };
|
||||
|
||||
/// Allow the CPU to read from this page.
|
||||
pub const READ: Self = Self { bits: 0b0000_0010 };
|
||||
|
||||
/// Allow the CPU to write to this page.
|
||||
pub const WRITE: Self = Self { bits: 0b0000_0100 };
|
||||
|
||||
/// Allow the CPU to execute from this page.
|
||||
pub const EXECUTE: Self = Self { bits: 0b0000_1000 };
|
||||
|
||||
/// Accessible from user mode
|
||||
pub const USERMODE: Self = Self { bits: 0b0001_0000 };
|
||||
|
||||
/// Globally-available
|
||||
pub const GLOBAL: Self = Self { bits: 0b0010_0000 };
|
||||
|
||||
/// Cache access status
|
||||
pub const ACCESSED: Self = Self { bits: 0b0100_0000 };
|
||||
|
||||
/// Page needs flushing
|
||||
pub const DIRTY: Self = Self { bits: 0b1000_0000 };
|
||||
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
pub fn from_bits(raw: usize) -> Option<MemoryFlags> {
|
||||
if raw > 255 {
|
||||
None
|
||||
} else {
|
||||
Some(MemoryFlags { bits: raw })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.bits == 0
|
||||
}
|
||||
|
||||
pub fn empty() -> MemoryFlags {
|
||||
MemoryFlags { bits: 0 }
|
||||
}
|
||||
|
||||
pub fn all() -> MemoryFlags {
|
||||
MemoryFlags { bits: 255 }
|
||||
}
|
||||
|
||||
pub fn contains(&self, other: MemoryFlags) -> bool {
|
||||
(self.bits & other.bits) == other.bits
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Binary for MemoryFlags {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::Binary::fmt(&self.bits, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Octal for MemoryFlags {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::Octal::fmt(&self.bits, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::LowerHex for MemoryFlags {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::LowerHex::fmt(&self.bits, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::UpperHex for MemoryFlags {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::fmt::UpperHex::fmt(&self.bits, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitOr for MemoryFlags {
|
||||
type Output = Self;
|
||||
|
||||
/// Returns the union of the two sets of flags.
|
||||
#[inline]
|
||||
fn bitor(self, other: MemoryFlags) -> Self {
|
||||
Self {
|
||||
bits: self.bits | other.bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitOrAssign for MemoryFlags {
|
||||
/// Adds the set of flags.
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, other: Self) {
|
||||
self.bits |= other.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitXor for MemoryFlags {
|
||||
type Output = Self;
|
||||
|
||||
/// Returns the left flags, but with all the right flags toggled.
|
||||
#[inline]
|
||||
fn bitxor(self, other: Self) -> Self {
|
||||
Self {
|
||||
bits: self.bits ^ other.bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitXorAssign for MemoryFlags {
|
||||
/// Toggles the set of flags.
|
||||
#[inline]
|
||||
fn bitxor_assign(&mut self, other: Self) {
|
||||
self.bits ^= other.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitAnd for MemoryFlags {
|
||||
type Output = Self;
|
||||
|
||||
/// Returns the intersection between the two sets of flags.
|
||||
#[inline]
|
||||
fn bitand(self, other: Self) -> Self {
|
||||
Self {
|
||||
bits: self.bits & other.bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::BitAndAssign for MemoryFlags {
|
||||
/// Disables all flags disabled in the set.
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, other: Self) {
|
||||
self.bits &= other.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub for MemoryFlags {
|
||||
type Output = Self;
|
||||
|
||||
/// Returns the set difference of the two sets of flags.
|
||||
#[inline]
|
||||
fn sub(self, other: Self) -> Self {
|
||||
Self {
|
||||
bits: self.bits & !other.bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::SubAssign for MemoryFlags {
|
||||
/// Disables all flags enabled in the set.
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
self.bits &= !other.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Not for MemoryFlags {
|
||||
type Output = Self;
|
||||
|
||||
/// Returns the complement of this set of flags.
|
||||
#[inline]
|
||||
fn not(self) -> Self {
|
||||
Self { bits: !self.bits } & MemoryFlags { bits: 255 }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for MemoryFlags {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let mut first = true;
|
||||
if self.contains(MemoryFlags::FREE) {
|
||||
write!(f, "FREE")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::VALID) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "VALID")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::READ) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "READ")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::WRITE) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "WRITE")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::EXECUTE) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "EXECUTE")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::USERMODE) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "USERMODE")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::GLOBAL) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "GLOBAL")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::ACCESSED) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "ACCESSED")?;
|
||||
first = false;
|
||||
}
|
||||
if self.contains(MemoryFlags::DIRTY) {
|
||||
if !first {
|
||||
write!(f, " | ")?;
|
||||
}
|
||||
write!(f, "DIRTY")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
296
src/xous/syscalls.rs
Normal file
296
src/xous/syscalls.rs
Normal file
@ -0,0 +1,296 @@
|
||||
use super::definitions::{SyscallErrorNumber, SyscallResultNumber};
|
||||
use super::services;
|
||||
use super::Memory;
|
||||
use super::SyscallResult;
|
||||
use riscv_cpu::cpu::Memory as OtherMemory;
|
||||
|
||||
pub fn map_memory(
|
||||
memory: &mut Memory,
|
||||
phys: i64,
|
||||
virt: i64,
|
||||
size: i64,
|
||||
_flags: i64,
|
||||
) -> SyscallResult {
|
||||
// print!(
|
||||
// "MapMemory(phys: {:08x}, virt: {:08x}, bytes: {}, flags: {:02x})",
|
||||
// phys, virt, size, _flags
|
||||
// );
|
||||
if virt != 0 {
|
||||
unimplemented!("Non-zero virt address");
|
||||
}
|
||||
if phys != 0 {
|
||||
unimplemented!("Non-zero phys address");
|
||||
}
|
||||
if let Some(region) = memory.allocate_virt_region(size as usize) {
|
||||
[
|
||||
SyscallResultNumber::MemoryRange as i64,
|
||||
region as i64,
|
||||
size,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
// self.print_mmu();
|
||||
println!(
|
||||
"Couldn't find a free spot to allocate {} bytes of virtual memory, or out of memory",
|
||||
size as usize
|
||||
);
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
SyscallErrorNumber::OutOfMemory as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(memory: &mut Memory, id: [u32; 4]) -> SyscallResult {
|
||||
// println!(
|
||||
// "Connect([0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}])",
|
||||
// id[0], id[1], id[2], id[3]
|
||||
// );
|
||||
if let Some(service) = super::super::xous::services::get_service(&id) {
|
||||
let connection_id = memory.connections.len() as u32 + 1;
|
||||
memory.connections.insert(connection_id, service);
|
||||
[
|
||||
SyscallResultNumber::ConnectionId as i64,
|
||||
connection_id as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
[
|
||||
SyscallResultNumber::ConnectionId as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_connect(memory: &mut Memory, id: [u32; 4]) -> SyscallResult {
|
||||
connect(memory, id)
|
||||
}
|
||||
|
||||
|
||||
pub fn send_message(
|
||||
memory: &mut Memory,
|
||||
connection_id: u32,
|
||||
kind: u32,
|
||||
opcode: u32,
|
||||
args: [u32; 4],
|
||||
) -> SyscallResult {
|
||||
// println!(
|
||||
// "SendMessage({}, {}, {}: {:x?})",
|
||||
// connection_id, kind, opcode, args
|
||||
// );
|
||||
let memory_region = if kind == 1 || kind == 2 || kind == 3 {
|
||||
let mut memory_region = vec![0; args[1] as usize];
|
||||
for (offset, value) in memory_region.iter_mut().enumerate() {
|
||||
*value = memory.read_u8(
|
||||
memory
|
||||
.virt_to_phys(args[0] + offset as u32)
|
||||
.expect("invalid memory address") as u64,
|
||||
);
|
||||
}
|
||||
Some(memory_region)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let Some(service) = memory.connections.get_mut(&connection_id) else {
|
||||
println!("Unhandled connection ID {}", connection_id);
|
||||
return [
|
||||
SyscallResultNumber::Error as i64,
|
||||
9, /* ServerNotFound */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into();
|
||||
};
|
||||
match kind {
|
||||
1..=3 => {
|
||||
let mut memory_region = memory_region.unwrap();
|
||||
let extra = [args[2], args[3]];
|
||||
match kind {
|
||||
1 => match service.lend_mut(0, opcode, &mut memory_region, extra) {
|
||||
services::LendResult::WaitForResponse(msg) => msg.into(),
|
||||
services::LendResult::MemoryReturned(result) => {
|
||||
for (offset, value) in memory_region.into_iter().enumerate() {
|
||||
memory.write_u8(args[0] as u64 + offset as u64, value);
|
||||
}
|
||||
[
|
||||
SyscallResultNumber::MemoryReturned as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
},
|
||||
2 => match service.lend(0, opcode, &memory_region, extra) {
|
||||
services::LendResult::WaitForResponse(msg) => msg.into(),
|
||||
services::LendResult::MemoryReturned(result) => [
|
||||
SyscallResultNumber::MemoryReturned as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
},
|
||||
3 => {
|
||||
service.send(0, opcode, &memory_region, extra);
|
||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
service.scalar(0, opcode, args);
|
||||
[SyscallResultNumber::Ok as i64, 0, 0, 0, 0, 0, 0, 0].into()
|
||||
}
|
||||
5 => match service.blocking_scalar(0, opcode, args) {
|
||||
services::ScalarResult::Scalar1(result) => [
|
||||
SyscallResultNumber::Scalar1 as i64,
|
||||
result as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::Scalar2(result) => [
|
||||
SyscallResultNumber::Scalar2 as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::Scalar5(result) => [
|
||||
SyscallResultNumber::Scalar5 as i64,
|
||||
result[0] as i64,
|
||||
result[1] as i64,
|
||||
result[2] as i64,
|
||||
result[3] as i64,
|
||||
result[4] as i64,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into(),
|
||||
services::ScalarResult::WaitForResponse(msg) => msg.into(),
|
||||
},
|
||||
_ => {
|
||||
println!("Unknown message kind {}", kind);
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
9, /* ServerNotFound */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_send_message(
|
||||
memory: &mut Memory,
|
||||
connection_id: u32,
|
||||
kind: u32,
|
||||
opcode: u32,
|
||||
args: [u32; 4],
|
||||
) -> SyscallResult {
|
||||
send_message(memory, connection_id, kind, opcode, args)
|
||||
}
|
||||
|
||||
pub fn increase_heap(memory: &mut Memory, delta: i64, _flags: i64) -> SyscallResult {
|
||||
assert!(delta & 0xfff == 0, "delta must be page-aligned");
|
||||
let increase_bytes = delta as u32;
|
||||
let heap_address = memory.heap_start + memory.heap_size;
|
||||
if delta == 0 {
|
||||
return [
|
||||
SyscallResultNumber::MemoryRange as i64,
|
||||
memory.heap_start as i64,
|
||||
if memory.heap_size == 0 {
|
||||
4096
|
||||
} else {
|
||||
memory.heap_size
|
||||
} as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into();
|
||||
}
|
||||
if heap_address.saturating_add(increase_bytes) > super::HEAP_END {
|
||||
[
|
||||
SyscallResultNumber::Error as i64,
|
||||
SyscallErrorNumber::OutOfMemory as i64,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
} else {
|
||||
for new_address in (heap_address..(heap_address + increase_bytes)).step_by(4096) {
|
||||
memory.ensure_page(new_address);
|
||||
}
|
||||
let new_heap_region = memory.heap_start + memory.heap_size;
|
||||
memory.heap_size += increase_bytes;
|
||||
[
|
||||
SyscallResultNumber::MemoryRange as i64,
|
||||
new_heap_region as i64,
|
||||
delta,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user