Example yunq implementation for one Yellowstone endpoint.
This commit is contained in:
parent
51d40f6db6
commit
3eea4d811a
|
@ -52,6 +52,14 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "testbed"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mammoth",
|
||||
"yunq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yunq"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mammoth",
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[workspace]
|
||||
|
||||
members = [
|
||||
"lib/mammoth", "usr/testbed",
|
||||
"lib/mammoth", "lib/yunq", "usr/testbed",
|
||||
]
|
||||
|
||||
# the profile used for `cargo build`
|
||||
|
|
|
@ -15,7 +15,7 @@ const Z_INIT_ENDPOINT: u64 = 0x4100_0000;
|
|||
|
||||
static mut SELF_PROC_CAP: syscall::zcap = 0;
|
||||
static mut SELF_VMAS_CAP: syscall::zcap = 0;
|
||||
static mut INIT_ENDPOINT: syscall::zcap = 0;
|
||||
pub static mut INIT_ENDPOINT: syscall::zcap = 0;
|
||||
|
||||
pub fn parse_init_port(port_cap: syscall::zcap) {
|
||||
loop {
|
||||
|
|
|
@ -59,7 +59,18 @@ impl From<u64> for ZError {
|
|||
|
||||
impl fmt::Debug for ZError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("ZError")
|
||||
let str = match self {
|
||||
ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT",
|
||||
ZError::BUFFER_SIZE => "BUFFER_SIZE",
|
||||
ZError::INTERNAL => "INTERNAL",
|
||||
ZError::UNIMPLEMENTED => "UNIMPLEMENTED",
|
||||
ZError::INVALID_RESPONSE => "INVALID_RESPONSE",
|
||||
ZError::CAP_NOT_FOUND => "CAP_NOT_FOUND",
|
||||
ZError::CAP_WRONG_TYPE => "CAP_WRONG_TYPE",
|
||||
ZError::CAP_PERMISSION_DENIED => "CAP_PERMISSION_DENIED",
|
||||
_ => "ZError",
|
||||
};
|
||||
f.write_str(str)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "yunq"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
mammoth = {path = "../mammoth"}
|
|
@ -0,0 +1,60 @@
|
|||
use alloc::boxed::Box;
|
||||
use mammoth::syscall::ZError;
|
||||
|
||||
pub struct ByteBuffer<const N: usize> {
|
||||
buffer: Box<[u8; N]>,
|
||||
}
|
||||
|
||||
impl<const N: usize> ByteBuffer<N> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
buffer: Box::new([0; N]),
|
||||
}
|
||||
}
|
||||
pub fn size(&self) -> u64 {
|
||||
N as u64
|
||||
}
|
||||
|
||||
pub fn raw_ptr(&self) -> *const u8 {
|
||||
self.buffer.as_ptr()
|
||||
}
|
||||
|
||||
pub fn mut_ptr(&mut self) -> *mut u8 {
|
||||
self.buffer.as_mut_ptr()
|
||||
}
|
||||
|
||||
pub fn write_at<T>(&mut self, offset: usize, obj: T) -> Result<(), ZError> {
|
||||
if (size_of::<T>() + offset) > N {
|
||||
return Err(ZError::BUFFER_SIZE);
|
||||
}
|
||||
unsafe {
|
||||
*(self.buffer[offset..].as_mut_ptr() as *mut T) = obj;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_str_at(&mut self, offset: usize, s: &str) -> Result<(), ZError> {
|
||||
if (s.len() + offset) > N {
|
||||
return Err(ZError::BUFFER_SIZE);
|
||||
}
|
||||
for i in 0..s.len() {
|
||||
self.buffer[offset + i] = s.as_bytes()[i];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn at<T: Copy>(&self, offset: usize) -> Result<T, ZError> {
|
||||
if (size_of::<T>() + offset) > N {
|
||||
return Err(ZError::BUFFER_SIZE);
|
||||
}
|
||||
unsafe { Ok(*(self.buffer[offset..].as_ptr() as *const T)) }
|
||||
}
|
||||
|
||||
pub fn str_at(&self, offset: usize, len: usize) -> Result<&str, ZError> {
|
||||
if (len + offset) > N {
|
||||
return Err(ZError::BUFFER_SIZE);
|
||||
}
|
||||
Ok(alloc::str::from_utf8(&self.buffer[offset..offset + len])
|
||||
.map_err(|_| ZError::INVALID_ARGUMENT)?)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
use crate::buffer::ByteBuffer;
|
||||
use crate::message::YunqMessage;
|
||||
use alloc::vec::Vec;
|
||||
use core::ffi::c_void;
|
||||
use mammoth::syscall::z_cap_t;
|
||||
use mammoth::syscall::ZError;
|
||||
|
||||
const SENTINEL: u32 = 0xBEEFDEAD;
|
||||
|
||||
pub fn call_endpoint<Req: YunqMessage, Resp: YunqMessage, const N: usize>(
|
||||
req: &Req,
|
||||
byte_buffer: &mut ByteBuffer<N>,
|
||||
endpoint_cap: z_cap_t,
|
||||
) -> Result<Resp, ZError> {
|
||||
byte_buffer.write_at(0, SENTINEL)?;
|
||||
byte_buffer.write_at(8, 1 as u64)?;
|
||||
|
||||
let mut cap_buffer = Vec::new();
|
||||
|
||||
let length = req.serialize(byte_buffer, 16, &mut cap_buffer)?;
|
||||
|
||||
byte_buffer.write_at(4, (16 + length) as u32)?;
|
||||
|
||||
let mut reply_port_cap: u64 = 0;
|
||||
let send_req = mammoth::syscall::ZEndpointSendReq {
|
||||
caps: cap_buffer.as_ptr(),
|
||||
num_caps: cap_buffer.len() as u64,
|
||||
endpoint_cap,
|
||||
data: byte_buffer.raw_ptr() as *const c_void,
|
||||
num_bytes: 16 + length as u64,
|
||||
reply_port_cap: &mut reply_port_cap as *mut z_cap_t,
|
||||
};
|
||||
|
||||
mammoth::syscall::syscall(mammoth::syscall::kZionEndpointSend, &send_req)?;
|
||||
// FIXME: Add a way to zero out the byte buffer.
|
||||
|
||||
let mut buffer_size = byte_buffer.size();
|
||||
let mut num_caps: u64 = 10;
|
||||
cap_buffer = vec![0; num_caps as usize];
|
||||
let recv_req = mammoth::syscall::ZReplyPortRecvReq {
|
||||
reply_port_cap,
|
||||
caps: cap_buffer.as_mut_ptr(),
|
||||
num_caps: &mut num_caps as *mut u64,
|
||||
data: byte_buffer.mut_ptr() as *mut c_void,
|
||||
num_bytes: &mut buffer_size as *mut u64,
|
||||
};
|
||||
|
||||
mammoth::syscall::syscall(mammoth::syscall::kZionReplyPortRecv, &recv_req)?;
|
||||
|
||||
if byte_buffer.at::<u32>(0)? != SENTINEL {
|
||||
return Err(ZError::INVALID_RESPONSE);
|
||||
}
|
||||
|
||||
let resp_code: u64 = byte_buffer.at(8)?;
|
||||
if resp_code != 0 {
|
||||
return Err(ZError::from(resp_code));
|
||||
}
|
||||
|
||||
Ok(Resp::parse(&byte_buffer, 16, &cap_buffer)?)
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
mod buffer;
|
||||
mod client;
|
||||
mod message;
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
pub use buffer::ByteBuffer;
|
||||
use mammoth::syscall::z_cap_t;
|
||||
use mammoth::syscall::ZError;
|
||||
pub use message::YunqMessage;
|
||||
|
||||
const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64
|
||||
|
||||
pub struct GetEndpointRequest {
|
||||
pub endpoint_name: String,
|
||||
}
|
||||
|
||||
impl YunqMessage for GetEndpointRequest {
|
||||
fn serialize<const N: usize>(
|
||||
&self,
|
||||
buf: &mut buffer::ByteBuffer<N>,
|
||||
offset: usize,
|
||||
_caps: &mut Vec<z_cap_t>,
|
||||
) -> Result<usize, ZError> {
|
||||
let core_size: u32 = (MESSAGE_HEADER_SIZE + 8 * 1) as u32;
|
||||
let mut next_extension = core_size;
|
||||
|
||||
let endpoint_name_offset = next_extension;
|
||||
let endpoint_name_length = self.endpoint_name.len() as u32;
|
||||
|
||||
buf.write_str_at(offset + next_extension as usize, &self.endpoint_name)?;
|
||||
next_extension += endpoint_name_length;
|
||||
|
||||
buf.write_at(field_offset(offset, 0), endpoint_name_offset)?;
|
||||
buf.write_at(field_offset(offset, 0) + 4, endpoint_name_length)?;
|
||||
|
||||
buf.write_at(offset + 0, message::MESSAGE_IDENT)?;
|
||||
buf.write_at(offset + 4, core_size)?;
|
||||
buf.write_at(offset + 8, next_extension)?;
|
||||
buf.write_at(offset + 12, 0 as u32)?;
|
||||
Ok(next_extension as usize)
|
||||
}
|
||||
|
||||
fn parse<const N: usize>(
|
||||
_buf: &ByteBuffer<N>,
|
||||
_offset: usize,
|
||||
_caps: &Vec<z_cap_t>,
|
||||
) -> Result<Self, ZError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Endpoint {
|
||||
pub endpoint: z_cap_t,
|
||||
}
|
||||
|
||||
fn field_offset(offset: usize, field_index: usize) -> usize {
|
||||
offset + MESSAGE_HEADER_SIZE + (8 * field_index)
|
||||
}
|
||||
|
||||
impl YunqMessage for Endpoint {
|
||||
fn parse<const N: usize>(
|
||||
buf: &ByteBuffer<N>,
|
||||
offset: usize,
|
||||
caps: &Vec<z_cap_t>,
|
||||
) -> Result<Self, ZError> {
|
||||
if buf.at::<u32>(offset + 0)? != message::MESSAGE_IDENT {
|
||||
return Err(ZError::INVALID_ARGUMENT);
|
||||
}
|
||||
// TODO: Parse core size.
|
||||
// TODO: Parse extension size.
|
||||
// TODO: Check CRC32
|
||||
// TODO: Parse options.
|
||||
|
||||
let endpoint_ptr = buf.at::<u64>(field_offset(offset, 0))?;
|
||||
let endpoint = caps[endpoint_ptr as usize];
|
||||
Ok(Endpoint { endpoint })
|
||||
}
|
||||
|
||||
fn serialize<const N: usize>(
|
||||
&self,
|
||||
_buf: &mut buffer::ByteBuffer<N>,
|
||||
_offset: usize,
|
||||
_caps: &mut Vec<z_cap_t>,
|
||||
) -> Result<usize, ZError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct YellowstoneClient {
|
||||
endpoint_cap: z_cap_t,
|
||||
byte_buffer: ByteBuffer<0x1000>,
|
||||
}
|
||||
|
||||
impl YellowstoneClient {
|
||||
pub fn new(endpoint_cap: z_cap_t) -> Self {
|
||||
Self {
|
||||
endpoint_cap,
|
||||
byte_buffer: ByteBuffer::new(),
|
||||
}
|
||||
}
|
||||
pub fn get_endpoint(&mut self, req: &GetEndpointRequest) -> Result<Endpoint, ZError> {
|
||||
client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use crate::buffer::ByteBuffer;
|
||||
use alloc::vec::Vec;
|
||||
use mammoth::syscall::z_cap_t;
|
||||
use mammoth::syscall::ZError;
|
||||
|
||||
pub const MESSAGE_IDENT: u32 = 0x33441122;
|
||||
|
||||
pub trait YunqMessage {
|
||||
fn parse<const N: usize>(
|
||||
buf: &ByteBuffer<N>,
|
||||
offset: usize,
|
||||
caps: &Vec<z_cap_t>,
|
||||
) -> Result<Self, ZError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn serialize<const N: usize>(
|
||||
&self,
|
||||
buf: &mut ByteBuffer<N>,
|
||||
offset: usize,
|
||||
caps: &mut Vec<z_cap_t>,
|
||||
) -> Result<usize, ZError>;
|
||||
}
|
|
@ -5,3 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
mammoth = { path = "../../lib/mammoth" }
|
||||
yunq = { path = "../../lib/yunq" }
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use mammoth::debug;
|
||||
use mammoth::define_entry;
|
||||
use mammoth::syscall::debug;
|
||||
|
@ -25,5 +26,19 @@ pub extern "C" fn main() -> z_err_t {
|
|||
};
|
||||
mammoth::syscall::syscall(mammoth::syscall::kZionMemoryObjectCreate, &obj_req)
|
||||
.expect("Failed to create memory object");
|
||||
|
||||
let mut yellowstone;
|
||||
unsafe {
|
||||
yellowstone = yunq::YellowstoneClient::new(mammoth::INIT_ENDPOINT);
|
||||
}
|
||||
|
||||
let endpoint = yellowstone
|
||||
.get_endpoint(&yunq::GetEndpointRequest {
|
||||
endpoint_name: "denali".to_string(),
|
||||
})
|
||||
.expect("Failed to get endpoint");
|
||||
|
||||
debug!("Got endpoint w/ cap: {:#x}", endpoint.endpoint);
|
||||
|
||||
0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue