Skip to main content

proka_exec/
header.rs

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