more tests passing
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
abef5b7db3
commit
36d4c143f1
256
src/xous.rs
256
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 definitions;
|
||||||
mod services;
|
mod services;
|
||||||
|
mod syscalls;
|
||||||
|
|
||||||
use definitions::{Syscall, SyscallNumber, SyscallResultNumber};
|
use definitions::{Syscall, SyscallNumber, SyscallResultNumber};
|
||||||
|
pub use riscv_cpu::mmu::SyscallResult;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeSet, HashMap, HashSet},
|
collections::{BTreeSet, HashMap, HashSet},
|
||||||
sync::{
|
sync::{
|
||||||
@ -12,8 +14,6 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::xous::definitions::SyscallErrorNumber;
|
|
||||||
|
|
||||||
const MEMORY_BASE: u32 = 0x8000_0000;
|
const MEMORY_BASE: u32 = 0x8000_0000;
|
||||||
const ALLOCATION_START: u32 = 0x4000_0000;
|
const ALLOCATION_START: u32 = 0x4000_0000;
|
||||||
const ALLOCATION_END: u32 = ALLOCATION_START + 5 * 1024 * 1024;
|
const ALLOCATION_END: u32 = ALLOCATION_START + 5 * 1024 * 1024;
|
||||||
@ -364,6 +364,7 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_page(&mut self, virt: u32) -> Option<bool> {
|
fn ensure_page(&mut self, virt: u32) -> Option<bool> {
|
||||||
|
assert!(virt != 0);
|
||||||
let mut allocated = false;
|
let mut allocated = false;
|
||||||
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
let vpn1 = ((virt >> 22) & ((1 << 10) - 1)) as usize * 4;
|
||||||
let vpn0 = ((virt >> 12) & ((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]));
|
// println!("Syscall {:?}", SyscallNumber::from(args[0]));
|
||||||
match syscall {
|
match syscall {
|
||||||
Syscall::IncreaseHeap(bytes, _flags) => {
|
Syscall::IncreaseHeap(bytes, flags) => syscalls::increase_heap(self, 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::MapMemory(phys, virt, size, _flags) => {
|
Syscall::MapMemory(phys, virt, size, flags) => {
|
||||||
// print!(
|
syscalls::map_memory(self, phys, virt, size, flags)
|
||||||
// "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::Connect(id) => syscalls::connect(self, id),
|
||||||
|
Syscall::TryConnect(id) => syscalls::try_connect(self, id),
|
||||||
Syscall::SendMessage(connection_id, kind, opcode, args) => {
|
Syscall::SendMessage(connection_id, kind, opcode, args) => {
|
||||||
// println!(
|
syscalls::send_message(self, connection_id, kind, opcode, args)
|
||||||
// "SendMessage({}, {}, {}: {:x?})",
|
}
|
||||||
// connection_id, kind, opcode, args
|
Syscall::TrySendMessage(connection_id, kind, opcode, args) => {
|
||||||
// );
|
syscalls::try_send_message(self, 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Syscall::UpdateMemoryFlags(address, range, value) => {
|
Syscall::UpdateMemoryFlags(address, range, value) => {
|
||||||
for addr in address..(address + range) {
|
for addr in address..(address + range) {
|
||||||
|
@ -73,12 +73,19 @@ pub enum Syscall {
|
|||||||
i64, /* name */
|
i64, /* name */
|
||||||
),
|
),
|
||||||
Connect([u32; 4] /* Server ID */),
|
Connect([u32; 4] /* Server ID */),
|
||||||
|
TryConnect([u32; 4] /* Server ID */),
|
||||||
SendMessage(
|
SendMessage(
|
||||||
u32, /* Connection ID */
|
u32, /* Connection ID */
|
||||||
u32, /* message kind */
|
u32, /* message kind */
|
||||||
u32, /* opcode */
|
u32, /* opcode */
|
||||||
[u32; 4], /* descriptor */
|
[u32; 4], /* descriptor */
|
||||||
),
|
),
|
||||||
|
TrySendMessage(
|
||||||
|
u32, /* Connection ID */
|
||||||
|
u32, /* message kind */
|
||||||
|
u32, /* opcode */
|
||||||
|
[u32; 4], /* descriptor */
|
||||||
|
),
|
||||||
UpdateMemoryFlags(
|
UpdateMemoryFlags(
|
||||||
i64, /* address */
|
i64, /* address */
|
||||||
i64, /* range */
|
i64, /* range */
|
||||||
@ -131,6 +138,12 @@ impl From<[i64; 8]> for Syscall {
|
|||||||
value[3] as u32,
|
value[3] as u32,
|
||||||
value[4] 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(
|
SyscallNumber::SendMessage => Syscall::SendMessage(
|
||||||
value[1] as u32,
|
value[1] as u32,
|
||||||
value[2] as u32,
|
value[2] as u32,
|
||||||
@ -142,6 +155,17 @@ impl From<[i64; 8]> for Syscall {
|
|||||||
value[7] as u32,
|
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 => {
|
SyscallNumber::UpdateMemoryFlags => {
|
||||||
Syscall::UpdateMemoryFlags(value[1], value[2], value[3])
|
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