Add ipc from old mikros std

This commit is contained in:
pjht 2024-06-05 16:12:27 -05:00
parent b68449acff
commit a428b626e5
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
9 changed files with 251 additions and 11 deletions

View File

@ -1,4 +1,7 @@
use super::{
#![stable(feature = "mikros", since = "1.80.0")]
#![allow(exported_private_dependencies)]
use crate::sys::{
buffers::KernelBufferAllocator,
syscalls::{copy_to, drop_space, map_assert_unused, map_only_unused, map_free, new_space},
};
@ -6,26 +9,35 @@
use crate::mem;
use crate::sync::Mutex;
use x86_64::{
structures::paging::{Page, PageTableFlags},
structures::paging::PageTableFlags,
VirtAddr,
};
#[stable(feature = "mikros", since = "1.80.0")]
pub use x86_64::structures::paging::Page;
#[stable(feature = "mikros", since = "1.80.0")]
#[allow(unused)]
pub static ACTIVE_SPACE: Mutex<AddressSpace> = Mutex::new(AddressSpace(0));
#[stable(feature = "mikros", since = "1.80.0")]
#[derive(Debug)]
pub struct AddressSpace(u64);
#[stable(feature = "mikros", since = "1.80.0")]
#[derive(Debug)]
pub struct PagingError;
#[allow(clippy::new_without_default)] // The idea of a "default" address space makes no sense
impl AddressSpace {
#[must_use]
#[stable(feature = "mikros", since = "1.80.0")]
pub fn new() -> Self {
Self(new_space())
}
#[must_use]
#[stable(feature = "mikros", since = "1.80.0")]
pub fn into_raw(self) -> u64 {
let id = self.0;
mem::forget(self);
@ -37,12 +49,14 @@ pub fn into_raw(self) -> u64 {
/// as it doesn't make sense to map garbage data read only.
/// The requested virtual page range is asserted to be unmapped, making this function safe.
#[allow(unused)]
#[stable(feature = "mikros", since = "1.80.0")]
pub fn map_assert_unused(&mut self, page: Page, num_pages: usize) -> Result<(), PagingError> {
map_assert_unused(self.0, page, num_pages, PageTableFlags::USER_ACCESSIBLE)
.map_err(|_| PagingError)
}
#[allow(unused)]
#[stable(feature = "mikros", since = "1.80.0")]
pub fn map_only_unused(&mut self, page: Page, num_pages: usize) -> Result<(), PagingError> {
map_only_unused(self.0, page, num_pages, PageTableFlags::USER_ACCESSIBLE)
.map_err(|_| PagingError)
@ -52,6 +66,7 @@ pub fn map_only_unused(&mut self, page: Page, num_pages: usize) -> Result<(), Pa
/// The newly allocated physical memory contains garbage data, so the mapping will always be writable,
/// as it doesn't make sense to map garbage data read only.
#[allow(unused)]
#[stable(feature = "mikros", since = "1.80.0")]
pub fn map_free(&mut self, num_pages: usize) -> Result<Page, PagingError> {
Page::from_start_address(VirtAddr::from_ptr(
map_free(self.0, num_pages, PageTableFlags::USER_ACCESSIBLE)
@ -60,6 +75,7 @@ pub fn map_free(&mut self, num_pages: usize) -> Result<Page, PagingError> {
.map_err(|_| PagingError)
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn copy_to(&self, dst: *mut u8, src: &[u8]) -> Result<(), PagingError> {
let mut buf = Vec::with_capacity_in(src.len(), KernelBufferAllocator::new());
buf.extend_from_slice(src);
@ -67,6 +83,7 @@ pub fn copy_to(&self, dst: *mut u8, src: &[u8]) -> Result<(), PagingError> {
}
}
#[stable(feature = "mikros", since = "1.80.0")]
impl Drop for AddressSpace {
fn drop(&mut self) {
drop_space(self.0);

View File

@ -0,0 +1,53 @@
#![stable(feature = "mikros", since = "1.80.0")]
pub mod rpc;
use crate::sync::{LazyLock, RwLock};
use crate::sys::{
buffers::KernelBufferAllocator, syscalls::{get_pid, ipc_recv, ipc_send}
};
use crate::collections::HashMap;
#[allow(clippy::type_complexity)] // Pulling out fn(Message) makes the type longer
static CALLBACKS: LazyLock<RwLock<HashMap<u16, fn(Message)>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
#[stable(feature = "mikros", since = "1.80.0")]
pub struct Message {
pub from: u64,
pub data: Vec<u8>,
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn register_callback(proto: u16, callback: fn(Message)) {
CALLBACKS.write().unwrap().insert(proto, callback);
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn unregister_callback(proto: u16) {
CALLBACKS.write().unwrap().remove(&proto);
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn send_msg(dst: u64, proto: u16, data: &[u8]) {
let mut buffer = Vec::with_capacity_in(data.len() + 16, KernelBufferAllocator::new());
buffer.extend_from_slice(&(get_pid().to_le_bytes()));
buffer.extend_from_slice(&(proto.to_le_bytes()));
buffer.extend_from_slice(data);
ipc_send(dst, buffer).unwrap();
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn process_messages() {
while let Some(msg) = ipc_recv() {
let proto = u16::from_le_bytes(msg[8..10].try_into().unwrap());
if let Some(callback) = CALLBACKS.read().unwrap().get(&proto) {
callback(Message {
from: u64::from_le_bytes(msg[0..8].try_into().unwrap()),
data: Vec::from(&msg[10..]),
});
}
}
}

View File

@ -0,0 +1,161 @@
#![stable(feature = "mikros", since = "1.80.0")]
use core::sync::atomic::{AtomicU64, Ordering};
use crate::sync::{Mutex, RwLock, LazyLock};
use crate::collections::HashMap;
type MessageCallback = fn(IncomingCall);
static CALLBACKS: LazyLock<RwLock<HashMap<u16, MessageCallback>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
static RETURNS: LazyLock<Mutex<HashMap<CallId, Vec<u8>>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
#[stable(feature = "mikros", since = "1.80.0")]
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct CallId(u64);
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
#[stable(feature = "mikros", since = "1.80.0")]
pub struct IncomingCall {
pub from: u64,
call_id: CallId,
pub proto: u16,
pub func: u16,
pub args: Vec<u8>,
}
impl IncomingCall {
#[stable(feature = "mikros", since = "1.80.0")]
pub fn send_return(self, data: &[u8]) {
let msg = Message {
typ: MessageType::Return,
call_id: self.call_id,
proto: 0,
func: 0,
data,
};
let mut buf = Vec::new();
msg.serialize(&mut buf);
super::send_msg(self.from, 0, &buf);
}
}
impl CallId {
#[stable(feature = "mikros", since = "1.80.0")]
pub fn try_get_return(&self) -> Option<Vec<u8>> {
RETURNS.lock().unwrap().remove(self)
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn get_return(self) -> Vec<u8> {
loop {
super::process_messages();
if let Some(ret) = self.try_get_return() {
break ret;
}
}
}
}
#[repr(u8)]
#[derive(Copy, Clone)]
enum MessageType {
Call,
Return,
}
impl TryFrom<u8> for MessageType {
type Error = u8;
fn try_from(val: u8) -> Result<Self, Self::Error> {
match val {
0 => Ok(MessageType::Call),
1 => Ok(MessageType::Return),
_ => Err(val)
}
}
}
struct Message<'a> {
typ: MessageType,
call_id: CallId,
proto: u16,
func: u16,
data: &'a [u8],
}
impl<'a> Message<'a> {
fn serialize(&self, buf: &mut Vec<u8>) {
buf.push(self.typ as u8);
buf.extend_from_slice(&self.call_id.0.to_ne_bytes());
buf.extend_from_slice(&self.proto.to_ne_bytes());
buf.extend_from_slice(&self.func.to_ne_bytes());
buf.extend_from_slice(self.data);
}
fn deserialize(buf: &'a [u8]) -> Self {
Self {
typ: MessageType::try_from(buf[0]).unwrap(),
call_id: CallId(u64::from_ne_bytes(buf[1..9].try_into().unwrap())),
proto: u16::from_ne_bytes(buf[9..11].try_into().unwrap()),
func: u16::from_ne_bytes(buf[11..13].try_into().unwrap()),
data: &buf[13..],
}
}
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn register_callback(proto: u16, callback: MessageCallback) {
CALLBACKS.write().unwrap().insert(proto, callback);
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn unregister_callback(proto: u16) {
CALLBACKS.write().unwrap().remove(&proto);
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn send_call(dst: u64, proto: u16, func: u16, data: &[u8]) -> CallId {
let call_id = CallId(NEXT_ID.fetch_add(1, Ordering::Relaxed));
let msg = Message {
typ: MessageType::Call,
call_id,
proto,
func,
data,
};
let mut buf = Vec::new();
msg.serialize(&mut buf);
super::send_msg(dst, 0, &buf);
call_id
}
#[stable(feature = "mikros", since = "1.80.0")]
pub fn msg_callback(msg: super::Message) {
let from = msg.from;
let msg = Message::deserialize(&msg.data);
match msg.typ {
MessageType::Call => {
if let Some(callback) = CALLBACKS.read().unwrap().get(&msg.proto) {
callback(IncomingCall {
from,
call_id: msg.call_id,
proto: msg.proto,
func: msg.func,
args: msg.data.into(),
});
}
}
MessageType::Return => {
RETURNS.lock().unwrap().insert(msg.call_id, msg.data.into());
}
}
}
pub(crate) fn init() {
super::register_callback(0, msg_callback);
}

View File

@ -0,0 +1,7 @@
//! Mikros-specific definitions
#![stable(feature = "mikros", since = "1.80.0")]
pub mod ipc;
pub mod address_space;

View File

@ -132,6 +132,8 @@ pub mod windows {}
pub mod l4re;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "mikros")]
pub mod mikros;
#[cfg(target_os = "netbsd")]
pub mod netbsd;
#[cfg(target_os = "nto")]

View File

@ -6,7 +6,7 @@
ptr::NonNull
};
use linked_list_allocator::hole::HoleList;
use super::address_space;
use crate::os::mikros::address_space;
struct Wrap(Mutex<HoleList>);

View File

@ -1,8 +1,11 @@
use crate::io as std_io;
use crate::os::mikros::ipc::rpc;
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
rpc::init();
}
// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.

View File

@ -2,9 +2,8 @@
#![allow(dead_code)]
#![allow(exported_private_dependencies)]
mod address_space;
mod syscalls;
mod buffers;
pub mod syscalls;
pub mod buffers;
pub mod alloc;
pub mod args;

View File

@ -8,10 +8,8 @@
use x86_64::structures::paging::{Page, PageTableFlags};
use crate::ptr;
use super::{
address_space::AddressSpace,
buffers::{IntoId, KernelBuffer, KernelBufferAllocator},
};
use super::buffers::{IntoId, KernelBuffer, KernelBufferAllocator};
use crate::os::mikros::address_space::AddressSpace;
pub(crate) fn print_char(chr: char) {
syscall1(0, chr as u64);