twizzler_abi/
kso.rs

1//! Functions to deal with Kernel State Objects (KSOs). These are objects created by the kernel to
2//! describe the running state of the system and expose device memory to userspace.
3
4use core::fmt::Display;
5
6use twizzler_rt_abi::{
7    error::{ArgumentError, TwzError},
8    Result,
9};
10
11use crate::object::ObjID;
12
13/// Maximum name length for a KSO.
14pub const KSO_NAME_MAX_LEN: usize = 512;
15/// The base struct for any kernel state object.
16#[repr(C)]
17pub struct KsoHdr {
18    version: u32,
19    flags: u16,
20    name_len: u16,
21    name: [u8; KSO_NAME_MAX_LEN],
22}
23
24impl Display for KsoHdr {
25    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26        write!(
27            f,
28            "{}",
29            core::str::from_utf8(&self.name[0..self.name_len as usize])
30                .map_err(|_| core::fmt::Error)?
31        )
32    }
33}
34
35impl KsoHdr {
36    /// Construct a new kernel state object header.
37    pub fn new(name: &str) -> Self {
38        let b = name.as_bytes();
39        let mut ret = Self {
40            version: 0,
41            flags: 0,
42            name_len: b.len() as u16,
43            name: [0; KSO_NAME_MAX_LEN],
44        };
45        for (i, v) in b.iter().take(KSO_NAME_MAX_LEN).enumerate() {
46            ret.name[i] = *v;
47        }
48        ret
49    }
50}
51
52/// A value to pass for a KAction.
53#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
54#[repr(C)]
55pub enum KactionValue {
56    U64(u64),
57    ObjID(ObjID),
58}
59
60impl From<(u64, u64)> for KactionValue {
61    fn from(x: (u64, u64)) -> Self {
62        if x.0 == 0xFFFFFFFFFFFFFFFF {
63            Self::U64(x.1)
64        } else {
65            Self::ObjID(ObjID::from_parts([x.0, x.1]))
66        }
67    }
68}
69
70impl From<KactionValue> for (u64, u64) {
71    fn from(x: KactionValue) -> Self {
72        let parts = match x {
73            KactionValue::U64(x) => [0xffffffffffffffff, x],
74            KactionValue::ObjID(id) => id.parts(),
75        };
76        (parts[0], parts[1])
77    }
78}
79
80impl KactionValue {
81    /// If the value is an object ID, return it, otherwise panic.
82    pub fn unwrap_objid(self) -> ObjID {
83        match self {
84            KactionValue::U64(_) => panic!("failed to unwrap ObjID"),
85            KactionValue::ObjID(o) => o,
86        }
87    }
88
89    /// If the value is an object ID, return it, otherwise return None.
90    pub fn objid(self) -> Option<ObjID> {
91        match self {
92            KactionValue::U64(_) => None,
93            KactionValue::ObjID(o) => Some(o),
94        }
95    }
96
97    /// If the value is a u64, return it, otherwise panic.
98    pub fn unwrap_u64(self) -> u64 {
99        match self {
100            KactionValue::ObjID(_) => panic!("failed to unwrap ObjID"),
101            KactionValue::U64(o) => o,
102        }
103    }
104
105    /// If the value is a u64, return it, otherwise return None.
106    pub fn u64(self) -> Option<u64> {
107        match self {
108            KactionValue::U64(x) => Some(x),
109            KactionValue::ObjID(_) => None,
110        }
111    }
112}
113
114bitflags::bitflags! {
115    /// Possible flags for kaction.
116    pub struct KactionFlags: u64 {
117    }
118}
119
120/// A generic kaction command, applies to all KSOs.
121#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
122#[repr(C)]
123pub enum KactionGenericCmd {
124    /// Get the root of the KSO tree.
125    GetKsoRoot,
126    /// Get a child object.
127    GetChild(u16),
128    /// Get a sub-object.
129    GetSubObject(u8, u8),
130    /// Pin pages of object memory.
131    PinPages(u16),
132    /// Release Pin
133    ReleasePin,
134    /// Map Physical Pages
135    MapPhys(u16),
136}
137
138impl From<KactionGenericCmd> for u32 {
139    fn from(x: KactionGenericCmd) -> Self {
140        let (h, l) = match x {
141            KactionGenericCmd::GetKsoRoot => (0, 0),
142            KactionGenericCmd::GetChild(v) => (1, v),
143            KactionGenericCmd::GetSubObject(t, v) => (2, ((t as u16) << 8) | (v as u16)),
144            KactionGenericCmd::PinPages(v) => (3, v),
145            KactionGenericCmd::ReleasePin => (4, 0),
146            KactionGenericCmd::MapPhys(v) => (5, v),
147        };
148        ((h as u32) << 16) | l as u32
149    }
150}
151
152impl TryFrom<u32> for KactionGenericCmd {
153    type Error = TwzError;
154    fn try_from(x: u32) -> Result<KactionGenericCmd> {
155        let (h, l) = ((x >> 16) as u16, (x & 0xffff) as u16);
156        let v = match h {
157            0 => KactionGenericCmd::GetKsoRoot,
158            1 => KactionGenericCmd::GetChild(l),
159            2 => KactionGenericCmd::GetSubObject((l >> 8) as u8, l as u8),
160            3 => KactionGenericCmd::PinPages(l),
161            4 => KactionGenericCmd::ReleasePin,
162            5 => KactionGenericCmd::MapPhys(l),
163            _ => return Err(TwzError::INVALID_ARGUMENT),
164        };
165        Ok(v)
166    }
167}
168
169/// A KAction command, either generic or KSO-specific.
170#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
171#[repr(C)]
172pub enum KactionCmd {
173    Generic(KactionGenericCmd),
174    Specific(u32),
175}
176
177impl From<KactionCmd> for u64 {
178    fn from(x: KactionCmd) -> Self {
179        let (h, l) = match x {
180            KactionCmd::Generic(x) => (0, x.into()),
181            KactionCmd::Specific(x) => (1, x),
182        };
183        ((h as u64) << 32) | l as u64
184    }
185}
186
187impl TryFrom<u64> for KactionCmd {
188    type Error = TwzError;
189    fn try_from(x: u64) -> Result<KactionCmd> {
190        let (h, l) = ((x >> 32) as u32, (x & 0xffffffff) as u32);
191        let v = match h {
192            0 => KactionCmd::Generic(KactionGenericCmd::try_from(l)?),
193            1 => KactionCmd::Specific(l),
194            _ => return Err(ArgumentError::InvalidArgument.into()),
195        };
196        Ok(v)
197    }
198}
199
200const KACTION_PACK_MASK: u64 = 0xffffffff;
201const KACTION_PACK_BITS: u64 = 32;
202pub fn pack_kaction_pin_start_and_len(start: u64, len: usize) -> Option<u64> {
203    let len: u64 = len.try_into().ok()?;
204    if len > KACTION_PACK_MASK || start > KACTION_PACK_MASK {
205        return None;
206    }
207    Some(len << KACTION_PACK_BITS | start)
208}
209
210pub fn unpack_kaction_pin_start_and_len(val: u64) -> Option<(u64, usize)> {
211    Some((
212        val & KACTION_PACK_MASK,
213        (val >> KACTION_PACK_BITS).try_into().ok()?,
214    ))
215}
216
217pub fn pack_kaction_pin_token_and_len(token: u32, len: usize) -> Option<u64> {
218    let len: u64 = len.try_into().ok()?;
219    let token: u64 = token.into();
220    if len > KACTION_PACK_MASK {
221        return None;
222    }
223    Some(len << KACTION_PACK_BITS | token)
224}
225
226pub fn unpack_kaction_pin_token_and_len(val: u64) -> Option<(u32, usize)> {
227    Some((
228        (val & KACTION_PACK_MASK) as u32,
229        (val >> KACTION_PACK_BITS).try_into().ok()?,
230    ))
231}
232
233#[derive(Debug)]
234#[repr(u32)]
235pub enum InterruptPriority {
236    High,
237    Normal,
238    Low,
239}
240
241bitflags::bitflags! {
242    #[derive(Debug)]
243    pub struct InterruptAllocateOptions:u32 {
244        const UNIQUE = 0x1;
245    }
246}
247
248pub fn pack_kaction_int_pri_and_opts(
249    pri: InterruptPriority,
250    opts: InterruptAllocateOptions,
251) -> u64 {
252    ((pri as u64) << KACTION_PACK_BITS) | opts.bits() as u64
253}
254
255pub fn unpack_kaction_int_pri_and_opts(
256    val: u64,
257) -> Option<(InterruptPriority, InterruptAllocateOptions)> {
258    let pri = match val >> KACTION_PACK_BITS {
259        1 => InterruptPriority::Low,
260        2 => InterruptPriority::High,
261        _ => InterruptPriority::Normal,
262    };
263    let opts = InterruptAllocateOptions::from_bits(val as u32)?;
264    Some((pri, opts))
265}