1#![cfg_attr(not(test), no_std)]
6
7pub 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
47pub 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
60pub 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#[derive(Debug)]
82pub struct ZbiItem<B: SplitByteSlice> {
83 pub header: Ref<B, ZbiHeader>,
85 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 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 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 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 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 let (payload, tail) = item_tail.split_at(payload_len).ok().unwrap();
236
237 Ok((ZbiItem { header, payload }, tail))
238 }
239}
240
241#[derive(Debug, PartialEq)]
247pub struct ZbiContainer<B: SplitByteSlice> {
248 pub header: Ref<B, ZbiHeader>,
255
256 payload_length: usize,
263
264 buffer: B,
267}
268
269impl<B: SplitByteSlice> ZbiContainer<B> {
270 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 pub fn get_payload_length_u32(&self) -> u32 {
284 self.header.length
285 }
286
287 pub fn get_payload_length_usize(&self) -> usize {
290 self.payload_length
291 }
292
293 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 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 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 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 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 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 {
398 let mut it = res.iter();
399 for b in &mut it {
400 b.is_valid()?;
401 }
402
403 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 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 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 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 pub fn create_entry(
579 &mut self,
580 type_: ZbiType,
581 extra: u32,
582 flags: ZbiFlags,
583 payload_length: usize,
584 ) -> ZbiResult<()> {
585 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 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 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 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 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 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 let dst = remains.get_mut(..other.len()).ok_or(ZbiError::TooBig)?;
711 dst.clone_from_slice(other);
712 let new_payload_len = ZbiContainer::parse(&mut dst[..])?.header.length;
714 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 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
735pub 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 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 core::mem::swap(&mut tail, &mut self.buffer);
768 Some(item)
769 }
770 Err(e) => {
771 self.state = Err(e);
774 None
775 }
776 }
777 }
778}
779
780#[repr(u32)]
781#[derive(IntoBytes, Clone, Copy, Debug, Eq, PartialEq, Immutable)]
782pub enum ZbiType {
784 Container = ZBI_TYPE_CONTAINER,
791
792 KernelX64 = ZBI_TYPE_KERNEL_X64,
796
797 KernelArm64 = ZBI_TYPE_KERNEL_ARM64,
801
802 KernelRiscv64 = ZBI_TYPE_KERNEL_RISCV64,
806
807 Discard = ZBI_TYPE_DISCARD,
815
816 StorageRamdisk = ZBI_TYPE_STORAGE_RAMDISK,
822
823 StorageBootFs = ZBI_TYPE_STORAGE_BOOTFS,
831
832 StorageKernel = ZBI_TYPE_STORAGE_KERNEL,
841
842 StorageBootFsFactory = ZBI_TYPE_STORAGE_BOOTFS_FACTORY,
848
849 CmdLine = ZBI_TYPE_CMDLINE,
859
860 CrashLog = ZBI_TYPE_CRASHLOG,
864
865 Nvram = ZBI_TYPE_NVRAM,
870
871 PlatformId = ZBI_TYPE_PLATFORM_ID,
875
876 DrvBoardInfo = ZBI_TYPE_DRV_BOARD_INFO,
880
881 CpuTopology = ZBI_TYPE_CPU_TOPOLOGY,
883
884 MemConfig = ZBI_TYPE_MEM_CONFIG,
888
889 KernelDriver = ZBI_TYPE_KERNEL_DRIVER,
895
896 AcpiRsdp = ZBI_TYPE_ACPI_RSDP,
900
901 Smbios = ZBI_TYPE_SMBIOS,
905
906 EfiSystemTable = ZBI_TYPE_EFI_SYSTEM_TABLE,
910
911 EfiMemoryAttributesTable = ZBI_TYPE_EFI_MEMORY_ATTRIBUTES_TABLE,
918
919 FrameBuffer = ZBI_TYPE_FRAMEBUFFER,
923
924 ImageArgs = ZBI_TYPE_IMAGE_ARGS,
932
933 BootVersion = ZBI_TYPE_BOOT_VERSION,
937
938 DrvMacAddress = ZBI_TYPE_DRV_MAC_ADDRESS,
945
946 DrvPartitionMap = ZBI_TYPE_DRV_PARTITION_MAP,
952
953 DrvBoardPrivate = ZBI_TYPE_DRV_BOARD_PRIVATE,
957
958 HwRebootReason = ZBI_TYPE_HW_REBOOT_REASON,
961
962 SerialNumber = ZBI_TYPE_SERIAL_NUMBER,
967
968 BootloaderFile = ZBI_TYPE_BOOTLOADER_FILE,
979
980 DeviceTree = ZBI_TYPE_DEVICETREE,
987
988 SecureEntropy = ZBI_TYPE_SECURE_ENTROPY,
995
996 DebugData = ZBI_TYPE_DEBUGDATA,
1003}
1004
1005impl ZbiType {
1006 pub fn is_kernel(&self) -> bool {
1012 ((*self as u32) & ZBI_TYPE_KERNEL_MASK) == ZBI_TYPE_KERNEL_PREFIX
1013 }
1014
1015 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 pub struct ZbiFlags: u32 {
1083 const VERSION = ZBI_FLAGS_VERSION;
1085 const CRC32 = ZBI_FLAGS_CRC32;
1088 }
1089}
1090
1091impl Default for ZbiFlags {
1093 fn default() -> ZbiFlags {
1094 ZbiFlags::VERSION
1095 }
1096}
1097
1098pub type ZbiHeader = zbi_header_t;
1131
1132impl ZbiHeader {
1133 pub fn get_flags(&self) -> ZbiFlags {
1135 ZbiFlags::from_bits_truncate(self.flags)
1136 }
1137 pub fn set_flags(&mut self, flags: &ZbiFlags) {
1139 self.flags = flags.bits();
1140 }
1141}
1142
1143pub type ZbiKernel = zbi_kernel_t;
1216
1217#[derive(Debug, PartialEq, Eq)]
1218pub enum ZbiError {
1220 Error,
1222 BadType,
1224 BadMagic,
1226 BadVersion,
1228 BadCrc,
1230 BadAlignment,
1232 Truncated,
1234 TooBig,
1236 IncompleteKernel,
1238 PlatformBadLength,
1240 Crc32NotSupported,
1242 LengthOverflow,
1244}
1245
1246impl 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
1268fn 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
1283fn 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
1291pub 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 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 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 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 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 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 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 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 + (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());
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 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 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 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 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 assert_eq!(
2228 container.get_payload_length_usize(),
2229 expected_items.len() * ZBI_HEADER_SIZE + expected_items .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 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 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 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 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 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; assert_eq!(container.get_next_payload(), Err(ZbiError::LengthOverflow));
2319 }
2320
2321 #[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 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 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 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 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 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 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 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 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}