android: support dttable for dtb in boot/vendor_boot

Bug: 405201147
Change-Id: I240beb9902e760683783840239c62e3f6ea92e37
Signed-off-by: Dmitrii Merkurev <dimorinny@google.com>
diff --git a/gbl/libgbl/src/android_boot/mod.rs b/gbl/libgbl/src/android_boot/mod.rs
index 132ab5d..f5b9932 100644
--- a/gbl/libgbl/src/android_boot/mod.rs
+++ b/gbl/libgbl/src/android_boot/mod.rs
@@ -29,7 +29,7 @@
 use core::{array::from_fn, ffi::CStr};
 use dttable::DtTableImage;
 use fastboot::local_session::LocalSession;
-use fdt::Fdt;
+use fdt::{Fdt, FdtHeader};
 use gbl_async::block_on;
 use liberror::Error;
 use libutils::{aligned_offset, aligned_subslice};
@@ -84,8 +84,26 @@
 
             if images.dtb.len() > 0 {
                 gbl_println!(ops, "Handling device tree from boot/vendor_boot");
-                remains =
-                    components.append(ops, DeviceTreeComponentSource::Boot, images.dtb, remains)?;
+                remains = if FdtHeader::from_bytes_ref(images.dtb).is_ok() {
+                    gbl_println!(ops, "Device tree found in boot/vendor_boot");
+                    components.append(ops, DeviceTreeComponentSource::Boot, images.dtb, remains)?
+                } else if let Ok(table) = DtTableImage::from_bytes(images.dtb) {
+                    gbl_println!(
+                        ops,
+                        "Dttable with {} entries found in boot/vendor_boot",
+                        table.entries_count()
+                    );
+                    components.append_from_dttable(
+                        DeviceTreeComponentSource::Boot,
+                        &table,
+                        remains,
+                    )?
+                } else {
+                    return Err(Error::Other(Some(
+                        "Invalid or unrecognized device tree format in boot/vendor_boot",
+                    ))
+                    .into());
+                }
             }
 
             if images.dtb_part.len() > 0 {
@@ -795,6 +813,46 @@
         test_android_load_verify_fixup_v3_or_v4_no_init_boot(4, 4, 'b', config, parts, fdt_prop);
     }
 
