Skip to main content

zbi/
lib.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![cfg_attr(not(test), no_std)]
6
7//! ZBI Processing Library
8//!
9//! This library is meant to be a generic processing library for the ZBI format
10//! defined in sdk/lib/zbi-format/include/lib/zbi-format/zbi.h.
11//!
12//! Mainly it provides [`ZbiContainer`] that can create ([`ZbiContainer::new`]) valid container in
13//! the provided buffer. Or parses and checks ([`ZbiContainer::parse`]) existing container in the
14//! buffer. In both cases it provides iterator to walk thorough the items in container.
15//!
16//! Note: in both cases provided buffer must be properly aligned to [`ZBI_ALIGNMENT_USIZE`].
17//! Using [`align_buffer`] would do proper alignment for you.
18//!
19//! ```
20//! use zbi::{ZbiContainer, ZbiFlags, ZbiType, align_buffer};
21//!
22//! let mut buffer = [0; 200];
23//! let mut buffer = align_buffer(&mut buffer[..]).unwrap();
24//! let mut container = ZbiContainer::new(buffer).unwrap();
25//! container.create_entry(ZbiType::DebugData, 0, ZbiFlags::default(), 10).unwrap();
26//! container.create_entry_with_payload(ZbiType::DebugData, 0, ZbiFlags::default(), &[]).unwrap();
27//!
28//! assert_eq!(container.iter().count(), 2);
29//!
30//! let mut it = container.iter();
31//! assert_eq!(it.next().unwrap().header.length, 10);
32//! assert_eq!(it.next().unwrap().header.length, 0);
33//! assert_eq!(it.next(), None);
34//! ```
35
36pub mod zbi_format;
37
38use bitflags::bitflags;
39use core::fmt::{Debug, Display, Formatter};
40use core::mem::{size_of, take};
41use core::ops::DerefMut;
42use zbi_format::*;
43use zerocopy::{Immutable, IntoByteSlice, IntoBytes, Ref, SplitByteSlice, SplitByteSliceMut};
44
45type ZbiResult<T> = Result<T, ZbiError>;
46
47/// [`ZbiContainer`] requires buffer and each entry to be aligned to this amount of bytes.
48/// [`align_buffer`] can be used to adjust buffer alignment to match this requirement.
49// ZBI_ALIGNMENT is u32 and it is not productive to `try_into()` to usize all the time.
50// Expectation is that value should always fit in `u32` and `usize`, which we test.
51pub const ZBI_ALIGNMENT_USIZE: usize = ZBI_ALIGNMENT as usize;
52
53#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
54const ZBI_ARCH_KERNEL_TYPE: ZbiType = ZbiType::KernelArm64;
55#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
56const ZBI_ARCH_KERNEL_TYPE: ZbiType = ZbiType::KernelX64;
57#[cfg(any(target_arch = "riscv", target_arch = "riscv64"))]
58const ZBI_ARCH_KERNEL_TYPE: ZbiType = ZbiType::KernelRiscv64;
59
60/// Aligns provided slice to [`ZBI_ALIGNMENT_USIZE`] bytes.
61///
62/// # Returns
63///
64/// * `Ok(aligned_slice)` - on success, which can have `length == 0`
65/// * [`ZbiError::TooBig`] - returned if there is not enough space to align the slice
66pub fn align_buffer<B: SplitByteSlice>(buffer: B) -> ZbiResult<B> {
67    let tail_offset = get_align_buffer_offset(&buffer[..])?;
68    let (_, aligned_buffer) = buffer.split_at(tail_offset).ok().unwrap();
69    Ok(aligned_buffer)
70}
71
72/// ZbiItem is element representation in [`ZbiContainer`]
73///
74/// It contains of `header` and `payload`. Both contain references to actual location in buffer.
75/// And `payload` goes right after `header` in the buffer.
76///
77/// Header must be [`ZBI_ALIGNMENT_USIZE`] aligned in the buffer.
78/// The length field specifies the actual payload length and does not include the size of padding.
79/// Since all headers in [`ZbiContainer`] are [`ZBI_ALIGNMENT_USIZE`] aligned payload may be followed by padding,
80/// which is included in [`ZbiContainer`] length, but not in each [`ZbiItem`]
81#[derive(Debug)]
82pub struct ZbiItem<B: SplitByteSlice> {
83    /// ZBI header
84    pub header: Ref<B, ZbiHeader>,
85    /// Payload corresponding to ZBI header
86    pub payload: B,
87}
88
89impl<B: SplitByteSlice, C: SplitByteSlice> PartialEq<ZbiItem<C>> for ZbiItem<B> {
90    fn eq(&self, other: &ZbiItem<C>) -> bool {
91        self.header.as_bytes() == other.header.as_bytes()
92            && self.payload.as_bytes() == other.payload.as_bytes()
93    }
94}
95
96impl<B: SplitByteSlice + PartialEq> ZbiItem<B> {
97    /// Attempts to parse provided buffer.
98    ///
99    /// # Arguments
100    /// * `buffer` - buffer to parse (can be mutable if further changes to element is required)
101    ///
102    /// # Returns
103    ///
104    /// * `Ok((ZbiItem, tail))` - if parsing was successful function returns `ZbiItem` and tail of
105    ///                           buffer that wasn't used.
106    /// * `Err(ZbiError)` - if parsing fails Err is returned.
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// use zbi::ZbiItem;
112    ///
113    /// # const LEN: usize = 100;
114    /// # #[repr(align(8))]
115    /// # struct ZbiAligned([u8; LEN]);
116    /// # let buffer = ZbiAligned(core::array::from_fn::<_, LEN, _>(|_| 0u8));
117    /// # let buffer = &buffer.0[..];
118    /// let (zbi_item, tail) = ZbiItem::parse(buffer).unwrap();
119    /// println!("{}", zbi_item.header.type_);
120    /// println!("{}", tail.len());
121    /// assert_eq!(zbi_item.header.length, zbi_item.payload.len() as u32);
122    /// ```
123    pub fn parse(buffer: B) -> ZbiResult<(ZbiItem<B>, B)> {
124        is_zbi_aligned(&buffer)?;
125
126        let (hdr, payload) =
127            Ref::<B, ZbiHeader>::from_prefix(buffer).map_err(|_| ZbiError::Error)?;
128
129        let item_payload_len =
130            usize::try_from(hdr.length).map_err(|_| ZbiError::PlatformBadLength)?;
131
132        let (item_payload, tail) =
133            payload.split_at(item_payload_len).map_err(|_| ZbiError::TooBig)?;
134        let item = ZbiItem { header: hdr, payload: item_payload };
135        Ok((item, tail))
136    }
137
138    /// Validates `ZbiItem` header values.
139    ///
140    /// # Example
141    ///
142    /// ```
143    /// use zbi::{ZbiItem, ZbiError};
144    ///
145    /// # const LEN: usize = 100;
146    /// # #[repr(align(8))]
147    /// # struct ZbiAligned([u8; LEN]);
148    /// # let buffer = ZbiAligned(core::array::from_fn::<_, LEN, _>(|_| 0u8));
149    /// # let buffer = &buffer.0[..];
150    /// // E.g. if `header.magic = 0` this is invalid value.
151    /// let (zbi_item, tail) = ZbiItem::parse(buffer).unwrap();
152    /// assert_eq!(zbi_item.header.magic, 0);
153    /// assert_eq!(zbi_item.is_valid(), Err(ZbiError::BadMagic));
154    /// ```
155    pub fn is_valid(&self) -> ZbiResult<()> {
156        if self.header.magic != ZBI_ITEM_MAGIC {
157            Err(ZbiError::BadMagic)
158        } else if !self.header.get_flags().contains(ZbiFlags::VERSION) {
159            Err(ZbiError::BadVersion)
160        } else if !self.header.get_flags().contains(ZbiFlags::CRC32)
161            && (self.header.crc32 != ZBI_ITEM_NO_CRC32)
162        {
163            Err(ZbiError::BadCrc)
164        } else {
165            Ok(())
166        }
167    }
168}
169
170impl<B: SplitByteSliceMut + PartialEq> ZbiItem<B> {
171    /// Create `ZbiItem` with provided information and payload length.
172    ///
173    ///
174    /// # Result
175    ///
176    /// * `(ZbiItem, tail)` - returned on success. `ZbiItem` would have payload of requested
177    ///                       length. And tail would be remaining part of the `buffer` that wasn't
178    ///                       used.
179    /// * `ZbiError::BadAlignment` - if buffer wasn't aligned.
180    /// * `ZbiError::TooBig` - if buffer is not long enough to hold
181    ///                        [`ZbiHeader`] + `payload` of `payload_len`.
182    /// * `ZbiError::PlatformBadLength` - if `payload_len` value is bigger than `u32::MAX`
183    ///
184    /// # Example
185    /// ```
186    /// use zbi::{ZbiItem, ZbiFlags, ZbiType};
187    ///
188    /// # const LEN: usize = 100;
189    /// # #[repr(align(8))]
190    /// # struct ZbiAligned([u8; LEN]);
191    /// # let mut buffer = ZbiAligned(core::array::from_fn::<_, LEN, _>(|_| 0u8));
192    /// # let mut buffer = &mut buffer.0[..];
193    /// let (item, _tail) = ZbiItem::new(
194    ///     &mut buffer[..],
195    ///     ZbiType::KernelX64,
196    ///     0,
197    ///     ZbiFlags::default(),
198    ///     2,
199    /// ).unwrap();
200    /// assert_eq!(item.header.length, 2);
201    /// assert_eq!(item.payload.len(), 2);
202    /// ```
203    pub fn new(
204        buffer: B,
205        type_: ZbiType,
206        extra: u32,
207        flags: ZbiFlags,
208        payload_len: usize,
209    ) -> ZbiResult<(ZbiItem<B>, B)> {
210        if buffer.len() < core::mem::size_of::<ZbiHeader>()
211            || buffer.len() - core::mem::size_of::<ZbiHeader>() < payload_len
212        {
213            return Err(ZbiError::TooBig);
214        }
215
216        is_zbi_aligned(&buffer)?;
217
218        // Need to convert payload_len to u32 type to put in structure
219        let payload_len_u32 =
220            u32::try_from(payload_len).map_err(|_| ZbiError::PlatformBadLength)?;
221
222        let (mut header, item_tail) =
223            Ref::<B, ZbiHeader>::from_prefix(buffer).map_err(|_| ZbiError::Error)?;
224        header.type_ = type_ as u32;
225        header.length = payload_len_u32;
226        header.extra = extra;
227        header.set_flags(&flags);
228        header.reserved0 = 0;
229        header.reserved1 = 0;
230        header.magic = ZBI_ITEM_MAGIC;
231        header.crc32 = ZBI_ITEM_NO_CRC32;
232
233        // It is safe to do split because we checked if input buffer big enough to contain header
234        // and requested payload size.
235        let (payload, tail) = item_tail.split_at(payload_len).ok().unwrap();
236
237        Ok((ZbiItem { header, payload }, tail))
238    }
239}
240
241/// Main structure to work with ZBI format.
242///
243/// It allows to create valid buffer as well as parse existing one.
244/// Both cases would allow to iterate over elements in the container via [`ZbiContainer::iter`] or
245/// [`ZbiContainer::iter_mut`].
246#[derive(Debug, PartialEq)]
247pub struct ZbiContainer<B: SplitByteSlice> {
248    /// Container specific [`ZbiHeader`], witch would be first element if ZBI buffer.
249    ///
250    /// `header.length` would show how many bytes after this header is used for ZBI elements and
251    /// padding.
252    ///
253    /// `header.type_` is always [`ZbiType::Container`]
254    pub header: Ref<B, ZbiHeader>,
255
256    // Same as header.header.length, but for convenience is `usize` to avoid use of try_into and
257    // returning ZbiError if we need to use it.
258    // Use getters and setters to access length:
259    //  - set_payload_length_usize()
260    //  - get_payload_length_u32()
261    //  - get_payload_length_usize()
262    payload_length: usize,
263
264    // Buffer that follows `header`. It contains ZbiItems + padding if any and remaining tail for
265    // possible growth.
266    buffer: B,
267}
268
269impl<B: SplitByteSlice> ZbiContainer<B> {
270    // Helper to construct [`ZbiContainer`] which handles `paload_length` value, which should be
271    // in sync with `header.length`.
272    fn construct(header: Ref<B, ZbiHeader>, buffer: B) -> ZbiResult<Self> {
273        Ok(Self {
274            payload_length: usize::try_from(header.length)
275                .map_err(|_| ZbiError::PlatformBadLength)?,
276            header,
277            buffer,
278        })
279    }
280
281    /// Returns current container length as `u32`. Length doesn't include container header, only
282    /// items and padding.
283    pub fn get_payload_length_u32(&self) -> u32 {
284        self.header.length
285    }
286
287    /// Returns current container length as `usize`. Length doesn't include container header, only
288    /// items and padding.
289    pub fn get_payload_length_usize(&self) -> usize {
290        self.payload_length
291    }
292
293    /// Returns the total size including the ZBI container header, payload length after padding.
294    pub fn container_size(&self) -> ZbiResult<usize> {
295        self.get_payload_length_usize().checked_add(size_of::<ZbiHeader>()).ok_or(ZbiError::TooBig)
296    }
297
298    /// Immutable iterator over ZBI elements. First element is first ZBI element after
299    /// container header. Container header is not available via iterator.
300    pub fn iter(
301        &self,
302    ) -> ZbiContainerIterator<
303        impl SplitByteSlice + IntoByteSlice<'_> + Default + Debug + PartialEq + '_,
304    > {
305        ZbiContainerIterator {
306            state: Ok(()),
307            buffer: &self.buffer[..self.get_payload_length_usize()],
308        }
309    }
310
311    /// Validates if ZBI is bootable for the target platform. And returns ZBI item kernel on
312    /// success.
313    ///
314    /// # Returns
315    ///
316    /// * `Ok(item)` - if bootable, where `item` is the ZBI kernel item.
317    /// * Err([`ZbiError::IncompleteKernel`]) - if first element in container has type not bootable
318    ///                                         on target platform.
319    /// * Err([`ZbiError::Truncated`]) - if container is empty
320    pub fn get_bootable_kernel_item(
321        &self,
322    ) -> ZbiResult<ZbiItem<impl SplitByteSlice + Default + Debug + PartialEq + '_>> {
323        let hdr = &self.header;
324        if hdr.length == 0 {
325            return Err(ZbiError::Truncated);
326        }
327
328        match self.iter().next() {
329            Some(v) if v.header.type_ == ZBI_ARCH_KERNEL_TYPE as u32 => Ok(v),
330            Some(_) => Err(ZbiError::IncompleteKernel),
331            None => Err(ZbiError::Truncated),
332        }
333    }
334
335    /// Returns the ZBI kernel `entry` and `reserved_memory_size` field value if the container is a
336    /// bootable ZBI kernel.
337    ///
338    /// # Returns
339    ///
340    /// * Returns `Ok((entry, reserved_memory_size))` on success.
341    /// * Returns `Err` if container is not a bootable ZBI kernel or is truncated.
342    pub fn get_kernel_entry_and_reserved_memory_size(&self) -> ZbiResult<(u64, u64)> {
343        let kernel = self.get_bootable_kernel_item()?;
344        let (header, _) = Ref::<_, zbi_kernel_t>::from_prefix(kernel.payload)
345            .map_err(|_| ZbiError::IncompleteKernel)?;
346        Ok((header.entry, header.reserve_memory_size))
347    }
348
349    /// Computes the required buffer size needed for relocating this ZBI kernel.
350    ///
351    /// # Returns
352    ///
353    /// * Returns `Ok(size)` on success.
354    /// * Returns `Err` if container is not a valid bootable ZBI kernel.
355    pub fn get_buffer_size_for_kernel_relocation(&self) -> ZbiResult<usize> {
356        let kernel = self.get_bootable_kernel_item()?;
357        let (_, reserve_memory_size) = self.get_kernel_entry_and_reserved_memory_size()?;
358        let kernel_size = 2 * size_of::<ZbiHeader>() + kernel.payload.as_bytes().len();
359        let reserve_memory_size =
360            usize::try_from(reserve_memory_size).map_err(|_| ZbiError::LengthOverflow)?;
361        kernel_size.checked_add(reserve_memory_size).ok_or(ZbiError::LengthOverflow)
362    }
363
364    /// Creates `ZbiContainer` from provided buffer.
365    ///
366    /// Buffer must be aligned to [`ZBI_ALIGNMENT_USIZE`] ([`align_buffer`] could be
367    /// used for that). If buffer is mutable than container can be mutable.
368    ///
369    /// # Returns
370    ///
371    /// * `Ok(ZbiContainer)` - if buffer is aligned and contain valid buffer.
372    /// * Err([`ZbiError`]) - if error occurred.
373    pub fn parse(buffer: B) -> ZbiResult<Self> {
374        is_zbi_aligned(&buffer)?;
375
376        let (header, payload) =
377            Ref::<B, ZbiHeader>::from_prefix(buffer).map_err(|_| ZbiError::Error)?;
378
379        let length: usize = header.length.try_into().map_err(|_| ZbiError::TooBig)?;
380        if length > payload.len() {
381            return Err(ZbiError::Truncated);
382        }
383
384        if header.type_ != ZbiType::Container as u32 {
385            return Err(ZbiError::BadType);
386        } else if header.extra != ZBI_CONTAINER_MAGIC || header.magic != ZBI_ITEM_MAGIC {
387            return Err(ZbiError::BadMagic);
388        } else if !header.get_flags().contains(ZbiFlags::VERSION) {
389            return Err(ZbiError::BadVersion);
390        } else if !header.get_flags().contains(ZbiFlags::CRC32) && header.crc32 != ZBI_ITEM_NO_CRC32
391        {
392            return Err(ZbiError::BadCrc);
393        }
394
395        let res = Self::construct(header, payload)?;
396        // Compiler thinks it is still borrowed when we reach Ok(res), so adding scope for it
397        {
398            let mut it = res.iter();
399            for b in &mut it {
400                b.is_valid()?;
401            }
402
403            // Check if there were item parsing errors
404            it.state?;
405        }
406        Ok(res)
407    }
408}
409
410impl<B: SplitByteSliceMut + PartialEq> ZbiContainer<B> {
411    fn set_payload_length_usize(&mut self, len: usize) -> ZbiResult<()> {
412        if self.buffer.len() < len {
413            return Err(ZbiError::Truncated);
414        }
415        self.header.length = u32::try_from(len).map_err(|_| ZbiError::PlatformBadLength)?;
416        self.payload_length = len;
417        Ok(())
418    }
419
420    /// Creates new empty `ZbiContainer` using provided buffer.
421    ///
422    /// # Returns
423    ///
424    /// * `Ok(ZbiContainer)` - on success
425    /// * Err([`ZbiError`]) - on error
426    pub fn new(buffer: B) -> ZbiResult<Self> {
427        let (item, buffer) =
428            ZbiItem::new(buffer, ZbiType::Container, ZBI_CONTAINER_MAGIC, ZbiFlags::default(), 0)?;
429
430        Self::construct(item.header, buffer)
431    }
432
433    fn align_tail(&mut self) -> ZbiResult<()> {
434        let length = self.get_payload_length_usize();
435        let align_offset = get_align_buffer_offset(&self.buffer[length..])?;
436        let new_length = length + align_offset;
437        self.set_payload_length_usize(new_length)?;
438        Ok(())
439    }
440
441    /// Get payload slice for the next ZBI entry Next.
442    ///
443    /// Next entry should be added using [`ZbiContainer::create_entry`].
444    ///
445    /// This is useful when it's non-trivial to determine the length of a payload ahead of time -
446    /// for example, loading a variable-length string from persistent storage.
447    ///
448    /// Rather than loading the payload into a temporary buffer, determining the length, then
449    /// copying it into the ZBI, this function allows loading data directly into the ZBI. Since this
450    /// buffer is currently unused area, loading data here does not affect the ZBI until
451    /// zbi_create_entry() is called.
452    ///
453    /// # Example
454    ///
455    /// ```
456    /// # use zbi::{ZbiContainer, ZbiFlags, ZbiType, align_buffer};
457    /// #
458    /// # let mut buffer = [0; 100];
459    /// # let mut buffer = align_buffer(&mut buffer[..]).unwrap();
460    /// # let mut container = ZbiContainer::new(buffer).unwrap();
461    /// #
462    /// # let payload_to_use = [1, 2, 3, 4];
463    /// let next_payload = container.get_next_payload().unwrap();
464    /// next_payload[..payload_to_use.len()].copy_from_slice(&payload_to_use[..]);
465    ///
466    /// container
467    ///     .create_entry(ZbiType::KernelX64, 0, ZbiFlags::default(), payload_to_use.len())
468    ///     .unwrap();
469    ///
470    /// assert_eq!(container.iter().count(), 1);
471    /// assert_eq!(&*container.iter().next().unwrap().payload, &payload_to_use[..]);
472    /// ```
473    ///
474    /// # Returns:
475    /// `Ok(&mut [u8])` - on success; slice of buffer where next entries payload would be located.
476    /// Err([`ZbiError::TooBig`]) - if buffer is not big enough for new element without payload.
477    pub fn get_next_payload(&mut self) -> ZbiResult<&mut [u8]> {
478        let length = self.get_payload_length_usize();
479        let align_payload_offset = length
480            .checked_add(size_of::<ZbiHeader>())
481            .ok_or(ZbiError::LengthOverflow)?
482            .checked_add(get_align_buffer_offset(&self.buffer[length..])?)
483            .ok_or(ZbiError::LengthOverflow)?;
484        if self.buffer.len() < align_payload_offset {
485            return Err(ZbiError::TooBig);
486        }
487        Ok(&mut self.buffer[align_payload_offset..])
488    }
489
490    /// Creates a new ZBI entry with the provided payload.
491    ///
492    /// The new entry is aligned to [`ZBI_ALIGNMENT_USIZE`]. The capacity of the base ZBI must
493    /// be large enough to fit the new entry.
494    ///
495    /// The [`ZbiFlags::VERSION`] is unconditionally set for the new entry.
496    ///
497    /// The [`ZbiFlags::CRC32`] flag yields an error because CRC computation is not yet
498    /// supported.
499    ///
500    /// # Arguments
501    ///   * `type_` - The new entry's type
502    ///   * `extra` - The new entry's type-specific data
503    ///   * `flags` - The new entry's flags
504    ///   * `payload` - The payload, copied into the new entry
505    ///
506    /// # Returns:
507    ///   * Ok(()) - on success
508    ///   * Err([`ZbiError::TooBig`]) - if buffer is not big enough for new element with payload
509    ///   * Err([`ZbiError::Crc32NotSupported`]) - if unsupported [`ZbiFlags::CRC32`] is set
510    ///   * Err([`ZbiError`]) - if other errors occurred
511    ///
512    /// # Example
513    /// ```
514    /// # use zbi::{ZbiContainer, ZbiFlags, ZbiType, align_buffer};
515    /// #
516    /// # let mut buffer = [0; 100];
517    /// # let mut buffer = align_buffer(&mut buffer[..]).unwrap();
518    /// # let mut container = ZbiContainer::new(buffer).unwrap();
519    /// #
520    /// container
521    ///     .create_entry_with_payload(ZbiType::KernelX64, 0, ZbiFlags::default(), &[1, 2, 3, 4])
522    ///     .unwrap();
523    /// assert_eq!(container.iter().count(), 1);
524    /// assert_eq!(&*container.iter().next().unwrap().payload, &[1, 2, 3, 4]);
525    /// ```
526    pub fn create_entry_with_payload(
527        &mut self,
528        type_: ZbiType,
529        extra: u32,
530        flags: ZbiFlags,
531        payload: &[u8],
532    ) -> ZbiResult<()> {
533        self.get_next_payload()?[..payload.len()].copy_from_slice(payload);
534        self.create_entry(type_, extra, flags, payload.len())
535    }
536
537    /// Creates a new ZBI entry and returns a pointer to the payload.
538    ///
539    /// The new entry is aligned to [`ZBI_ALIGNMENT_USIZE`]. The capacity of the base ZBI must
540    /// be large enough to fit the new entry.
541    ///
542    /// The [`ZbiFlags::VERSION`] is unconditionally set for the new entry.
543    ///
544    /// The [`ZbiFlags::CRC32`] flag yields an error because CRC computation is not yet
545    /// supported.
546    ///
547    /// # Arguments
548    ///   * `type_` - The new entry's type.
549    ///   * `extra` - The new entry's type-specific data.
550    ///   * `flags` - The new entry's flags.
551    ///   * `payload_length` - The length of the new entry's payload.
552    ///
553    /// # Returns
554    ///   * Ok(()) - On success.
555    ///   * Err([`ZbiError::TooBig`]) - if buffer is not big enough for new element with payload
556    ///   * Err([`ZbiError::Crc32NotSupported`]) - if unsupported [`ZbiFlags::CRC32`] is set
557    ///   * Err([`ZbiError`]) - if other errors occurred
558    ///
559    /// # Example
560    /// ```
561    /// # use zbi::{ZbiContainer, ZbiFlags, ZbiType, align_buffer};
562    /// #
563    /// # let mut buffer = [0; 100];
564    /// # let mut buffer = align_buffer(&mut buffer[..]).unwrap();
565    /// # let mut container = ZbiContainer::new(buffer).unwrap();
566    /// #
567    /// # let payload_to_use = [1, 2, 3, 4];
568    /// let next_payload = container.get_next_payload().unwrap();
569    /// next_payload[..payload_to_use.len()].copy_from_slice(&payload_to_use[..]);
570    ///
571    /// container
572    ///     .create_entry(ZbiType::KernelX64, 0, ZbiFlags::default(), payload_to_use.len())
573    ///     .unwrap();
574    ///
575    /// assert_eq!(container.iter().count(), 1);
576    /// assert_eq!(&*container.iter().next().unwrap().payload, &payload_to_use[..]);
577    /// ```
578    pub fn create_entry(
579        &mut self,
580        type_: ZbiType,
581        extra: u32,
582        flags: ZbiFlags,
583        payload_length: usize,
584    ) -> ZbiResult<()> {
585        // We don't support CRC computation (yet?)
586        if flags.contains(ZbiFlags::CRC32) {
587            return Err(ZbiError::Crc32NotSupported);
588        }
589
590        let length = self.get_payload_length_usize();
591        let (item, _) =
592            ZbiItem::new(&mut self.buffer[length..], type_, extra, flags, payload_length)?;
593        let used = length
594            .checked_add(core::mem::size_of::<ZbiHeader>())
595            .ok_or(ZbiError::LengthOverflow)?
596            .checked_add(item.payload.len())
597            .ok_or(ZbiError::LengthOverflow)?;
598        self.set_payload_length_usize(used)?;
599        self.align_tail()?;
600        Ok(())
601    }
602
603    /// Extends a ZBI container with another container's payload.
604    ///
605    /// # Arguments
606    ///   * `other` - The container to copy the payload from.
607    ///
608    /// # Returns
609    ///   * `Ok(())` - On success.
610    ///   * Err([`ZbiError::TooBig`]) - If container is too small.
611    ///
612    /// # Example
613    /// ```
614    /// # use zbi::{ZbiContainer, ZbiType, ZbiFlags, align_buffer};
615    /// #
616    /// # let mut buffer = [0; 200];
617    /// # let mut buffer = align_buffer(&mut buffer[..]).unwrap();
618    /// let mut container_0 = ZbiContainer::new(&mut buffer[..]).unwrap();
619    /// container_0
620    ///     .create_entry_with_payload(ZbiType::DebugData, 0, ZbiFlags::default(), &[0, 1])
621    ///     .unwrap();
622    ///
623    /// # let mut buffer = [0; 200];
624    /// # let mut buffer = align_buffer(&mut buffer[..]).unwrap();
625    /// let mut container_1 = ZbiContainer::new(&mut buffer[..]).unwrap();
626    /// container_1
627    ///     .create_entry_with_payload(ZbiType::KernelX64, 0, ZbiFlags::default(), &[0, 1, 3, 4])
628    ///     .unwrap();
629    ///
630    /// container_0.extend(&container_1).unwrap();
631    ///
632    /// assert_eq!(container_0.iter().count(), 2);
633    /// # let cont0_element_1 = &container_0
634    /// #     .iter()
635    /// #     .enumerate()
636    /// #     .filter_map(|(i, e)| if i == 1 { Some(e) } else { None })
637    /// #     .collect::<Vec<_>>()[0];
638    /// # let cont1_element_0 = &container_1.iter().next().unwrap();
639    /// # assert_eq!(cont0_element_1, cont1_element_0);
640    /// ```
641    pub fn extend(
642        &mut self,
643        other: &ZbiContainer<impl SplitByteSlice + PartialEq>,
644    ) -> ZbiResult<()> {
645        let new_length = self
646            .get_payload_length_usize()
647            .checked_add(other.get_payload_length_usize())
648            .ok_or(ZbiError::LengthOverflow)?;
649        if self.buffer.len() < new_length {
650            return Err(ZbiError::TooBig);
651        }
652
653        for b in other.iter() {
654            let start = self.get_payload_length_usize();
655            let end = start + core::mem::size_of::<ZbiHeader>();
656            self.buffer[start..end].clone_from_slice(Ref::bytes(&b.header));
657            let start = end;
658            let end = start + b.payload.len();
659            self.buffer[start..end].clone_from_slice(&b.payload);
660            self.set_payload_length_usize(end)?;
661            self.align_tail()?;
662        }
663        Ok(())
664    }
665
666    /// Extends a ZBI container with another ZBI item.
667    ///
668    /// # Arguments
669    ///   * `iter` - ZBI container iterator. Elements starting from `iter` till the end are to be
670    ///   appended to the container.
671    ///
672    /// # Returns
673    ///   * `Ok(())` - On success.
674    ///   * Err([`ZbiError::TooBig`]) - If container is too small.
675    pub fn extend_items<'a>(
676        &mut self,
677        iter: ZbiContainerIterator<impl SplitByteSlice + Default + Debug + PartialEq + 'a>,
678    ) -> ZbiResult<()> {
679        for i in iter {
680            // Make sure `extend_blob` for header and payload would not fail due to lack of space
681            if self.get_next_payload()?.len() < i.payload.as_bytes().len() {
682                return Err(ZbiError::TooBig);
683            }
684            self.extend_blob(i.header.as_bytes())?;
685            self.extend_blob(i.payload.as_bytes())?;
686            self.align_tail()?;
687        }
688        Ok(())
689    }
690
691    // Append blob data to the container.
692    // The intend use is to help with item copy from iterator
693    fn extend_blob<'a>(&mut self, blob: &[u8]) -> ZbiResult<()> {
694        let length = self.get_payload_length_usize();
695        let new_used = length.checked_add(blob.len()).ok_or(ZbiError::LengthOverflow)?;
696        self.buffer[length..new_used].copy_from_slice(blob);
697        self.set_payload_length_usize(new_used)?;
698        Ok(())
699    }
700
701    /// Extends with another ZBI container stored on a potentially unaligned buffer.
702    ///
703    /// The method copies `other` into the unused space first before checking validity and
704    /// extending. Thus if `other.len()` is greater than the remaining space in the container, it
705    /// it will be rejected, regardless of the actual container size.
706    pub fn extend_unaligned(&mut self, other: &[u8]) -> ZbiResult<()> {
707        let sz = self.get_payload_length_usize();
708        let remains = &mut self.buffer[sz..];
709        // Copies `other` to `dst` which is guaranteed aligned.
710        let dst = remains.get_mut(..other.len()).ok_or(ZbiError::TooBig)?;
711        dst.clone_from_slice(other);
712        // Checks the incoming container and extracts payload length (without padding).
713        let new_payload_len = ZbiContainer::parse(&mut dst[..])?.header.length;
714        // Shifts forward the payload to remove the ZBI header. This effectively appends the
715        // payload.
716        dst.copy_within(size_of::<ZbiHeader>().., 0);
717        self.set_payload_length_usize(
718            sz + usize::try_from(new_payload_len).map_err(|_| ZbiError::LengthOverflow)?,
719        )?;
720        self.align_tail()
721    }
722}
723
724impl<B: SplitByteSlice + PartialEq + DerefMut> ZbiContainer<B> {
725    /// Mutable iterator over ZBI elements. First element is first ZBI element after
726    /// container header. Container header is not available via iterator.
727    pub fn iter_mut(
728        &mut self,
729    ) -> ZbiContainerIterator<impl SplitByteSliceMut + Debug + Default + PartialEq + '_> {
730        let length = self.get_payload_length_usize();
731        ZbiContainerIterator { state: Ok(()), buffer: &mut self.buffer[..length] }
732    }
733}
734
735/// Container iterator
736// State is required to check elements are valid during parsing.
737// During this parsing can fail and we need to check if iterator returned `None` because there are
738// no more elements left or because there was an error.
739// If container object already exist state should never contain error, since container was already
740// verified.
741pub struct ZbiContainerIterator<B> {
742    state: ZbiResult<()>,
743    buffer: B,
744}
745
746impl<B: SplitByteSlice + PartialEq + Default + Debug> Iterator for ZbiContainerIterator<B> {
747    type Item = ZbiItem<B>;
748
749    fn next(&mut self) -> Option<Self::Item> {
750        // Align buffer before parsing
751        match align_buffer(take(&mut self.buffer)) {
752            Ok(v) => self.buffer = v,
753            Err(_) => {
754                self.state = Err(ZbiError::Truncated);
755                return None;
756            }
757        };
758
759        if self.buffer.is_empty() {
760            return None;
761        }
762
763        match ZbiItem::<B>::parse(take(&mut self.buffer)) {
764            Ok((item, mut tail)) => {
765                // Remove item that was just parsed from the buffer for next
766                // iteration before returning it.
767                core::mem::swap(&mut tail, &mut self.buffer);
768                Some(item)
769            }
770            Err(e) => {
771                // If there was an error during item parsing,
772                // make sure to set state to error, before signalling end of iteration.
773                self.state = Err(e);
774                None
775            }
776        }
777    }
778}
779
780#[repr(u32)]
781#[derive(IntoBytes, Clone, Copy, Debug, Eq, PartialEq, Immutable)]
782/// All possible [`ZbiHeader`]`.type` values.
783pub enum ZbiType {
784    /// Each ZBI starts with a container header.
785    /// * `length`: Total size of the image after this header. This includes all item headers,
786    ///             payloads, and padding. It does not include the container header itself.
787    ///             Must be a multiple of [`ZBI_ALIGNMENT_USIZE`].
788    /// * `extra`:  Must be `ZBI_CONTAINER_MAGIC`.
789    /// * `flags`:  Must be [`ZbiFlags::VERSION`] and no other flags.
790    Container = ZBI_TYPE_CONTAINER,
791
792    /// x86-64 kernel. See [`ZbiKernel`] for a payload description.
793    //
794    // 'KRNL'
795    KernelX64 = ZBI_TYPE_KERNEL_X64,
796
797    /// ARM64 kernel. See [`ZbiKernel`] for a payload description.
798    //
799    // KRN8
800    KernelArm64 = ZBI_TYPE_KERNEL_ARM64,
801
802    /// RISC-V kernel. See [`ZbiKernel`] for a payload description.
803    //
804    // 'KRNV'
805    KernelRiscv64 = ZBI_TYPE_KERNEL_RISCV64,
806
807    /// A discarded item that should just be ignored.  This is used for an
808    /// item that was already processed and should be ignored by whatever
809    /// stage is now looking at the ZBI.  An earlier stage already "consumed"
810    /// this information, but avoided copying data around to remove it from
811    /// the ZBI item stream.
812    //
813    // 'SKIP'
814    Discard = ZBI_TYPE_DISCARD,
815
816    /// A virtual disk image.  This is meant to be treated as if it were a
817    /// storage device.  The payload (after decompression) is the contents of
818    /// the storage device, in whatever format that might be.
819    //
820    // 'RDSK'
821    StorageRamdisk = ZBI_TYPE_STORAGE_RAMDISK,
822
823    /// The /boot filesystem in BOOTFS format, specified in
824    /// <lib/zbi-format/internal/bootfs.h>.  This represents an internal
825    /// contract between Zircon userboot (//docs/userboot.md), which handles
826    /// the contents of this filesystem, and platform tooling, which prepares
827    /// them.
828    //
829    // 'BFSB'
830    StorageBootFs = ZBI_TYPE_STORAGE_BOOTFS,
831
832    /// Storage used by the kernel (such as a compressed image containing the
833    /// actual kernel).  The meaning and format of the data is specific to the
834    /// kernel, though it always uses the standard (private) storage
835    /// compression protocol. Each particular `ZbiType::Kernel{ARCH}` item image and its
836    /// `StorageKernel` item image are intimately tied and one cannot work
837    /// without the exact correct corresponding other.
838    //
839    // 'KSTR'
840    StorageKernel = ZBI_TYPE_STORAGE_KERNEL,
841
842    /// Device-specific factory data, stored in BOOTFS format.
843    //
844    // TODO(https://fxbug.dev/42109921): This should not use the "STORAGE" infix.
845    //
846    // 'BFSF'
847    StorageBootFsFactory = ZBI_TYPE_STORAGE_BOOTFS_FACTORY,
848
849    /// A kernel command line fragment, a UTF-8 string that need not be
850    /// NULL-terminated.  The kernel's own option parsing accepts only printable
851    /// 'ASCI'I and treats all other characters as equivalent to whitespace. Multiple
852    /// `ZbiType::CmdLine` items can appear.  They are treated as if concatenated with
853    /// ' ' between each item, in the order they appear: first items in the bootable
854    /// ZBI containing the kernel; then items in the ZBI synthesized by the boot
855    /// loader.  The kernel interprets the [whole command line](../../../../docs/kernel_cmdline.md).
856    //
857    // 'CMDL'
858    CmdLine = ZBI_TYPE_CMDLINE,
859
860    /// The crash log from the previous boot, a UTF-8 string.
861    //
862    // 'BOOM'
863    CrashLog = ZBI_TYPE_CRASHLOG,
864
865    /// Physical memory region that will persist across warm boots. See `zbi_nvram_t`
866    /// for payload description.
867    //
868    // 'NVLL'
869    Nvram = ZBI_TYPE_NVRAM,
870
871    /// Platform ID Information.
872    //
873    // 'PLID'
874    PlatformId = ZBI_TYPE_PLATFORM_ID,
875
876    /// Board-specific information.
877    //
878    // mBSI
879    DrvBoardInfo = ZBI_TYPE_DRV_BOARD_INFO,
880
881    /// CPU configuration. See `zbi_topology_node_t` for a description of the payload.
882    CpuTopology = ZBI_TYPE_CPU_TOPOLOGY,
883
884    /// Device memory configuration. See `zbi_mem_range_t` for a description of the payload.
885    //
886    // 'MEMC'
887    MemConfig = ZBI_TYPE_MEM_CONFIG,
888
889    /// Kernel driver configuration.  The `ZbiHeader.extra` field gives a
890    /// ZBI_KERNEL_DRIVER_* type that determines the payload format.
891    /// See <lib/zbi-format/driver-config.h> for details.
892    //
893    // 'KDRV'
894    KernelDriver = ZBI_TYPE_KERNEL_DRIVER,
895
896    /// 'ACPI' Root Table Pointer, a `u64` physical address.
897    //
898    // 'RSDP'
899    AcpiRsdp = ZBI_TYPE_ACPI_RSDP,
900
901    /// 'SMBI'OS entry point, a [u64] physical address.
902    //
903    // 'SMBI'
904    Smbios = ZBI_TYPE_SMBIOS,
905
906    /// EFI system table, a [u64] physical address.
907    //
908    // 'EFIS'
909    EfiSystemTable = ZBI_TYPE_EFI_SYSTEM_TABLE,
910
911    /// EFI memory attributes table. An example of this format can be found in UEFI 2.10
912    /// section 4.6.4, but the consumer of this item is responsible for interpreting whatever
913    /// the bootloader supplies (in particular the "version" field may differ as the format
914    /// evolves).
915    //
916    // 'EMAT'
917    EfiMemoryAttributesTable = ZBI_TYPE_EFI_MEMORY_ATTRIBUTES_TABLE,
918
919    /// Framebuffer parameters, a `zbi_swfb_t` entry.
920    //
921    // 'SWFB'
922    FrameBuffer = ZBI_TYPE_FRAMEBUFFER,
923
924    /// The image arguments, data is a trivial text format of one "key=value" per line
925    /// with leading whitespace stripped and "#" comment lines and blank lines ignored.
926    /// It is processed by bootsvc and parsed args are shared to others via Arguments service.
927    /// TODO: the format can be streamlined after the /config/additional_boot_args compat support is
928    /// removed.
929    //
930    // 'IARG'
931    ImageArgs = ZBI_TYPE_IMAGE_ARGS,
932
933    /// A copy of the boot version stored within the sysconfig partition
934    //
935    // 'BVRS'
936    BootVersion = ZBI_TYPE_BOOT_VERSION,
937
938    /// MAC address for Ethernet, Wifi, Bluetooth, etc.  `ZbiHeader.extra`
939    /// is a board-specific index to specify which device the MAC address
940    /// applies to.  `ZbiHeader.length` gives the size in bytes, which
941    /// varies depending on the type of address appropriate for the device.
942    //
943    // mMAC
944    DrvMacAddress = ZBI_TYPE_DRV_MAC_ADDRESS,
945
946    /// A partition map for a storage device, a `zbi_partition_map_t` header
947    /// followed by one or more `zbi_partition_t` entries.  `ZbiHeader.extra`
948    /// is a board-specific index to specify which device this applies to.
949    //
950    // mPRT
951    DrvPartitionMap = ZBI_TYPE_DRV_PARTITION_MAP,
952
953    /// Private information for the board driver.
954    //
955    // mBOR
956    DrvBoardPrivate = ZBI_TYPE_DRV_BOARD_PRIVATE,
957
958    /// Information about reboot
959    // 'HWRB'
960    HwRebootReason = ZBI_TYPE_HW_REBOOT_REASON,
961
962    /// The serial number, an unterminated ASCII string of printable non-whitespace
963    /// characters with length `ZbiHeader.length`.
964    //
965    // 'SRLN'
966    SerialNumber = ZBI_TYPE_SERIAL_NUMBER,
967
968    /// This type specifies a binary file passed in by the bootloader.
969    /// The first byte specifies the length of the filename without a NUL terminator.
970    /// The filename starts on the second byte.
971    /// The file contents are located immediately after the filename.
972    /// ```none
973    /// Layout: | name_len |        name       |   payload
974    ///           ^(1 byte)  ^(name_len bytes)     ^(length of file)
975    /// ```
976    //
977    // 'BTFL'
978    BootloaderFile = ZBI_TYPE_BOOTLOADER_FILE,
979
980    /// The devicetree blob from the legacy boot loader, if any.  This is used only
981    /// for diagnostic and development purposes.  Zircon kernel and driver
982    /// configuration is entirely driven by specific ZBI items from the boot
983    /// loader.  The boot shims for legacy boot loaders pass the raw devicetree
984    /// along for development purposes, but extract information from it to populate
985    /// specific ZBI items such as [`ZbiType::KernelDriver`] et al.
986    DeviceTree = ZBI_TYPE_DEVICETREE,
987
988    /// An arbitrary number of random bytes attested to have high entropy.  Any
989    /// number of items of any size can be provided, but no data should be provided
990    /// that is not true entropy of cryptographic quality.  This is used to seed
991    /// secure cryptographic pseudo-random number generators.
992    //
993    // 'RAND'
994    SecureEntropy = ZBI_TYPE_SECURE_ENTROPY,
995
996    /// This provides a data dump and associated logging from a boot loader,
997    /// shim, or earlier incarnation that wants its data percolated up by the
998    /// booting Zircon kernel. See `zbi_debugdata_t` for a description of the
999    /// payload.
1000    //
1001    // 'DBGD'
1002    DebugData = ZBI_TYPE_DEBUGDATA,
1003}
1004
1005impl ZbiType {
1006    /// Checks if [`ZbiType`] is a Kernel type. (E.g. [`ZbiType::KernelX64`])
1007    /// ```
1008    /// # use zbi::ZbiType;
1009    /// assert!(ZbiType::KernelX64.is_kernel());
1010    /// ```
1011    pub fn is_kernel(&self) -> bool {
1012        ((*self as u32) & ZBI_TYPE_KERNEL_MASK) == ZBI_TYPE_KERNEL_PREFIX
1013    }
1014
1015    /// Checks if [`ZbiType`] is a Driver Metadata type. (E.g. [`ZbiType::DrvBoardInfo`])
1016    /// ```
1017    /// # use zbi::ZbiType;
1018    /// assert!(ZbiType::DrvBoardInfo.is_driver_metadata());
1019    /// ```
1020    pub fn is_driver_metadata(&self) -> bool {
1021        ((*self as u32) & ZBI_TYPE_DRIVER_METADATA_MASK) == ZBI_TYPE_DRIVER_METADATA_PREFIX
1022    }
1023}
1024
1025impl From<ZbiType> for u32 {
1026    fn from(val: ZbiType) -> Self {
1027        val as u32
1028    }
1029}
1030
1031impl TryFrom<u32> for ZbiType {
1032    type Error = ZbiError;
1033    fn try_from(val: u32) -> Result<Self, Self::Error> {
1034        match val {
1035            ZBI_TYPE_KERNEL_X64 => Ok(Self::KernelX64),
1036            ZBI_TYPE_KERNEL_ARM64 => Ok(Self::KernelArm64),
1037            ZBI_TYPE_KERNEL_RISCV64 => Ok(Self::KernelRiscv64),
1038            ZBI_TYPE_CONTAINER => Ok(Self::Container),
1039            ZBI_TYPE_DISCARD => Ok(Self::Discard),
1040            ZBI_TYPE_STORAGE_RAMDISK => Ok(Self::StorageRamdisk),
1041            ZBI_TYPE_STORAGE_BOOTFS => Ok(Self::StorageBootFs),
1042            ZBI_TYPE_STORAGE_KERNEL => Ok(Self::StorageKernel),
1043            ZBI_TYPE_STORAGE_BOOTFS_FACTORY => Ok(Self::StorageBootFsFactory),
1044            ZBI_TYPE_CMDLINE => Ok(Self::CmdLine),
1045            ZBI_TYPE_CRASHLOG => Ok(Self::CrashLog),
1046            ZBI_TYPE_NVRAM => Ok(Self::Nvram),
1047            ZBI_TYPE_PLATFORM_ID => Ok(Self::PlatformId),
1048            ZBI_TYPE_DRV_BOARD_INFO => Ok(Self::DrvBoardInfo),
1049            ZBI_TYPE_CPU_TOPOLOGY => Ok(Self::CpuTopology),
1050            ZBI_TYPE_MEM_CONFIG => Ok(Self::MemConfig),
1051            ZBI_TYPE_KERNEL_DRIVER => Ok(Self::KernelDriver),
1052            ZBI_TYPE_ACPI_RSDP => Ok(Self::AcpiRsdp),
1053            ZBI_TYPE_SMBIOS => Ok(Self::Smbios),
1054            ZBI_TYPE_EFI_SYSTEM_TABLE => Ok(Self::EfiSystemTable),
1055            ZBI_TYPE_EFI_MEMORY_ATTRIBUTES_TABLE => Ok(Self::EfiMemoryAttributesTable),
1056            ZBI_TYPE_FRAMEBUFFER => Ok(Self::FrameBuffer),
1057            ZBI_TYPE_IMAGE_ARGS => Ok(Self::ImageArgs),
1058            ZBI_TYPE_BOOT_VERSION => Ok(Self::BootVersion),
1059            ZBI_TYPE_DRV_MAC_ADDRESS => Ok(Self::DrvMacAddress),
1060            ZBI_TYPE_DRV_PARTITION_MAP => Ok(Self::DrvPartitionMap),
1061            ZBI_TYPE_DRV_BOARD_PRIVATE => Ok(Self::DrvBoardPrivate),
1062            ZBI_TYPE_HW_REBOOT_REASON => Ok(Self::HwRebootReason),
1063            ZBI_TYPE_SERIAL_NUMBER => Ok(Self::SerialNumber),
1064            ZBI_TYPE_BOOTLOADER_FILE => Ok(Self::BootloaderFile),
1065            ZBI_TYPE_DEVICETREE => Ok(Self::DeviceTree),
1066            ZBI_TYPE_SECURE_ENTROPY => Ok(Self::SecureEntropy),
1067            ZBI_TYPE_DEBUGDATA => Ok(Self::DebugData),
1068            _ => Err(ZbiError::BadType),
1069        }
1070    }
1071}
1072
1073bitflags! {
1074    /// Flags associated with an item.
1075    ///
1076    /// A valid flags value must always include [`ZbiFlags::VERSION`].
1077    /// Values should also contain [`ZbiFlags::CRC32`] for any item
1078    /// where it's feasible to compute the [`ZbiFlags::CRC32`] at build time.
1079    /// Other flags are specific to each type.
1080    ///
1081    /// Matches C-reference `zbi_flags_t` which is `uint32_t`.
1082    pub struct ZbiFlags: u32 {
1083        /// This flag is always required.
1084        const VERSION = ZBI_FLAGS_VERSION;
1085        /// ZBI items with the `CRC32` flag must have a valid `crc32`.
1086        /// Otherwise their `crc32` field must contain `ZBI_ITEM_NO_CRC32`
1087        const CRC32 = ZBI_FLAGS_CRC32;
1088    }
1089}
1090
1091/// A valid flags must always include [`ZbiFlags::VERSION`].
1092impl Default for ZbiFlags {
1093    fn default() -> ZbiFlags {
1094        ZbiFlags::VERSION
1095    }
1096}
1097
1098/// Rust type generated from C-reference structure `zbi_header_t`.
1099///
1100/// It must correspond to following definition:
1101/// ```c++
1102/// typedef struct {
1103///   // ZBI_TYPE_* constant.
1104///   zbi_type_t type;
1105///
1106///   // Size of the payload immediately following this header.  This
1107///   // does not include the header itself nor any alignment padding
1108///   // after the payload.
1109///   uint32_t length;
1110///
1111///   // Type-specific extra data.  Each type specifies the use of this
1112///   // field.  When not explicitly specified, it should be zero.
1113///   uint32_t extra;
1114///
1115///   // Flags for this item.
1116///   zbi_flags_t flags;
1117///
1118///   // For future expansion.  Set to 0.
1119///   uint32_t reserved0;
1120///   uint32_t reserved1;
1121///
1122///   // Must be ZBI_ITEM_MAGIC.
1123///   uint32_t magic;
1124///
1125///   // Must be the CRC32 of payload if ZBI_FLAGS_CRC32 is set,
1126///   // otherwise must be ZBI_ITEM_NO_CRC32.
1127///   uint32_t crc32;
1128/// } zbi_header_t;
1129/// ```
1130pub type ZbiHeader = zbi_header_t;
1131
1132impl ZbiHeader {
1133    /// Helper function to get `ZbiHeader.flags: u32` as `ZbiFlags`.
1134    pub fn get_flags(&self) -> ZbiFlags {
1135        ZbiFlags::from_bits_truncate(self.flags)
1136    }
1137    /// Helper function to set `ZbiHeader.flags: u32` from `ZbiFlags`.
1138    pub fn set_flags(&mut self, flags: &ZbiFlags) {
1139        self.flags = flags.bits();
1140    }
1141}
1142
1143/// The kernel image.
1144///
1145/// In a bootable ZBI this item must always be first,
1146/// immediately after the [`ZbiType::Container`] header.  The contiguous memory
1147/// image of the kernel is formed from the [`ZbiType::Container`] header, the
1148/// `ZbiType::Kernel{ARCH}` header, and the payload.
1149///
1150/// The boot loader loads the whole image starting with the container header
1151/// through to the end of the kernel item's payload into contiguous physical
1152/// memory.  It then constructs a partial ZBI elsewhere in memory, which has
1153/// a [`ZbiType::Container`] header of its own followed by all the other items
1154/// that were in the booted ZBI plus other items synthesized by the boot
1155/// loader to describe the machine.  This partial ZBI must be placed at an
1156/// address (where the container header is found) that is aligned to the
1157/// machine's page size.  The precise protocol for transferring control to
1158/// the kernel's entry point varies by machine.
1159///
1160/// On all machines, the kernel requires some amount of scratch memory to be
1161/// available immediately after the kernel image at boot.  It needs this
1162/// space for early setup work before it has a chance to read any memory-map
1163/// information from the boot loader.  The `reserve_memory_size` field tells
1164/// the boot loader how much space after the kernel's load image it must
1165/// leave available for the kernel's use.  The boot loader must place its
1166/// constructed ZBI or other reserved areas at least this many bytes after
1167/// the kernel image.
1168///
1169/// # x86-64
1170///
1171/// The kernel assumes it was loaded at a fixed physical address of
1172/// 0x100000 (1MB).  `ZbiKernel.entry` is the absolute physical address
1173/// of the PC location where the kernel will start.
1174/// TODO(https://fxbug.dev/42098994): Perhaps this will change??
1175/// The processor is in 64-bit mode with direct virtual to physical
1176/// mapping covering the physical memory where the kernel and
1177/// bootloader-constructed ZBI were loaded.
1178/// The %rsi register holds the physical address of the
1179/// bootloader-constructed ZBI.
1180/// All other registers are unspecified.
1181///
1182/// # ARM64
1183///
1184/// `ZbiKernel.entry` is an offset from the beginning of the image
1185/// (i.e., the [`ZbiType::Container`] header before the [`ZbiType::KernelArm64`]
1186/// header) to the PC location in the image where the kernel will
1187/// start.  The processor is in physical address mode at EL1 or
1188/// above.  The kernel image and the bootloader-constructed ZBI each
1189/// can be loaded anywhere in physical memory.  The x0 register
1190/// holds the physical address of the bootloader-constructed ZBI.
1191/// All other registers are unspecified.
1192///
1193/// # RISCV64
1194///
1195/// `ZbiKernel.entry` is an offset from the beginning of the image (i.e.,
1196/// the [`ZbiType::Container`] header before the [`ZbiType::KernelRiscv64`] header)
1197/// to the PC location in the image where the kernel will start.  The
1198/// processor is in S mode, satp is zero, sstatus.SIE is zero.  The kernel
1199/// image and the bootloader-constructed ZBI each can be loaded anywhere in
1200/// physical memory, aligned to 4KiB.  The a0 register holds the HART ID,
1201/// and the a1 register holds the 4KiB-aligned physical address of the
1202/// bootloader-constructed ZBI.  All other registers are unspecified.
1203///
1204/// # C-reference type
1205/// ```c
1206/// typedef struct {
1207///   // Entry-point address.  The interpretation of this differs by machine.
1208///   uint64_t entry;
1209///
1210///   // Minimum amount (in bytes) of scratch memory that the kernel requires
1211///   // immediately after its load image.
1212///   uint64_t reserve_memory_size;
1213/// } zbi_kernel_t;
1214/// ```
1215pub type ZbiKernel = zbi_kernel_t;
1216
1217#[derive(Debug, PartialEq, Eq)]
1218/// Error values that can be returned by function in this library
1219pub enum ZbiError {
1220    /// Generic error
1221    Error,
1222    /// Bad type
1223    BadType,
1224    /// Bad magic
1225    BadMagic,
1226    /// Bad version
1227    BadVersion,
1228    /// Bad CRC
1229    BadCrc,
1230    /// Bad Alignment
1231    BadAlignment,
1232    /// Truncaded error
1233    Truncated,
1234    /// Too big
1235    TooBig,
1236    /// Incomplete Kernel
1237    IncompleteKernel,
1238    /// Bad ZBI length for this platform
1239    PlatformBadLength,
1240    /// CRC32 is not supported yet
1241    Crc32NotSupported,
1242    /// Length type overflow
1243    LengthOverflow,
1244}
1245
1246// Unfortunately thiserror is not available in `no_std` world.
1247// Thus `Display` implementation is required.
1248impl Display for ZbiError {
1249    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1250        let str = match self {
1251            ZbiError::Error => "Generic error",
1252            ZbiError::BadType => "Bad type",
1253            ZbiError::BadMagic => "Bad magic",
1254            ZbiError::BadVersion => "Bad version",
1255            ZbiError::BadCrc => "Bad CRC",
1256            ZbiError::BadAlignment => "Bad Alignment",
1257            ZbiError::Truncated => "Truncaded error",
1258            ZbiError::TooBig => "Too big",
1259            ZbiError::IncompleteKernel => "Incomplete Kernel",
1260            ZbiError::PlatformBadLength => "Bad ZBI length for this platform",
1261            ZbiError::Crc32NotSupported => "CRC32 is not supported yet",
1262            ZbiError::LengthOverflow => "Length type overflow",
1263        };
1264        write!(f, "{str}")
1265    }
1266}
1267
1268// Returns offset/idx of the first buffer element that will be aligned to `ZBI_ALIGNMENT`
1269fn get_align_buffer_offset(buffer: impl SplitByteSlice) -> ZbiResult<usize> {
1270    let addr = buffer.as_ptr() as usize;
1271    match addr % ZBI_ALIGNMENT_USIZE {
1272        0 => Ok(0),
1273        rem => {
1274            let tail_offset = ZBI_ALIGNMENT_USIZE - rem;
1275            if tail_offset > buffer.len() {
1276                return Err(ZbiError::TooBig);
1277            }
1278            Ok(tail_offset)
1279        }
1280    }
1281}
1282
1283// Check if buffer is ZbiAligned
1284fn is_zbi_aligned(buffer: &impl SplitByteSlice) -> ZbiResult<()> {
1285    match (buffer.as_ptr() as usize) % ZBI_ALIGNMENT_USIZE {
1286        0 => Ok(()),
1287        _ => Err(ZbiError::BadAlignment),
1288    }
1289}
1290
1291/// Merges two ZBI containers stored on the same buffer.
1292///
1293/// A typical use scenario is when the caller wants to append ZBI items that need to borrow the
1294/// existing container in order to be created, but wants to reuse the unused buffer for memory
1295/// optimization. The caller can split out the unused buffer, borrow the existing container,
1296/// creates a new container in the unused buffer, and then use this API to merge them together.
1297///
1298/// # Args:
1299///
1300/// * `buffer`: The buffer that contains the two ZBI containers. The first container must start
1301///   from the beginning.
1302/// * `second_start`: The offset to the second container in the buffer. The offset must be aligned
1303///   to `ZBI_ALIGNMENT_USIZE`.
1304///
1305/// # Returns
1306///
1307/// * On success returns an instance of `ZbiContainer` representing the merged container.
1308pub fn merge_within(buffer: &mut [u8], second_start: usize) -> ZbiResult<ZbiContainer<&mut [u8]>> {
1309    let first_container_size = ZbiContainer::parse(&mut buffer[..])?.container_size()?;
1310    if first_container_size > second_start {
1311        return Err(ZbiError::Error);
1312    }
1313    let second_payload_len =
1314        ZbiContainer::parse(&mut buffer[second_start..])?.get_payload_length_usize();
1315    // Copies the payload part directly to the end of the first container.
1316    let second_payload_start = second_start + size_of::<ZbiHeader>();
1317    let second_payload_end = second_payload_start + second_payload_len;
1318    buffer.copy_within(second_payload_start..second_payload_end, first_container_size);
1319    // Updates first ZBI header length
1320    let hdr = Ref::into_mut(Ref::<_, ZbiHeader>::from_prefix(&mut buffer[..]).unwrap().0);
1321    hdr.length = hdr
1322        .length
1323        .checked_add(u32::try_from(second_payload_len).unwrap())
1324        .ok_or(ZbiError::LengthOverflow)?;
1325    ZbiContainer::parse(buffer)
1326}
1327
1328#[cfg(test)]
1329mod tests {
1330    use super::*;
1331
1332    #[derive(Debug, PartialEq, Default)]
1333    struct TestZbiBuilder<'a> {
1334        buffer: &'a mut [u8],
1335        tail_offset: usize,
1336    }
1337    impl<'a> TestZbiBuilder<'a> {
1338        pub fn new(buffer: &'a mut [u8]) -> TestZbiBuilder<'a> {
1339            TestZbiBuilder { buffer, tail_offset: 0 }
1340        }
1341        pub fn add<T: IntoBytes + Immutable>(mut self, t: T) -> Self {
1342            t.write_to_prefix(&mut self.buffer[self.tail_offset..]).unwrap();
1343            self.tail_offset += size_of::<T>();
1344            self
1345        }
1346        pub fn add_slice(mut self, buf: &'a [u8]) -> Self {
1347            self.buffer[self.tail_offset..self.tail_offset + buf.len()].copy_from_slice(buf);
1348            self.tail_offset += buf.len();
1349            self
1350        }
1351        pub fn get_header_default() -> ZbiHeader {
1352            ZbiHeader {
1353                type_: ZbiType::KernelX64 as u32,
1354                length: 0,
1355                extra: ZBI_ITEM_MAGIC,
1356                flags: ZbiFlags::default().bits(),
1357                magic: ZBI_ITEM_MAGIC,
1358                crc32: ZBI_ITEM_NO_CRC32,
1359                ..Default::default()
1360            }
1361        }
1362        pub fn item_default(self, payload: &'a [u8]) -> Self {
1363            self.item(
1364                ZbiHeader {
1365                    length: payload.len().try_into().unwrap(),
1366                    ..Self::get_header_default()
1367                },
1368                payload,
1369            )
1370        }
1371        pub fn item(self, header: ZbiHeader, payload: &'a [u8]) -> Self {
1372            self.add(header).add_slice(&payload[..payload.len()])
1373        }
1374        pub fn container_hdr(self, payload_len: usize) -> Self {
1375            self.item(
1376                ZbiHeader {
1377                    type_: ZBI_TYPE_CONTAINER,
1378                    length: payload_len.try_into().unwrap(),
1379                    extra: ZBI_CONTAINER_MAGIC,
1380                    flags: ZbiFlags::default().bits(),
1381                    magic: ZBI_ITEM_MAGIC,
1382                    crc32: ZBI_ITEM_NO_CRC32,
1383                    ..Default::default()
1384                },
1385                &[],
1386            )
1387        }
1388        pub fn padding(mut self, val: u8, bytes: usize) -> Self {
1389            self.buffer[self.tail_offset..self.tail_offset + bytes].fill(val);
1390            self.tail_offset += bytes;
1391            self
1392        }
1393        pub fn align(mut self) -> Self {
1394            let rem = self.tail_offset % ZBI_ALIGNMENT_USIZE;
1395            if rem != 0 {
1396                self.tail_offset += ZBI_ALIGNMENT_USIZE - rem;
1397            }
1398            self
1399        }
1400        // Assumption is that first item in buffer is container header/item
1401        pub fn update_container_length(self) -> Self {
1402            let payload_length = self.tail_offset - size_of::<ZbiHeader>();
1403            let item = ZbiHeader {
1404                type_: ZBI_TYPE_CONTAINER,
1405                length: payload_length.try_into().unwrap(),
1406                extra: ZBI_CONTAINER_MAGIC,
1407                flags: ZbiFlags::default().bits(),
1408                magic: ZBI_ITEM_MAGIC,
1409                crc32: ZBI_ITEM_NO_CRC32,
1410                ..Default::default()
1411            };
1412            item.write_to_prefix(&mut self.buffer[..]).unwrap();
1413            self
1414        }
1415        pub fn build(self) -> &'a mut [u8] {
1416            &mut self.buffer[..self.tail_offset]
1417        }
1418    }
1419
1420    const ZBI_HEADER_SIZE: usize = core::mem::size_of::<ZbiHeader>();
1421    const ALIGNED_8_SIZE: usize = ZBI_HEADER_SIZE * 20;
1422    #[repr(align(8))]
1423    struct ZbiAligned([u8; ALIGNED_8_SIZE]);
1424    impl Default for ZbiAligned {
1425        fn default() -> Self {
1426            ZbiAligned(core::array::from_fn::<_, ALIGNED_8_SIZE, _>(|_| 0u8))
1427        }
1428    }
1429
1430    #[test]
1431    fn zbi_align_overflow() {
1432        assert!(usize::MAX > ZBI_ALIGNMENT.try_into().unwrap());
1433        assert_eq!(u32::try_from(ZBI_ALIGNMENT_USIZE).unwrap(), ZBI_ALIGNMENT);
1434    }
1435
1436    #[test]
1437    fn zbi_item_new() {
1438        let mut buffer = ZbiAligned::default();
1439        let expect = get_test_zbi_headers(1)[0];
1440
1441        let (item, _) = ZbiItem::new(
1442            &mut buffer.0[..],
1443            expect.type_.try_into().unwrap(),
1444            expect.extra,
1445            expect.get_flags(),
1446            expect.length.try_into().unwrap(),
1447        )
1448        .unwrap();
1449
1450        assert_eq!(*item.header, expect);
1451        assert_eq!(item.payload.len(), expect.length.try_into().unwrap());
1452
1453        let u32_array =
1454            Ref::<&[u8], [u32]>::from_prefix_with_elems(&buffer.0[..ZBI_HEADER_SIZE], 8).unwrap().0;
1455        assert_eq!(u32_array[0], expect.type_);
1456        assert_eq!(u32_array[1], expect.length);
1457        assert_eq!(u32_array[2], expect.extra);
1458        assert_eq!(u32_array[3], expect.flags);
1459        // u32_array[4..5] - reserved
1460        assert_eq!(u32_array[6], expect.magic);
1461        assert_eq!(u32_array[7], expect.crc32);
1462    }
1463
1464    #[test]
1465    fn zbi_item_new_too_small() {
1466        let mut buffer = ZbiAligned::default();
1467
1468        assert_eq!(
1469            ZbiItem::new(
1470                &mut buffer.0[..ZBI_HEADER_SIZE - 1],
1471                ZbiType::Container,
1472                0,
1473                ZbiFlags::default(),
1474                0
1475            ),
1476            Err(ZbiError::TooBig)
1477        );
1478    }
1479
1480    #[test]
1481    fn zbi_item_new_not_aligned() {
1482        let mut buffer = ZbiAligned::default();
1483        for offset in [1, 2, 4] {
1484            assert_eq!(
1485                ZbiItem::new(
1486                    &mut buffer.0[offset..ZBI_HEADER_SIZE + offset],
1487                    ZbiType::Container,
1488                    0,
1489                    ZbiFlags::default(),
1490                    0
1491                ),
1492                Err(ZbiError::BadAlignment)
1493            );
1494        }
1495    }
1496
1497    #[test]
1498    fn zbi_item_parse() {
1499        let mut buffer = ZbiAligned::default();
1500        let buffer = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0).build();
1501        let buffer_hdr_extra_expected =
1502            Ref::<&[u8], [u32]>::from_prefix_with_elems(&buffer[8..12], 1).unwrap().0[0];
1503
1504        let (zbi_item, _tail) = ZbiItem::parse(buffer).unwrap();
1505
1506        assert_eq!(zbi_item.header.extra, buffer_hdr_extra_expected);
1507    }
1508
1509    #[test]
1510    fn zbi_item_edit() {
1511        let mut buffer = ZbiAligned::default();
1512        let buffer_build = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0).build();
1513        let buffer_hdr_type =
1514            Ref::<&[u8], [u32]>::from_prefix_with_elems(&buffer_build[0..4], 1).unwrap().0[0];
1515        assert_eq!(buffer_hdr_type, ZBI_TYPE_CONTAINER);
1516
1517        let (mut zbi_item, _tail) = ZbiItem::parse(&mut buffer_build[..]).unwrap();
1518        zbi_item.header.type_ = ZBI_TYPE_KERNEL_X64;
1519        let buffer_hdr_type =
1520            Ref::<&[u8], [u32]>::from_prefix_with_elems(&buffer_build[0..4], 1).unwrap().0[0];
1521        assert_eq!(buffer_hdr_type, ZBI_TYPE_KERNEL_X64);
1522    }
1523
1524    #[test]
1525    fn zbi_container_new() {
1526        let mut buffer = ZbiAligned::default();
1527        let _container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1528        let expect_hdr = ZbiHeader {
1529            type_: ZBI_TYPE_CONTAINER,
1530            length: 0,
1531            extra: ZBI_CONTAINER_MAGIC,
1532            flags: ZbiFlags::default().bits(),
1533            magic: ZBI_ITEM_MAGIC,
1534            crc32: ZBI_ITEM_NO_CRC32,
1535            ..Default::default()
1536        };
1537
1538        let (item, _) = ZbiItem::parse(&buffer.0[..]).unwrap();
1539        assert_eq!(*item.header, expect_hdr);
1540        assert_eq!(item.payload.len(), 0);
1541    }
1542
1543    #[test]
1544    fn zbi_container_new_too_small() {
1545        let mut buffer = ZbiAligned::default();
1546        assert_eq!(ZbiContainer::new(&mut buffer.0[..ZBI_HEADER_SIZE - 1]), Err(ZbiError::TooBig));
1547    }
1548
1549    #[test]
1550    fn zbi_container_new_unaligned() {
1551        let mut buffer = ZbiAligned::default();
1552        for offset in [1, 2, 3, 4, 5, 6, 7] {
1553            assert_eq!(
1554                ZbiContainer::new(&mut buffer.0[offset..ZBI_HEADER_SIZE + offset]),
1555                Err(ZbiError::BadAlignment)
1556            );
1557        }
1558    }
1559
1560    #[test]
1561    fn zbi_container_parse_empty() {
1562        let mut buffer = ZbiAligned::default();
1563        let _container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1564        let expect_hdr = ZbiHeader {
1565            type_: ZBI_TYPE_CONTAINER,
1566            length: 0,
1567            extra: ZBI_CONTAINER_MAGIC,
1568            flags: ZbiFlags::default().bits(),
1569            magic: ZBI_ITEM_MAGIC,
1570            crc32: ZBI_ITEM_NO_CRC32,
1571            ..Default::default()
1572        };
1573
1574        let ZbiContainer { header, buffer: _, payload_length } =
1575            ZbiContainer::parse(&buffer.0[..]).unwrap();
1576        assert_eq!(*header, expect_hdr);
1577        assert_eq!(payload_length, 0);
1578    }
1579
1580    #[test]
1581    fn zbi_container_parse_bad_type() {
1582        let mut buffer = ZbiAligned::default();
1583        let _ = TestZbiBuilder::new(&mut buffer.0[..])
1584            .item(
1585                ZbiHeader {
1586                    type_: 0,
1587                    length: 0,
1588                    extra: ZBI_CONTAINER_MAGIC,
1589                    flags: ZbiFlags::default().bits(),
1590                    magic: ZBI_ITEM_MAGIC,
1591                    crc32: ZBI_ITEM_NO_CRC32,
1592                    ..Default::default()
1593                },
1594                &[],
1595            )
1596            .build();
1597
1598        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadType))
1599    }
1600
1601    #[test]
1602    fn zbi_container_parse_bad_magic() {
1603        let mut buffer = ZbiAligned::default();
1604        let _ = TestZbiBuilder::new(&mut buffer.0[..])
1605            .item(
1606                ZbiHeader {
1607                    type_: ZBI_TYPE_CONTAINER,
1608                    length: 0,
1609                    extra: ZBI_CONTAINER_MAGIC,
1610                    flags: ZbiFlags::default().bits(),
1611                    magic: 0,
1612                    crc32: ZBI_ITEM_NO_CRC32,
1613                    ..Default::default()
1614                },
1615                &[],
1616            )
1617            .build();
1618
1619        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadMagic))
1620    }
1621
1622    #[test]
1623    fn zbi_container_parse_bad_version() {
1624        let mut buffer = ZbiAligned::default();
1625        let _ = TestZbiBuilder::new(&mut buffer.0[..])
1626            .item(
1627                ZbiHeader {
1628                    type_: ZBI_TYPE_CONTAINER,
1629                    length: 0,
1630                    extra: ZBI_CONTAINER_MAGIC,
1631                    flags: (ZbiFlags::default() & !ZbiFlags::VERSION).bits(),
1632                    magic: ZBI_ITEM_MAGIC,
1633                    crc32: ZBI_ITEM_NO_CRC32,
1634                    ..Default::default()
1635                },
1636                &[],
1637            )
1638            .build();
1639
1640        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadVersion))
1641    }
1642
1643    #[test]
1644    fn zbi_container_parse_bad_crc32() {
1645        let mut buffer = ZbiAligned::default();
1646        let _ = TestZbiBuilder::new(&mut buffer.0[..])
1647            .item(
1648                ZbiHeader {
1649                    type_: ZBI_TYPE_CONTAINER,
1650                    length: 0,
1651                    extra: ZBI_CONTAINER_MAGIC,
1652                    flags: (ZbiFlags::default() & !ZbiFlags::CRC32).bits(),
1653                    magic: ZBI_ITEM_MAGIC,
1654                    crc32: 0,
1655                    ..Default::default()
1656                },
1657                &[],
1658            )
1659            .build();
1660
1661        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadCrc))
1662    }
1663
1664    #[test]
1665    fn zbi_container_parse_entries_bad_magic() {
1666        let mut buffer = ZbiAligned::default();
1667        let _ = TestZbiBuilder::new(&mut buffer.0[..])
1668            .item(
1669                ZbiHeader {
1670                    type_: ZBI_TYPE_CONTAINER,
1671                    length: 0,
1672                    extra: ZBI_CONTAINER_MAGIC,
1673                    flags: (ZbiFlags::default() & !ZbiFlags::CRC32).bits(),
1674                    magic: ZBI_ITEM_MAGIC,
1675                    crc32: 0,
1676                    ..Default::default()
1677                },
1678                &[],
1679            )
1680            .build();
1681
1682        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadCrc))
1683    }
1684
1685    #[test]
1686    fn zbi_container_parse() {
1687        let expected_payloads: [&[u8]; 9] = [
1688            &[1],
1689            &[1, 2],
1690            &[1, 2, 3],
1691            &[1, 2, 3, 4],
1692            &[1, 2, 3, 4, 5],
1693            &[1, 2, 3, 4, 5, 6],
1694            &[1, 2, 3, 4, 5, 6, 7],
1695            &[1, 2, 3, 4, 5, 6, 7, 8],
1696            &[1, 2, 3, 4, 5, 6, 7, 8, 9],
1697        ];
1698        let expected_items = expected_payloads.map(|x| {
1699            (
1700                ZbiHeader {
1701                    length: x.len().try_into().unwrap(),
1702                    ..TestZbiBuilder::get_header_default()
1703                },
1704                x,
1705            )
1706        });
1707        let mut buffer = ZbiAligned::default();
1708        let mut builder = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0);
1709        for payloads in expected_payloads {
1710            builder = builder.align().item_default(payloads).align()
1711        }
1712        let buffer = builder.update_container_length().build();
1713
1714        let zbi_container = ZbiContainer::parse(&*buffer).unwrap();
1715
1716        let mut it = zbi_container.iter();
1717        for (expected_hdr, expected_payload) in expected_items.iter() {
1718            let Some(item) = it.next() else { panic!("expecting iterator with value") };
1719            assert_eq!(Ref::into_ref(item.header), expected_hdr);
1720            assert_eq!(&item.payload[..], *expected_payload);
1721        }
1722        assert!(it.next().is_none());
1723    }
1724
1725    #[test]
1726    fn zbi_container_parse_unaligned() {
1727        let buffer = ZbiAligned::default();
1728        for offset in [1, 2, 3, 4, 5, 6, 7] {
1729            assert_eq!(ZbiContainer::parse(&buffer.0[offset..]), Err(ZbiError::BadAlignment));
1730        }
1731    }
1732
1733    #[test]
1734    fn zbi_container_parse_without_last_padding_fail_truncated() {
1735        let mut buffer = ZbiAligned::default();
1736        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
1737            .container_hdr(0)
1738            .align()
1739            .item_default(&[1])
1740            .align()
1741            .item_default(&[1, 2])
1742            .update_container_length()
1743            .build();
1744
1745        assert_eq!(ZbiContainer::parse(&*buffer), Err(ZbiError::Truncated));
1746    }
1747
1748    #[test]
1749    fn zbi_container_parse_error_payload_truncated() {
1750        let mut buffer = ZbiAligned::default();
1751        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
1752            .container_hdr(0)
1753            .add_slice(&[1])
1754            .update_container_length()
1755            .build();
1756
1757        assert_eq!(ZbiContainer::parse(&buffer[..buffer.len() - 1]), Err(ZbiError::Truncated));
1758    }
1759
1760    #[test]
1761    fn zbi_container_parse_error_truncated() {
1762        let mut buffer = ZbiAligned::default();
1763        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
1764            .container_hdr(0)
1765            .padding(0, 1)
1766            .update_container_length()
1767            .build();
1768
1769        assert_eq!(ZbiContainer::parse(&buffer[..buffer.len() - 1]), Err(ZbiError::Truncated));
1770    }
1771
1772    #[test]
1773    fn zbi_container_parse_bad_first_entry_marked() {
1774        let mut buffer = get_test_creference_buffer();
1775        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
1776
1777        container
1778            .iter_mut()
1779            .filter(|e| {
1780                [ZbiType::CmdLine as u32, ZbiType::StorageRamdisk as u32].contains(&e.header.type_)
1781            })
1782            .for_each(|mut e| e.header.magic = 0);
1783
1784        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadMagic));
1785    }
1786
1787    #[test]
1788    fn zbi_container_parse_bad_entry_magic() {
1789        let mut buffer = get_test_creference_buffer();
1790        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
1791
1792        container
1793            .iter_mut()
1794            .filter(|e| ZbiType::CmdLine as u32 == e.header.type_)
1795            .for_each(|mut e| e.header.magic = 0);
1796
1797        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadMagic));
1798    }
1799
1800    #[test]
1801    fn zbi_container_parse_bad_entry_version() {
1802        let mut buffer = get_test_creference_buffer();
1803        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
1804
1805        container
1806            .iter_mut()
1807            .filter(|e| ZbiType::CmdLine as u32 == e.header.type_)
1808            .for_each(|mut e| e.header.flags &= (!ZbiFlags::VERSION).bits());
1809
1810        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadVersion));
1811    }
1812
1813    #[test]
1814    fn zbi_container_parse_bad_entry_crc() {
1815        let mut buffer = get_test_creference_buffer();
1816        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
1817
1818        container.iter_mut().filter(|e| ZbiType::CmdLine as u32 == e.header.type_).for_each(
1819            |mut e| {
1820                e.header.flags &= (!ZbiFlags::CRC32).bits();
1821                e.header.crc32 = 0;
1822            },
1823        );
1824
1825        assert_eq!(ZbiContainer::parse(&buffer.0[..]), Err(ZbiError::BadCrc));
1826    }
1827
1828    #[test]
1829    fn zbi_container_new_entry() {
1830        let mut buffer = ZbiAligned::default();
1831        let new_entries = get_test_entries_all();
1832
1833        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1834        for (e, payload) in &new_entries {
1835            container.get_next_payload().unwrap()[..payload.len()].copy_from_slice(payload);
1836            container
1837                .create_entry(e.type_.try_into().unwrap(), e.extra, e.get_flags(), payload.len())
1838                .unwrap();
1839        }
1840
1841        let container = ZbiContainer::parse(&buffer.0[..]).unwrap();
1842        check_container_made_of(&container, &new_entries);
1843    }
1844
1845    #[test]
1846    fn zbi_container_new_entry_crc32_not_supported() {
1847        let mut buffer = ZbiAligned::default();
1848        let (new_entry, payload) = get_test_entry_nonempty_payload();
1849        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1850        assert_eq!(
1851            container.create_entry_with_payload(
1852                new_entry.type_.try_into().unwrap(),
1853                new_entry.extra,
1854                ZbiFlags::default() | ZbiFlags::CRC32,
1855                payload,
1856            ),
1857            Err(ZbiError::Crc32NotSupported)
1858        );
1859    }
1860
1861    #[test]
1862    fn zbi_container_new_entry_no_space_left() {
1863        let mut buffer = ZbiAligned::default();
1864        let new_entry = get_test_entry_empty_payload().0;
1865
1866        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1867
1868        for _ in 1..(ALIGNED_8_SIZE / ZBI_HEADER_SIZE) {
1869            container
1870                .create_entry(
1871                    new_entry.type_.try_into().unwrap(),
1872                    new_entry.extra,
1873                    new_entry.get_flags(),
1874                    new_entry.length.try_into().unwrap(),
1875                )
1876                .unwrap();
1877        }
1878
1879        // Now there is not enough space and it should fail
1880        assert_eq!(
1881            container.create_entry(
1882                new_entry.type_.try_into().unwrap(),
1883                new_entry.extra,
1884                new_entry.get_flags(),
1885                new_entry.length.try_into().unwrap(),
1886            ),
1887            Err(ZbiError::TooBig)
1888        );
1889    }
1890
1891    #[test]
1892    fn zbi_container_new_entry_no_space_for_header() {
1893        let mut buffer = ZbiAligned::default();
1894        let new_entry = get_test_entry_empty_payload().0;
1895
1896        let buf_len = 2 * core::mem::size_of::<ZbiHeader>() - 1;
1897        let mut container = ZbiContainer::new(&mut buffer.0[..buf_len]).unwrap();
1898
1899        // Now there is not enough space for header and it should fail
1900        assert_eq!(
1901            container.create_entry(
1902                new_entry.type_.try_into().unwrap(),
1903                new_entry.extra,
1904                new_entry.get_flags(),
1905                0,
1906            ),
1907            Err(ZbiError::TooBig)
1908        );
1909    }
1910
1911    #[test]
1912    fn zbi_container_new_entry_no_space_for_payload() {
1913        let mut buffer = ZbiAligned::default();
1914        let (new_entry, payload) = get_test_entry_nonempty_payload();
1915
1916        let buf_len = 2 * core::mem::size_of::<ZbiHeader>() + payload.len() - 1;
1917        let mut container = ZbiContainer::new(&mut buffer.0[..buf_len]).unwrap();
1918
1919        // Now there is not enough space for header and it should fail
1920        assert_eq!(
1921            container.create_entry(
1922                new_entry.type_.try_into().unwrap(),
1923                new_entry.extra,
1924                new_entry.get_flags(),
1925                new_entry.length.try_into().unwrap(),
1926            ),
1927            Err(ZbiError::TooBig)
1928        );
1929    }
1930
1931    #[test]
1932    fn zbi_container_new_entry_with_payload_just_enough_to_fit_no_align() {
1933        let mut buffer = ZbiAligned::default();
1934        let (new_entry, _payload) = get_test_entry_empty_payload();
1935        let payload = [0; ZBI_ALIGNMENT_USIZE];
1936        let buf_len = 2 * core::mem::size_of::<ZbiHeader>()
1937            + payload.len()
1938            + (/*alignment*/ZBI_ALIGNMENT_USIZE - payload.len());
1939        let mut container = ZbiContainer::new(&mut buffer.0[..buf_len]).unwrap();
1940        assert_eq!(
1941            container.create_entry(
1942                new_entry.type_.try_into().unwrap(),
1943                new_entry.extra,
1944                new_entry.get_flags(),
1945                payload.len(),
1946            ),
1947            Ok(())
1948        );
1949    }
1950    #[test]
1951    fn zbi_container_new_entry_with_payload_just_enough_to_fit_with_alignment() {
1952        let mut buffer = ZbiAligned::default();
1953        let (new_entry, payload) = get_test_entry_nonempty_payload();
1954        let buf_len = 2 * core::mem::size_of::<ZbiHeader>()
1955            + payload.len()
1956            + (ZBI_ALIGNMENT_USIZE - payload.len()/*alignment*/);
1957        let mut container = ZbiContainer::new(&mut buffer.0[..buf_len]).unwrap();
1958        assert_eq!(
1959            container.create_entry(
1960                new_entry.type_.try_into().unwrap(),
1961                new_entry.extra,
1962                new_entry.get_flags(),
1963                new_entry.length.try_into().unwrap(),
1964            ),
1965            Ok(())
1966        );
1967    }
1968
1969    #[test]
1970    fn zbi_container_new_entry_payload_too_big() {
1971        let mut buffer = ZbiAligned::default();
1972        let (new_entry, _payload) = get_test_entry_nonempty_payload();
1973        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1974        assert_eq!(
1975            container.create_entry(
1976                new_entry.type_.try_into().unwrap(),
1977                new_entry.extra,
1978                new_entry.get_flags(),
1979                usize::MAX,
1980            ),
1981            Err(ZbiError::TooBig)
1982        );
1983    }
1984
1985    #[test]
1986    fn zbi_container_new_entry_no_space_left_unaligned() {
1987        let mut buffer = ZbiAligned::default();
1988        let new_entry = get_test_entry_empty_payload().0;
1989
1990        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
1991
1992        for _ in 1..(ALIGNED_8_SIZE / ZBI_HEADER_SIZE) {
1993            container
1994                .create_entry(
1995                    new_entry.type_.try_into().unwrap(),
1996                    new_entry.extra,
1997                    new_entry.get_flags(),
1998                    new_entry.length.try_into().unwrap(),
1999                )
2000                .unwrap();
2001        }
2002
2003        // Now there is not enough space and it should fail
2004        assert_eq!(
2005            container.create_entry(
2006                new_entry.type_.try_into().unwrap(),
2007                new_entry.extra,
2008                new_entry.get_flags(),
2009                new_entry.length.try_into().unwrap(),
2010            ),
2011            Err(ZbiError::TooBig)
2012        );
2013    }
2014
2015    #[test]
2016    fn zbi_container_extend_new() {
2017        let mut buffer = ZbiAligned::default();
2018        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2019            .container_hdr(0)
2020            .align()
2021            .item_default(&[1])
2022            .align()
2023            .update_container_length()
2024            .build();
2025        let container_0 = ZbiContainer::parse(buffer).unwrap();
2026        let mut buffer = ZbiAligned::default();
2027        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2028            .container_hdr(0)
2029            .align()
2030            .item_default(&[1, 2])
2031            .align()
2032            .update_container_length()
2033            .build();
2034        let container_1 = ZbiContainer::parse(buffer).unwrap();
2035
2036        let mut buffer = ZbiAligned::default();
2037        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2038        container.extend(&container_0).unwrap();
2039        container.extend(&container_1).unwrap();
2040
2041        let container_check = ZbiContainer::parse(&buffer.0[..]).unwrap();
2042        assert_eq!(container_check.iter().count(), 2);
2043        assert_eq!(container_0.iter().count(), 1);
2044        assert_eq!(container_1.iter().count(), 1);
2045        let mut it = container_check.iter();
2046        assert_eq!(it.next().unwrap(), container_0.iter().next().unwrap());
2047        assert_eq!(it.next().unwrap(), container_1.iter().next().unwrap());
2048        assert!(it.next().is_none());
2049    }
2050
2051    #[test]
2052    fn zbi_container_extend_unaligned() {
2053        let mut buffer_0 = ZbiAligned::default();
2054        let mut container_0 = ZbiContainer::new(&mut buffer_0.0[..]).unwrap();
2055        container_0
2056            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"0")
2057            .unwrap();
2058        let container_size_0 = container_0.container_size().unwrap();
2059        // Copies to unaligned address.
2060        let mut unaligned_0 = ZbiAligned::default();
2061        let unaligned_0 = &mut unaligned_0.0[1..][..container_size_0];
2062        unaligned_0.clone_from_slice(&buffer_0.0[..unaligned_0.len()]);
2063
2064        let mut buffer_1 = ZbiAligned::default();
2065        let mut container_1 = ZbiContainer::new(&mut buffer_1.0[..]).unwrap();
2066        container_1
2067            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"1")
2068            .unwrap();
2069        let container_size_1 = container_1.container_size().unwrap();
2070        // Copies to unaligned address.
2071        let mut unaligned_1 = ZbiAligned::default();
2072        let unaligned_1 = &mut unaligned_1.0[1..][..container_size_1];
2073        unaligned_1.clone_from_slice(&buffer_1.0[..unaligned_1.len()]);
2074
2075        let mut buffer = ZbiAligned::default();
2076        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2077        let container_0 = ZbiContainer::parse(&mut buffer_0.0[..]).unwrap();
2078        let container_1 = ZbiContainer::parse(&mut buffer_1.0[..]).unwrap();
2079        container.extend_unaligned(unaligned_0).unwrap();
2080        container.extend_unaligned(unaligned_1).unwrap();
2081        let mut it = container.iter();
2082        assert_eq!(it.next().unwrap(), container_0.iter().next().unwrap());
2083        assert_eq!(it.next().unwrap(), container_1.iter().next().unwrap());
2084        assert!(it.next().is_none());
2085    }
2086
2087    #[test]
2088    fn zbi_container_extend_unaligned_too_big() {
2089        let mut buffer = ZbiAligned::default();
2090        let buffer_len = buffer.0.len();
2091        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2092        let remains = buffer_len - container.container_size().unwrap();
2093        let mut extend = ZbiAligned::default();
2094        let _ = ZbiContainer::new(&mut extend.0[..]).unwrap();
2095        container.extend_unaligned(&extend.0[..remains]).unwrap();
2096        // Should fail since there is not enough space to copy the incoming buffer first, despite
2097        // that the container to extend has zero payload.
2098        assert!(container.extend_unaligned(&extend.0[..remains + 1]).is_err());
2099    }
2100
2101    #[test]
2102    fn zbi_container_extend_unaligned_invalid_container() {
2103        let mut buffer = ZbiAligned::default();
2104        let buffer_len = buffer.0.len();
2105        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2106        let remains = buffer_len - container.container_size().unwrap();
2107        assert!(container.extend_unaligned(&vec![0u8; remains][..]).is_err());
2108    }
2109
2110    #[test]
2111    fn zbi_container_extend_with_empty() {
2112        let mut buffer = ZbiAligned::default();
2113        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2114            .container_hdr(0)
2115            .align()
2116            .item_default(&[1])
2117            .align()
2118            .update_container_length()
2119            .build();
2120        let mut container_0 = ZbiContainer::parse(&mut buffer[..]).unwrap();
2121        let mut buffer = ZbiAligned::default();
2122        let buffer = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0).build();
2123        let container_1 = ZbiContainer::parse(&mut buffer[..]).unwrap();
2124
2125        assert_eq!(container_0.iter().count(), 1);
2126        container_0.extend(&container_1).unwrap();
2127        assert_eq!(container_0.iter().count(), 1);
2128    }
2129
2130    #[test]
2131    fn zbi_container_extend_full() {
2132        let mut buffer = ZbiAligned::default();
2133        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2134            .container_hdr(0)
2135            .align()
2136            .update_container_length()
2137            .build();
2138        let mut container_full = ZbiContainer::parse(&mut buffer[..]).unwrap();
2139        let mut buffer = ZbiAligned::default();
2140        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2141            .container_hdr(0)
2142            .align()
2143            .item_default(&[1, 2])
2144            .align()
2145            .update_container_length()
2146            .build();
2147        let container = ZbiContainer::parse(buffer).unwrap();
2148
2149        assert_eq!(container_full.extend(&container), Err(ZbiError::TooBig));
2150    }
2151
2152    #[test]
2153    fn zbi_container_extend_1_byte_short() {
2154        let mut buffer = ZbiAligned::default();
2155        let _ = TestZbiBuilder::new(&mut buffer.0[..])
2156            .container_hdr(0)
2157            .align()
2158            .update_container_length()
2159            .build();
2160        let mut container_small =
2161            ZbiContainer::parse(&mut buffer.0[..ZBI_HEADER_SIZE * 2 + ZBI_ALIGNMENT_USIZE - 1])
2162                .unwrap();
2163        let mut buffer = ZbiAligned::default();
2164        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2165            .container_hdr(0)
2166            .align()
2167            .item_default(&[1, 2])
2168            .align()
2169            .update_container_length()
2170            .build();
2171        let container = ZbiContainer::parse(buffer).unwrap();
2172
2173        assert_eq!(container_small.extend(&container), Err(ZbiError::TooBig));
2174    }
2175
2176    #[test]
2177    fn zbi_container_extend_use_all_buffer() {
2178        let mut buffer = ZbiAligned::default();
2179        let _ = TestZbiBuilder::new(&mut buffer.0[..])
2180            .container_hdr(0)
2181            .align()
2182            .update_container_length()
2183            .build();
2184        let mut container_full = ZbiContainer::parse(
2185            &mut buffer.0[..ZBI_HEADER_SIZE + ZBI_HEADER_SIZE + ZBI_ALIGNMENT_USIZE],
2186        )
2187        .unwrap();
2188        let mut buffer = ZbiAligned::default();
2189        let buffer = TestZbiBuilder::new(&mut buffer.0[..])
2190            .container_hdr(0)
2191            .align()
2192            .item_default(&[1, 2])
2193            .align()
2194            .update_container_length()
2195            .build();
2196        let container = ZbiContainer::parse(buffer).unwrap();
2197
2198        assert!(container_full.extend(&container).is_ok());
2199    }
2200
2201    #[test]
2202    fn zbi_container_new_entry_with_payload() {
2203        let mut buffer = ZbiAligned::default();
2204        let new_entries = get_test_entries_all();
2205
2206        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2207        for (e, payload) in &new_entries {
2208            container
2209                .create_entry_with_payload(
2210                    e.type_.try_into().unwrap(),
2211                    e.extra,
2212                    e.get_flags(),
2213                    payload,
2214                )
2215                .unwrap();
2216        }
2217
2218        let container = ZbiContainer::parse(&buffer.0[..]).unwrap();
2219        check_container_made_of(&container, &new_entries);
2220    }
2221
2222    fn check_container_made_of<B: SplitByteSlice + PartialEq>(
2223        container: &ZbiContainer<B>,
2224        expected_items: &[(ZbiHeader, &[u8])],
2225    ) {
2226        // Check container header length
2227        assert_eq!(
2228            container.get_payload_length_usize(),
2229            expected_items.len() * ZBI_HEADER_SIZE // add header len
2230                + expected_items // add payloads
2231                    .iter()
2232                    .map(|(_, payload)| -> usize {
2233                        payload.len() +
2234                        match payload.len() % ZBI_ALIGNMENT_USIZE{
2235                            0 => 0,
2236                            rem => ZBI_ALIGNMENT_USIZE- rem,
2237                        }
2238                    })
2239                    .sum::<usize>()
2240        );
2241        assert_eq!(
2242            container.container_size().unwrap(),
2243            container.get_payload_length_usize() + size_of::<ZbiHeader>()
2244        );
2245
2246        // Check if container elements match provided items
2247        let mut it = expected_items.iter();
2248        for b in container.iter() {
2249            let (header, payload) = it.next().unwrap();
2250            assert_eq!(*b.header, *header);
2251            assert_eq!(b.payload.len(), payload.len());
2252            assert!(b.payload.iter().zip(payload.iter()).all(|(a, b)| a == b))
2253        }
2254    }
2255
2256    #[test]
2257    fn zbi_container_get_next_paylad() {
2258        let mut buffer = ZbiAligned::default();
2259        let new_entries = get_test_entries_all();
2260
2261        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2262
2263        for (e, payload) in &new_entries {
2264            let next_payload: &mut [u8] = container.get_next_payload().unwrap();
2265            next_payload[..payload.len()].copy_from_slice(payload);
2266            container
2267                .create_entry(e.type_.try_into().unwrap(), e.extra, e.get_flags(), payload.len())
2268                .unwrap();
2269        }
2270
2271        let container = ZbiContainer::parse(&buffer.0[..]).unwrap();
2272        check_container_made_of(&container, &new_entries);
2273    }
2274
2275    #[test]
2276    fn zbi_container_get_next_paylad_length() {
2277        let mut buffer = ZbiAligned::default();
2278        // Expected payload length is same as buffer - container header - item header
2279        let expected_payload_len = buffer.0.len() - 2 * core::mem::size_of::<ZbiHeader>();
2280
2281        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2282        let next_payload: &mut [u8] = container.get_next_payload().unwrap();
2283
2284        assert_eq!(next_payload.len(), expected_payload_len);
2285    }
2286
2287    #[test]
2288    fn zbi_container_get_next_paylad_only_header_can_fit() {
2289        let mut buffer = ZbiAligned::default();
2290        // Buffer length that only fits container and item header.
2291        let len = 2 * core::mem::size_of::<ZbiHeader>();
2292
2293        let mut container = ZbiContainer::new(&mut buffer.0[..len]).unwrap();
2294        let next_payload: &mut [u8] = container.get_next_payload().unwrap();
2295
2296        assert_eq!(next_payload.len(), 0);
2297    }
2298
2299    #[test]
2300    fn zbi_container_get_next_paylad_header_cant_fit() {
2301        let mut buffer = ZbiAligned::default();
2302        // Buffer length that only fits container but not item header.
2303        let len = 2 * core::mem::size_of::<ZbiHeader>() - 1;
2304
2305        let mut container = ZbiContainer::new(&mut buffer.0[..len]).unwrap();
2306        assert_eq!(container.get_next_payload(), Err(ZbiError::TooBig));
2307    }
2308
2309    #[test]
2310    fn zbi_container_get_next_paylad_length_overflow() {
2311        let mut buffer = ZbiAligned::default();
2312        // Buffer length that only fits container but not item header.
2313        let len = 2 * core::mem::size_of::<ZbiHeader>() - 1;
2314
2315        let mut container = ZbiContainer::new(&mut buffer.0[..len]).unwrap();
2316        container.payload_length = usize::MAX; // Pretend that length is too big and cause
2317                                               // overflow in following functions
2318        assert_eq!(container.get_next_payload(), Err(ZbiError::LengthOverflow));
2319    }
2320
2321    /* Binary blob for parsing container was generated from C implementation, running following
2322     * test:
2323     * --- a/src/firmware/lib/zbi/test/zbi.cc
2324     * +++ b/src/firmware/lib/zbi/test/zbi.cc
2325     * @@ -926,3 +926,21 @@ TEST(ZbiTests, ZbiTestNoOverflow) {
2326     *
2327     *    ASSERT_NE(zbi_extend(dst_buffer, kUsableBufferSize, src_buffer), ZBI_RESULT_OK);
2328     *  }
2329     * +
2330     * +TEST(ZbiTests, ZbiTestGenDataForRustTest) {
2331     * +  const size_t kExtraBytes = 10;
2332     * +  uint8_t* buffer = get_test_zbi_extra(kExtraBytes);
2333     * +  // Based on `get_test_zbi_extra()` implementation this is buffer size
2334     * +  const size_t kBufferSize = sizeof(test_zbi_t) + kExtraBytes;
2335     * +
2336     * +  printf("buffer length = %zu\n", kBufferSize);
2337     * +  printf("----BEGIN----\n");
2338     * +  for (size_t i = 0; i < kBufferSize; i++) {
2339     * +    if (i % 16 == 0) {
2340     * +      printf("\n");
2341     * +    }
2342     * +    printf("%02x", buffer[i]);
2343     * +  }
2344     * +  printf("\n");
2345     * +  printf("-----END-----\n");
2346     * +}
2347     */
2348    #[test]
2349    fn zbi_container_parse_c_reference() {
2350        let ref_buffer = get_test_creference_buffer_vec();
2351        let expected_container_hdr = ZbiHeader {
2352            type_: ZBI_TYPE_CONTAINER,
2353            extra: ZBI_CONTAINER_MAGIC,
2354            length: 184,
2355            magic: ZBI_ITEM_MAGIC,
2356            crc32: ZBI_ITEM_NO_CRC32,
2357            flags: ZbiFlags::default().bits(),
2358            ..Default::default()
2359        };
2360        // Reference C implementation test uses cstrings for payload. That is why we need '\0' at
2361        // the end of the string.
2362        let expected_entries = get_test_entries_creference();
2363
2364        let mut buffer = ZbiAligned::default();
2365        buffer.0[..ref_buffer.len()].clone_from_slice(&ref_buffer);
2366
2367        let container = ZbiContainer::parse(&buffer.0[..ref_buffer.len()]).unwrap();
2368        assert_eq!(*container.header, expected_container_hdr);
2369        check_container_made_of(&container, &expected_entries);
2370    }
2371
2372    #[test]
2373    fn zbi_container_new_entry_iterate() {
2374        let mut buffer = ZbiAligned::default();
2375        let new_entry = get_test_entry_nonempty_payload();
2376
2377        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2378        let (e, payload) = new_entry;
2379        container
2380            .create_entry_with_payload(e.type_.try_into().unwrap(), e.extra, e.get_flags(), payload)
2381            .unwrap();
2382
2383        assert_eq!(container.iter().count(), 1);
2384        let mut it = container.iter();
2385        let item = it.next().unwrap();
2386        assert_eq!(*item.header, e);
2387        assert_eq!(&item.payload[..], payload);
2388        assert!(it.next().is_none());
2389    }
2390
2391    #[test]
2392    fn zbi_container_new_entry_mut_iterate() {
2393        let mut buffer = ZbiAligned::default();
2394        let new_entry = get_test_entry_nonempty_payload();
2395
2396        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2397        let (e, payload) = new_entry;
2398        container
2399            .create_entry_with_payload(e.type_.try_into().unwrap(), e.extra, e.get_flags(), payload)
2400            .unwrap();
2401
2402        {
2403            let mut item = container.iter_mut().next().unwrap();
2404            assert_ne!(item.header.type_, ZbiType::DebugData.into());
2405            item.header.type_ = ZbiType::DebugData.into();
2406        }
2407        {
2408            let item = container.iter().next().unwrap();
2409            assert_eq!(item.header.type_, ZbiType::DebugData.into());
2410        }
2411    }
2412
2413    #[test]
2414    fn zbi_container_parse_new_entry_mut_iterate() {
2415        let mut buffer = ZbiAligned::default();
2416        let _ = TestZbiBuilder::new(&mut buffer.0[..])
2417            .container_hdr(0)
2418            .align()
2419            .item_default(&[1, 2])
2420            .align()
2421            .update_container_length()
2422            .build();
2423        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
2424        let new_entry = get_test_entry_nonempty_payload();
2425
2426        let (e, payload) = new_entry;
2427        container
2428            .create_entry_with_payload(e.type_.try_into().unwrap(), e.extra, e.get_flags(), payload)
2429            .unwrap();
2430
2431        assert_eq!(container.iter().count(), 2);
2432        for mut item in container.iter_mut() {
2433            assert_ne!(item.header.type_, ZbiType::DebugData.into());
2434            item.header.type_ = ZbiType::DebugData.into();
2435        }
2436
2437        for item in container.iter() {
2438            assert_eq!(item.header.type_, ZbiType::DebugData.into());
2439        }
2440    }
2441
2442    #[test]
2443    fn zbi_container_iterate_empty() {
2444        let mut buffer = ZbiAligned::default();
2445        let _ = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0).build();
2446
2447        assert_eq!(ZbiContainer::parse(&buffer.0[..]).unwrap().iter().count(), 0);
2448        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
2449        assert_eq!(container.iter().count(), 0);
2450        assert_eq!(container.iter_mut().count(), 0);
2451    }
2452
2453    fn byteslice_cmp(byteslice: impl SplitByteSlice, slice: &[u8]) -> bool {
2454        byteslice.len() == slice.len() && byteslice.iter().zip(slice.iter()).all(|(a, b)| a == b)
2455    }
2456
2457    #[test]
2458    fn zbi_container_iterate_ref() {
2459        let mut buffer = get_test_creference_buffer();
2460        let container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
2461
2462        assert_eq!(container.iter().count(), 4);
2463        assert!(container.iter().zip(get_test_entries_creference().iter()).all(
2464            |(it, (entry, payload))| { *it.header == *entry && byteslice_cmp(it.payload, payload) }
2465        ));
2466    }
2467
2468    #[test]
2469    fn zbi_container_iterate_modify() {
2470        let mut buffer = ZbiAligned::default();
2471        let _ = TestZbiBuilder::new(&mut buffer.0[..])
2472            .container_hdr(0)
2473            .align()
2474            .item_default(b"A")
2475            .align()
2476            .item_default(b"BB")
2477            .align()
2478            .item_default(b"CCC")
2479            .align()
2480            .update_container_length()
2481            .build();
2482        let mut container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
2483
2484        container.iter_mut().for_each(|mut item| item.payload[0] = b'D');
2485
2486        assert!(container.iter().all(|b| b.payload[0] == b'D'));
2487    }
2488
2489    #[test]
2490    fn zbi_bad_type() {
2491        assert_eq!(ZbiType::try_from(0), Err(ZbiError::BadType));
2492    }
2493
2494    fn get_all_zbi_type_values() -> Vec<ZbiType> {
2495        // strum and enum-iterator crates are not available at the moment, so just hard coding
2496        // values
2497        vec![
2498            ZbiType::KernelX64,
2499            ZbiType::KernelArm64,
2500            ZbiType::KernelRiscv64,
2501            ZbiType::Container,
2502            ZbiType::Discard,
2503            ZbiType::StorageRamdisk,
2504            ZbiType::StorageBootFs,
2505            ZbiType::StorageKernel,
2506            ZbiType::StorageBootFsFactory,
2507            ZbiType::CmdLine,
2508            ZbiType::CrashLog,
2509            ZbiType::Nvram,
2510            ZbiType::PlatformId,
2511            ZbiType::DrvBoardInfo,
2512            ZbiType::CpuTopology,
2513            ZbiType::MemConfig,
2514            ZbiType::KernelDriver,
2515            ZbiType::AcpiRsdp,
2516            ZbiType::Smbios,
2517            ZbiType::EfiSystemTable,
2518            ZbiType::EfiMemoryAttributesTable,
2519            ZbiType::FrameBuffer,
2520            ZbiType::ImageArgs,
2521            ZbiType::BootVersion,
2522            ZbiType::DrvMacAddress,
2523            ZbiType::DrvPartitionMap,
2524            ZbiType::DrvBoardPrivate,
2525            ZbiType::HwRebootReason,
2526            ZbiType::SerialNumber,
2527            ZbiType::BootloaderFile,
2528            ZbiType::DeviceTree,
2529            ZbiType::SecureEntropy,
2530            ZbiType::DebugData,
2531        ]
2532    }
2533
2534    fn get_kernel_zbi_types() -> Vec<ZbiType> {
2535        vec![ZbiType::KernelRiscv64, ZbiType::KernelX64, ZbiType::KernelArm64]
2536    }
2537    fn get_metadata_zbi_types() -> Vec<ZbiType> {
2538        vec![
2539            ZbiType::DrvBoardInfo,
2540            ZbiType::DrvMacAddress,
2541            ZbiType::DrvPartitionMap,
2542            ZbiType::DrvBoardPrivate,
2543        ]
2544    }
2545
2546    #[test]
2547    fn zbi_type_is_kernel() {
2548        assert!(get_kernel_zbi_types().iter().all(|t| t.is_kernel()))
2549    }
2550
2551    #[test]
2552    fn zbi_type_is_not_kernel() {
2553        assert!(get_all_zbi_type_values()
2554            .iter()
2555            .filter(|v| !get_kernel_zbi_types().contains(v))
2556            .all(|v| !v.is_kernel()));
2557    }
2558
2559    #[test]
2560    fn zbi_type_is_driver_metadata() {
2561        assert!(get_metadata_zbi_types().iter().all(|t| t.is_driver_metadata()));
2562    }
2563
2564    #[test]
2565    fn zbi_type_is_not_driver_metadata() {
2566        assert!(get_all_zbi_type_values()
2567            .iter()
2568            .filter(|v| !get_metadata_zbi_types().contains(v))
2569            .all(|v| !v.is_driver_metadata()));
2570    }
2571
2572    #[test]
2573    fn zbi_default_type_has_version() {
2574        assert!(ZbiFlags::default().contains(ZbiFlags::VERSION));
2575    }
2576
2577    #[test]
2578    fn zbi_get_bootable_kernel_item() {
2579        let mut buffer = ZbiAligned::default();
2580        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2581
2582        container
2583            .create_entry_with_payload(ZBI_ARCH_KERNEL_TYPE, 0, ZbiFlags::default(), &[])
2584            .unwrap();
2585
2586        assert!(container.get_bootable_kernel_item().is_ok());
2587    }
2588
2589    #[cfg(target_arch = "x86_64")]
2590    #[test]
2591    fn zbi_iget_bootable_kernel_item_reference() {
2592        let ref_buffer = get_test_creference_buffer_vec();
2593        let mut buffer = ZbiAligned::default();
2594        buffer.0[..ref_buffer.len()].clone_from_slice(&ref_buffer);
2595        let container = ZbiContainer::parse(&buffer.0[..]).unwrap();
2596        assert!(container.get_bootable_kernel_item().is_ok());
2597    }
2598
2599    #[test]
2600    fn zbi_get_bootable_kernel_item_empty_container() {
2601        let mut buffer = ZbiAligned::default();
2602        let container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2603        assert_eq!(container.get_bootable_kernel_item(), Err(ZbiError::Truncated));
2604    }
2605
2606    #[test]
2607    fn zbi_get_bootable_kernel_item_wrong_arch() {
2608        let mut buffer = ZbiAligned::default();
2609        let _ = TestZbiBuilder::new(&mut buffer.0[..])
2610            .container_hdr(0)
2611            .align()
2612            .item(ZbiHeader { type_: 0, ..TestZbiBuilder::get_header_default() }, &[])
2613            .align()
2614            .update_container_length()
2615            .build();
2616        let container = ZbiContainer::parse(&mut buffer.0[..]).unwrap();
2617        assert_eq!(container.get_bootable_kernel_item(), Err(ZbiError::IncompleteKernel));
2618    }
2619
2620    #[test]
2621    fn zbi_get_bootable_kernel_item_not_first_item_fail() {
2622        let mut buffer = ZbiAligned::default();
2623        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2624
2625        container
2626            .create_entry_with_payload(ZbiType::DebugData, 0, ZbiFlags::default(), &[])
2627            .unwrap();
2628        container
2629            .create_entry_with_payload(ZBI_ARCH_KERNEL_TYPE, 0, ZbiFlags::default(), &[])
2630            .unwrap();
2631
2632        assert_eq!(container.get_bootable_kernel_item(), Err(ZbiError::IncompleteKernel));
2633    }
2634
2635    #[test]
2636    fn zbi_get_kernel_entry_and_reserved_memory_size() {
2637        let mut buffer = ZbiAligned::default();
2638        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2639        let bytes = [1u64.to_le_bytes(), 2u64.to_le_bytes()].concat();
2640        container
2641            .create_entry_with_payload(ZBI_ARCH_KERNEL_TYPE, 0, ZbiFlags::default(), &bytes)
2642            .unwrap();
2643        assert_eq!(container.get_kernel_entry_and_reserved_memory_size().unwrap(), (1, 2));
2644    }
2645
2646    #[test]
2647    fn zbi_get_kernel_entry_and_reserved_memory_size_truncated() {
2648        let mut buffer = ZbiAligned::default();
2649        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2650        container
2651            .create_entry_with_payload(ZBI_ARCH_KERNEL_TYPE, 0, ZbiFlags::default(), &[])
2652            .unwrap();
2653        assert!(container.get_kernel_entry_and_reserved_memory_size().is_err());
2654    }
2655
2656    #[test]
2657    fn zbi_get_buffer_size_for_kernel_relocation() {
2658        let mut buffer = ZbiAligned::default();
2659        let mut container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2660        let bytes = [0u64.to_le_bytes(), 1024u64.to_le_bytes()].concat();
2661        container
2662            .create_entry_with_payload(ZBI_ARCH_KERNEL_TYPE, 0, ZbiFlags::default(), &bytes)
2663            .unwrap();
2664        assert_eq!(
2665            container.get_buffer_size_for_kernel_relocation().unwrap(),
2666            container.container_size().unwrap() + 1024
2667        );
2668    }
2669
2670    #[test]
2671    fn zbi_header_alignment() {
2672        assert_eq!(core::mem::size_of::<ZbiHeader>() & ZBI_ALIGNMENT_USIZE, 0);
2673    }
2674
2675    fn get_test_payloads_all() -> Vec<&'static [u8]> {
2676        vec![
2677            &[],
2678            &[1],
2679            &[1, 2],
2680            &[1, 2, 3, 4, 5],
2681            // This 4 elements are for C reference binary testing
2682            b"4567\0",
2683            b"0123\0",
2684            b"0123456789\0",
2685            b"abcdefghijklmnopqrs\0",
2686        ]
2687    }
2688
2689    fn get_test_zbi_headers_all() -> Vec<ZbiHeader> {
2690        let test_payloads = get_test_payloads_all();
2691        vec![
2692            ZbiHeader {
2693                type_: ZBI_TYPE_KERNEL_RISCV64,
2694                length: test_payloads[0].len().try_into().unwrap(),
2695                extra: 0,
2696                flags: ZbiFlags::default().bits(),
2697                magic: ZBI_ITEM_MAGIC,
2698                crc32: ZBI_ITEM_NO_CRC32,
2699                ..Default::default()
2700            },
2701            ZbiHeader {
2702                type_: ZBI_TYPE_KERNEL_ARM64,
2703                length: test_payloads[1].len().try_into().unwrap(),
2704                extra: 0,
2705                flags: ZbiFlags::default().bits(),
2706                magic: ZBI_ITEM_MAGIC,
2707                crc32: ZBI_ITEM_NO_CRC32,
2708                ..Default::default()
2709            },
2710            ZbiHeader {
2711                type_: ZBI_TYPE_KERNEL_RISCV64,
2712                length: test_payloads[2].len().try_into().unwrap(),
2713                extra: 0,
2714                flags: ZbiFlags::default().bits(),
2715                magic: ZBI_ITEM_MAGIC,
2716                crc32: ZBI_ITEM_NO_CRC32,
2717                ..Default::default()
2718            },
2719            ZbiHeader {
2720                type_: ZBI_TYPE_KERNEL_X64,
2721                length: test_payloads[3].len().try_into().unwrap(),
2722                extra: 0,
2723                flags: ZbiFlags::default().bits(),
2724                magic: ZBI_ITEM_MAGIC,
2725                crc32: ZBI_ITEM_NO_CRC32,
2726                ..Default::default()
2727            },
2728            ZbiHeader {
2729                type_: ZBI_TYPE_KERNEL_X64,
2730                length: test_payloads[4].len().try_into().unwrap(),
2731                extra: 0,
2732                flags: ZbiFlags::default().bits(),
2733                magic: ZBI_ITEM_MAGIC,
2734                crc32: ZBI_ITEM_NO_CRC32,
2735                ..Default::default()
2736            },
2737            ZbiHeader {
2738                type_: ZBI_TYPE_CMDLINE,
2739                length: test_payloads[5].len().try_into().unwrap(),
2740                extra: 0,
2741                flags: ZbiFlags::default().bits(),
2742                magic: ZBI_ITEM_MAGIC,
2743                crc32: ZBI_ITEM_NO_CRC32,
2744                ..Default::default()
2745            },
2746            ZbiHeader {
2747                type_: ZBI_TYPE_STORAGE_RAMDISK,
2748                length: test_payloads[6].len().try_into().unwrap(),
2749                extra: 0,
2750                flags: ZbiFlags::default().bits(),
2751                magic: ZBI_ITEM_MAGIC,
2752                crc32: ZBI_ITEM_NO_CRC32,
2753                ..Default::default()
2754            },
2755            ZbiHeader {
2756                type_: ZBI_TYPE_STORAGE_BOOTFS,
2757                length: test_payloads[7].len().try_into().unwrap(),
2758                extra: 0,
2759                flags: ZbiFlags::default().bits(),
2760                magic: ZBI_ITEM_MAGIC,
2761                crc32: ZBI_ITEM_NO_CRC32,
2762                ..Default::default()
2763            },
2764        ]
2765    }
2766
2767    fn get_test_zbi_headers(num: usize) -> Vec<ZbiHeader> {
2768        get_test_zbi_headers_all()[..num].to_vec()
2769    }
2770
2771    fn get_test_entries_all() -> Vec<(ZbiHeader, &'static [u8])> {
2772        let headers = get_test_zbi_headers_all();
2773        let payloads = get_test_payloads_all();
2774        assert_eq!(headers.len(), payloads.len());
2775        headers.iter().cloned().zip(payloads.iter().cloned()).collect()
2776    }
2777
2778    fn get_test_entries(num: usize) -> Vec<(ZbiHeader, &'static [u8])> {
2779        get_test_entries_all()[..num].to_vec()
2780    }
2781
2782    fn get_test_entry_empty_payload() -> (ZbiHeader, &'static [u8]) {
2783        get_test_entries(1)[0]
2784    }
2785
2786    fn get_test_entry_nonempty_payload() -> (ZbiHeader, &'static [u8]) {
2787        get_test_entries(2)[1]
2788    }
2789
2790    fn get_test_entries_creference() -> Vec<(ZbiHeader, &'static [u8])> {
2791        let entries = get_test_entries_all();
2792        entries[entries.len() - 4..].to_vec()
2793    }
2794
2795    fn get_test_creference_buffer() -> ZbiAligned {
2796        let entries = get_test_entries_creference();
2797        let mut buffer = ZbiAligned::default();
2798        let mut builder = TestZbiBuilder::new(&mut buffer.0[..]).container_hdr(0);
2799        for entry in entries {
2800            builder = builder.item(entry.0, entry.1).align();
2801        }
2802        let _ = builder.update_container_length().padding(0xab_u8, 10).build();
2803        buffer
2804    }
2805
2806    fn get_test_creference_buffer_vec() -> Vec<u8> {
2807        hex::decode(
2808            "424f4f54b8000000e6f78c8600000100\
2809            0000000000000000291778b5d6e8874a\
2810            4b524e4c050000000000000000000100\
2811            0000000000000000291778b5d6e8874a\
2812            3435363700000000434d444c05000000\
2813            00000000000001000000000000000000\
2814            291778b5d6e8874a3031323300000000\
2815            5244534b0b0000000000000000000100\
2816            0000000000000000291778b5d6e8874a\
2817            30313233343536373839000000000000\
2818            42465342140000000000000000000100\
2819            0000000000000000291778b5d6e8874a\
2820            6162636465666768696a6b6c6d6e6f70\
2821            7172730000000000abababababababab\
2822            abab",
2823        )
2824        .unwrap()
2825    }
2826
2827    #[test]
2828    fn creference_buffer_generation() {
2829        let ref_buffer = get_test_creference_buffer_vec();
2830        let buffer = get_test_creference_buffer();
2831        assert_eq!(&ref_buffer[..ref_buffer.len()], &buffer.0[..ref_buffer.len()]);
2832    }
2833
2834    #[test]
2835    fn zbi_zbi_error() {
2836        let e = ZbiError::Error;
2837        println!("{e}");
2838        println!("{e:?}");
2839        println!("{e:#?}");
2840    }
2841
2842    #[test]
2843    fn zbi_container_align_buffer() {
2844        let buffer = ZbiAligned::default();
2845        let original_len = buffer.0.len();
2846        let buffer = align_buffer(&buffer.0[1..]).unwrap();
2847        assert_eq!(buffer.as_ptr() as usize % ZBI_ALIGNMENT_USIZE, 0);
2848        assert_eq!(buffer.len(), original_len - ZBI_ALIGNMENT_USIZE);
2849    }
2850
2851    #[test]
2852    fn zbi_container_align_buffer_empty() {
2853        let buffer = ZbiAligned::default();
2854        let buffer = align_buffer(&buffer.0[..0]).unwrap();
2855        assert_eq!(buffer.as_ptr() as usize % ZBI_ALIGNMENT_USIZE, 0);
2856        assert_eq!(buffer.len(), 0);
2857    }
2858
2859    #[test]
2860    fn zbi_container_align_buffer_too_short() {
2861        let buffer = ZbiAligned::default();
2862        assert_eq!(align_buffer(&buffer.0[1..ZBI_ALIGNMENT_USIZE - 1]), Err(ZbiError::TooBig));
2863    }
2864
2865    #[test]
2866    fn zbi_container_align_buffer_just_enough() {
2867        let buffer = ZbiAligned::default();
2868        let buffer = align_buffer(&buffer.0[1..ZBI_ALIGNMENT_USIZE]).unwrap();
2869        assert_eq!(buffer.as_ptr() as usize % ZBI_ALIGNMENT_USIZE, 0);
2870        assert_eq!(buffer.len(), 0);
2871    }
2872
2873    #[test]
2874    fn merge_within_good() {
2875        let mut buffer = vec![0u8; 1024];
2876        let buffer = align_buffer(&mut buffer[..]).unwrap();
2877
2878        let mut container_0 = ZbiContainer::new(&mut buffer[..]).unwrap();
2879        container_0
2880            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"0")
2881            .unwrap();
2882        let container_size_0 = container_0.container_size().unwrap();
2883        let mut container_1 = ZbiContainer::new(&mut buffer[container_size_0..]).unwrap();
2884        container_1
2885            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"1")
2886            .unwrap();
2887
2888        // Makes a copy of the buffer for performing the merge.
2889        let mut copy = buffer.to_vec();
2890        let merged = merge_within(&mut copy[..], container_size_0).unwrap();
2891
2892        let (buffer_0, buffer_1) = buffer.split_at_mut(container_size_0);
2893        let container_0 = ZbiContainer::parse(buffer_0).unwrap();
2894        let container_1 = ZbiContainer::parse(buffer_1).unwrap();
2895        let mut it = merged.iter();
2896        assert_eq!(it.next().unwrap(), container_0.iter().next().unwrap());
2897        assert_eq!(it.next().unwrap(), container_1.iter().next().unwrap());
2898        assert!(it.next().is_none());
2899    }
2900
2901    #[test]
2902    fn merge_within_invalid_second_start() {
2903        let mut buffer = ZbiAligned::default();
2904        let _ = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2905        assert!(merge_within(&mut buffer.0[..], 0).is_err());
2906    }
2907
2908    #[test]
2909    fn merge_within_invalid_first_container() {
2910        let mut buffer = ZbiAligned::default();
2911        let _ = ZbiContainer::new(&mut buffer.0[2 * ZBI_ALIGNMENT_USIZE..]).unwrap();
2912        assert!(merge_within(&mut buffer.0[..], 2 * ZBI_ALIGNMENT_USIZE).is_err());
2913    }
2914
2915    #[test]
2916    fn merge_within_invalid_second_container() {
2917        let mut buffer = ZbiAligned::default();
2918        let first = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2919        let first_sz = first.container_size().unwrap();
2920        assert!(merge_within(&mut buffer.0[..], first_sz).is_err());
2921    }
2922
2923    #[test]
2924    fn container_size_overflow() {
2925        let mut buffer = ZbiAligned::default();
2926        let mut zbi_container = ZbiContainer::new(&mut buffer.0[..]).unwrap();
2927        zbi_container.payload_length = usize::MAX;
2928        let res = zbi_container.container_size();
2929        assert_eq!(res, Err(ZbiError::TooBig));
2930    }
2931
2932    #[test]
2933    fn extend_items_good() {
2934        // Container 0: 152 bytes
2935        //   ZbiHeader:  32
2936        //   3 ZbiItems: (32 + 8)*3
2937        // Container 1: 72 bytes
2938        //   ZbiHeader:  32
2939        //   1 ZbiItem:  32 + 8
2940        //
2941        // Container 1 append 2 ZbiItems: 72 + 2(32+8) = 152 bytes
2942        //
2943        // Min buffer size = Cont0 + Cont1extended = 304
2944        //
2945        let mut buffer = vec![0u8; 304];
2946        let buffer = align_buffer(&mut buffer[..]).unwrap();
2947
2948        let mut container_0 = ZbiContainer::new(&mut buffer[..]).unwrap();
2949        container_0
2950            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"0")
2951            .unwrap();
2952        container_0
2953            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"1")
2954            .unwrap();
2955        container_0
2956            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"2")
2957            .unwrap();
2958        let container_size_0 = container_0.container_size().unwrap();
2959        let mut container_1 = ZbiContainer::new(&mut buffer[container_size_0..]).unwrap();
2960        container_1
2961            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"3")
2962            .unwrap();
2963
2964        let (buffer_0, buffer_1) = buffer.split_at_mut(container_size_0);
2965        let container_0 = ZbiContainer::parse(buffer_0).unwrap();
2966        let mut container_1 = ZbiContainer::parse(buffer_1).unwrap();
2967
2968        // Copy last items from container 0 to 1
2969        let mut last_2_item_iter = container_0.iter();
2970        let _ = last_2_item_iter.next();
2971        container_1.extend_items(last_2_item_iter).unwrap();
2972
2973        assert_eq!(container_1.iter().count(), 3);
2974        let mut it0 = container_0.iter();
2975        let mut it1 = container_1.iter();
2976        let _ = it0.next();
2977        let _ = it1.next();
2978        assert_eq!(it0.next().unwrap(), it1.next().unwrap());
2979        assert_eq!(it0.next().unwrap(), it1.next().unwrap());
2980        assert!(it0.next().is_none());
2981        assert!(it1.next().is_none());
2982    }
2983
2984    #[test]
2985    fn extend_items_too_big() {
2986        // Container 0: 152 bytes
2987        //   ZbiHeader:  32
2988        //   3 ZbiItems: (32 + 8)*3
2989        // Container 1: 72 bytes
2990        //   ZbiHeader:  32
2991        //   1 ZbiItem:  32 + 8
2992        //
2993        // Container 1 append 2 ZbiItems: 72 + 2(32+8) = 152 bytes
2994        //
2995        // Min buffer size = Cont0 + Cont1extended = 304
2996        //
2997        let mut buffer = vec![0u8; 304 - 1];
2998        let buffer = align_buffer(&mut buffer[..]).unwrap();
2999
3000        let mut container_0 = ZbiContainer::new(&mut buffer[..]).unwrap();
3001        container_0
3002            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"0")
3003            .unwrap();
3004        container_0
3005            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"1")
3006            .unwrap();
3007        container_0
3008            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"2")
3009            .unwrap();
3010        let container_size_0 = container_0.container_size().unwrap();
3011        let mut container_1 = ZbiContainer::new(&mut buffer[container_size_0..]).unwrap();
3012        container_1
3013            .create_entry_with_payload(ZbiType::CmdLine, 0, ZbiFlags::default(), b"3")
3014            .unwrap();
3015
3016        let (buffer_0, buffer_1) = buffer.split_at_mut(container_size_0);
3017        let container_0 = ZbiContainer::parse(buffer_0).unwrap();
3018        let mut container_1 = ZbiContainer::parse(buffer_1).unwrap();
3019
3020        // Copy last items from container 0 to 1
3021        let mut last_2_item_iter = container_0.iter();
3022        let _ = last_2_item_iter.next();
3023        assert_eq!(container_1.extend_items(last_2_item_iter), Err(ZbiError::TooBig));
3024    }
3025}