1use anyhow::{Error, anyhow};
6use std::fmt::Write as _;
7use std::slice;
8use zbi::zbi_format::{ZBI_FLAGS_CRC32, ZBI_FLAGS_STORAGE_COMPRESSED};
9use zbi::{ZbiContainer, ZbiType};
10use zerocopy::IntoBytes as _;
11use zx::{Name, VmarFlags, Vmo};
12use zx_libc::sanitizer::Log;
13
14pub fn get_zbi_container(
16 zbi_vmo: &Vmo,
17 vmar: &zx::Vmar,
18) -> Result<ZbiContainer<&'static [u8]>, Error> {
19 let zbi_size = zbi_vmo.get_size()? as usize;
20 let zbi_addr = vmar.map(0, zbi_vmo, 0, zbi_size, VmarFlags::PERM_READ)?;
21 let zbi_slice = unsafe {
24 slice::from_raw_parts(core::ptr::with_exposed_provenance::<u8>(zbi_addr), zbi_size)
25 };
26 ZbiContainer::parse(zbi_slice).map_err(|e| anyhow!("Failed to parse ZBI: {e:?}"))
27}
28
29pub fn get_bootfs_vmo(
31 container: &ZbiContainer<&[u8]>,
32 vmar: &zx::Vmar,
33 check_crc: bool,
34 log: &mut Log,
35) -> Result<Vmo, Error> {
36 let bootfs_item = container
37 .iter()
38 .find(|item| item.header.type_ == ZbiType::StorageBootFs as u32)
39 .ok_or_else(|| anyhow!("StorageBootFs item not found in ZBI"))?;
40
41 if check_crc && (bootfs_item.header.flags & ZBI_FLAGS_CRC32) != 0 {
42 writeln!(log, "Checking BOOTFS item CRC32 {:#x}...", bootfs_item.header.crc32)?;
43 let mut header_without_crc = *bootfs_item.header;
44 header_without_crc.crc32 = 0;
45 let mut hasher = crc32fast::Hasher::new();
46 hasher.update(header_without_crc.as_bytes());
47 hasher.update(bootfs_item.payload.as_bytes());
48 if hasher.finalize() == bootfs_item.header.crc32 {
49 writeln!(log, "BOOTFS payload matches item CRC32.")?;
50 } else {
51 writeln!(log, "*** BOOTFS payload DOES NOT MATCH item CRC32! ***")?;
52 }
53 }
54
55 let is_compressed = (bootfs_item.header.flags & ZBI_FLAGS_STORAGE_COMPRESSED) != 0;
56 let bootfs_vmo = if is_compressed {
57 let uncompressed_size = bootfs_item.header.extra as usize;
58 let vmo = Vmo::create(uncompressed_size as u64)?;
59 let bootfs_addr =
60 vmar.map(0, &vmo, 0, uncompressed_size, VmarFlags::PERM_READ | VmarFlags::PERM_WRITE)?;
61
62 let payload = bootfs_item.payload.as_bytes();
63 let dst_slice = unsafe {
66 slice::from_raw_parts_mut(
67 core::ptr::with_exposed_provenance_mut::<u8>(bootfs_addr),
68 uncompressed_size,
69 )
70 };
71 zstd_safe::decompress(dst_slice, payload)
72 .map_err(|e| anyhow!("zstd decompression failed with error code: {}", e))?;
73
74 unsafe {
76 vmar.unmap(bootfs_addr, uncompressed_size)?;
77 }
78 vmo
79 } else {
80 let payload_bytes = bootfs_item.payload.as_bytes();
81 let vmo = Vmo::create(payload_bytes.len() as u64)?;
82 vmo.write(payload_bytes, 0)?;
83 vmo
84 };
85
86 bootfs_vmo.set_name(&Name::new("uncompressed-bootfs")?)?;
87 Ok(bootfs_vmo)
88}