+    /// Helper for testing `android_load_verify_fixup` with dttable vendor_boot
+    fn test_android_load_verify_fixup_v4_vendor_boot_dttable(
+        slot: char,
+        expected_vendor_bootconfig: &str,
+        additional_parts: &[(CString, String)],
+        additional_expected_fdt_properties: &[(&str, &CStr, Option<&[u8]>)],
+    ) {
+        let vbmeta = format!("vbmeta_v4_dttable_{slot}.img");
+        let mut parts: Vec<(CString, String)> = vec![
+            (CString::new(format!("boot_{slot}")).unwrap(), format!("boot_v4_{slot}.img")),
+            (
+                CString::new(format!("vendor_boot_{slot}")).unwrap(),
+                format!("vendor_boot_v4_dttable_{slot}.img"),
+            ),
+            (CString::new(format!("vbmeta_{slot}")).unwrap(), vbmeta.clone()),
+        ];
+        parts.extend_from_slice(additional_parts);
+        test_android_load_verify_fixup_v3_or_v4(
+            slot,
+            &parts,
+            &vbmeta,
+            expected_vendor_bootconfig,
+            additional_expected_fdt_properties,
+        );
+    }
+
+    #[test]
+    fn test_android_load_verify_fixup_v4_v4_no_init_boot_slot_dttable_vendor_boot_a() {
+        let fdt_prop: &[(&str, &CStr, Option<&[u8]>)] = &[("/chosen", c"builtin", Some(&[1]))];
+        let config = TEST_VENDOR_BOOTCONFIG;
+        test_android_load_verify_fixup_v4_vendor_boot_dttable('a', config, &[], fdt_prop);
+    }
+
+    #[test]
+    fn test_android_load_verify_fixup_v4_v4_no_init_boot_slot_dttable_vendor_boot_b() {
+        let fdt_prop: &[(&str, &CStr, Option<&[u8]>)] = &[("/chosen", c"builtin", Some(&[1]))];
+        let config = TEST_VENDOR_BOOTCONFIG;
+        test_android_load_verify_fixup_v4_vendor_boot_dttable('b', config, &[], fdt_prop);
+    }
+
     /// Helper for testing `android_load_verify_fixup` for v3/v4 boot image with init_boot.
     fn test_android_load_verify_fixup_v3_or_v4_init_boot(
         boot_ver: u32,
diff --git a/gbl/libgbl/testdata/android/dtb.img b/gbl/libgbl/testdata/android/dtb.img
new file mode 100644
index 0000000..1ea26fa
--- /dev/null
+++ b/gbl/libgbl/testdata/android/dtb.img
Binary files differ
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.boot.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.boot.digest.txt
new file mode 100644
index 0000000..8cc8826
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.boot.digest.txt
@@ -0,0 +1 @@
+fe6845837f27613699770d58a19b2405c4b23c203fe1edb0133b30e3d496945c
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.digest.txt
new file mode 100644
index 0000000..c09919d
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.digest.txt
@@ -0,0 +1 @@
+450823eddf5bf1600790b612b24b32552d9454a1420188cdf7a279844431a3a2a82ecc367125d265c724066427993ffe2adc303782fb93850fef1cc10866b215
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtb.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtb.digest.txt
new file mode 100644
index 0000000..8460aa7
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtb.digest.txt
@@ -0,0 +1 @@
+74024f7c9577215434dba9b695c3501eb626f66b97c810ff5307912c7fac7938
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtbo.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtbo.digest.txt
new file mode 100644
index 0000000..0013aed
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.dtbo.digest.txt
@@ -0,0 +1 @@
+18964fe84fd9214ae7d61c7f0d7d951412b6ce7f1c3e49a8f896a40da2ddde3f
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.img b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.img
new file mode 100644
index 0000000..12f0ac8
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.img
Binary files differ
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.vendor_boot.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.vendor_boot.digest.txt
new file mode 100644
index 0000000..8c33e8a
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_a.vendor_boot.digest.txt
@@ -0,0 +1 @@
+f9cad72ad63c87e97ca0ef89e00d5297b4731145a7916cf34cdcd6c03d68a0ca
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.boot.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.boot.digest.txt
new file mode 100644
index 0000000..c7fb6e2
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.boot.digest.txt
@@ -0,0 +1 @@
+54c83f6d25648f1628b9049978f05eaac878523e2ad9da50e80e4591f709e8db
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.digest.txt
new file mode 100644
index 0000000..0ee67db
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.digest.txt
@@ -0,0 +1 @@
+7062df4c2e595c354a31e07ae33a627a0fdaae0bfd80b35ba569df0978165f7b4761184226f62efc479cff8fe85d032e2f5f9e7bced536dd5761ef054a0d8548
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtb.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtb.digest.txt
new file mode 100644
index 0000000..22afb3f
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtb.digest.txt
@@ -0,0 +1 @@
+6227f3fbf15d3049f03c9829016372e1387cd07eb1b23bc8ae640545c0b3a398
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtbo.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtbo.digest.txt
new file mode 100644
index 0000000..74ca578
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.dtbo.digest.txt
@@ -0,0 +1 @@
+8e3d69eba96fb6723bb4f29a1fa4dd3737bc352d1b3c05a7946778e685307fe4
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.img b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.img
new file mode 100644
index 0000000..79c8c21
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.img
Binary files differ
diff --git a/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.vendor_boot.digest.txt b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.vendor_boot.digest.txt
new file mode 100644
index 0000000..a2af6a3
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vbmeta_v4_dttable_b.vendor_boot.digest.txt
@@ -0,0 +1 @@
+1686ca796de1300d09238cbe1828d59405224b7e5dc913a653071734af6f01da
diff --git a/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_a.img b/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_a.img
new file mode 100644
index 0000000..2ea1bfa
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_a.img
Binary files differ
diff --git a/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_b.img b/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_b.img
new file mode 100644
index 0000000..941024f
--- /dev/null
+++ b/gbl/libgbl/testdata/android/vendor_boot_v4_dttable_b.img
Binary files differ
diff --git a/gbl/libgbl/testdata/gen_test_data.py b/gbl/libgbl/testdata/gen_test_data.py
index 8c55a19..1c37d29 100755
--- a/gbl/libgbl/testdata/gen_test_data.py
+++ b/gbl/libgbl/testdata/gen_test_data.py
@@ -176,6 +176,19 @@
     gen_dtb(
         out_dir / "device_tree_custom.dts", out_dir / "device_tree_custom.dtb"
     )
+    # Generates dtb to be used inside boot/vendor_boot
+    subprocess.run(
+        [
+            MKDTBOIMG_TOOL,
+            "create",
+            out_dir / "dtb.img",
+            "--id=0x1",
+            "--rev=0x0",
+            out_dir / "device_tree.dtb",
+        ],
+        stderr=subprocess.STDOUT,
+        check=True,
+    )
 
     # Generates dtb_a/dtb_b
     gen_dtb(out_dir / "device_tree_a.dts", out_dir / "device_tree_a.dtb")
@@ -439,6 +452,8 @@
             subprocess.run(
                 common
                 + [
+                    "--dtb",
+                    out_dir / "device_tree.dtb",
                     "--vendor_boot",
                     out_dir / f"vendor_boot_v3_{slot}.img",
                     "--header_version",
@@ -451,6 +466,8 @@
             subprocess.run(
                 common
                 + [
+                    "--dtb",
+                    out_dir / "device_tree.dtb",
                     "--vendor_boot",
                     out_dir / f"vendor_boot_v4_{slot}.img",
                     "--vendor_bootconfig",
@@ -461,6 +478,22 @@
                 stderr=subprocess.STDOUT,
                 check=True,
             )
+            # Generates vendor_boot v4 with dttable structure
+            subprocess.run(
+                common
+                + [
+                    "--dtb",
+                    out_dir / "dtb.img",
+                    "--vendor_boot",
+                    out_dir / f"vendor_boot_v4_dttable_{slot}.img",
+                    "--vendor_bootconfig",
+                    vendor_bootconfig,
+                    "--header_version",
+                    "4",
+                ],
+                stderr=subprocess.STDOUT,
+                check=True,
+            )
 
             # Generates a vbmeta data for v0 - v2 setup
             for i in [0, 1, 2]:
@@ -508,6 +541,19 @@
 
                         gen_android_test_vbmeta(parts, out_dir / vbmeta_out)
 
+            # Generate v4 vbmeta image for vendor_boot with dttable structure
+            vbmeta_out = out_dir / \
+                f"vbmeta_v4_dttable_{slot}.img"
+            parts = [
+                (f"boot", out_dir /
+                    f"boot_v4_{slot}.img"),
+                (f"vendor_boot", out_dir /
+                    f"vendor_boot_v4_dttable_{slot}.img"),
+                ("dtbo", out_dir / f"dtbo_{slot}.img"),
+                ("dtb", out_dir / f"dtb_{slot}.img"),
+            ]
+            gen_android_test_vbmeta(parts, vbmeta_out)
+
             # Generate v4 vbmeta images for both gzip and lz4 kernel compression.
             if slot == "a":
                 for compression in ["gz", "lz4"]: