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}