From ecb0142b6932b6e2c9eb77281ae1203d32548fc5 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Wed, 4 Sep 2024 11:06:21 +0800 Subject: [PATCH] feat: uapi/syscall: define reply convention --- uapi/src/error.rs | 1 + uapi/src/syscall.rs | 116 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/uapi/src/error.rs b/uapi/src/error.rs index 3ed3c5a..8b67e64 100644 --- a/uapi/src/error.rs +++ b/uapi/src/error.rs @@ -1,6 +1,7 @@ #[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] pub enum SysError { Ok, + Invalid, InvalidArgument, CapTypeMismatch, // Cap, Untyped SlotNotEmpty, // Untyped diff --git a/uapi/src/syscall.rs b/uapi/src/syscall.rs index e3d6599..ef677e9 100644 --- a/uapi/src/syscall.rs +++ b/uapi/src/syscall.rs @@ -15,6 +15,14 @@ pub enum Syscall { // Reply = 7, } +#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] +pub enum ReplyLabel { + Invalid = 0, + Message = 1, + Signal = 2, + Fault = 3, +} + /* Syscall convention: * > Call: * > > +----------+-------------------------+--------------------+ @@ -27,9 +35,16 @@ pub enum Syscall { * > > if info.transfer_cap { Arguments[-2] = cap_ptr; Arguments[-1] = n_bits; } * > * > Reply: - * > TODO: figure out how vanilla seL4 handle reply + * > > +----------+-------------------------+--------------+ + * > > | [a0] | REG_REPLY_INFO | ReplyInfo | + * > > | [a1] | REG_BADGE | Badge | + * > > | [a2..a7] | REG_ARG_0..=REG_ARG_MAX | Replied Data | + * > > | buffer | REG_ARG_MAX+1.. | Replied Data | + * > > +----------+-------------------------+--------------+ + * > > length = (a0..).length(), extra data are stored on ipc buffer */ +// Call pub const REG_MESSAGE_INFO: usize = 0; pub const REG_CAP_PTR: usize = 1; pub const REG_ARG_0: usize = 2; @@ -38,6 +53,10 @@ pub const REG_ARG_MAX: usize = 7; pub const LEN_ARG_OFFSET_CPTR: usize = 2; pub const LEN_ARG_OFFSET_BITS: usize = 1; +// Reply +pub const REG_REPLY_INFO: usize = 0; +pub const REG_BADGE: usize = 1; + /* MessageInfo layout: * > +---------+--------+--------+--------------+ * > | label | bits | length | transfer_cap | @@ -65,9 +84,9 @@ impl MessageInfo { const TRANSFER_CAP_OFFSET: usize = 0; pub fn new(label: Syscall, bits: usize, length: usize, transfer_cap: bool) -> Self { - let label = label.to_usize().unwrap_or(0); + let label = label.to_usize().unwrap(); let bits = bits - 1; // stored as n_bits - 1 - let transfer_cap = transfer_cap as usize; + let transfer_cap = if transfer_cap { 1 } else { 0 }; assert!(label <= Self::LABEL_MASK); assert!(bits <= Self::BITS_MASK); @@ -117,6 +136,95 @@ impl TryFrom for MessageInfo { fn try_from(value: usize) -> Result { let info = Self(value); - (info.label() != Syscall::Invalid).then_ok(info, SysError::InvalidArgument) + (info.label() != Syscall::Invalid).then_ok(info, SysError::Invalid) + } +} + +/* ReplyInfo layout: + * > +---------+--------+--------+------------+-------+ + * > | label | length | badged | transfered | error | + * > | [16:14] | [13:7] | [6] | [5] | [4:0] | + * > +---------+--------+--------+------------+-------+ + * > label: reply label + * > length: args.len() + * > badged: if badged + * > transfered: if cap is transfered + * > error: error code + */ +pub struct ReplyInfo(usize); + +impl ReplyInfo { + const LABEL_MASK: usize = MASK!(16 - 14 + 1); + const LABEL_OFFSET: usize = 14; + + const LENGTH_MASK: usize = MASK!(13 - 7 + 1); + const LENGTH_OFFSET: usize = 7; + + const BADGED_MASK: usize = MASK!(1); + const BADGED_OFFSET: usize = 6; + + const TRANSFERED_MASK: usize = MASK!(1); + const TRANSFERED_OFFSET: usize = 5; + + const ERROR_MASK: usize = MASK!(4 - 0 + 1); + const ERROR_OFFSET: usize = 0; + + pub fn new(label: ReplyLabel, length: usize, badged: bool, transfered: bool, error: SysError) -> Self { + let label = label.to_usize().unwrap(); + let badged = if badged { 1 } else { 0 }; + let transfered = if transfered { 1 } else { 0 }; + let error = error.to_usize().unwrap(); + + assert!(label <= Self::LABEL_MASK); + assert!(length <= Self::LENGTH_MASK); + assert!(error <= Self::ERROR_MASK); + + let info = ((label & Self::LABEL_MASK) << Self::LABEL_OFFSET) + | ((length & Self::LENGTH_MASK) << Self::LENGTH_OFFSET) + | ((badged & Self::BADGED_MASK) << Self::BADGED_OFFSET) + | ((transfered & Self::TRANSFERED_MASK) << Self::TRANSFERED_OFFSET) + | ((error & Self::ERROR_MASK) << Self::ERROR_OFFSET); + Self(info) + } + + pub fn label(&self) -> ReplyLabel { + ReplyLabel::from_usize((self.0 >> Self::LABEL_OFFSET) & Self::LABEL_MASK).unwrap_or(ReplyLabel::Invalid) + } + + pub fn length(&self) -> usize { + (self.0 >> Self::LENGTH_OFFSET) & Self::LENGTH_MASK + } + + pub fn badged(&self) -> bool { + (self.0 >> Self::BADGED_OFFSET) & Self::BADGED_MASK != 0 + } + + pub fn transfered(&self) -> bool { + (self.0 >> Self::TRANSFERED_OFFSET) & Self::TRANSFERED_MASK != 0 + } + + pub fn error(&self) -> SysError { + SysError::from_usize((self.0 >> Self::ERROR_OFFSET) & Self::ERROR_MASK).unwrap_or(SysError::Invalid) + } +} + +impl Debug for ReplyInfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ReplyInfo") + .field("label", &self.label()) + .field("length", &self.length()) + .field("badged", &self.badged()) + .field("transfered", &self.transfered()) + .field("error", &self.error()) + .finish() + } +} + +impl TryFrom for ReplyInfo { + type Error = SysError; + + fn try_from(value: usize) -> Result { + let info = Self(value); + (info.label() != ReplyLabel::Invalid).then_ok(info, SysError::Invalid) } }