about summary refs log tree commit diff
path: root/library/std/src/sys/pal/xous/os/params.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/pal/xous/os/params.rs')
-rw-r--r--library/std/src/sys/pal/xous/os/params.rs271
1 files changed, 271 insertions, 0 deletions
diff --git a/library/std/src/sys/pal/xous/os/params.rs b/library/std/src/sys/pal/xous/os/params.rs
new file mode 100644
index 00000000000..0d02cf35477
--- /dev/null
+++ b/library/std/src/sys/pal/xous/os/params.rs
@@ -0,0 +1,271 @@
+/// Xous passes a pointer to the parameter block as the second argument.
+/// This is used for passing flags such as environment variables. The
+/// format of the argument block is:
+///
+/// #[repr(C)]
+/// struct BlockHeader {
+///     /// Magic number that identifies this block. Must be printable ASCII.
+///     magic: [u8; 4],
+///
+///     /// The size of the data block. Does not include this header. May be 0.
+///     size: u32,
+///
+///     /// The contents of this block. Varies depending on the block type.
+///     data: [u8; 0],
+/// }
+///
+/// There is a BlockHeader at the start that has magic `AppP`, and the data
+/// that follows is the number of blocks present:
+///
+/// #[repr(C)]
+/// struct ApplicationParameters {
+///     magic: b"AppP",
+///     size: 4u32,
+///
+///     /// The size of the entire application slice, in bytes, including all headers
+///     length: u32,
+///
+///     /// Number of application parameters present. Must be at least 1 (this block)
+///     entries: (parameter_count as u32).to_bytes_le(),
+/// }
+///
+/// #[repr(C)]
+/// struct EnvironmentBlock {
+///     magic: b"EnvB",
+///
+///     /// Total number of bytes, excluding this header
+///     size: 2+data.len(),
+///
+///     /// The number of environment variables
+///     count: u16,
+///
+///     /// Environment variable iteration
+///     data: [u8; 0],
+/// }
+///
+/// Environment variables are present in an `EnvB` block. The `data` section is
+/// a sequence of bytes of the form:
+///
+///      (u16 /* key_len */; [0u8; key_len as usize] /* key */,
+///       u16 /* val_len */ [0u8; val_len as usize])
+///
+/// #[repr(C)]
+/// struct ArgumentList {
+///     magic: b"ArgL",
+///
+///     /// Total number of bytes, excluding this header
+///     size: 2+data.len(),
+///
+///     /// The number of arguments variables
+///     count: u16,
+///
+///     /// Argument variable iteration
+///     data: [u8; 0],
+/// }
+///
+/// Args are just an array of strings that represent command line arguments.
+/// They are a sequence of the form:
+///
+///      (u16 /* val_len */ [0u8; val_len as usize])
+use core::slice;
+
+use crate::ffi::OsString;
+
+/// Magic number indicating we have an environment block
+const ENV_MAGIC: [u8; 4] = *b"EnvB";
+
+/// Command line arguments list
+const ARGS_MAGIC: [u8; 4] = *b"ArgL";
+
+/// Magic number indicating the loader has passed application parameters
+const PARAMS_MAGIC: [u8; 4] = *b"AppP";
+
+#[cfg(test)]
+mod tests;
+
+pub(crate) struct ApplicationParameters {
+    data: &'static [u8],
+    offset: usize,
+    _entries: usize,
+}
+
+impl ApplicationParameters {
+    pub(crate) unsafe fn new_from_ptr(data: *const u8) -> Option<ApplicationParameters> {
+        if data.is_null() {
+            return None;
+        }
+
+        let magic = unsafe { core::slice::from_raw_parts(data, 4) };
+        let block_length = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(4), 4).try_into().ok()?) as usize
+        };
+        let data_length = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(8), 4).try_into().ok()?) as usize
+        };
+        let entries = unsafe {
+            u32::from_le_bytes(slice::from_raw_parts(data.add(12), 4).try_into().ok()?) as usize
+        };
+
+        // Check for the main header
+        if data_length < 16 || magic != PARAMS_MAGIC || block_length != 8 {
+            return None;
+        }
+
+        let data = unsafe { slice::from_raw_parts(data, data_length) };
+
+        Some(ApplicationParameters { data, offset: 0, _entries: entries })
+    }
+}
+
+impl Iterator for ApplicationParameters {
+    type Item = ApplicationParameter;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // Fetch magic, ensuring we don't run off the end
+        if self.offset + 4 > self.data.len() {
+            return None;
+        }
+        let magic = &self.data[self.offset..self.offset + 4];
+        self.offset += 4;
+
+        // Fetch header size
+        if self.offset + 4 > self.data.len() {
+            return None;
+        }
+        let size = u32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap())
+            as usize;
+        self.offset += 4;
+
+        // Fetch data contents
+        if self.offset + size > self.data.len() {
+            return None;
+        }
+        let data = &self.data[self.offset..self.offset + size];
+        self.offset += size;
+
+        Some(ApplicationParameter { data, magic: magic.try_into().unwrap() })
+    }
+}
+
+pub(crate) struct ApplicationParameter {
+    data: &'static [u8],
+    magic: [u8; 4],
+}
+
+pub(crate) struct ApplicationParameterError;
+
+pub(crate) struct EnvironmentBlock {
+    _count: usize,
+    data: &'static [u8],
+    offset: usize,
+}
+
+impl TryFrom<&ApplicationParameter> for EnvironmentBlock {
+    type Error = ApplicationParameterError;
+
+    fn try_from(value: &ApplicationParameter) -> Result<Self, Self::Error> {
+        if value.data.len() < 2 || value.magic != ENV_MAGIC {
+            return Err(ApplicationParameterError);
+        }
+
+        let count = u16::from_le_bytes(value.data[0..2].try_into().unwrap()) as usize;
+
+        Ok(EnvironmentBlock { data: &value.data[2..], offset: 0, _count: count })
+    }
+}
+
+pub(crate) struct EnvironmentEntry {
+    pub key: &'static str,
+    pub value: &'static str,
+}
+
+impl Iterator for EnvironmentBlock {
+    type Item = EnvironmentEntry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let key_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + key_len > self.data.len() {
+            return None;
+        }
+        let key = core::str::from_utf8(&self.data[self.offset..self.offset + key_len]).ok()?;
+        self.offset += key_len;
+
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let value_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + value_len > self.data.len() {
+            return None;
+        }
+        let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?;
+        self.offset += value_len;
+
+        Some(EnvironmentEntry { key, value })
+    }
+}
+
+pub(crate) struct ArgumentList {
+    data: &'static [u8],
+    _count: usize,
+    offset: usize,
+}
+
+impl TryFrom<&ApplicationParameter> for ArgumentList {
+    type Error = ApplicationParameterError;
+
+    fn try_from(value: &ApplicationParameter) -> Result<Self, Self::Error> {
+        if value.data.len() < 2 || value.magic != ARGS_MAGIC {
+            return Err(ApplicationParameterError);
+        }
+        let count =
+            u16::from_le_bytes(value.data[0..2].try_into().or(Err(ApplicationParameterError))?)
+                as usize;
+        Ok(ArgumentList { data: &value.data[2..], _count: count, offset: 0 })
+    }
+}
+
+pub(crate) struct ArgumentEntry {
+    value: &'static str,
+}
+
+impl Into<&str> for ArgumentEntry {
+    fn into(self) -> &'static str {
+        self.value
+    }
+}
+
+impl Into<OsString> for ArgumentEntry {
+    fn into(self) -> OsString {
+        self.value.into()
+    }
+}
+
+impl Iterator for ArgumentList {
+    type Item = ArgumentEntry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.offset + 2 > self.data.len() {
+            return None;
+        }
+        let value_len =
+            u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().ok()?) as usize;
+        self.offset += 2;
+
+        if self.offset + value_len > self.data.len() {
+            return None;
+        }
+        let value = core::str::from_utf8(&self.data[self.offset..self.offset + value_len]).ok()?;
+        self.offset += value_len;
+
+        Some(ArgumentEntry { value })
+    }
+}