amebazii/types/
header.rs

1use std::io;
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4
5use crate::{
6    error::Error, is_valid_data, read_padding, read_valid_data, util::write_fill, write_data,
7    write_padding,
8};
9
10use super::{
11    enums::{ImageType, SectionType, XipPageRemapSize},
12    BinarySize, DataRefType, DataType, FromStream, ToStream,
13};
14
15/// A struct representing the key block with two public keys:
16/// * an encryption public key and
17/// * a hash public key.
18#[derive(Debug)]
19pub struct KeyBlock {
20    enc_pubkey: [u8; 32],  // Encryption public key (32 bytes)
21    hash_pubkey: [u8; 32], // Hash public key (32 bytes)
22}
23
24impl Default for KeyBlock {
25    /// Creates a default `KeyBlock` with both public keys initialized to `[0xFF; 32]`.
26    ///
27    /// # Returns
28    /// - A `KeyBlock` instance with both the encryption and hash public keys set to `0xFF`.
29    fn default() -> Self {
30        KeyBlock {
31            enc_pubkey: [0xFF; 32],
32            hash_pubkey: [0xFF; 32],
33        }
34    }
35}
36
37impl BinarySize for KeyBlock {
38    /// Returns the binary size of the `KeyBlock` in bytes.
39    ///
40    /// Since the struct contains two 32-byte fields (`enc_pubkey` and `hash_pubkey`), the total size is 64 bytes.
41    ///
42    /// # Returns
43    /// - `64`: The size in bytes required to serialize a `KeyBlock`.
44    fn binary_size() -> usize {
45        64
46    }
47}
48
49impl FromStream for KeyBlock {
50    /// Deserializes a `KeyBlock` from a stream.
51    ///
52    /// This method reads 64 bytes (32 bytes for each of the `enc_pubkey` and `hash_pubkey`) from the provided
53    /// reader and populates the `KeyBlock` instance fields accordingly.
54    ///
55    /// # Parameters
56    /// - `reader`: A mutable reference to a reader implementing `io::Read` and `io::Seek`.
57    ///
58    /// # Returns
59    /// - `Ok(())`: If the `KeyBlock` was successfully deserialized.
60    /// - `Err(Error)`: If an error occurs while reading from the stream.
61    fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
62    where
63        R: std::io::Read + std::io::Seek,
64    {
65        reader.read_exact(&mut self.enc_pubkey)?;
66        reader.read_exact(&mut self.hash_pubkey)?;
67        Ok(())
68    }
69}
70
71impl ToStream for KeyBlock {
72    /// Serializes a `KeyBlock` to a stream.
73    ///
74    /// # Parameters
75    /// - `writer`: A mutable reference to a writer implementing `io::Write` and `io::Seek`.
76    ///
77    /// # Returns
78    /// - `Ok(())`: If the `KeyBlock` was successfully written to the stream.
79    /// - `Err(Error)`: If an error occurs while writing to the stream.
80    fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
81    where
82        W: std::io::Write + std::io::Seek,
83    {
84        writer.write_all(&self.enc_pubkey)?;
85        writer.write_all(&self.hash_pubkey)?;
86        Ok(())
87    }
88}
89
90impl KeyBlock {
91    /// Checks if the encryption public key is valid.
92    ///
93    /// # Returns
94    /// - `true` if the encryption public key is valid.
95    /// - `false` if the encryption public key is invalid.
96    pub fn is_enc_pubkey_valid(&self) -> bool {
97        is_valid_data!(&self.enc_pubkey)
98    }
99
100    /// Checks if the hash public key is valid.
101    ///
102    /// # Returns
103    /// - `true` if the hash public key is valid.
104    /// - `false` if the hash public key is invalid.
105    pub fn is_hash_pubkey_valid(&self) -> bool {
106        is_valid_data!(&self.hash_pubkey)
107    }
108
109    /// Retrieves the encryption public key.
110    ///
111    /// # Returns
112    /// - A reference to the encryption public key (32 bytes).
113    pub fn get_enc_pubkey(&self) -> &[u8; 32] {
114        &self.enc_pubkey
115    }
116
117    /// Retrieves the hash public key.
118    ///
119    /// # Returns
120    /// - A reference to the hash public key (32 bytes).
121    pub fn get_hash_pubkey(&self) -> &[u8; 32] {
122        &self.hash_pubkey
123    }
124
125    /// Retrieves a mutable reference to the encryption public key.
126    ///
127    /// # Returns
128    /// - A mutable reference to the encryption public key (32 bytes).
129    pub fn get_enc_pubkey_mut(&mut self) -> &mut [u8; 32] {
130        &mut self.enc_pubkey
131    }
132
133    /// Retrieves a mutable reference to the hash public key.
134    ///
135    /// # Returns
136    /// - A mutable reference to the hash public key (32 bytes).
137    pub fn get_hash_pubkey_mut(&mut self) -> &mut [u8; 32] {
138        &mut self.hash_pubkey
139    }
140}
141
142// --- Generic Header ---
143// According to _create_img_header
144//          +---+---+---+---+----+----+----+---+----------+----------------+--------------+---------------+----+----+----+----+
145//          | 0 | 1 | 2 | 3 | 4  | 5  | 6  | 7 | 8        | 9              | 10           | 11            | 12 | 13 | 14 | 15 |
146// +========+===+===+===+===+====+====+====+===+==========+================+==============+===============+====+====+====+====+
147// | 0x00   |  length: u32  | next_offset: u32 | type: u8 | is_encrypt: u8 | pkey_idx: u8 | key_valid: u8 |                   |
148// +--------+---------------+------------------+----------+----------------+--------------+---------------+-------------------+
149// | 0x10   |               |   serial: u32    |                                                                              |
150// +--------+---------------+------------------+------------------------------------------------------------------------------+
151// | 0x20   |                                                 key1: bytes[32]                                                 |
152// +--------+-----------------------------------------------------------------------------------------------------------------+
153// | 0x40   |                                                 key2: bytes[32]                                                 |
154// +--------+-----------------------------------------------------------------------------------------------------------------+
155// size: 0x60 = 96 bytes
156
157/// Generic image header.
158///
159/// This struct contains metadata for an image, such as the segment size, offset to the next image header,
160/// the image type, encryption flag, and user keys.
161#[derive(Debug)]
162pub struct ImageHeader {
163    /// The size of the image segment in bytes.
164    ///
165    /// This field specifies the size of the image's data segment, which can be used to determine how much
166    /// data is associated with the current image header.
167    pub segment_size: u32,
168
169    /// Offset to the next image header.
170    ///
171    /// If there is no next image header, this field is set to `None`. Otherwise, it holds the
172    /// byte offset to the next image header.
173    pub next_offset: Option<u32>,
174
175    /// The type of the image.
176    ///
177    /// This field stores the image type, which can represent different image types such as boot images,
178    /// partition tables, etc.
179    pub img_type: ImageType,
180
181    /// Flag indicating whether the image is encrypted.
182    ///
183    /// This boolean flag indicates whether the image is encrypted (`true`) or not (`false`).
184    pub is_encrypt: bool,
185
186    /// The serial number associated with the image. (version number)
187    ///
188    /// This field stores the image's serial number. It is initialized to `0xFFFF_FFFF` by default.
189    pub serial: u32,
190
191    /// User key 1, used for encryption
192    pub user_key1: DataType<32>,
193
194    /// User key 2, used for encryption
195    pub user_key2: DataType<32>,
196}
197
198impl Default for ImageHeader {
199    /// Creates a default `ImageHeader` instance with the following default values:
200    /// - `segment_size`: `0` (default size is zero)
201    /// - `next_offset`: `0xFFFF_FFFF` (indicating no next header) == None
202    /// - `img_type`: `ImageType::Parttab` (default is partition table)
203    /// - `is_encrypt`: `false` (default is no encryption)
204    /// - `serial`: `0xFFFF_FFFF` (default invalid serial number)
205    /// - `user_key1`: `[0xFF; 32]` (default invalid key)
206    /// - `user_key2`: `[0xFF; 32]` (default invalid key)
207    ///
208    /// # Returns
209    /// - A new `ImageHeader` with the default values.
210    fn default() -> Self {
211        ImageHeader {
212            segment_size: 0,
213            next_offset: None,            // invalid by default
214            img_type: ImageType::Parttab, // partition table by default
215            is_encrypt: false,
216            serial: 0xFFFF_FFFF,
217            user_key1: None, // invalid by default
218            user_key2: None,
219        }
220    }
221}
222
223impl BinarySize for ImageHeader {
224    /// Returns the binary size of the `ImageHeader` in bytes.
225    #[inline]
226    fn binary_size() -> usize {
227        0x60 // 96 bytes total size
228    }
229}
230
231impl FromStream for ImageHeader {
232    /// Reads an `ImageHeader` from a stream, populating its fields.
233    ///
234    /// # Parameters
235    /// - `reader`: A mutable reference to a reader that implements both `io::Read` and `io::Seek`. This is used
236    ///   to read the raw byte data representing the `ImageHeader`.
237    ///
238    /// # Returns
239    /// - `Ok(())`: If the header is successfully read from the stream and all fields are populated.
240    /// - `Err(Error)`: If any errors occur while reading the data from the stream.
241    fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
242    where
243        R: std::io::Read + std::io::Seek,
244    {
245        self.segment_size = reader.read_u32::<LittleEndian>()?;
246
247        let offset = reader.read_u32::<LittleEndian>()?;
248        self.next_offset = if offset != 0xFFFF_FFFF {
249            Some(offset)
250        } else {
251            None
252        };
253
254        self.img_type = ImageType::try_from(reader.read_u8()?)?;
255        self.is_encrypt = reader.read_u8()? != 0;
256
257        // Skip the next byte (reserved - seems to be pkey_index)
258        read_padding!(reader, 1);
259
260        // REVIIST: unused
261        let _flags = reader.read_u8()?;
262
263        read_padding!(reader, 8);
264        self.serial = reader.read_u32::<LittleEndian>()?;
265        read_padding!(reader, 8);
266
267        read_valid_data!(self.user_key1, 32, reader);
268        read_valid_data!(self.user_key2, 32, reader);
269        Ok(())
270    }
271}
272
273impl ToStream for ImageHeader {
274    /// Serializes the `ImageHeader` struct to a stream.
275    ///
276    /// # Parameters
277    /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
278    ///   be written to this stream.
279    ///
280    /// # Returns
281    /// - `Ok(())`: If the data is written successfully.
282    /// - `Err(Error)`: If there is an issue writing the data to the stream.
283    fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
284    where
285        W: std::io::Write,
286    {
287        writer.write_u32::<LittleEndian>(self.segment_size)?;
288        writer.write_u32::<LittleEndian>(self.next_offset.unwrap_or(0xFFFF_FFFF))?;
289        writer.write_u8(self.img_type as u8)?;
290        writer.write_u8(self.is_encrypt as u8)?;
291        writer.write_u8(0x00)?;
292
293        // Write the key validity flags (1 byte), combining key1_valid and key2_valid
294        let key1_valid = self.is_key1_valid();
295        let key2_valid = self.is_key2_valid();
296        writer.write_u8((key1_valid as u8) | ((key2_valid as u8) << 1))?;
297
298        write_padding!(writer, 8);
299        writer.write_u32::<LittleEndian>(self.serial)?;
300        write_padding!(writer, 8);
301
302        // If key1 is valid, write user_key1 (32 bytes), otherwise write padding
303        write_data!(writer, self.user_key1, 32);
304        write_data!(writer, self.user_key2, 32);
305        Ok(())
306    }
307}
308
309impl ImageHeader {
310    // ------------------------------------------------------------------------------------
311    // instance methods
312    // ------------------------------------------------------------------------------------
313
314    /// Checks if the first user key (`user_key1`) is valid.
315    ///
316    /// # Returns
317    /// - `true` if `user_key1` is valid (i.e., not all bytes are `0xFF`).
318    /// - `false` if `user_key1` is invalid (i.e., all bytes are `0xFF`).
319    pub fn is_key1_valid(&self) -> bool {
320        match &self.user_key1 {
321            None => false,
322            Some(key) => key.iter().any(|&byte| byte != 0xFF),
323        }
324    }
325
326    /// Checks if the second user key (`user_key2`) is valid.
327    ///
328    /// # Returns
329    /// - `true` if `user_key2` is valid (i.e., not all bytes are `0xFF`).
330    /// - `false` if `user_key2` is invalid (i.e., all bytes are `0xFF`).
331    pub fn is_key2_valid(&self) -> bool {
332        match &self.user_key2 {
333            None => false,
334            Some(key) => key.iter().any(|&byte| byte != 0xFF),
335        }
336    }
337
338    /// Checks if there is a next image header.
339    ///
340    /// The `next_offset` field indicates the offset to the next image header. If the value
341    /// is `0xFFFF_FFFF`, it means there is no next image. This method returns `true` if the
342    /// `next_offset` is not `0xFFFF_FFFF`, indicating there is a next image header.
343    ///
344    /// # Returns
345    /// - `true` if there is a next image (i.e., `next_offset` is not `0xFFFF_FFFF`).
346    /// - `false` if there is no next image (i.e., `next_offset` is `0xFFFF_FFFF`).
347    pub fn has_next(&self) -> bool {
348        self.next_offset.is_some()
349    }
350
351    /// Gets the first user key (`user_key1`).
352    ///
353    /// # Returns
354    /// A reference to the `user_key1` array (32 bytes).
355    pub fn get_user_key1(&self) -> DataRefType<'_, 32> {
356        self.user_key1.as_ref()
357    }
358
359    /// Gets the second user key (`user_key2`).
360    ///
361    /// # Returns
362    /// A reference to the `user_key2` array (32 bytes).
363    pub fn get_user_key2(&self) -> DataRefType<'_, 32> {
364        self.user_key2.as_ref()
365    }
366
367    /// Sets the first user key (`user_key1`) in the image header.
368    ///
369    /// # Arguments
370    ///
371    /// * `key` - A `DataType<32>` representing the new value for `user_key1`.
372    pub fn set_user_key1(&mut self, key: DataType<32>) {
373        self.user_key1 = key;
374    }
375
376    /// Sets the second user key (`user_key2`) in the image header.
377    ///
378    /// # Arguments
379    ///
380    /// * `key` - A `DataType<32>` representing the new value for `user_key2`.
381    pub fn set_user_key2(&mut self, key: DataType<32>) {
382        self.user_key2 = key;
383    }
384}
385
386// --- Sub-Image Header ---
387// Layout
388//          +---+---+---+---+----+----+----+---+----------------------+-----------------+-----------------+------------------+----+----+----+----+
389//          | 0 | 1 | 2 | 3 | 4  | 5  | 6  | 7 | 8                    | 9               | 10              | 11               | 12 | 13 | 14 | 15 |
390// +========+===+===+===+===+====+====+====+===+======================+=================+=================+==================+====+====+====+====+
391// | 0x00   |  length: u32  | next_offset: u32 |     sec_type: u8     | sce_enabled: u8 | xip_pg_size: u8 | xip_sec_size: u8 |                   |
392// +--------+---------------+------------------+----------------------+-----------------+-----------------+------------------+-------------------+
393// | 0x10   |        validpat: bytes[8]        | xip_key_iv_valid: u8 |                                                                          |
394// +--------+----------------------------------+----------------------+--------------------------------------------------------------------------+
395// | 0x20   |                                                         xip_key: bytes[16]                                                         |
396// +--------+------------------------------------------------------------------------------------------------------------------------------------+
397// | 0x30   |                                                         xip_iv: bytes[16]                                                          |
398// +--------+------------------------------------------------------------------------------------------------------------------------------------+
399// | 0x40   |                                                        alignment: bytes[32]                                                        |
400// +--------+------------------------------------------------------------------------------------------------------------------------------------+
401// size: 0x60 = 96 bytes
402
403/// Represents the header of a section in a binary image.
404///
405/// The `SectionHeader` struct contains information about the section's length, type,
406/// offset to the next section, as well as details about encryption, remapping, and
407/// validation. The struct is designed to handle sections in a memory or file layout
408/// where the sections could represent different types of data, such as executable code
409/// (XIP), memory regions (DTCM, ITCM), and more. Fields like `xip_page_size`, `xip_key`,
410/// and `xip_iv` are especially relevant when dealing with Execute-In-Place (XIP) sections.
411#[derive(Debug)]
412pub struct SectionHeader {
413    /// The length of the section in bytes.
414    ///
415    /// This field stores the total size of the section, which may include data and metadata.
416    /// The exact meaning and content depend on the section type (`sect_type`).
417    pub length: u32,
418
419    /// Offset to the next section.
420    ///
421    /// This field indicates the position of the next section in memory. A value of `0xFFFF_FFFF`
422    /// indicates that this is the last section, and no further sections exist.
423    pub next_offset: Option<u32>,
424
425    /// The type of the current section.
426    pub sect_type: SectionType,
427
428    /// Indicates whether Secure Copy Engine (SCE) is enabled for this section.
429    pub sce_enabled: bool,
430
431    /// XIP (Execute-In-Place) page size and remapping setting.
432    ///
433    /// This field indicates the page size used for remapping during XIP operations. The value is an
434    /// integer representing one of three possible values: 0 (16K), 1 (32K), and 2 (64K).
435    pub xip_page_size: XipPageRemapSize,
436
437    /// Block size for XIP remapping.
438    ///
439    /// This field defines the block size used for XIP remapping, typically represented in bytes.
440    /// The default value is `0`, which means that remapping block size is not defined.
441    pub xip_block_size: u8,
442
443    /// A valid pattern used to verify the integrity of the section header.
444    valid_pattern: [u8; 8],
445
446    /// The encryption key used for XIP operations.
447    ///
448    /// This is a 16-byte key used during the XIP process. If encryption is enabled for the section,
449    /// this key is used for decryption. The default value is an array of `0xFF` bytes, indicating an
450    /// invalid key by default.
451    xip_key: DataType<16>,
452
453    /// The initialization vector (IV) used for XIP encryption.
454    ///
455    /// This is a 16-byte initialization vector (IV) used in conjunction with the `xip_key` during XIP
456    /// encryption operations. As with the key, it is initialized to an invalid value of `0xFF` bytes.
457    xip_iv: DataType<16>,
458}
459
460impl BinarySize for SectionHeader {
461    /// Returns the binary size (in bytes) of the `SectionHeader` struct.
462    ///
463    /// # Returns
464    /// Returns the binary size as a constant `usize` value, which is `0x60` (96 bytes).
465    #[inline]
466    fn binary_size() -> usize {
467        return 0x60;
468    }
469}
470
471impl Default for SectionHeader {
472    /// Returns the default `SectionHeader` instance with predefined values.
473    ///
474    /// - `length` set to `0`, representing an empty section.
475    /// - `next_offset` set to `0xFFFF_FFFF`, which indicates the absence of a next section.
476    /// - `sect_type` set to `SectionType::XIP`, as a default section type.
477    /// - `sce_enabled` set to `false` (assuming encryption is not enabled by default).
478    /// - `xip_page_size` set to `XipPageRemapSize::_16K`, the smallest page size for XIP remapping.
479    /// - `xip_block_size` set to `0`, indicating no block size set.
480    /// - `valid_pattern` set to a default validation pattern of increasing values.
481    /// - `xip_key` and `xip_iv` both set to `0xFF`, representing uninitialized keys/IV.
482    ///
483    /// # Returns
484    /// Returns a `SectionHeader` with the default values.
485    fn default() -> SectionHeader {
486        return SectionHeader {
487            length: 0,
488            next_offset: None, // make last as default
489            sect_type: SectionType::XIP,
490            sce_enabled: false, // encrypted currently not supported
491            xip_page_size: XipPageRemapSize::_16K,
492            xip_block_size: 0,
493            valid_pattern: [0, 1, 2, 3, 4, 5, 6, 7],
494            xip_key: None,
495            xip_iv: None,
496        };
497    }
498}
499
500impl FromStream for SectionHeader {
501    /// Reads the `SectionHeader` struct from a stream.
502    ///
503    /// # Error Handling
504    /// This method may return an error if there is an issue with reading from the stream or if
505    /// an invalid value is encountered during deserialization (e.g., an invalid enum value for `sect_type`
506    /// or `xip_page_size`). Any errors encountered during reading from the stream will be propagated as an `Error`.
507    ///
508    /// # Returns
509    /// - `Ok(())` if the `SectionHeader` was successfully read from the stream.
510    /// - `Err(Error)` if there was an issue reading from the stream or an invalid value was encountered.
511    ///
512    /// # Panics
513    /// This function assumes that the binary data is well-formed and follows the expected format. If
514    /// the format is incorrect or the stream is malformed, this function will return an error instead of
515    /// panicking. However, it is still important to handle errors appropriately in calling code.
516    fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
517    where
518        R: std::io::Read + std::io::Seek,
519    {
520        self.length = reader.read_u32::<LittleEndian>()?;
521        self.next_offset = match reader.read_u32::<LittleEndian>()? {
522            0xFFFF_FFFF => None,
523            offset => Some(offset),
524        };
525        self.sect_type = SectionType::try_from(reader.read_u8()?)?;
526        self.sce_enabled = reader.read_u8()? != 0;
527        self.xip_page_size = XipPageRemapSize::try_from(reader.read_u8()?)?;
528        self.xip_block_size = reader.read_u8()?;
529
530        read_padding!(reader, 4);
531        reader.read_exact(&mut self.valid_pattern)?;
532
533        let sce_key_iv_valid = reader.read_u8()? & 0b01 == 1;
534        read_padding!(reader, 7);
535
536        if sce_key_iv_valid {
537            read_valid_data!(self.xip_key, 16, reader);
538            read_valid_data!(self.xip_iv, 16, reader);
539            // Align to 96 bytes (by skipping 32 bytes)
540            read_padding!(reader, 32);
541        } else {
542            self.xip_key = None;
543            self.xip_iv = None;
544            // Align to 96 bytes by skipping 64 bytes if no key/IV is present
545            read_padding!(reader, 64);
546        }
547        Ok(())
548    }
549}
550
551impl ToStream for SectionHeader {
552    /// Serializes the `SectionHeader` struct to a stream.
553    ///
554    /// # Parameters
555    /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
556    ///   be written to this stream.
557    ///
558    /// # Returns
559    /// - `Ok(())`: If the data is written successfully.
560    /// - `Err(Error)`: If there is an issue writing the data to the stream.
561    fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
562    where
563        W: io::Write + io::Seek,
564    {
565        writer.write_u32::<LittleEndian>(self.length)?;
566        writer.write_u32::<LittleEndian>(self.next_offset.unwrap_or(0xFFFF_FFFF))?;
567        writer.write_u8(self.sect_type as u8)?;
568        writer.write_u8(self.sce_enabled as u8)?;
569        writer.write_u8(self.xip_page_size as u8)?;
570        writer.write_u8(self.xip_block_size)?;
571
572        write_padding!(writer, 4);
573        writer.write_all(&self.valid_pattern)?;
574        writer.write_u8(self.xip_key_iv_valid() as u8)?;
575        write_padding!(writer, 7);
576
577        write_data!(writer, self.xip_key, 16);
578        write_data!(writer, self.xip_iv, 16);
579        write_padding!(writer, 32);
580        Ok(())
581    }
582}
583
584impl SectionHeader {
585    // ------------------------------------------------------------------------------------
586    // instance methods
587    // ------------------------------------------------------------------------------------
588
589    /// Checks if the section has a next section.
590    ///
591    /// This method checks if the `next_offset` field of the `SectionHeader` is set to the special
592    /// value `0xFFFF_FFFF`, which indicates that there is no next section. If `next_offset` is
593    /// different from this value, it implies that there is a subsequent section, and the method
594    /// returns `true`. Otherwise, it returns `false`, indicating this is the last section.
595    ///
596    /// # Returns
597    /// - `true` if the section has a next section (i.e., `next_offset` is not `0xFFFF_FFFF`).
598    /// - `false` if this is the last section (i.e., `next_offset` is `0xFFFF_FFFF`).
599    pub fn has_next(&self) -> bool {
600        return self.next_offset.is_some();
601    }
602
603    /// Checks if both the `xip_key` and `xip_iv` fields are valid.
604    ///
605    /// This method uses the `is_valid_data!` macro to check the validity of both the `xip_key`
606    /// and `xip_iv` fields. It returns `true` if both fields are valid (i.e., they do not consist
607    /// entirely of `0xFF` bytes). If either field is invalid, it returns `false`.
608    ///
609    /// This method is typically used to determine if the section is encrypted and can be used
610    /// for cryptographic operations.
611    ///
612    /// # Returns
613    /// - `true` if both `xip_key` and `xip_iv` are valid.
614    /// - `false` if either `xip_key` or `xip_iv` is invalid.
615    pub fn xip_key_iv_valid(&self) -> bool {
616        match (&self.xip_key, &self.xip_iv) {
617            (Some(xip_key), Some(xip_iv)) => {
618                return is_valid_data!(xip_key) && is_valid_data!(xip_iv);
619            }
620            _ => return false,
621        }
622    }
623
624    /// Retrieves the XIP key.
625    pub fn get_xip_key(&self) -> DataRefType<'_, 16> {
626        self.xip_key.as_ref()
627    }
628
629    /// Retrieves the XIP IV.
630    pub fn get_xip_iv(&self) -> DataRefType<'_, 16> {
631        self.xip_iv.as_ref()
632    }
633
634    /// Retrieves the valid pattern.
635    pub fn get_valid_pattern(&self) -> &[u8; 8] {
636        &self.valid_pattern
637    }
638
639    pub fn set_xip_iv(&mut self, iv: DataType<16>) {
640        self.xip_iv = iv;
641    }
642
643    pub fn set_xip_key(&mut self, key: DataType<16>) {
644        self.xip_key = key;
645    }
646}
647
648// -- entry header --
649// Layout recovered from
650//  - entry_header_t *_create_entry_header(uint length, uint load_address, uint entry_address)
651//
652//          +---+---+---+---+----+----+----+----+----+----+-----+----+----+----+----+----+
653//          | 0 | 1 | 2 | 3 | 4  | 5  | 6  | 7  | 8  | 9  | 10  | 11 | 12 | 13 | 14 | 15 |
654// +========+===+===+===+===+====+====+====+====+====+====+=====+====+====+====+====+====+
655// | 0x00   |  length: u32  | load_address: u32 | entry_address: u32 |                   |
656// +--------+---------------+-------------------+--------------------+-------------------+
657// | 0x10   |                                                                            |
658// +--------+----------------------------------------------------------------------------+
659// size = 0x20
660
661/// `EntryHeader` represents the header of a specific entry within a binary image.
662/// It includes metadata about the entry, such as its length, load address, and entry point.
663///
664/// This structure is used to describe a segment or block of data that is loaded into memory
665/// at a specified address and contains an entry point that the system can use to jump to
666/// the start of execution.
667///
668/// Fields:
669/// - `length`: The length of the entry in bytes. This defines how much memory the entry occupies.
670/// - `load_address`: The memory address at which the entry is loaded into the system's memory space.
671/// - `entry_address`: The address to which control is transferred when the entry is executed.
672///   By default, it's set to `0xFFFF_FFFF` (None), which indicates an invalid entry address.
673#[derive(Debug)]
674pub struct EntryHeader {
675    /// The length of the entry in bytes.
676    pub length: u32,
677
678    /// The load address in memory where the entry will be loaded.
679    pub load_address: u32,
680
681    /// The entry address, the address to which the system will jump to start execution.
682    /// Defaults to `0xFFFF_FFFF` (None), indicating an invalid address.
683    pub entry_address: Option<u32>,
684}
685
686impl BinarySize for EntryHeader {
687    /// Returns the binary size of the `EntryHeader` struct in bytes.
688    ///
689    /// # Returns
690    /// - `0x20`: The size of the `EntryHeader` struct in bytes.
691    fn binary_size() -> usize {
692        return 0x20;
693    }
694}
695
696impl Default for EntryHeader {
697    /// Returns the default values for the `EntryHeader` struct.
698    ///
699    /// The default values are:
700    /// - `length`: `0` (indicating no data or length of the entry).
701    /// - `load_address`: `0` (indicating the entry is not loaded anywhere).
702    /// - `entry_address`: `0xFFFF_FFFF` (None) (invalid entry address, typically indicating no valid entry).
703    ///
704    /// # Returns
705    /// - `EntryHeader`: A struct with default values.
706    fn default() -> EntryHeader {
707        return EntryHeader {
708            length: 0,
709            load_address: 0,
710            entry_address: None,
711        };
712    }
713}
714
715impl FromStream for EntryHeader {
716    /// Reads an `EntryHeader` from the provided reader (e.g., a file or memory buffer).
717    ///
718    /// # Arguments
719    /// - `reader`: A mutable reference to an object that implements `Read` and `Seek` (e.g., a file or buffer).
720    ///
721    /// # Returns
722    /// - `Ok(())`: If the deserialization is successful.
723    /// - `Err(Error)`: If there is an error reading from the stream, such as an unexpected end of data.
724    fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
725    where
726        R: std::io::Read + std::io::Seek,
727    {
728        self.length = reader.read_u32::<LittleEndian>()?;
729        self.load_address = reader.read_u32::<LittleEndian>()?;
730        self.entry_address = match reader.read_u32::<LittleEndian>()? {
731            0xFFFF_FFFF => None,
732            address => Some(address),
733        };
734        read_padding!(reader, 20);
735        Ok(())
736    }
737}
738
739impl ToStream for EntryHeader {
740    /// Serializes the `EntryHeader` struct to a stream.
741    ///
742    /// # Parameters
743    /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
744    ///   be written to this stream.
745    ///
746    /// # Returns
747    /// - `Ok(())`: If the data is written successfully.
748    /// - `Err(Error)`: If there is an issue writing the data to the stream.
749    fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
750    where
751        W: io::Write + io::Seek,
752    {
753        writer.write_u32::<LittleEndian>(self.length)?;
754        writer.write_u32::<LittleEndian>(self.load_address)?;
755        writer.write_u32::<LittleEndian>(self.entry_address.unwrap_or(0xFFFF_FFFF))?;
756        write_padding!(writer, 20);
757        Ok(())
758    }
759}