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}
135
136impl From<KactionGenericCmd> for u32 {
137    fn from(x: KactionGenericCmd) -> Self {
138        let (h, l) = match x {
139            KactionGenericCmd::GetKsoRoot => (0, 0),
140            KactionGenericCmd::GetChild(v) => (1, v),
141            KactionGenericCmd::GetSubObject(t, v) => (2, ((t as u16) << 8) | (v as u16)),
142            KactionGenericCmd::PinPages(v) => (3, v),
143            KactionGenericCmd::ReleasePin => (4, 0),
144        };
145        ((h as u32) << 16) | l as u32
146    }
147}
148
149impl TryFrom<u32> for KactionGenericCmd {
150    type Error = TwzError;
151    fn try_from(x: u32) -> Result<KactionGenericCmd> {
152        let (h, l) = ((x >> 16) as u16, (x & 0xffff) as u16);
153        let v = match h {
154            0 => KactionGenericCmd::GetKsoRoot,
155            1 => KactionGenericCmd::GetChild(l),
156            2 => KactionGenericCmd::GetSubObject((l >> 8) as u8, l as u8),
157            3 => KactionGenericCmd::PinPages(l),
158            4 => KactionGenericCmd::ReleasePin,
159            _ => return Err(ArgumentError::InvalidArgument.into()),
160        };
161        Ok(v)
162    }
163}
164
165/// A KAction command, either generic or KSO-specific.
166#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
167#[repr(C)]
168pub enum KactionCmd {
169    Generic(KactionGenericCmd),
170    Specific(u32),
171}
172
173impl From<KactionCmd> for u64 {
174    fn from(x: KactionCmd) -> Self {
175        let (h, l) = match x {
176            KactionCmd::Generic(x) => (0, x.into()),
177            KactionCmd::Specific(x) => (1, x),
178        };
179        ((h as u64) << 32) | l as u64
180    }
181}
182
183impl TryFrom<u64> for KactionCmd {
184    type Error = TwzError;
185    fn try_from(x: u64) -> Result<KactionCmd> {
186        let (h, l) = ((x >> 32) as u32, (x & 0xffffffff) as u32);
187        let v = match h {
188            0 => KactionCmd::Generic(KactionGenericCmd::try_from(l)?),
189            1 => KactionCmd::Specific(l),
190            _ => return Err(ArgumentError::InvalidArgument.into()),
191        };
192        Ok(v)
193    }
194}
195
196const KACTION_PACK_MASK: u64 = 0xffffffff;
197const KACTION_PACK_BITS: u64 = 32;
198pub fn pack_kaction_pin_start_and_len(start: u64, len: usize) -> Option<u64> {
199    let len: u64 = len.try_into().ok()?;
200    if len > KACTION_PACK_MASK || start > KACTION_PACK_MASK {
201        return None;
202    }
203    Some(len << KACTION_PACK_BITS | start)
204}
205
206pub fn unpack_kaction_pin_start_and_len(val: u64) -> Option<(u64, usize)> {
207    Some((
208        val & KACTION_PACK_MASK,
209        (val >> KACTION_PACK_BITS).try_into().ok()?,
210    ))
211}
212
213pub fn pack_kaction_pin_token_and_len(token: u32, len: usize) -> Option<u64> {
214    let len: u64 = len.try_into().ok()?;
215    let token: u64 = token.into();
216    if len > KACTION_PACK_MASK {
217        return None;
218    }
219    Some(len << KACTION_PACK_BITS | token)
220}
221
222pub fn unpack_kaction_pin_token_and_len(val: u64) -> Option<(u32, usize)> {
223    Some((
224        (val & KACTION_PACK_MASK) as u32,
225        (val >> KACTION_PACK_BITS).try_into().ok()?,
226    ))
227}
228
229#[derive(Debug)]
230#[repr(u32)]
231pub enum InterruptPriority {
232    High,
233    Normal,
234    Low,
235}
236
237bitflags::bitflags! {
238    #[derive(Debug)]
239    pub struct InterruptAllocateOptions:u32 {
240        const UNIQUE = 0x1;
241    }
242}
243
244pub fn pack_kaction_int_pri_and_opts(
245    pri: InterruptPriority,
246    opts: InterruptAllocateOptions,
247) -> u64 {
248    ((pri as u64) << KACTION_PACK_BITS) | opts.bits() as u64
249}
250
251pub fn unpack_kaction_int_pri_and_opts(
252    val: u64,
253) -> Option<(InterruptPriority, InterruptAllocateOptions)> {
254    let pri = match val >> KACTION_PACK_BITS {
255        1 => InterruptPriority::Low,
256        2 => InterruptPriority::High,
257        _ => InterruptPriority::Normal,
258    };
259    let opts = InterruptAllocateOptions::from_bits(val as u32)?;
260    Some((pri, opts))
261}