Skip to main content

proka_exec/
header.rs

1//! The header definitions.
2use bitflags::bitflags;
3use bytemuck::{Pod, Zeroable, bytes_of};
4use crate::{Error, HEADER_SIZE, Result, VERSION_CURRENT, VERSION_MINIMAL};
5
6/// The magic number, fixed to 'PKEX'
7pub const PKEX_MAGIC: u32 = 0x58454B50;
8
9/// Error types in header.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum HeaderError {
12    /// Magic number error.
13    ///
14    /// Contains the incorrect magic number.
15    MagicNumberError(u32),
16}
17
18/// The main header struct, which contains the metadata of the PKE file.
19#[repr(C)]
20#[derive(Debug, Clone, Copy, Pod, Zeroable)]
21pub struct Header {
22    /// The magic number, fixed to 'PKEX'
23    pub magic: u32,
24
25    /// Format version used to generate this PKEX binary.
26    ///
27    /// Represents the PKEX file specification revision that the builder followed
28    /// when creating this executable. This is separate from `version_minimum`.
29    ///
30    /// - Breaking binary layout changes: increment this value, set `version_minimum` equal to it.
31    /// - Backward-compatible extensions (only using reserved space): increment this value,
32    ///   leave `version_minimum` unchanged.
33    pub version_current: u32,
34
35    /// Lowest PKEX format version that can parse this binary correctly.
36    ///
37    /// Loader enforcement rule: If the maximum format version supported by the loader
38    /// is less than this value, the loader **MUST reject loading this executable**.
39    pub version_minimal: u32,
40
41    /// Padding field #1.
42    _pad1: [u8; 4],
43
44    /// The minimal kernel version supported.
45    ///
46    /// # Note
47    /// As the `proka-bootloader`'s definitions, its format is similar
48    /// like `[major, minor, fix]`. See [`proka-bootloader`](https://docs.rs/proka-bootloader) crate for more informations.
49    pub min: [u16; 3],
50
51    /// Padding field #2.
52    _pad2: [u8; 2],
53
54    /// The maximum kernel supported.
55    ///
56    /// For notes, see above.
57    pub max: [u16; 3],
58
59    /// Padding field #3.
60    _pad3: [u8; 2],
61
62    /// Signifies is this executable run as `userapp` or `coredrv`.
63    pub mode: ExecMode,
64
65    /// Padding field #4.
66    _pad4: [u8; 3],
67
68    /// The section table count.
69    pub sections: u16,
70
71    /// The section which contains the entry point.
72    pub entry_sec: u16,
73
74    /// The entry offset of the section.
75    pub entry_off: u32,
76
77    /// The author name (max length is 32 bytes).
78    pub author: [u8; 32],
79
80    /// The executable/project name.
81    pub name: [u8; 32],
82
83    /// Reserved fields
84    pub _reserved: [u8; 20],
85}
86
87impl Default for Header {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl Header {
94    /// Create a header object.
95    pub fn new() -> Self {
96        Self {
97            magic: PKEX_MAGIC,
98            version_current: VERSION_CURRENT,
99            version_minimal: VERSION_MINIMAL,
100            _pad1: [0; 4],
101            min: [0; 3],
102            _pad2: [0; 2],
103            max: [0; 3],
104            _pad3: [0; 2],
105            mode: ExecMode::UserApp,
106            _pad4: [0; 3],
107            sections: 0,
108            entry_sec: 0,
109            entry_off: HEADER_SIZE as u32,
110            author: [0; 32],
111            name: [0; 32],
112            _reserved: [0; 20],
113        }
114    }
115
116    /// Validate is this a valid proka executable.
117    #[inline]
118    pub fn validate(&self) -> Result<()> {
119        if self.magic != PKEX_MAGIC {
120            return Err(Error::HeaderError(HeaderError::MagicNumberError(
121                self.magic,
122            )));
123        }
124        Ok(())
125    }
126
127    /// Convert this header to array
128    #[inline]
129    pub fn to_array(&self) -> [u8; HEADER_SIZE] {
130        let mut arr = [0u8; HEADER_SIZE];
131        arr.copy_from_slice(bytes_of(self));
132        arr
133    }
134}
135
136bitflags! {
137    /// The executable mode.
138    #[repr(transparent)]
139    #[derive(Debug, Clone, Copy, PartialEq, Eq, Pod, Zeroable)]
140    pub struct ExecMode: u8 {
141        /// Run in `userapp` mode (Ring 3).
142        const UserApp = 0x00;
143
144        /// Run in `coredrv` mode (Ring 0).
145        const CoreDrv = 0x01;
146    }
147}
148
149// Tests
150#[cfg(test)]
151mod tests {
152    use super::*;
153
154    #[test]
155    fn test_header_length() {
156        assert_eq!(crate::HEADER_SIZE, 128);
157        assert_eq!(core::mem::size_of::<Header>(), 128)
158    }
159}