Merge "Port Android boot image structures and parsing to Rust" into main
diff --git a/rust/Android.bp b/rust/Android.bp
new file mode 100644
index 0000000..353070e
--- /dev/null
+++ b/rust/Android.bp
@@ -0,0 +1,50 @@
+// Copyright 2023 The Android Open Source Project
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+    name: "libbootimg_private_defaults",
+    srcs: ["bootimg_priv.rs"],
+    rustlibs: ["libzerocopy"],
+    lints: "none",
+}
+
+rust_library {
+    name: "libbootimg_private",
+    crate_name: "bootimg_private",
+    vendor_available: true,
+    defaults: ["libbootimg_private_defaults"],
+    host_supported: true,
+    visibility: [":__subpackages__"],
+}
+
+rust_test_host {
+    name: "libbootimg_tests_priv",
+    auto_gen_config: true,
+    defaults: ["libbootimg_private_defaults"],
+}
+
+rust_defaults {
+    name: "libbootimg_defaults",
+    srcs: ["bootimg.rs"],
+    rustlibs: [
+        "libzerocopy",
+        "libbootimg_private",
+    ],
+}
+
+rust_library {
+    name: "libbootimg",
+    crate_name: "bootimg",
+    vendor_available: true,
+    host_supported: true,
+    defaults: ["libbootimg_defaults"],
+}
+
+rust_test_host {
+    name: "libbootimg_tests",
+    auto_gen_config: true,
+    defaults: ["libbootimg_defaults"],
+}
diff --git a/rust/bindgen.sh b/rust/bindgen.sh
new file mode 100755
index 0000000..b854d10
--- /dev/null
+++ b/rust/bindgen.sh
@@ -0,0 +1,76 @@
+#! /usr/bin/env bash
+# Copyright 2023, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+# Run this script to regenerate bootimg_priv.rs if
+# include/bootimg/bootimg.h ever changes.
+# The rust_bindgen rule is not cooperative, causing custom derive types
+# to not percolate to the generated structures.
+# It's just easier to do all the munging in a script.
+
+SCRATCH_DIR=$(mktemp -d)
+
+cleanup (){
+    rm -rf ${SCRATCH_DIR}
+}
+
+trap cleanup EXIT
+pushd ~/aosp > /dev/null
+
+BOOTIMG_DIR=$(realpath system/tools/mkbootimg/)
+# The stdint include generates a lot of unnecessary types that the
+# generated rust bindings really don't need.
+BLOCKED_TYPES_RE="__.+|.?int.+"
+# The stdint include generates a lot of unnecessary constants that the
+# generated rust bindings really don't need.
+BLOCKED_ITEMS_RE="_.+|.?INT.+|PTR.+|ATOMIC.+|.+SOURCE|.+_H|SIG_.+|SIZE_.+|.?CHAR.+"
+CUSTOM_STRUCT_RE="(vendor_)?(boot_img_hdr|ramdisk_table_entry)_v\d+"
+CUSTOM_STRUCT_DERIVES="AsBytes,FromBytes,PartialEq,Copy,Clone,Debug"
+BINDGEN_FLAGS="--use-core --with-derive-default"
+BOOTIMG_PRIV=${BOOTIMG_DIR}/rust/bootimg_priv.rs
+
+# We need C++ isms, and the only obvious way to convince bindgen
+# that the source is C++ is with a C++ extension.
+cp ${BOOTIMG_DIR}/include/bootimg/bootimg.h ${SCRATCH_DIR}/bootimg.hpp
+
+./out/host/linux-x86/bin/bindgen \
+    --blocklist-type="${BLOCKED_TYPES_RE}" \
+    --blocklist-item="${BLOCKED_ITEMS_RE}" \
+    --with-derive-custom-struct="${CUSTOM_STRUCT_RE}=${CUSTOM_STRUCT_DERIVES}" \
+    ${BINDGEN_FLAGS} \
+    ${SCRATCH_DIR}/bootimg.hpp \
+    -o ${SCRATCH_DIR}/bootimg_gen.rs
+
+cat << EOF | cat - ${SCRATCH_DIR}/bootimg_gen.rs > ${BOOTIMG_PRIV}
+// Copyright $(date +%Y), The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use zerocopy::{AsBytes, FromBytes};
+
+EOF
+
+rustfmt ${BOOTIMG_PRIV} --config-path system/tools/aidl/rustfmt.toml
diff --git a/rust/bootimg.rs b/rust/bootimg.rs
new file mode 100644
index 0000000..bc83eb1
--- /dev/null
+++ b/rust/bootimg.rs
@@ -0,0 +1,399 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! The public interface for bootimg structs
+use zerocopy::{ByteSlice, LayoutVerified};
+
+use bootimg_private::{
+    boot_img_hdr_v0, boot_img_hdr_v1, boot_img_hdr_v2, boot_img_hdr_v3, boot_img_hdr_v4,
+    vendor_boot_img_hdr_v3, vendor_boot_img_hdr_v4, BOOT_MAGIC, BOOT_MAGIC_SIZE, VENDOR_BOOT_MAGIC,
+    VENDOR_BOOT_MAGIC_SIZE,
+};
+
+/// Generalized boot image from a backing store of bytes.
+#[derive(PartialEq, Debug)]
+pub enum BootImage<B: ByteSlice + PartialEq> {
+    /// Version 0 header
+    V0(LayoutVerified<B, boot_img_hdr_v0>),
+    /// Version 1 header
+    V1(LayoutVerified<B, boot_img_hdr_v1>),
+    /// Version 2 header
+    V2(LayoutVerified<B, boot_img_hdr_v2>),
+    /// Version 3 header
+    V3(LayoutVerified<B, boot_img_hdr_v3>),
+    /// Version 4 header
+    V4(LayoutVerified<B, boot_img_hdr_v4>),
+}
+
+/// Generalized vendor boot header from a backing store of bytes.
+#[derive(PartialEq, Debug)]
+pub enum VendorImageHeader<B: ByteSlice + PartialEq> {
+    /// Version 3 header
+    V3(LayoutVerified<B, vendor_boot_img_hdr_v3>),
+    /// Version 4 header
+    V4(LayoutVerified<B, vendor_boot_img_hdr_v4>),
+}
+
+/// Boot related errors.
+#[derive(PartialEq, Debug)]
+pub enum ImageError {
+    /// The provided buffer was too small to hold a header.
+    BufferTooSmall,
+    /// The magic string was incorrect.
+    BadMagic,
+    /// The header version present is not supported.
+    UnexpectedVersion,
+    /// Catch-all for remaining errors.
+    Unknown,
+}
+
+impl core::fmt::Display for ImageError {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        let str = match self {
+            Self::BufferTooSmall => "The provided buffer is too small",
+            Self::BadMagic => "The magic string is incorrect",
+            Self::UnexpectedVersion => "Header version is not supported",
+            Self::Unknown => "Unknown error",
+        };
+        write!(f, "{str}")
+    }
+}
+
+/// Common result type for use with boot headers
+pub type BootResult<T> = Result<T, ImageError>;
+
+fn parse_header<B: ByteSlice + PartialEq, T>(buffer: B) -> BootResult<LayoutVerified<B, T>> {
+    Ok(LayoutVerified::<B, T>::new_from_prefix(buffer).ok_or(ImageError::BufferTooSmall)?.0)
+}
+
+impl<B: ByteSlice + PartialEq> BootImage<B> {
+    /// Given a byte buffer, attempt to parse the contents and return a zero-copy reference
+    /// to the associated boot image header.
+    ///
+    /// # Arguments
+    /// * `buffer` - buffer to parse
+    ///
+    /// # Returns
+    ///
+    /// * `Ok(BootImage)` - if parsing was successful.
+    /// * `Err(ImageError)` - if `buffer` does not contain a valid boot image header.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use bootimg::BootImage;
+    ///
+    /// let mut buffer = [0; 4096];
+    /// // Not shown: read first 4096 bytes of boot image into buffer
+    /// let header = BootImage::parse(&buffer[..]).unwrap();
+    /// ```
+    pub fn parse(buffer: B) -> BootResult<Self> {
+        let magic_size = BOOT_MAGIC_SIZE as usize;
+        // Note: even though the v3 header is not a prefix for the v0, v1, or v2 header,
+        // the version and the magic string exist at the same offset and have the same types.
+        // Make a v3 temporary because it is the smallest.
+        let (hdr, _) =
+            LayoutVerified::<&[u8], boot_img_hdr_v3>::new_from_prefix(buffer.get(..).unwrap())
+                .ok_or(ImageError::BufferTooSmall)?;
+
+        if hdr.magic.ne(&BOOT_MAGIC[..magic_size]) {
+            return Err(ImageError::BadMagic);
+        }
+
+        match hdr.header_version {
+            0 => Ok(Self::V0(parse_header::<B, boot_img_hdr_v0>(buffer)?)),
+            1 => Ok(Self::V1(parse_header::<B, boot_img_hdr_v1>(buffer)?)),
+            2 => Ok(Self::V2(parse_header::<B, boot_img_hdr_v2>(buffer)?)),
+            3 => Ok(Self::V3(parse_header::<B, boot_img_hdr_v3>(buffer)?)),
+            4 => Ok(Self::V4(parse_header::<B, boot_img_hdr_v4>(buffer)?)),
+            _ => Err(ImageError::UnexpectedVersion),
+        }
+    }
+}
+
+impl<B: ByteSlice + PartialEq> VendorImageHeader<B> {
+    /// Given a byte buffer, attempt to parse the contents and return a zero-copy reference
+    /// to the associated vendor boot image header.
+    ///
+    /// # Arguments
+    /// * `buffer` - buffer to parse
+    ///
+    /// # Returns
+    ///
+    /// * `Ok(VendorImageHeader)` - if parsing was successful.
+    /// * `Err(ImageError)` - If `buffer` does not contain a valid boot image header.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use bootimg::VendorImageHeader;
+    ///
+    /// let mut buffer = [0; 4096];
+    /// // Not shown: read first 4096 bytes of vendor image into buffer
+    /// let header = VendorImageHeader::parse(&buffer[..]).unwrap();
+    /// ```
+    pub fn parse(buffer: B) -> BootResult<Self> {
+        let magic_size = VENDOR_BOOT_MAGIC_SIZE as usize;
+        let (hdr, _) = LayoutVerified::<&[u8], vendor_boot_img_hdr_v3>::new_from_prefix(
+            buffer.get(..).unwrap(),
+        )
+        .ok_or(ImageError::BufferTooSmall)?;
+
+        if hdr.magic.ne(&VENDOR_BOOT_MAGIC[..magic_size]) {
+            return Err(ImageError::BadMagic);
+        }
+
+        match hdr.header_version {
+            3 => Ok(Self::V3(parse_header::<B, vendor_boot_img_hdr_v3>(buffer)?)),
+            4 => Ok(Self::V4(parse_header::<B, vendor_boot_img_hdr_v4>(buffer)?)),
+            _ => Err(ImageError::UnexpectedVersion),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use zerocopy::AsBytes;
+
+    const MAGIC_SIZE: usize = BOOT_MAGIC_SIZE as usize;
+    const VENDOR_MAGIC_SIZE: usize = VENDOR_BOOT_MAGIC_SIZE as usize;
+
+    pub fn add<T: AsBytes>(buffer: &mut [u8], t: T) {
+        t.write_to_prefix(buffer).unwrap();
+    }
+
+    #[test]
+    fn buffer_too_small_for_version() {
+        let buffer = [0; 40];
+        assert_eq!(BootImage::parse(&buffer[..]), Err(ImageError::BufferTooSmall));
+    }
+
+    #[test]
+    fn buffer_too_small_valid_version() {
+        // Note: because the v1 header fully encapsulates the v0 header,
+        // we can trigger a buffer-too-small error by providing
+        // a perfectly valid v0 header and changing the version to 1.
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v0>()];
+        add::<boot_img_hdr_v0>(
+            &mut buffer,
+            boot_img_hdr_v0 {
+                magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                header_version: 1,
+                ..Default::default()
+            },
+        );
+        assert_eq!(BootImage::parse(&buffer[..]), Err(ImageError::BufferTooSmall));
+    }
+
+    #[test]
+    fn bad_magic() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v0>()];
+        add::<boot_img_hdr_v0>(
+            &mut buffer,
+            boot_img_hdr_v0 { magic: *b"ANDROGEN", ..Default::default() },
+        );
+        assert_eq!(BootImage::parse(&buffer[..]), Err(ImageError::BadMagic));
+    }
+
+    #[test]
+    fn bad_version() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v0>()];
+        add::<boot_img_hdr_v0>(
+            &mut buffer,
+            boot_img_hdr_v0 {
+                magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                header_version: 2112,
+                ..Default::default()
+            },
+        );
+        assert_eq!(BootImage::parse(&buffer[..]), Err(ImageError::UnexpectedVersion));
+    }
+
+    #[test]
+    fn parse_v0() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v0>()];
+        add::<boot_img_hdr_v0>(
+            &mut buffer,
+            boot_img_hdr_v0 {
+                magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                header_version: 0,
+                ..Default::default()
+            },
+        );
+        let expected =
+            Ok(BootImage::V0(LayoutVerified::<&[u8], boot_img_hdr_v0>::new(&buffer).unwrap()));
+        assert_eq!(BootImage::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn parse_v1() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v1>()];
+        add::<boot_img_hdr_v1>(
+            &mut buffer,
+            boot_img_hdr_v1 {
+                _base: boot_img_hdr_v0 {
+                    magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                    header_version: 1,
+                    ..Default::default()
+                },
+                ..Default::default()
+            },
+        );
+        let expected =
+            Ok(BootImage::V1(LayoutVerified::<&[u8], boot_img_hdr_v1>::new(&buffer).unwrap()));
+        assert_eq!(BootImage::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn parse_v2() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v2>()];
+        add::<boot_img_hdr_v2>(
+            &mut buffer,
+            boot_img_hdr_v2 {
+                _base: boot_img_hdr_v1 {
+                    _base: boot_img_hdr_v0 {
+                        magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                        header_version: 2,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                ..Default::default()
+            },
+        );
+        let expected =
+            Ok(BootImage::V2(LayoutVerified::<&[u8], boot_img_hdr_v2>::new(&buffer).unwrap()));
+        assert_eq!(BootImage::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn parse_v3() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v3>()];
+        add::<boot_img_hdr_v3>(
+            &mut buffer,
+            boot_img_hdr_v3 {
+                magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                header_version: 3,
+                ..Default::default()
+            },
+        );
+        let expected =
+            Ok(BootImage::V3(LayoutVerified::<&[u8], boot_img_hdr_v3>::new(&buffer).unwrap()));
+        assert_eq!(BootImage::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn parse_v4() {
+        let mut buffer = [0; core::mem::size_of::<boot_img_hdr_v4>()];
+        add::<boot_img_hdr_v4>(
+            &mut buffer,
+            boot_img_hdr_v4 {
+                _base: boot_img_hdr_v3 {
+                    magic: BOOT_MAGIC[0..MAGIC_SIZE].try_into().unwrap(),
+                    header_version: 4,
+                    ..Default::default()
+                },
+                ..Default::default()
+            },
+        );
+        let expected =
+            Ok(BootImage::V4(LayoutVerified::<&[u8], boot_img_hdr_v4>::new(&buffer).unwrap()));
+        assert_eq!(BootImage::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn vendor_buffer_too_small_for_version() {
+        let buffer = [0; VENDOR_MAGIC_SIZE + 3];
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), Err(ImageError::BufferTooSmall));
+    }
+
+    #[test]
+    fn vendor_bad_magic() {
+        let mut buffer = [0; core::mem::size_of::<vendor_boot_img_hdr_v3>()];
+        add::<vendor_boot_img_hdr_v3>(
+            &mut buffer,
+            vendor_boot_img_hdr_v3 { magic: *b"VNDRBOOK", header_version: 3, ..Default::default() },
+        );
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), Err(ImageError::BadMagic));
+    }
+
+    #[test]
+    fn vendor_bad_version() {
+        let mut buffer = [0; core::mem::size_of::<vendor_boot_img_hdr_v3>()];
+        add::<vendor_boot_img_hdr_v3>(
+            &mut buffer,
+            vendor_boot_img_hdr_v3 {
+                magic: VENDOR_BOOT_MAGIC[0..VENDOR_MAGIC_SIZE].try_into().unwrap(),
+                header_version: 2112,
+                ..Default::default()
+            },
+        );
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), Err(ImageError::UnexpectedVersion));
+    }
+
+    #[test]
+    fn vendor_buffer_too_small_valid_version() {
+        let mut buffer = [0; core::mem::size_of::<vendor_boot_img_hdr_v3>()];
+        add::<vendor_boot_img_hdr_v3>(
+            &mut buffer,
+            vendor_boot_img_hdr_v3 {
+                magic: VENDOR_BOOT_MAGIC[0..VENDOR_MAGIC_SIZE].try_into().unwrap(),
+                // Note: because the v4 header fully encapsulates the v3 header,
+                // we can trigger a buffer-too-small error by providing
+                // a perfectly valid v3 header and changing the version to 4.
+                header_version: 4,
+                ..Default::default()
+            },
+        );
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), Err(ImageError::BufferTooSmall));
+    }
+
+    #[test]
+    fn vendor_parse_v3() {
+        let mut buffer = [0; core::mem::size_of::<vendor_boot_img_hdr_v3>()];
+        add::<vendor_boot_img_hdr_v3>(
+            &mut buffer,
+            vendor_boot_img_hdr_v3 {
+                magic: VENDOR_BOOT_MAGIC[0..VENDOR_MAGIC_SIZE].try_into().unwrap(),
+                header_version: 3,
+                ..Default::default()
+            },
+        );
+        let expected = Ok(VendorImageHeader::V3(
+            LayoutVerified::<&[u8], vendor_boot_img_hdr_v3>::new(&buffer).unwrap(),
+        ));
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), expected);
+    }
+
+    #[test]
+    fn vendor_parse_v4() {
+        let mut buffer = [0; core::mem::size_of::<vendor_boot_img_hdr_v4>()];
+        add::<vendor_boot_img_hdr_v4>(
+            &mut buffer,
+            vendor_boot_img_hdr_v4 {
+                _base: vendor_boot_img_hdr_v3 {
+                    magic: VENDOR_BOOT_MAGIC[0..VENDOR_MAGIC_SIZE].try_into().unwrap(),
+                    header_version: 4,
+                    ..Default::default()
+                },
+                ..Default::default()
+            },
+        );
+        let expected = Ok(VendorImageHeader::V4(
+            LayoutVerified::<&[u8], vendor_boot_img_hdr_v4>::new(&buffer).unwrap(),
+        ));
+        assert_eq!(VendorImageHeader::parse(&buffer[..]), expected);
+    }
+}
diff --git a/rust/bootimg_priv.rs b/rust/bootimg_priv.rs
new file mode 100644
index 0000000..fbd883c
--- /dev/null
+++ b/rust/bootimg_priv.rs
@@ -0,0 +1,669 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use zerocopy::{AsBytes, FromBytes};
+
+/* automatically generated by rust-bindgen 0.65.1 */
+
+pub const BOOT_MAGIC: &[u8; 9usize] = b"ANDROID!\0";
+pub const BOOT_MAGIC_SIZE: u32 = 8;
+pub const BOOT_NAME_SIZE: u32 = 16;
+pub const BOOT_ARGS_SIZE: u32 = 512;
+pub const BOOT_EXTRA_ARGS_SIZE: u32 = 1024;
+pub const VENDOR_BOOT_MAGIC: &[u8; 9usize] = b"VNDRBOOT\0";
+pub const VENDOR_BOOT_MAGIC_SIZE: u32 = 8;
+pub const VENDOR_BOOT_ARGS_SIZE: u32 = 2048;
+pub const VENDOR_BOOT_NAME_SIZE: u32 = 16;
+pub const VENDOR_RAMDISK_TYPE_NONE: u32 = 0;
+pub const VENDOR_RAMDISK_TYPE_PLATFORM: u32 = 1;
+pub const VENDOR_RAMDISK_TYPE_RECOVERY: u32 = 2;
+pub const VENDOR_RAMDISK_TYPE_DLKM: u32 = 3;
+pub const VENDOR_RAMDISK_NAME_SIZE: u32 = 32;
+pub const VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE: u32 = 16;
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct boot_img_hdr_v0 {
+    pub magic: [u8; 8usize],
+    pub kernel_size: u32,
+    pub kernel_addr: u32,
+    pub ramdisk_size: u32,
+    pub ramdisk_addr: u32,
+    pub second_size: u32,
+    pub second_addr: u32,
+    pub tags_addr: u32,
+    pub page_size: u32,
+    pub header_version: u32,
+    pub os_version: u32,
+    pub name: [u8; 16usize],
+    pub cmdline: [u8; 512usize],
+    pub id: [u32; 8usize],
+    pub extra_cmdline: [u8; 1024usize],
+}
+#[test]
+fn bindgen_test_layout_boot_img_hdr_v0() {
+    const UNINIT: ::core::mem::MaybeUninit<boot_img_hdr_v0> = ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<boot_img_hdr_v0>(),
+        1632usize,
+        concat!("Size of: ", stringify!(boot_img_hdr_v0))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<boot_img_hdr_v0>(),
+        1usize,
+        concat!("Alignment of ", stringify!(boot_img_hdr_v0))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).magic) as usize - ptr as usize },
+        0usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(magic))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).kernel_size) as usize - ptr as usize },
+        8usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(kernel_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).kernel_addr) as usize - ptr as usize },
+        12usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(kernel_addr))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_size) as usize - ptr as usize },
+        16usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(ramdisk_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_addr) as usize - ptr as usize },
+        20usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(ramdisk_addr))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).second_size) as usize - ptr as usize },
+        24usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(second_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).second_addr) as usize - ptr as usize },
+        28usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(second_addr))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).tags_addr) as usize - ptr as usize },
+        32usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(tags_addr))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).page_size) as usize - ptr as usize },
+        36usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(page_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_version) as usize - ptr as usize },
+        40usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(header_version))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).os_version) as usize - ptr as usize },
+        44usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(os_version))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).name) as usize - ptr as usize },
+        48usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(name))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).cmdline) as usize - ptr as usize },
+        64usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(cmdline))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).id) as usize - ptr as usize },
+        576usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(id))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).extra_cmdline) as usize - ptr as usize },
+        608usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v0), "::", stringify!(extra_cmdline))
+    );
+}
+impl Default for boot_img_hdr_v0 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+pub type boot_img_hdr = boot_img_hdr_v0;
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct boot_img_hdr_v1 {
+    pub _base: boot_img_hdr_v0,
+    pub recovery_dtbo_size: u32,
+    pub recovery_dtbo_offset: u64,
+    pub header_size: u32,
+}
+#[test]
+fn bindgen_test_layout_boot_img_hdr_v1() {
+    const UNINIT: ::core::mem::MaybeUninit<boot_img_hdr_v1> = ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<boot_img_hdr_v1>(),
+        1648usize,
+        concat!("Size of: ", stringify!(boot_img_hdr_v1))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<boot_img_hdr_v1>(),
+        1usize,
+        concat!("Alignment of ", stringify!(boot_img_hdr_v1))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).recovery_dtbo_size) as usize - ptr as usize },
+        1632usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(boot_img_hdr_v1),
+            "::",
+            stringify!(recovery_dtbo_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).recovery_dtbo_offset) as usize - ptr as usize },
+        1636usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(boot_img_hdr_v1),
+            "::",
+            stringify!(recovery_dtbo_offset)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_size) as usize - ptr as usize },
+        1644usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v1), "::", stringify!(header_size))
+    );
+}
+impl Default for boot_img_hdr_v1 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct boot_img_hdr_v2 {
+    pub _base: boot_img_hdr_v1,
+    pub dtb_size: u32,
+    pub dtb_addr: u64,
+}
+#[test]
+fn bindgen_test_layout_boot_img_hdr_v2() {
+    const UNINIT: ::core::mem::MaybeUninit<boot_img_hdr_v2> = ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<boot_img_hdr_v2>(),
+        1660usize,
+        concat!("Size of: ", stringify!(boot_img_hdr_v2))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<boot_img_hdr_v2>(),
+        1usize,
+        concat!("Alignment of ", stringify!(boot_img_hdr_v2))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).dtb_size) as usize - ptr as usize },
+        1648usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v2), "::", stringify!(dtb_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).dtb_addr) as usize - ptr as usize },
+        1652usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v2), "::", stringify!(dtb_addr))
+    );
+}
+impl Default for boot_img_hdr_v2 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct boot_img_hdr_v3 {
+    pub magic: [u8; 8usize],
+    pub kernel_size: u32,
+    pub ramdisk_size: u32,
+    pub os_version: u32,
+    pub header_size: u32,
+    pub reserved: [u32; 4usize],
+    pub header_version: u32,
+    pub cmdline: [u8; 1536usize],
+}
+#[test]
+fn bindgen_test_layout_boot_img_hdr_v3() {
+    const UNINIT: ::core::mem::MaybeUninit<boot_img_hdr_v3> = ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<boot_img_hdr_v3>(),
+        1580usize,
+        concat!("Size of: ", stringify!(boot_img_hdr_v3))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<boot_img_hdr_v3>(),
+        1usize,
+        concat!("Alignment of ", stringify!(boot_img_hdr_v3))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).magic) as usize - ptr as usize },
+        0usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(magic))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).kernel_size) as usize - ptr as usize },
+        8usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(kernel_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_size) as usize - ptr as usize },
+        12usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(ramdisk_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).os_version) as usize - ptr as usize },
+        16usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(os_version))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_size) as usize - ptr as usize },
+        20usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(header_size))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize },
+        24usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(reserved))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_version) as usize - ptr as usize },
+        40usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(header_version))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).cmdline) as usize - ptr as usize },
+        44usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v3), "::", stringify!(cmdline))
+    );
+}
+impl Default for boot_img_hdr_v3 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct vendor_boot_img_hdr_v3 {
+    pub magic: [u8; 8usize],
+    pub header_version: u32,
+    pub page_size: u32,
+    pub kernel_addr: u32,
+    pub ramdisk_addr: u32,
+    pub vendor_ramdisk_size: u32,
+    pub cmdline: [u8; 2048usize],
+    pub tags_addr: u32,
+    pub name: [u8; 16usize],
+    pub header_size: u32,
+    pub dtb_size: u32,
+    pub dtb_addr: u64,
+}
+#[test]
+fn bindgen_test_layout_vendor_boot_img_hdr_v3() {
+    const UNINIT: ::core::mem::MaybeUninit<vendor_boot_img_hdr_v3> =
+        ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<vendor_boot_img_hdr_v3>(),
+        2112usize,
+        concat!("Size of: ", stringify!(vendor_boot_img_hdr_v3))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<vendor_boot_img_hdr_v3>(),
+        1usize,
+        concat!("Alignment of ", stringify!(vendor_boot_img_hdr_v3))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).magic) as usize - ptr as usize },
+        0usize,
+        concat!("Offset of field: ", stringify!(vendor_boot_img_hdr_v3), "::", stringify!(magic))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_version) as usize - ptr as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(header_version)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).page_size) as usize - ptr as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(page_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).kernel_addr) as usize - ptr as usize },
+        16usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(kernel_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_addr) as usize - ptr as usize },
+        20usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(ramdisk_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).vendor_ramdisk_size) as usize - ptr as usize },
+        24usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(vendor_ramdisk_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).cmdline) as usize - ptr as usize },
+        28usize,
+        concat!("Offset of field: ", stringify!(vendor_boot_img_hdr_v3), "::", stringify!(cmdline))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).tags_addr) as usize - ptr as usize },
+        2076usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(tags_addr)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).name) as usize - ptr as usize },
+        2080usize,
+        concat!("Offset of field: ", stringify!(vendor_boot_img_hdr_v3), "::", stringify!(name))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).header_size) as usize - ptr as usize },
+        2096usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(header_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).dtb_size) as usize - ptr as usize },
+        2100usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(dtb_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).dtb_addr) as usize - ptr as usize },
+        2104usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v3),
+            "::",
+            stringify!(dtb_addr)
+        )
+    );
+}
+impl Default for vendor_boot_img_hdr_v3 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct boot_img_hdr_v4 {
+    pub _base: boot_img_hdr_v3,
+    pub signature_size: u32,
+}
+#[test]
+fn bindgen_test_layout_boot_img_hdr_v4() {
+    const UNINIT: ::core::mem::MaybeUninit<boot_img_hdr_v4> = ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<boot_img_hdr_v4>(),
+        1584usize,
+        concat!("Size of: ", stringify!(boot_img_hdr_v4))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<boot_img_hdr_v4>(),
+        1usize,
+        concat!("Alignment of ", stringify!(boot_img_hdr_v4))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).signature_size) as usize - ptr as usize },
+        1580usize,
+        concat!("Offset of field: ", stringify!(boot_img_hdr_v4), "::", stringify!(signature_size))
+    );
+}
+impl Default for boot_img_hdr_v4 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct vendor_boot_img_hdr_v4 {
+    pub _base: vendor_boot_img_hdr_v3,
+    pub vendor_ramdisk_table_size: u32,
+    pub vendor_ramdisk_table_entry_num: u32,
+    pub vendor_ramdisk_table_entry_size: u32,
+    pub bootconfig_size: u32,
+}
+#[test]
+fn bindgen_test_layout_vendor_boot_img_hdr_v4() {
+    const UNINIT: ::core::mem::MaybeUninit<vendor_boot_img_hdr_v4> =
+        ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<vendor_boot_img_hdr_v4>(),
+        2128usize,
+        concat!("Size of: ", stringify!(vendor_boot_img_hdr_v4))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<vendor_boot_img_hdr_v4>(),
+        1usize,
+        concat!("Alignment of ", stringify!(vendor_boot_img_hdr_v4))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).vendor_ramdisk_table_size) as usize - ptr as usize },
+        2112usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v4),
+            "::",
+            stringify!(vendor_ramdisk_table_size)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            ::core::ptr::addr_of!((*ptr).vendor_ramdisk_table_entry_num) as usize - ptr as usize
+        },
+        2116usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v4),
+            "::",
+            stringify!(vendor_ramdisk_table_entry_num)
+        )
+    );
+    assert_eq!(
+        unsafe {
+            ::core::ptr::addr_of!((*ptr).vendor_ramdisk_table_entry_size) as usize - ptr as usize
+        },
+        2120usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v4),
+            "::",
+            stringify!(vendor_ramdisk_table_entry_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).bootconfig_size) as usize - ptr as usize },
+        2124usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_boot_img_hdr_v4),
+            "::",
+            stringify!(bootconfig_size)
+        )
+    );
+}
+impl Default for vendor_boot_img_hdr_v4 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C, packed)]
+#[derive(AsBytes, FromBytes, PartialEq, Copy, Clone, Debug)]
+pub struct vendor_ramdisk_table_entry_v4 {
+    pub ramdisk_size: u32,
+    pub ramdisk_offset: u32,
+    pub ramdisk_type: u32,
+    pub ramdisk_name: [u8; 32usize],
+    pub board_id: [u32; 16usize],
+}
+#[test]
+fn bindgen_test_layout_vendor_ramdisk_table_entry_v4() {
+    const UNINIT: ::core::mem::MaybeUninit<vendor_ramdisk_table_entry_v4> =
+        ::core::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::core::mem::size_of::<vendor_ramdisk_table_entry_v4>(),
+        108usize,
+        concat!("Size of: ", stringify!(vendor_ramdisk_table_entry_v4))
+    );
+    assert_eq!(
+        ::core::mem::align_of::<vendor_ramdisk_table_entry_v4>(),
+        1usize,
+        concat!("Alignment of ", stringify!(vendor_ramdisk_table_entry_v4))
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_size) as usize - ptr as usize },
+        0usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_ramdisk_table_entry_v4),
+            "::",
+            stringify!(ramdisk_size)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_offset) as usize - ptr as usize },
+        4usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_ramdisk_table_entry_v4),
+            "::",
+            stringify!(ramdisk_offset)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_type) as usize - ptr as usize },
+        8usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_ramdisk_table_entry_v4),
+            "::",
+            stringify!(ramdisk_type)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).ramdisk_name) as usize - ptr as usize },
+        12usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_ramdisk_table_entry_v4),
+            "::",
+            stringify!(ramdisk_name)
+        )
+    );
+    assert_eq!(
+        unsafe { ::core::ptr::addr_of!((*ptr).board_id) as usize - ptr as usize },
+        44usize,
+        concat!(
+            "Offset of field: ",
+            stringify!(vendor_ramdisk_table_entry_v4),
+            "::",
+            stringify!(board_id)
+        )
+    );
+}
+impl Default for vendor_ramdisk_table_entry_v4 {
+    fn default() -> Self {
+        let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}