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}