patches and low-level development discussion
 help / color / mirror / code / Atom feed
From: Alyssa Ross <alyssa.ross@unikie.com>
To: devel@spectrum-os.org
Cc: Puck Meerburg <puck@puckipedia.com>,
	Ville Ilvonen <ville.ilvonen@unikie.com>
Subject: [RFC PATCH nixpkgs v2 7/9] cloud-hypervisor: add virtio-gpu support
Date: Fri, 30 Sep 2022 21:09:04 +0000	[thread overview]
Message-ID: <20220930210906.1696349-8-alyssa.ross@unikie.com> (raw)
In-Reply-To: <20220930210906.1696349-1-alyssa.ross@unikie.com>

The virtio-bindings changes update the bindings for recent kernels,
and the vhost change is cherry-picked from crosvm's fork of the crate
to add support for their custom extensions.

Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
---
 .../0001-build-use-local-vhost.patch          |   39 +
 ...dings-regenerate-with-bindgen-0.60.1.patch | 2589 ++++++++++++
 ...0002-build-use-local-virtio-bindings.patch |   39 +
 ...gs-remove-workaround-for-old-bindgen.patch |   28 +
 ...-bindings-regenerate-with-Glibc-2.36.patch |  247 ++
 ...0003-virtio-devices-add-a-GPU-device.patch | 1279 ++++++
 ...-bindings-regenerate-with-Linux-5.19.patch | 1067 +++++
 ...tio-bindings-add-virtio-gpu-bindings.patch | 3587 +++++++++++++++++
 .../cloud-hypervisor/default.nix              |   64 +-
 ...ser-add-shared-memory-region-support.patch |  724 ++++
 10 files changed, 9661 insertions(+), 2 deletions(-)
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0002-build-use-local-virtio-bindings.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0002-virtio-bindings-remove-workaround-for-old-bindgen.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-bindings-regenerate-with-Glibc-2.36.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0004-virtio-bindings-regenerate-with-Linux-5.19.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0005-virtio-bindings-add-virtio-gpu-bindings.patch
 create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch

diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch b/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch
new file mode 100644
index 00000000000..c4152ae3504
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch
@@ -0,0 +1,39 @@
+From 53848d798c617110c5c3f975db47a9555bc276f4 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 28 Sep 2022 12:18:19 +0000
+Subject: [PATCH 1/3] build: use local vhost
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ Cargo.lock | 2 --
+ Cargo.toml | 1 +
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/Cargo.lock b/Cargo.lock
+index 5d026652..b869b6ee 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -1256,8 +1256,6 @@ dependencies = [
+ [[package]]
+ name = "vhost"
+ version = "0.4.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "53567fd9ab820e4f3cc156f24146882fee3c365194c3e1dea74723265f27fc88"
+ dependencies = [
+  "bitflags",
+  "libc",
+diff --git a/Cargo.toml b/Cargo.toml
+index ba8377bb..2294b4c3 100644
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -41,6 +41,7 @@ clap = { version = "3.2.17", features = ["cargo"] }
+ kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
+ kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
+ versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
++vhost = { path = "../vhost" }
+ 
+ [dev-dependencies]
+ dirs = "4.0.0"
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch b/pkgs/applications/virtualization/cloud-hypervisor/0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch
new file mode 100644
index 00000000000..c5ba66e8b36
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch
@@ -0,0 +1,2589 @@
+From c3c2f34c2f89156769d37bc8b450ace9ff7fdbe9 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Tue, 30 Aug 2022 16:18:51 +0000
+Subject: [PATCH 1/5] virtio-bindings: regenerate with bindgen 0.60.1
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/virtio-bindings/CONTRIBUTING.md    |   4 +-
+ crates/virtio-bindings/src/virtio_blk.rs  | 958 +++++++++++++---------
+ crates/virtio-bindings/src/virtio_net.rs  | 817 +++++++++++-------
+ crates/virtio-bindings/src/virtio_ring.rs | 540 +++++++-----
+ 4 files changed, 1426 insertions(+), 893 deletions(-)
+
+diff --git a/crates/virtio-bindings/CONTRIBUTING.md b/crates/virtio-bindings/CONTRIBUTING.md
+index 18c4653..1b3da2f 100644
+--- a/crates/virtio-bindings/CONTRIBUTING.md
++++ b/crates/virtio-bindings/CONTRIBUTING.md
+@@ -4,9 +4,9 @@
+ 
+ ### Bindgen
+ The bindings are currently generated using
+-[bindgen](https://crates.io/crates/bindgen) version 0.49.0:
++[bindgen](https://crates.io/crates/bindgen) version 0.60.1:
+ ```bash
+-cargo install bindgen --vers 0.49.0
++cargo install bindgen --vers 0.60.1
+ ```
+ 
+ ### Linux Kernel
+diff --git a/crates/virtio-bindings/src/virtio_blk.rs b/crates/virtio-bindings/src/virtio_blk.rs
+index 80ddab0..94daca3 100644
+--- a/crates/virtio-bindings/src/virtio_blk.rs
++++ b/crates/virtio-bindings/src/virtio_blk.rs
+@@ -1,4 +1,4 @@
+-/* automatically generated by rust-bindgen */
++/* automatically generated by rust-bindgen 0.60.1 */
+ 
+ pub const __BITS_PER_LONG: u32 = 64;
+ pub const __FD_SETSIZE: u32 = 1024;
+@@ -83,16 +83,23 @@ fn bindgen_test_layout___kernel_fd_set() {
+         8usize,
+         concat!("Alignment of ", stringify!(__kernel_fd_set))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fd_set),
+-            "::",
+-            stringify!(fds_bits)
+-        )
+-    );
++    fn test_field_fds_bits() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fd_set>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fd_set),
++                "::",
++                stringify!(fds_bits)
++            )
++        );
++    }
++    test_field_fds_bits();
+ }
+ pub type __kernel_sighandler_t =
+     ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+@@ -133,16 +140,23 @@ fn bindgen_test_layout___kernel_fsid_t() {
+         4usize,
+         concat!("Alignment of ", stringify!(__kernel_fsid_t))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fsid_t),
+-            "::",
+-            stringify!(val)
+-        )
+-    );
++    fn test_field_val() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fsid_t>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fsid_t),
++                "::",
++                stringify!(val)
++            )
++        );
++    }
++    test_field_val();
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+@@ -214,45 +228,60 @@ fn bindgen_test_layout_virtio_blk_config_virtio_blk_geometry() {
+             stringify!(virtio_blk_config_virtio_blk_geometry)
+         )
+     );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config_virtio_blk_geometry>())).cylinders as *const _
+-                as usize
+-        },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config_virtio_blk_geometry),
+-            "::",
+-            stringify!(cylinders)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config_virtio_blk_geometry>())).heads as *const _
+-                as usize
+-        },
+-        2usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config_virtio_blk_geometry),
+-            "::",
+-            stringify!(heads)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config_virtio_blk_geometry>())).sectors as *const _
+-                as usize
+-        },
+-        3usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config_virtio_blk_geometry),
+-            "::",
+-            stringify!(sectors)
+-        )
+-    );
++    fn test_field_cylinders() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_blk_config_virtio_blk_geometry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).cylinders) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config_virtio_blk_geometry),
++                "::",
++                stringify!(cylinders)
++            )
++        );
++    }
++    test_field_cylinders();
++    fn test_field_heads() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_blk_config_virtio_blk_geometry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).heads) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config_virtio_blk_geometry),
++                "::",
++                stringify!(heads)
++            )
++        );
++    }
++    test_field_heads();
++    fn test_field_sectors() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_blk_config_virtio_blk_geometry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).sectors) as usize - ptr as usize
++            },
++            3usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config_virtio_blk_geometry),
++                "::",
++                stringify!(sectors)
++            )
++        );
++    }
++    test_field_sectors();
+ }
+ #[test]
+ fn bindgen_test_layout_virtio_blk_config() {
+@@ -266,215 +295,329 @@ fn bindgen_test_layout_virtio_blk_config() {
+         1usize,
+         concat!("Alignment of ", stringify!(virtio_blk_config))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).capacity as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(capacity)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).size_max as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(size_max)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).seg_max as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(seg_max)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).geometry as *const _ as usize },
+-        16usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(geometry)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).blk_size as *const _ as usize },
+-        20usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(blk_size)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).physical_block_exp as *const _ as usize
+-        },
+-        24usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(physical_block_exp)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).alignment_offset as *const _ as usize
+-        },
+-        25usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(alignment_offset)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).min_io_size as *const _ as usize },
+-        26usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(min_io_size)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).opt_io_size as *const _ as usize },
+-        28usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(opt_io_size)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).wce as *const _ as usize },
+-        32usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(wce)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).unused as *const _ as usize },
+-        33usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(unused)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).num_queues as *const _ as usize },
+-        34usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(num_queues)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).max_discard_sectors as *const _ as usize
+-        },
+-        36usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(max_discard_sectors)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).max_discard_seg as *const _ as usize
+-        },
+-        40usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(max_discard_seg)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).discard_sector_alignment as *const _
+-                as usize
+-        },
+-        44usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(discard_sector_alignment)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).max_write_zeroes_sectors as *const _
+-                as usize
+-        },
+-        48usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(max_write_zeroes_sectors)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).max_write_zeroes_seg as *const _ as usize
+-        },
+-        52usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(max_write_zeroes_seg)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_config>())).write_zeroes_may_unmap as *const _
+-                as usize
+-        },
+-        56usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(write_zeroes_may_unmap)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_config>())).unused1 as *const _ as usize },
+-        57usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_config),
+-            "::",
+-            stringify!(unused1)
+-        )
+-    );
++    fn test_field_capacity() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capacity) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(capacity)
++            )
++        );
++    }
++    test_field_capacity();
++    fn test_field_size_max() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).size_max) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(size_max)
++            )
++        );
++    }
++    test_field_size_max();
++    fn test_field_seg_max() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).seg_max) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(seg_max)
++            )
++        );
++    }
++    test_field_seg_max();
++    fn test_field_geometry() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).geometry) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(geometry)
++            )
++        );
++    }
++    test_field_geometry();
++    fn test_field_blk_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).blk_size) as usize - ptr as usize
++            },
++            20usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(blk_size)
++            )
++        );
++    }
++    test_field_blk_size();
++    fn test_field_physical_block_exp() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).physical_block_exp) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(physical_block_exp)
++            )
++        );
++    }
++    test_field_physical_block_exp();
++    fn test_field_alignment_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).alignment_offset) as usize - ptr as usize
++            },
++            25usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(alignment_offset)
++            )
++        );
++    }
++    test_field_alignment_offset();
++    fn test_field_min_io_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).min_io_size) as usize - ptr as usize
++            },
++            26usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(min_io_size)
++            )
++        );
++    }
++    test_field_min_io_size();
++    fn test_field_opt_io_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).opt_io_size) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(opt_io_size)
++            )
++        );
++    }
++    test_field_opt_io_size();
++    fn test_field_wce() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).wce) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(wce)
++            )
++        );
++    }
++    test_field_wce();
++    fn test_field_unused() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).unused) as usize - ptr as usize
++            },
++            33usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(unused)
++            )
++        );
++    }
++    test_field_unused();
++    fn test_field_num_queues() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_queues) as usize - ptr as usize
++            },
++            34usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(num_queues)
++            )
++        );
++    }
++    test_field_num_queues();
++    fn test_field_max_discard_sectors() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_discard_sectors) as usize - ptr as usize
++            },
++            36usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(max_discard_sectors)
++            )
++        );
++    }
++    test_field_max_discard_sectors();
++    fn test_field_max_discard_seg() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_discard_seg) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(max_discard_seg)
++            )
++        );
++    }
++    test_field_max_discard_seg();
++    fn test_field_discard_sector_alignment() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).discard_sector_alignment) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(discard_sector_alignment)
++            )
++        );
++    }
++    test_field_discard_sector_alignment();
++    fn test_field_max_write_zeroes_sectors() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_write_zeroes_sectors) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(max_write_zeroes_sectors)
++            )
++        );
++    }
++    test_field_max_write_zeroes_sectors();
++    fn test_field_max_write_zeroes_seg() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_write_zeroes_seg) as usize - ptr as usize
++            },
++            52usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(max_write_zeroes_seg)
++            )
++        );
++    }
++    test_field_max_write_zeroes_seg();
++    fn test_field_write_zeroes_may_unmap() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).write_zeroes_may_unmap) as usize - ptr as usize
++            },
++            56usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(write_zeroes_may_unmap)
++            )
++        );
++    }
++    test_field_write_zeroes_may_unmap();
++    fn test_field_unused1() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).unused1) as usize - ptr as usize
++            },
++            57usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_config),
++                "::",
++                stringify!(unused1)
++            )
++        );
++    }
++    test_field_unused1();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -495,36 +638,57 @@ fn bindgen_test_layout_virtio_blk_outhdr() {
+         8usize,
+         concat!("Alignment of ", stringify!(virtio_blk_outhdr))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_outhdr>())).type_ as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_outhdr),
+-            "::",
+-            stringify!(type_)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_outhdr>())).ioprio as *const _ as usize },
+-        4usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_outhdr),
+-            "::",
+-            stringify!(ioprio)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_blk_outhdr>())).sector as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_outhdr),
+-            "::",
+-            stringify!(sector)
+-        )
+-    );
++    fn test_field_type() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_outhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_outhdr),
++                "::",
++                stringify!(type_)
++            )
++        );
++    }
++    test_field_type();
++    fn test_field_ioprio() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_outhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).ioprio) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_outhdr),
++                "::",
++                stringify!(ioprio)
++            )
++        );
++    }
++    test_field_ioprio();
++    fn test_field_sector() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_outhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).sector) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_outhdr),
++                "::",
++                stringify!(sector)
++            )
++        );
++    }
++    test_field_sector();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -545,43 +709,57 @@ fn bindgen_test_layout_virtio_blk_discard_write_zeroes() {
+         8usize,
+         concat!("Alignment of ", stringify!(virtio_blk_discard_write_zeroes))
+     );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_discard_write_zeroes>())).sector as *const _ as usize
+-        },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_discard_write_zeroes),
+-            "::",
+-            stringify!(sector)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_discard_write_zeroes>())).num_sectors as *const _
+-                as usize
+-        },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_discard_write_zeroes),
+-            "::",
+-            stringify!(num_sectors)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_blk_discard_write_zeroes>())).flags as *const _ as usize
+-        },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_blk_discard_write_zeroes),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
++    fn test_field_sector() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_discard_write_zeroes>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).sector) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_discard_write_zeroes),
++                "::",
++                stringify!(sector)
++            )
++        );
++    }
++    test_field_sector();
++    fn test_field_num_sectors() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_discard_write_zeroes>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_sectors) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_discard_write_zeroes),
++                "::",
++                stringify!(num_sectors)
++            )
++        );
++    }
++    test_field_num_sectors();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_blk_discard_write_zeroes>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_blk_discard_write_zeroes),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -603,44 +781,72 @@ fn bindgen_test_layout_virtio_scsi_inhdr() {
+         4usize,
+         concat!("Alignment of ", stringify!(virtio_scsi_inhdr))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_scsi_inhdr>())).errors as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_scsi_inhdr),
+-            "::",
+-            stringify!(errors)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_scsi_inhdr>())).data_len as *const _ as usize },
+-        4usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_scsi_inhdr),
+-            "::",
+-            stringify!(data_len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_scsi_inhdr>())).sense_len as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_scsi_inhdr),
+-            "::",
+-            stringify!(sense_len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_scsi_inhdr>())).residual as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_scsi_inhdr),
+-            "::",
+-            stringify!(residual)
+-        )
+-    );
++    fn test_field_errors() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_scsi_inhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).errors) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_scsi_inhdr),
++                "::",
++                stringify!(errors)
++            )
++        );
++    }
++    test_field_errors();
++    fn test_field_data_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_scsi_inhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).data_len) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_scsi_inhdr),
++                "::",
++                stringify!(data_len)
++            )
++        );
++    }
++    test_field_data_len();
++    fn test_field_sense_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_scsi_inhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).sense_len) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_scsi_inhdr),
++                "::",
++                stringify!(sense_len)
++            )
++        );
++    }
++    test_field_sense_len();
++    fn test_field_residual() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_scsi_inhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).residual) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_scsi_inhdr),
++                "::",
++                stringify!(residual)
++            )
++        );
++    }
++    test_field_residual();
+ }
+diff --git a/crates/virtio-bindings/src/virtio_net.rs b/crates/virtio-bindings/src/virtio_net.rs
+index c788791..479392e 100644
+--- a/crates/virtio-bindings/src/virtio_net.rs
++++ b/crates/virtio-bindings/src/virtio_net.rs
+@@ -1,20 +1,20 @@
+-/* automatically generated by rust-bindgen */
++/* automatically generated by rust-bindgen 0.60.1 */
+ 
+ #[repr(C)]
+ #[derive(Default)]
+ pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
+ impl<T> __IncompleteArrayField<T> {
+     #[inline]
+-    pub fn new() -> Self {
++    pub const fn new() -> Self {
+         __IncompleteArrayField(::std::marker::PhantomData, [])
+     }
+     #[inline]
+-    pub unsafe fn as_ptr(&self) -> *const T {
+-        ::std::mem::transmute(self)
++    pub fn as_ptr(&self) -> *const T {
++        self as *const _ as *const T
+     }
+     #[inline]
+-    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+-        ::std::mem::transmute(self)
++    pub fn as_mut_ptr(&mut self) -> *mut T {
++        self as *mut _ as *mut T
+     }
+     #[inline]
+     pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+@@ -30,12 +30,6 @@ impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+         fmt.write_str("__IncompleteArrayField")
+     }
+ }
+-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+-    #[inline]
+-    fn clone(&self) -> Self {
+-        Self::new()
+-    }
+-}
+ pub const __BITS_PER_LONG: u32 = 64;
+ pub const __FD_SETSIZE: u32 = 1024;
+ pub const VIRTIO_ID_NET: u32 = 1;
+@@ -250,16 +244,23 @@ fn bindgen_test_layout___kernel_fd_set() {
+         8usize,
+         concat!("Alignment of ", stringify!(__kernel_fd_set))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fd_set),
+-            "::",
+-            stringify!(fds_bits)
+-        )
+-    );
++    fn test_field_fds_bits() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fd_set>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fd_set),
++                "::",
++                stringify!(fds_bits)
++            )
++        );
++    }
++    test_field_fds_bits();
+ }
+ pub type __kernel_sighandler_t =
+     ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+@@ -300,16 +301,23 @@ fn bindgen_test_layout___kernel_fsid_t() {
+         4usize,
+         concat!("Alignment of ", stringify!(__kernel_fsid_t))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fsid_t),
+-            "::",
+-            stringify!(val)
+-        )
+-    );
++    fn test_field_val() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fsid_t>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fsid_t),
++                "::",
++                stringify!(val)
++            )
++        );
++    }
++    test_field_val();
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+@@ -352,36 +360,57 @@ fn bindgen_test_layout_ethhdr() {
+         1usize,
+         concat!("Alignment of ", stringify!(ethhdr))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<ethhdr>())).h_dest as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(ethhdr),
+-            "::",
+-            stringify!(h_dest)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<ethhdr>())).h_source as *const _ as usize },
+-        6usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(ethhdr),
+-            "::",
+-            stringify!(h_source)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<ethhdr>())).h_proto as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(ethhdr),
+-            "::",
+-            stringify!(h_proto)
+-        )
+-    );
++    fn test_field_h_dest() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<ethhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).h_dest) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(ethhdr),
++                "::",
++                stringify!(h_dest)
++            )
++        );
++    }
++    test_field_h_dest();
++    fn test_field_h_source() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<ethhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).h_source) as usize - ptr as usize
++            },
++            6usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(ethhdr),
++                "::",
++                stringify!(h_source)
++            )
++        );
++    }
++    test_field_h_source();
++    fn test_field_h_proto() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<ethhdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).h_proto) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(ethhdr),
++                "::",
++                stringify!(h_proto)
++            )
++        );
++    }
++    test_field_h_proto();
+ }
+ #[repr(C, packed)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -405,68 +434,108 @@ fn bindgen_test_layout_virtio_net_config() {
+         1usize,
+         concat!("Alignment of ", stringify!(virtio_net_config))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_config>())).mac as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(mac)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_config>())).status as *const _ as usize },
+-        6usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(status)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_net_config>())).max_virtqueue_pairs as *const _ as usize
+-        },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(max_virtqueue_pairs)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_config>())).mtu as *const _ as usize },
+-        10usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(mtu)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_config>())).speed as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(speed)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_config>())).duplex as *const _ as usize },
+-        16usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_config),
+-            "::",
+-            stringify!(duplex)
+-        )
+-    );
++    fn test_field_mac() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).mac) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(mac)
++            )
++        );
++    }
++    test_field_mac();
++    fn test_field_status() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).status) as usize - ptr as usize
++            },
++            6usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(status)
++            )
++        );
++    }
++    test_field_status();
++    fn test_field_max_virtqueue_pairs() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_virtqueue_pairs) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(max_virtqueue_pairs)
++            )
++        );
++    }
++    test_field_max_virtqueue_pairs();
++    fn test_field_mtu() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).mtu) as usize - ptr as usize
++            },
++            10usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(mtu)
++            )
++        );
++    }
++    test_field_mtu();
++    fn test_field_speed() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).speed) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(speed)
++            )
++        );
++    }
++    test_field_speed();
++    fn test_field_duplex() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).duplex) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(duplex)
++            )
++        );
++    }
++    test_field_duplex();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -491,76 +560,125 @@ fn bindgen_test_layout_virtio_net_hdr_v1() {
+         2usize,
+         concat!("Alignment of ", stringify!(virtio_net_hdr_v1))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).flags as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).gso_type as *const _ as usize },
+-        1usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(gso_type)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).hdr_len as *const _ as usize },
+-        2usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(hdr_len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).gso_size as *const _ as usize },
+-        4usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(gso_size)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).csum_start as *const _ as usize },
+-        6usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(csum_start)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).csum_offset as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(csum_offset)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_v1>())).num_buffers as *const _ as usize },
+-        10usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_v1),
+-            "::",
+-            stringify!(num_buffers)
+-        )
+-    );
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_gso_type() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).gso_type) as usize - ptr as usize
++            },
++            1usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(gso_type)
++            )
++        );
++    }
++    test_field_gso_type();
++    fn test_field_hdr_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr_len) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(hdr_len)
++            )
++        );
++    }
++    test_field_hdr_len();
++    fn test_field_gso_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).gso_size) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(gso_size)
++            )
++        );
++    }
++    test_field_gso_size();
++    fn test_field_csum_start() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_start) as usize - ptr as usize
++            },
++            6usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(csum_start)
++            )
++        );
++    }
++    test_field_csum_start();
++    fn test_field_csum_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_offset) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(csum_offset)
++            )
++        );
++    }
++    test_field_csum_offset();
++    fn test_field_num_buffers() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_buffers) as usize - ptr as usize
++            },
++            10usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1),
++                "::",
++                stringify!(num_buffers)
++            )
++        );
++    }
++    test_field_num_buffers();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -584,66 +702,108 @@ fn bindgen_test_layout_virtio_net_hdr() {
+         2usize,
+         concat!("Alignment of ", stringify!(virtio_net_hdr))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).flags as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).gso_type as *const _ as usize },
+-        1usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(gso_type)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).hdr_len as *const _ as usize },
+-        2usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(hdr_len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).gso_size as *const _ as usize },
+-        4usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(gso_size)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).csum_start as *const _ as usize },
+-        6usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(csum_start)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr>())).csum_offset as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr),
+-            "::",
+-            stringify!(csum_offset)
+-        )
+-    );
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_gso_type() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).gso_type) as usize - ptr as usize
++            },
++            1usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(gso_type)
++            )
++        );
++    }
++    test_field_gso_type();
++    fn test_field_hdr_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr_len) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(hdr_len)
++            )
++        );
++    }
++    test_field_hdr_len();
++    fn test_field_gso_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).gso_size) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(gso_size)
++            )
++        );
++    }
++    test_field_gso_size();
++    fn test_field_csum_start() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_start) as usize - ptr as usize
++            },
++            6usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(csum_start)
++            )
++        );
++    }
++    test_field_csum_start();
++    fn test_field_csum_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_offset) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr),
++                "::",
++                stringify!(csum_offset)
++            )
++        );
++    }
++    test_field_csum_offset();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -663,28 +823,40 @@ fn bindgen_test_layout_virtio_net_hdr_mrg_rxbuf() {
+         2usize,
+         concat!("Alignment of ", stringify!(virtio_net_hdr_mrg_rxbuf))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_hdr_mrg_rxbuf>())).hdr as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_mrg_rxbuf),
+-            "::",
+-            stringify!(hdr)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_net_hdr_mrg_rxbuf>())).num_buffers as *const _ as usize
+-        },
+-        10usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_hdr_mrg_rxbuf),
+-            "::",
+-            stringify!(num_buffers)
+-        )
+-    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_mrg_rxbuf>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_mrg_rxbuf),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_num_buffers() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_mrg_rxbuf>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_buffers) as usize - ptr as usize
++            },
++            10usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_mrg_rxbuf),
++                "::",
++                stringify!(num_buffers)
++            )
++        );
++    }
++    test_field_num_buffers();
+ }
+ #[repr(C, packed)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -704,30 +876,43 @@ fn bindgen_test_layout_virtio_net_ctrl_hdr() {
+         1usize,
+         concat!("Alignment of ", stringify!(virtio_net_ctrl_hdr))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_ctrl_hdr>())).class as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_ctrl_hdr),
+-            "::",
+-            stringify!(class)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<virtio_net_ctrl_hdr>())).cmd as *const _ as usize },
+-        1usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_ctrl_hdr),
+-            "::",
+-            stringify!(cmd)
+-        )
+-    );
++    fn test_field_class() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).class) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_ctrl_hdr),
++                "::",
++                stringify!(class)
++            )
++        );
++    }
++    test_field_class();
++    fn test_field_cmd() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).cmd) as usize - ptr as usize
++            },
++            1usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_ctrl_hdr),
++                "::",
++                stringify!(cmd)
++            )
++        );
++    }
++    test_field_cmd();
+ }
+ pub type virtio_net_ctrl_ack = __u8;
+ #[repr(C, packed)]
+-#[derive(Default)]
+ pub struct virtio_net_ctrl_mac {
+     pub entries: __virtio32,
+     pub macs: __IncompleteArrayField<[__u8; 6usize]>,
+@@ -745,6 +930,15 @@ fn bindgen_test_layout_virtio_net_ctrl_mac() {
+         concat!("Alignment of ", stringify!(virtio_net_ctrl_mac))
+     );
+ }
++impl Default for virtio_net_ctrl_mac {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
++}
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+ pub struct virtio_net_ctrl_mq {
+@@ -762,16 +956,21 @@ fn bindgen_test_layout_virtio_net_ctrl_mq() {
+         2usize,
+         concat!("Alignment of ", stringify!(virtio_net_ctrl_mq))
+     );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<virtio_net_ctrl_mq>())).virtqueue_pairs as *const _ as usize
+-        },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(virtio_net_ctrl_mq),
+-            "::",
+-            stringify!(virtqueue_pairs)
+-        )
+-    );
++    fn test_field_virtqueue_pairs() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_ctrl_mq>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).virtqueue_pairs) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_ctrl_mq),
++                "::",
++                stringify!(virtqueue_pairs)
++            )
++        );
++    }
++    test_field_virtqueue_pairs();
+ }
+diff --git a/crates/virtio-bindings/src/virtio_ring.rs b/crates/virtio-bindings/src/virtio_ring.rs
+index 0d51550..13fa409 100644
+--- a/crates/virtio-bindings/src/virtio_ring.rs
++++ b/crates/virtio-bindings/src/virtio_ring.rs
+@@ -1,20 +1,20 @@
+-/* automatically generated by rust-bindgen */
++/* automatically generated by rust-bindgen 0.60.1 */
+ 
+ #[repr(C)]
+ #[derive(Default)]
+ pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
+ impl<T> __IncompleteArrayField<T> {
+     #[inline]
+-    pub fn new() -> Self {
++    pub const fn new() -> Self {
+         __IncompleteArrayField(::std::marker::PhantomData, [])
+     }
+     #[inline]
+-    pub unsafe fn as_ptr(&self) -> *const T {
+-        ::std::mem::transmute(self)
++    pub fn as_ptr(&self) -> *const T {
++        self as *const _ as *const T
+     }
+     #[inline]
+-    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
+-        ::std::mem::transmute(self)
++    pub fn as_mut_ptr(&mut self) -> *mut T {
++        self as *mut _ as *mut T
+     }
+     #[inline]
+     pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+@@ -30,12 +30,6 @@ impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+         fmt.write_str("__IncompleteArrayField")
+     }
+ }
+-impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
+-    #[inline]
+-    fn clone(&self) -> Self {
+-        Self::new()
+-    }
+-}
+ pub const _STDINT_H: u32 = 1;
+ pub const _FEATURES_H: u32 = 1;
+ pub const _DEFAULT_SOURCE: u32 = 1;
+@@ -190,16 +184,23 @@ fn bindgen_test_layout___fsid_t() {
+         4usize,
+         concat!("Alignment of ", stringify!(__fsid_t))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__fsid_t>())).__val as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__fsid_t),
+-            "::",
+-            stringify!(__val)
+-        )
+-    );
++    fn test_field___val() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__fsid_t>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).__val) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__fsid_t),
++                "::",
++                stringify!(__val)
++            )
++        );
++    }
++    test_field___val();
+ }
+ pub type __clock_t = ::std::os::raw::c_long;
+ pub type __rlim_t = ::std::os::raw::c_ulong;
+@@ -271,16 +272,23 @@ fn bindgen_test_layout___kernel_fd_set() {
+         8usize,
+         concat!("Alignment of ", stringify!(__kernel_fd_set))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fd_set>())).fds_bits as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fd_set),
+-            "::",
+-            stringify!(fds_bits)
+-        )
+-    );
++    fn test_field_fds_bits() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fd_set>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fd_set),
++                "::",
++                stringify!(fds_bits)
++            )
++        );
++    }
++    test_field_fds_bits();
+ }
+ pub type __kernel_sighandler_t =
+     ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
+@@ -321,16 +329,23 @@ fn bindgen_test_layout___kernel_fsid_t() {
+         4usize,
+         concat!("Alignment of ", stringify!(__kernel_fsid_t))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<__kernel_fsid_t>())).val as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(__kernel_fsid_t),
+-            "::",
+-            stringify!(val)
+-        )
+-    );
++    fn test_field_val() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fsid_t>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fsid_t),
++                "::",
++                stringify!(val)
++            )
++        );
++    }
++    test_field_val();
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
+@@ -374,46 +389,74 @@ fn bindgen_test_layout_vring_desc() {
+         8usize,
+         concat!("Alignment of ", stringify!(vring_desc))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_desc>())).addr as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_desc),
+-            "::",
+-            stringify!(addr)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_desc>())).len as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_desc),
+-            "::",
+-            stringify!(len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_desc>())).flags as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_desc),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_desc>())).next as *const _ as usize },
+-        14usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_desc),
+-            "::",
+-            stringify!(next)
+-        )
+-    );
++    fn test_field_addr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_desc),
++                "::",
++                stringify!(addr)
++            )
++        );
++    }
++    test_field_addr();
++    fn test_field_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_desc),
++                "::",
++                stringify!(len)
++            )
++        );
++    }
++    test_field_len();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_desc),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_next() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).next) as usize - ptr as usize
++            },
++            14usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_desc),
++                "::",
++                stringify!(next)
++            )
++        );
++    }
++    test_field_next();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default)]
+@@ -453,26 +496,40 @@ fn bindgen_test_layout_vring_used_elem() {
+         4usize,
+         concat!("Alignment of ", stringify!(vring_used_elem))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_used_elem>())).id as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_used_elem),
+-            "::",
+-            stringify!(id)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_used_elem>())).len as *const _ as usize },
+-        4usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_used_elem),
+-            "::",
+-            stringify!(len)
+-        )
+-    );
++    fn test_field_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_used_elem>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_used_elem),
++                "::",
++                stringify!(id)
++            )
++        );
++    }
++    test_field_id();
++    fn test_field_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_used_elem>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_used_elem),
++                "::",
++                stringify!(len)
++            )
++        );
++    }
++    test_field_len();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default)]
+@@ -480,7 +537,6 @@ pub struct vring_used {
+     pub flags: __virtio16,
+     pub idx: __virtio16,
+     pub ring: __IncompleteArrayField<vring_used_elem>,
+-    pub __bindgen_align: [u32; 0usize],
+ }
+ #[test]
+ fn bindgen_test_layout_vring_used() {
+@@ -515,50 +571,82 @@ fn bindgen_test_layout_vring() {
+         8usize,
+         concat!("Alignment of ", stringify!(vring))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring>())).num as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring),
+-            "::",
+-            stringify!(num)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring>())).desc as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring),
+-            "::",
+-            stringify!(desc)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring>())).avail as *const _ as usize },
+-        16usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring),
+-            "::",
+-            stringify!(avail)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring>())).used as *const _ as usize },
+-        24usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring),
+-            "::",
+-            stringify!(used)
+-        )
+-    );
++    fn test_field_num() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring),
++                "::",
++                stringify!(num)
++            )
++        );
++    }
++    test_field_num();
++    fn test_field_desc() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).desc) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring),
++                "::",
++                stringify!(desc)
++            )
++        );
++    }
++    test_field_desc();
++    fn test_field_avail() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).avail) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring),
++                "::",
++                stringify!(avail)
++            )
++        );
++    }
++    test_field_avail();
++    fn test_field_used() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).used) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring),
++                "::",
++                stringify!(used)
++            )
++        );
++    }
++    test_field_used();
+ }
+ impl Default for vring {
+     fn default() -> Self {
+-        unsafe { ::std::mem::zeroed() }
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
+     }
+ }
+ #[repr(C)]
+@@ -579,28 +667,40 @@ fn bindgen_test_layout_vring_packed_desc_event() {
+         2usize,
+         concat!("Alignment of ", stringify!(vring_packed_desc_event))
+     );
+-    assert_eq!(
+-        unsafe {
+-            &(*(::std::ptr::null::<vring_packed_desc_event>())).off_wrap as *const _ as usize
+-        },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc_event),
+-            "::",
+-            stringify!(off_wrap)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_packed_desc_event>())).flags as *const _ as usize },
+-        2usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc_event),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
++    fn test_field_off_wrap() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc_event>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).off_wrap) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc_event),
++                "::",
++                stringify!(off_wrap)
++            )
++        );
++    }
++    test_field_off_wrap();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc_event>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc_event),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -622,44 +722,72 @@ fn bindgen_test_layout_vring_packed_desc() {
+         8usize,
+         concat!("Alignment of ", stringify!(vring_packed_desc))
+     );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_packed_desc>())).addr as *const _ as usize },
+-        0usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc),
+-            "::",
+-            stringify!(addr)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_packed_desc>())).len as *const _ as usize },
+-        8usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc),
+-            "::",
+-            stringify!(len)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_packed_desc>())).id as *const _ as usize },
+-        12usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc),
+-            "::",
+-            stringify!(id)
+-        )
+-    );
+-    assert_eq!(
+-        unsafe { &(*(::std::ptr::null::<vring_packed_desc>())).flags as *const _ as usize },
+-        14usize,
+-        concat!(
+-            "Offset of field: ",
+-            stringify!(vring_packed_desc),
+-            "::",
+-            stringify!(flags)
+-        )
+-    );
++    fn test_field_addr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc),
++                "::",
++                stringify!(addr)
++            )
++        );
++    }
++    test_field_addr();
++    fn test_field_len() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc),
++                "::",
++                stringify!(len)
++            )
++        );
++    }
++    test_field_len();
++    fn test_field_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc),
++                "::",
++                stringify!(id)
++            )
++        );
++    }
++    test_field_id();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_packed_desc>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            14usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_packed_desc),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
+ }
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0002-build-use-local-virtio-bindings.patch b/pkgs/applications/virtualization/cloud-hypervisor/0002-build-use-local-virtio-bindings.patch
new file mode 100644
index 00000000000..e5d56924154
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0002-build-use-local-virtio-bindings.patch
@@ -0,0 +1,39 @@
+From f8d05ec6b4b581069da14fe54df93b932223cd24 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 28 Sep 2022 12:30:42 +0000
+Subject: [PATCH 2/3] build: use local virtio-bindings
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ Cargo.lock | 2 --
+ Cargo.toml | 1 +
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/Cargo.lock b/Cargo.lock
+index b869b6ee..d119f28e 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -1319,8 +1319,6 @@ dependencies = [
+ [[package]]
+ name = "virtio-bindings"
+ version = "0.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
+ 
+ [[package]]
+ name = "virtio-devices"
+diff --git a/Cargo.toml b/Cargo.toml
+index 2294b4c3..8900236a 100644
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -42,6 +42,7 @@ kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branc
+ kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
+ versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
+ vhost = { path = "../vhost" }
++virtio-bindings = { path = "../virtio-bindings" }
+ 
+ [dev-dependencies]
+ dirs = "4.0.0"
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0002-virtio-bindings-remove-workaround-for-old-bindgen.patch b/pkgs/applications/virtualization/cloud-hypervisor/0002-virtio-bindings-remove-workaround-for-old-bindgen.patch
new file mode 100644
index 00000000000..3bf339d320f
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0002-virtio-bindings-remove-workaround-for-old-bindgen.patch
@@ -0,0 +1,28 @@
+From f29e97e490efac68d3d8c92a50716fb2db76e7df Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 31 Aug 2022 16:37:13 +0000
+Subject: [PATCH 2/5] virtio-bindings: remove workaround for old bindgen
+
+The linked issue was fixed in bindgen 0.60.0.
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/virtio-bindings/src/lib.rs | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/crates/virtio-bindings/src/lib.rs b/crates/virtio-bindings/src/lib.rs
+index 257ebfc..9702f17 100644
+--- a/crates/virtio-bindings/src/lib.rs
++++ b/crates/virtio-bindings/src/lib.rs
+@@ -5,8 +5,6 @@
+ #![allow(non_upper_case_globals)]
+ #![allow(non_camel_case_types)]
+ #![allow(non_snake_case)]
+-// Keep this until https://github.com/rust-lang/rust-bindgen/issues/1651 is fixed.
+-#![cfg_attr(test, allow(deref_nullptr, unaligned_references))]
+ 
+ pub mod virtio_blk;
+ pub mod virtio_net;
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-bindings-regenerate-with-Glibc-2.36.patch b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-bindings-regenerate-with-Glibc-2.36.patch
new file mode 100644
index 00000000000..99efa76e393
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-bindings-regenerate-with-Glibc-2.36.patch
@@ -0,0 +1,247 @@
+From e83b5b0a8d2c3b7a380d7741d7e20824cdc8245f Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 31 Aug 2022 16:28:41 +0000
+Subject: [PATCH 3/5] virtio-bindings: regenerate with Glibc 2.36
+
+In future, it would be good to exclude a lot of these Glibc
+re-exports.  They're probably not required for all the virtio bindings
+we want to expose.
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/virtio-bindings/src/virtio_net.rs  |  34 ++++++
+ crates/virtio-bindings/src/virtio_ring.rs | 122 +++++++++++++++++++++-
+ 2 files changed, 151 insertions(+), 5 deletions(-)
+
+diff --git a/crates/virtio-bindings/src/virtio_net.rs b/crates/virtio-bindings/src/virtio_net.rs
+index 479392e..5707375 100644
+--- a/crates/virtio-bindings/src/virtio_net.rs
++++ b/crates/virtio-bindings/src/virtio_net.rs
+@@ -929,6 +929,40 @@ fn bindgen_test_layout_virtio_net_ctrl_mac() {
+         1usize,
+         concat!("Alignment of ", stringify!(virtio_net_ctrl_mac))
+     );
++    fn test_field_entries() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_ctrl_mac>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).entries) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_ctrl_mac),
++                "::",
++                stringify!(entries)
++            )
++        );
++    }
++    test_field_entries();
++    fn test_field_macs() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_ctrl_mac>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).macs) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_ctrl_mac),
++                "::",
++                stringify!(macs)
++            )
++        );
++    }
++    test_field_macs();
+ }
+ impl Default for virtio_net_ctrl_mac {
+     fn default() -> Self {
+diff --git a/crates/virtio-bindings/src/virtio_ring.rs b/crates/virtio-bindings/src/virtio_ring.rs
+index 13fa409..60b84ab 100644
+--- a/crates/virtio-bindings/src/virtio_ring.rs
++++ b/crates/virtio-bindings/src/virtio_ring.rs
+@@ -33,6 +33,7 @@ impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
+ pub const _STDINT_H: u32 = 1;
+ pub const _FEATURES_H: u32 = 1;
+ pub const _DEFAULT_SOURCE: u32 = 1;
++pub const __GLIBC_USE_ISOC2X: u32 = 0;
+ pub const __USE_ISOC11: u32 = 1;
+ pub const __USE_ISOC99: u32 = 1;
+ pub const __USE_ISOC95: u32 = 1;
+@@ -46,6 +47,10 @@ pub const __USE_POSIX199506: u32 = 1;
+ pub const __USE_XOPEN2K: u32 = 1;
+ pub const __USE_XOPEN2K8: u32 = 1;
+ pub const _ATFILE_SOURCE: u32 = 1;
++pub const __WORDSIZE: u32 = 64;
++pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
++pub const __SYSCALL_WORDSIZE: u32 = 64;
++pub const __TIMESIZE: u32 = 64;
+ pub const __USE_MISC: u32 = 1;
+ pub const __USE_ATFILE: u32 = 1;
+ pub const __USE_FORTIFY_LEVEL: u32 = 0;
+@@ -53,27 +58,31 @@ pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0;
+ pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0;
+ pub const _STDC_PREDEF_H: u32 = 1;
+ pub const __STDC_IEC_559__: u32 = 1;
++pub const __STDC_IEC_60559_BFP__: u32 = 201404;
+ pub const __STDC_IEC_559_COMPLEX__: u32 = 1;
++pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404;
+ pub const __STDC_ISO_10646__: u32 = 201706;
+ pub const __GNU_LIBRARY__: u32 = 6;
+ pub const __GLIBC__: u32 = 2;
+-pub const __GLIBC_MINOR__: u32 = 29;
++pub const __GLIBC_MINOR__: u32 = 36;
+ pub const _SYS_CDEFS_H: u32 = 1;
+ pub const __glibc_c99_flexarr_available: u32 = 1;
+-pub const __WORDSIZE: u32 = 64;
+-pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1;
+-pub const __SYSCALL_WORDSIZE: u32 = 64;
++pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0;
+ pub const __HAVE_GENERIC_SELECTION: u32 = 1;
+ pub const __GLIBC_USE_LIB_EXT2: u32 = 0;
+ pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0;
++pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 0;
++pub const __GLIBC_USE_IEC_60559_EXT: u32 = 0;
+ pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0;
++pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 0;
+ pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0;
+ pub const _BITS_TYPES_H: u32 = 1;
+-pub const __TIMESIZE: u32 = 64;
+ pub const _BITS_TYPESIZES_H: u32 = 1;
+ pub const __OFF_T_MATCHES_OFF64_T: u32 = 1;
+ pub const __INO_T_MATCHES_INO64_T: u32 = 1;
+ pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1;
++pub const __STATFS_MATCHES_STATFS64: u32 = 1;
++pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1;
+ pub const __FD_SETSIZE: u32 = 1024;
+ pub const _BITS_TIME64_H: u32 = 1;
+ pub const _BITS_WCHAR_H: u32 = 1;
+@@ -209,6 +218,7 @@ pub type __id_t = ::std::os::raw::c_uint;
+ pub type __time_t = ::std::os::raw::c_long;
+ pub type __useconds_t = ::std::os::raw::c_uint;
+ pub type __suseconds_t = ::std::os::raw::c_long;
++pub type __suseconds64_t = ::std::os::raw::c_long;
+ pub type __daddr_t = ::std::os::raw::c_int;
+ pub type __key_t = ::std::os::raw::c_int;
+ pub type __clockid_t = ::std::os::raw::c_int;
+@@ -477,6 +487,57 @@ fn bindgen_test_layout_vring_avail() {
+         2usize,
+         concat!("Alignment of ", stringify!(vring_avail))
+     );
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_avail>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_avail),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_idx() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_avail>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).idx) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_avail),
++                "::",
++                stringify!(idx)
++            )
++        );
++    }
++    test_field_idx();
++    fn test_field_ring() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_avail>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).ring) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_avail),
++                "::",
++                stringify!(ring)
++            )
++        );
++    }
++    test_field_ring();
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+@@ -550,6 +611,57 @@ fn bindgen_test_layout_vring_used() {
+         4usize,
+         concat!("Alignment of ", stringify!(vring_used))
+     );
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_used>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_used),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_idx() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_used>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).idx) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_used),
++                "::",
++                stringify!(idx)
++            )
++        );
++    }
++    test_field_idx();
++    fn test_field_ring() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<vring_used>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).ring) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(vring_used),
++                "::",
++                stringify!(ring)
++            )
++        );
++    }
++    test_field_ring();
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy, Clone, PartialEq)]
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch
new file mode 100644
index 00000000000..20b1f9da3af
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch
@@ -0,0 +1,1279 @@
+From cadce3914276387389d10fd2d180c85c46d77f20 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 7 Sep 2022 14:16:29 +0000
+Subject: [PATCH 3/3] virtio-devices: add a GPU device
+
+This adds support for exposing a virtio-gpu device to guest by
+implementing a vhost-user frontend compatible with crosvm's GPU device
+backend.
+
+Note that this is not the same as the "vhost-user-gpu" protocol
+implemented by QEMU.
+
+Adding a GPU device from the command line looks like this:
+
+    --gpu socket=/path/to/crosvm-gpu-vhost-user.sock
+
+As a workaround, We fall back to trying to map shared memory as
+read-only if it can't be mapped read-write, because wlroots' keymaps
+are read-only, and crosvm does not properly handle this, causing
+cloud-hypervisor to crash.
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+Co-authored-by: Puck Meerburg <puck@puckipedia.com>
+Signed-off-by: Puck Meerburg <puck@puckipedia.com>
+---
+ Cargo.lock                                    |   1 +
+ src/main.rs                                   |   9 +
+ virtio-devices/src/device.rs                  |   8 +-
+ virtio-devices/src/lib.rs                     |   2 +
+ virtio-devices/src/seccomp_filters.rs         |  10 +
+ virtio-devices/src/transport/pci_device.rs    |   4 +-
+ virtio-devices/src/vhost_user/gpu.rs          | 372 ++++++++++++++++++
+ virtio-devices/src/vhost_user/mod.rs          |   2 +
+ .../src/vhost_user/vu_common_ctrl.rs          |  14 +-
+ vmm/Cargo.toml                                |   1 +
+ vmm/src/api/mod.rs                            |   7 +
+ vmm/src/config.rs                             | 123 ++++++
+ vmm/src/device_manager.rs                     | 140 ++++++-
+ vmm/src/lib.rs                                |  83 ++++
+ vmm/src/vm.rs                                 |  33 +-
+ 15 files changed, 793 insertions(+), 16 deletions(-)
+ create mode 100644 virtio-devices/src/vhost_user/gpu.rs
+
+diff --git a/Cargo.lock b/Cargo.lock
+index d119f28e..c8a20cef 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -1463,6 +1463,7 @@ dependencies = [
+  "vfio-ioctls",
+  "vfio_user",
+  "vhdx",
++ "virtio-bindings",
+  "virtio-devices",
+  "virtio-queue",
+  "vm-allocator",
+diff --git a/src/main.rs b/src/main.rs
+index 8725129a..eac7a126 100644
+--- a/src/main.rs
++++ b/src/main.rs
+@@ -263,6 +263,14 @@ fn create_app<'a>(
+                 .min_values(1)
+                 .group("vm-config"),
+         )
++        .arg(
++            Arg::new("gpu")
++                .long("gpu")
++                .help(config::GpuConfig::SYNTAX)
++                .takes_value(true)
++                .min_values(1)
++                .group("vm-config"),
++        )
+         .arg(
+             Arg::new("pmem")
+                 .long("pmem")
+@@ -724,6 +732,7 @@ mod unit_tests {
+             },
+             balloon: None,
+             fs: None,
++            gpu: None,
+             pmem: None,
+             serial: ConsoleConfig {
+                 file: None,
+diff --git a/virtio-devices/src/device.rs b/virtio-devices/src/device.rs
+index c09adbb2..8bdbb7b9 100644
+--- a/virtio-devices/src/device.rs
++++ b/virtio-devices/src/device.rs
+@@ -11,7 +11,7 @@ use crate::{
+     VIRTIO_F_RING_INDIRECT_DESC,
+ };
+ use libc::EFD_NONBLOCK;
+-use std::collections::HashMap;
++use std::collections::{BTreeMap, HashMap};
+ use std::io::Write;
+ use std::num::Wrapping;
+ use std::sync::{
+@@ -47,19 +47,19 @@ pub struct UserspaceMapping {
+     pub mergeable: bool,
+ }
+ 
+-#[derive(Clone)]
++#[derive(Clone, Debug)]
+ pub struct VirtioSharedMemory {
+     pub offset: u64,
+     pub len: u64,
+ }
+ 
+-#[derive(Clone)]
++#[derive(Clone, Debug)]
+ pub struct VirtioSharedMemoryList {
+     pub host_addr: u64,
+     pub mem_slot: u32,
+     pub addr: GuestAddress,
+     pub len: GuestUsize,
+-    pub region_list: Vec<VirtioSharedMemory>,
++    pub region_list: BTreeMap<u8, VirtioSharedMemory>,
+ }
+ 
+ /// Trait for virtio devices to be driven by a virtio transport.
+diff --git a/virtio-devices/src/lib.rs b/virtio-devices/src/lib.rs
+index 8316d1ce..d1e31f27 100644
+--- a/virtio-devices/src/lib.rs
++++ b/virtio-devices/src/lib.rs
+@@ -88,6 +88,8 @@ pub enum ActivateError {
+     ThreadSpawn(std::io::Error),
+     #[error("Failed to setup vhost-user-fs daemon: {0}")]
+     VhostUserFsSetup(vhost_user::Error),
++    #[error("Failed to setup vhost-user-gpu daemon: {0}")]
++    VhostUserGpuSetup(vhost_user::Error),
+     #[error("Failed to setup vhost-user-blk daemon: {0}")]
+     VhostUserBlkSetup(vhost_user::Error),
+     #[error("Failed to create seccomp filter: {0}")]
+diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs
+index 6044231b..a1ec89d8 100644
+--- a/virtio-devices/src/seccomp_filters.rs
++++ b/virtio-devices/src/seccomp_filters.rs
+@@ -22,6 +22,7 @@ pub enum Thread {
+     VirtioRng,
+     VirtioVhostBlock,
+     VirtioVhostFs,
++    VirtioVhostGpu,
+     VirtioVhostNet,
+     VirtioVhostNetCtl,
+     VirtioVsock,
+@@ -168,6 +169,14 @@ fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
+     ]
+ }
+ 
++fn virtio_vhost_gpu_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
++    vec![
++        (libc::SYS_getcwd, vec![]),
++        (libc::SYS_recvmsg, vec![]),
++        (libc::SYS_sendmsg, vec![]),
++    ]
++}
++
+ fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
+     vec![]
+ }
+@@ -230,6 +239,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
+         Thread::VirtioRng => virtio_rng_thread_rules(),
+         Thread::VirtioVhostBlock => virtio_vhost_block_thread_rules(),
+         Thread::VirtioVhostFs => virtio_vhost_fs_thread_rules(),
++        Thread::VirtioVhostGpu => virtio_vhost_gpu_thread_rules(),
+         Thread::VirtioVhostNet => virtio_vhost_net_thread_rules(),
+         Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(),
+         Thread::VirtioVsock => virtio_vsock_thread_rules(),
+diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs
+index 748d4328..6b0d0daa 100644
+--- a/virtio-devices/src/transport/pci_device.rs
++++ b/virtio-devices/src/transport/pci_device.rs
+@@ -949,11 +949,11 @@ impl PciDevice for VirtioPciDevice {
+ 
+             bars.push(bar);
+ 
+-            for (idx, shm) in shm_list.region_list.iter().enumerate() {
++            for (shmid, shm) in shm_list.region_list.iter() {
+                 let shm_cap = VirtioPciCap64::new(
+                     PciCapabilityType::SharedMemoryConfig,
+                     VIRTIO_SHM_BAR_INDEX as u8,
+-                    idx as u8,
++                    *shmid,
+                     shm.offset,
+                     shm.len,
+                 );
+diff --git a/virtio-devices/src/vhost_user/gpu.rs b/virtio-devices/src/vhost_user/gpu.rs
+new file mode 100644
+index 00000000..2eb18445
+--- /dev/null
++++ b/virtio-devices/src/vhost_user/gpu.rs
+@@ -0,0 +1,372 @@
++// Copyright 2019 Intel Corporation. All Rights Reserved.
++// Copyright 2022 Unikie
++// Copyright 2022 Puck Meerburg
++// SPDX-License-Identifier: Apache-2.0
++
++use crate::seccomp_filters::Thread;
++use crate::thread_helper::spawn_virtio_thread;
++use crate::vhost_user::vu_common_ctrl::VhostUserHandle;
++use crate::vhost_user::{Error, Result, VhostUserCommon};
++use crate::{
++    ActivateError, ActivateResult, GuestMemoryMmap, GuestRegionMmap, MmapRegion, UserspaceMapping,
++    VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioSharedMemoryList,
++    VIRTIO_F_VERSION_1,
++};
++use seccompiler::SeccompAction;
++use std::io::{self, Write};
++use std::os::unix::prelude::AsRawFd;
++use std::sync::{Arc, Barrier, Mutex};
++use std::thread;
++use vhost::vhost_user::message::{
++    VhostUserConfigFlags, VhostUserProtocolFeatures, VhostUserShmemMapMsg, VhostUserShmemUnmapMsg,
++    VhostUserVirtioFeatures,
++};
++use vhost::vhost_user::{
++    HandlerResult, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler,
++};
++use virtio_bindings::virtio_gpu::{
++    VIRTIO_GPU_F_CONTEXT_INIT, VIRTIO_GPU_F_RESOURCE_BLOB, VIRTIO_GPU_F_RESOURCE_UUID,
++    VIRTIO_GPU_F_VIRGL,
++};
++use virtio_queue::Queue;
++use vm_memory::GuestMemoryAtomic;
++use vm_migration::Pausable;
++use vmm_sys_util::eventfd::EventFd;
++
++const QUEUE_SIZES: &[u16] = &[256, 16];
++const NUM_QUEUES: u16 = QUEUE_SIZES.len() as _;
++
++struct SlaveReqHandler {
++    cache_size: u64,
++    mmap_cache_addr: u64,
++}
++
++impl SlaveReqHandler {
++    // Make sure request is within cache range
++    fn is_req_valid(&self, offset: u64, len: u64) -> bool {
++        let end = match offset.checked_add(len) {
++            Some(n) => n,
++            None => return false,
++        };
++
++        !(offset >= self.cache_size || end > self.cache_size)
++    }
++}
++
++impl VhostUserMasterReqHandler for SlaveReqHandler {
++    fn shmem_map(&self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
++        if !self.is_req_valid(req.shm_offset, req.len) {
++            return Err(io::Error::from_raw_os_error(libc::EINVAL));
++        }
++
++        let addr = self.mmap_cache_addr + req.shm_offset;
++        let mut ret = unsafe {
++            libc::mmap(
++                addr as *mut libc::c_void,
++                req.len as usize,
++                req.flags.bits() as i32,
++                libc::MAP_SHARED | libc::MAP_FIXED,
++                fd.as_raw_fd(),
++                req.fd_offset as libc::off_t,
++            )
++        };
++
++        if ret == libc::MAP_FAILED {
++            ret = unsafe {
++                libc::mmap(
++                    addr as *mut libc::c_void,
++                    req.len as usize,
++                    (req.flags.bits() as i32) & !libc::PROT_WRITE,
++                    libc::MAP_SHARED | libc::MAP_FIXED,
++                    fd.as_raw_fd(),
++                    req.fd_offset as libc::off_t,
++                )
++            };
++        }
++
++        if ret == libc::MAP_FAILED {
++            return Err(io::Error::last_os_error());
++        }
++
++        Ok(0)
++    }
++
++    fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        if !self.is_req_valid(req.shm_offset, req.len) {
++            return Err(io::Error::from_raw_os_error(libc::EINVAL));
++        }
++
++        let addr = self.mmap_cache_addr + req.shm_offset;
++        let ret = unsafe {
++            libc::mmap(
++                addr as *mut libc::c_void,
++                req.len as usize,
++                libc::PROT_NONE,
++                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_FIXED,
++                -1,
++                0,
++            )
++        };
++        if ret == libc::MAP_FAILED {
++            return Err(io::Error::last_os_error());
++        }
++
++        Ok(0)
++    }
++}
++
++#[derive(Default)]
++#[repr(C, packed)]
++pub struct VirtioGpuConfig {
++    pub events_read: u32,
++    pub events_clear: u32,
++    pub num_scanouts: u32,
++    pub num_capsets: u32,
++}
++
++pub struct Gpu {
++    common: VirtioCommon,
++    vu_common: VhostUserCommon,
++    id: String,
++    // Hold ownership of the memory that is allocated for the device
++    // which will be automatically dropped when the device is dropped
++    cache: Option<(VirtioSharedMemoryList, MmapRegion)>,
++    slave_req_support: bool,
++    epoll_thread: Option<thread::JoinHandle<()>>,
++    seccomp_action: SeccompAction,
++    exit_evt: EventFd,
++}
++
++impl Gpu {
++    /// Create a new virtio-gpu device.
++    pub fn new(
++        id: String,
++        path: &str,
++        cache: Option<(VirtioSharedMemoryList, MmapRegion)>,
++        seccomp_action: SeccompAction,
++        restoring: bool,
++        exit_evt: EventFd,
++        iommu: bool,
++    ) -> Result<Gpu> {
++        assert!(!restoring);
++
++        // Connect to the vhost-user socket.
++        let mut vu = VhostUserHandle::connect_vhost_user(false, path, NUM_QUEUES as u64, false)?;
++
++        let avail_features = 1 << VIRTIO_F_VERSION_1
++            | 1 << VIRTIO_GPU_F_VIRGL
++            | 1 << VIRTIO_GPU_F_RESOURCE_UUID
++            | 1 << VIRTIO_GPU_F_RESOURCE_BLOB
++            | 1 << VIRTIO_GPU_F_CONTEXT_INIT
++            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
++
++        let avail_protocol_features =
++            VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::SLAVE_REQ;
++
++        let (acked_features, acked_protocol_features) =
++            vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?;
++
++        Ok(Gpu {
++            common: VirtioCommon {
++                device_type: VirtioDeviceType::Gpu as u32,
++                avail_features: acked_features,
++                // If part of the available features that have been acked, the
++                // PROTOCOL_FEATURES bit must be already set through the VIRTIO
++                // acked features as we know the guest would never ack it, this
++                // the feature would be lost.
++                acked_features: acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(),
++                paused_sync: Some(Arc::new(Barrier::new(NUM_QUEUES as usize))),
++                queue_sizes: QUEUE_SIZES.to_vec(),
++                min_queues: NUM_QUEUES,
++                ..Default::default()
++            },
++            vu_common: VhostUserCommon {
++                vu: Some(Arc::new(Mutex::new(vu))),
++                acked_protocol_features,
++                socket_path: path.to_string(),
++                vu_num_queues: NUM_QUEUES as usize,
++                ..Default::default()
++            },
++            id,
++            slave_req_support: acked_protocol_features
++                & VhostUserProtocolFeatures::SLAVE_REQ.bits()
++                != 0,
++            cache,
++            seccomp_action,
++            epoll_thread: None,
++            exit_evt,
++        })
++    }
++}
++
++impl Drop for Gpu {
++    fn drop(&mut self) {
++        if let Some(kill_evt) = self.common.kill_evt.take() {
++            // Ignore the result because there is nothing we can do about it.
++            let _ = kill_evt.write(1);
++        }
++    }
++}
++
++impl VirtioDevice for Gpu {
++    fn device_type(&self) -> u32 {
++        self.common.device_type
++    }
++
++    fn queue_max_sizes(&self) -> &[u16] {
++        &self.common.queue_sizes
++    }
++
++    fn features(&self) -> u64 {
++        self.common.avail_features
++    }
++
++    fn ack_features(&mut self, value: u64) {
++        self.common.ack_features(value)
++    }
++
++    fn read_config(&self, offset: u64, mut data: &mut [u8]) {
++        if let Some(vu) = &self.vu_common.vu {
++            if let Err(e) = vu
++                .lock()
++                .unwrap()
++                .socket_handle()
++                .get_config(
++                    offset as u32,
++                    data.len() as u32,
++                    VhostUserConfigFlags::WRITABLE,
++                    &data,
++                )
++                .map_err(|e| format!("{:?}", e))
++                .and_then(|(_, config)| data.write_all(&config).map_err(|e| format!("{:?}", e)))
++            {
++                error!("Failed getting vhost-user-gpu configuration: {:?}", e);
++            } else {
++                eprintln!("read_config({}, {:?})", offset, data);
++            }
++        }
++    }
++
++    fn activate(
++        &mut self,
++        mem: GuestMemoryAtomic<GuestMemoryMmap>,
++        interrupt_cb: Arc<dyn VirtioInterrupt>,
++        queues: Vec<(usize, Queue, EventFd)>,
++    ) -> ActivateResult {
++        self.common.activate(&queues, &interrupt_cb)?;
++
++        // Initialize slave communication.
++        let slave_req_handler = if self.slave_req_support {
++            if let Some(cache) = self.cache.as_ref() {
++                let vu_master_req_handler = Arc::new(SlaveReqHandler {
++                    cache_size: cache.0.len,
++                    mmap_cache_addr: cache.0.host_addr,
++                });
++
++                let mut req_handler =
++                    MasterReqHandler::new(vu_master_req_handler).map_err(|e| {
++                        ActivateError::VhostUserGpuSetup(Error::MasterReqHandlerCreation(e))
++                    })?;
++
++                if self.vu_common.acked_protocol_features
++                    & VhostUserProtocolFeatures::REPLY_ACK.bits()
++                    != 0
++                {
++                    req_handler.set_reply_ack_flag(true);
++                }
++
++                Some(req_handler)
++            } else {
++                None
++            }
++        } else {
++            None
++        };
++
++        // Run a dedicated thread for handling potential reconnections with
++        // the backend.
++        let (kill_evt, pause_evt) = self.common.dup_eventfds();
++
++        let mut handler = self.vu_common.activate(
++            mem,
++            queues,
++            interrupt_cb,
++            self.common.acked_features,
++            slave_req_handler,
++            kill_evt,
++            pause_evt,
++        )?;
++
++        let paused = self.common.paused.clone();
++        let paused_sync = self.common.paused_sync.clone();
++
++        let mut epoll_threads = Vec::new();
++        spawn_virtio_thread(
++            &self.id,
++            &self.seccomp_action,
++            Thread::VirtioVhostGpu,
++            &mut epoll_threads,
++            &self.exit_evt,
++            move || handler.run(paused, paused_sync.unwrap()),
++        )?;
++        self.epoll_thread = Some(epoll_threads.remove(0));
++
++        event!("virtio-device", "activated", "id", &self.id);
++        Ok(())
++    }
++
++    fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
++        // We first must resume the virtio thread if it was paused.
++        if self.common.pause_evt.take().is_some() {
++            self.common.resume().ok()?;
++        }
++
++        if let Some(vu) = &self.vu_common.vu {
++            if let Err(e) = vu.lock().unwrap().reset_vhost_user() {
++                error!("Failed to reset vhost-user daemon: {:?}", e);
++                return None;
++            }
++        }
++
++        if let Some(kill_evt) = self.common.kill_evt.take() {
++            // Ignore the result because there is nothing we can do about it.
++            let _ = kill_evt.write(1);
++        }
++
++        event!("virtio-device", "reset", "id", &self.id);
++
++        // Return the interrupt
++        Some(self.common.interrupt_cb.take().unwrap())
++    }
++
++    fn shutdown(&mut self) {
++        self.vu_common.shutdown()
++    }
++
++    fn get_shm_regions(&self) -> Option<VirtioSharedMemoryList> {
++        // It would be possible to the size of the region from the
++        // backend over vhost-user, but since we need to know the size
++        // up front in cloud-hypervisor to construct Self, it wouldn't
++        // help.  The user is thereforce responsible for configuring
++        // the correct region size in VM configuration.
++        self.cache.as_ref().map(|cache| cache.0.clone())
++    }
++
++    fn set_shm_regions(
++        &mut self,
++        shm_regions: VirtioSharedMemoryList,
++    ) -> std::result::Result<(), crate::Error> {
++        todo!("set_shm_regions({:?})", shm_regions)
++    }
++
++    fn add_memory_region(
++        &mut self,
++        region: &Arc<GuestRegionMmap>,
++    ) -> std::result::Result<(), crate::Error> {
++        todo!("add_memory_region({:?})", region)
++    }
++
++    fn userspace_mappings(&self) -> Vec<UserspaceMapping> {
++        todo!()
++    }
++}
+diff --git a/virtio-devices/src/vhost_user/mod.rs b/virtio-devices/src/vhost_user/mod.rs
+index 81c48edf..669a962b 100644
+--- a/virtio-devices/src/vhost_user/mod.rs
++++ b/virtio-devices/src/vhost_user/mod.rs
+@@ -31,11 +31,13 @@ use vu_common_ctrl::VhostUserHandle;
+ 
+ pub mod blk;
+ pub mod fs;
++pub mod gpu;
+ pub mod net;
+ pub mod vu_common_ctrl;
+ 
+ pub use self::blk::Blk;
+ pub use self::fs::*;
++pub use self::gpu::*;
+ pub use self::net::Net;
+ pub use self::vu_common_ctrl::VhostUserConfig;
+ 
+diff --git a/virtio-devices/src/vhost_user/vu_common_ctrl.rs b/virtio-devices/src/vhost_user/vu_common_ctrl.rs
+index 0ab0bdda..fd6716a2 100644
+--- a/virtio-devices/src/vhost_user/vu_common_ctrl.rs
++++ b/virtio-devices/src/vhost_user/vu_common_ctrl.rs
+@@ -199,6 +199,14 @@ impl VhostUserHandle {
+                 .map_err(Error::VhostUserSetInflight)?;
+         }
+ 
++        // FIXME: crosvm's vhost-user backend requires this to come first.
++        // Can we fix that in crosvm?
++        if let Some(slave_req_handler) = slave_req_handler {
++            self.vu
++                .set_slave_request_fd(&slave_req_handler.get_tx_raw_fd())
++                .map_err(Error::VhostUserSetSlaveRequestFd)?;
++        }
++
+         let mut vrings_info = Vec::new();
+         for (queue_index, queue, queue_evt) in queues.iter() {
+             let actual_size: usize = queue.size().try_into().unwrap();
+@@ -267,12 +275,6 @@ impl VhostUserHandle {
+ 
+         self.enable_vhost_user_vrings(self.queue_indexes.clone(), true)?;
+ 
+-        if let Some(slave_req_handler) = slave_req_handler {
+-            self.vu
+-                .set_slave_request_fd(&slave_req_handler.get_tx_raw_fd())
+-                .map_err(Error::VhostUserSetSlaveRequestFd)?;
+-        }
+-
+         self.vrings_info = Some(vrings_info);
+         self.ready = true;
+ 
+diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml
+index c95384b5..87a36722 100644
+--- a/vmm/Cargo.toml
++++ b/vmm/Cargo.toml
+@@ -49,6 +49,7 @@ versionize_derive = "0.1.4"
+ vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
+ vfio_user = { path = "../vfio_user" }
+ vhdx = { path = "../vhdx" }
++virtio-bindings = "0.1.0"
+ virtio-devices = { path = "../virtio-devices" }
+ virtio-queue = "0.5.0"
+ vm-allocator = { path = "../vm-allocator" }
+diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs
+index 0513ef37..9a9942fc 100644
+--- a/vmm/src/api/mod.rs
++++ b/vmm/src/api/mod.rs
+@@ -34,6 +34,7 @@ pub use self::http::start_http_path_thread;
+ pub mod http;
+ pub mod http_endpoint;
+ 
++use crate::config::GpuConfig;
+ use crate::config::{
+     DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, UserDeviceConfig,
+     VdpaConfig, VmConfig, VsockConfig,
+@@ -132,6 +133,9 @@ pub enum ApiError {
+     /// The fs could not be added to the VM.
+     VmAddFs(VmError),
+ 
++    /// The gpu could not be added to the VM.
++    VmAddGpu(VmError),
++
+     /// The pmem device could not be added to the VM.
+     VmAddPmem(VmError),
+ 
+@@ -301,6 +305,9 @@ pub enum ApiRequest {
+     /// Add a fs to the VM.
+     VmAddFs(Arc<FsConfig>, Sender<ApiResponse>),
+ 
++    /// Add a gpu to the VM.
++    VmAddGpu(Arc<GpuConfig>, Sender<ApiResponse>),
++
+     /// Add a pmem device to the VM.
+     VmAddPmem(Arc<PmemConfig>, Sender<ApiResponse>),
+ 
+diff --git a/vmm/src/config.rs b/vmm/src/config.rs
+index 9d72f8fe..193f948d 100644
+--- a/vmm/src/config.rs
++++ b/vmm/src/config.rs
+@@ -43,6 +43,8 @@ pub enum Error {
+     ParseFsTagMissing,
+     /// Filesystem socket is missing
+     ParseFsSockMissing,
++    /// GPU socket is missing
++    ParseGpuSockMissing,
+     /// Missing persistent memory file parameter.
+     ParsePmemFileMissing,
+     /// Missing vsock socket path parameter.
+@@ -71,6 +73,8 @@ pub enum Error {
+     ParseBalloon(OptionParserError),
+     /// Error parsing filesystem parameters
+     ParseFileSystem(OptionParserError),
++    /// Error parsing GPU parameters
++    ParseGpu(OptionParserError),
+     /// Error parsing persistent memory parameters
+     ParsePersistentMemory(OptionParserError),
+     /// Failed parsing console
+@@ -292,6 +296,8 @@ impl fmt::Display for Error {
+             ParseFileSystem(o) => write!(f, "Error parsing --fs: {}", o),
+             ParseFsSockMissing => write!(f, "Error parsing --fs: socket missing"),
+             ParseFsTagMissing => write!(f, "Error parsing --fs: tag missing"),
++            ParseGpu(o) => write!(f, "Error parsing --gpu: {}", o),
++            ParseGpuSockMissing => write!(f, "Error parsing --gpu: socket missing"),
+             ParsePersistentMemory(o) => write!(f, "Error parsing --pmem: {}", o),
+             ParsePmemFileMissing => write!(f, "Error parsing --pmem: file missing"),
+             ParseVsock(o) => write!(f, "Error parsing --vsock: {}", o),
+@@ -352,6 +358,7 @@ pub struct VmParams<'a> {
+     pub rng: &'a str,
+     pub balloon: Option<&'a str>,
+     pub fs: Option<Vec<&'a str>>,
++    pub gpu: Option<Vec<&'a str>>,
+     pub pmem: Option<Vec<&'a str>>,
+     pub serial: &'a str,
+     pub console: &'a str,
+@@ -387,6 +394,7 @@ impl<'a> VmParams<'a> {
+         let console = args.value_of("console").unwrap();
+         let balloon = args.value_of("balloon");
+         let fs: Option<Vec<&str>> = args.values_of("fs").map(|x| x.collect());
++        let gpu: Option<Vec<&str>> = args.values_of("gpu").map(|x| x.collect());
+         let pmem: Option<Vec<&str>> = args.values_of("pmem").map(|x| x.collect());
+         let devices: Option<Vec<&str>> = args.values_of("device").map(|x| x.collect());
+         let user_devices: Option<Vec<&str>> = args.values_of("user-device").map(|x| x.collect());
+@@ -414,6 +422,7 @@ impl<'a> VmParams<'a> {
+             rng,
+             balloon,
+             fs,
++            gpu,
+             pmem,
+             serial,
+             console,
+@@ -1668,6 +1677,73 @@ impl FsConfig {
+     }
+ }
+ 
++#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
++pub struct GpuConfig {
++    pub socket: PathBuf,
++    #[serde(default = "default_gpuconfig_cache_size")]
++    pub cache_size: u64,
++    pub id: Option<String>,
++    pub pci_segment: u16,
++}
++
++fn default_gpuconfig_cache_size() -> u64 {
++    1 << 33
++}
++
++impl GpuConfig {
++    pub const SYNTAX: &'static str =
++        "GPU parameters \"socket=<socket_path>,cache_size=<default 8GiB>,\
++        id=<device_id>,pci_segment=<segment_id>\"";
++
++    pub fn parse(gpu: &str) -> Result<Self> {
++        let mut parser = OptionParser::new();
++        parser
++            .add("socket")
++            .add("cache_size")
++            .add("id")
++            .add("pci_segment");
++        parser.parse(gpu).map_err(Error::ParseGpu)?;
++
++        let socket = PathBuf::from(parser.get("socket").ok_or(Error::ParseGpuSockMissing)?);
++        let cache_size = parser
++            .convert::<ByteSized>("cache_size")
++            .map_err(Error::ParseGpu)?
++            .unwrap_or_else(|| ByteSized(default_gpuconfig_cache_size()))
++            .0;
++        let id = parser.get("id");
++
++        let pci_segment = parser
++            .convert("pci_segment")
++            .map_err(Error::ParseGpu)?
++            .unwrap_or_default();
++
++        Ok(GpuConfig {
++            socket,
++            cache_size,
++            id,
++            pci_segment,
++        })
++    }
++
++    pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
++        if let Some(platform_config) = vm_config.platform.as_ref() {
++            if self.pci_segment >= platform_config.num_pci_segments {
++                return Err(ValidationError::InvalidPciSegment(self.pci_segment));
++            }
++
++            if let Some(iommu_segments) = platform_config.iommu_segments.as_ref() {
++                if iommu_segments.contains(&self.pci_segment) {
++                    return Err(ValidationError::IommuNotSupportedOnSegment(
++                        self.pci_segment,
++                    ));
++                }
++            }
++        }
++
++        Ok(())
++    }
++}
++
+ #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
+ pub struct PmemConfig {
+     pub file: PathBuf,
+@@ -2280,6 +2356,7 @@ pub struct VmConfig {
+     pub rng: RngConfig,
+     pub balloon: Option<BalloonConfig>,
+     pub fs: Option<Vec<FsConfig>>,
++    pub gpu: Option<Vec<GpuConfig>>,
+     pub pmem: Option<Vec<PmemConfig>>,
+     #[serde(default = "ConsoleConfig::default_serial")]
+     pub serial: ConsoleConfig,
+@@ -2415,6 +2492,17 @@ impl VmConfig {
+             }
+         }
+ 
++        if let Some(gpus) = &self.gpu {
++            if !gpus.is_empty() && !self.memory.shared {
++                return Err(ValidationError::VhostUserRequiresSharedMemory);
++            }
++            for gpu in gpus {
++                gpu.validate(self)?;
++
++                Self::validate_identifier(&mut id_list, &gpu.id)?;
++            }
++        }
++
+         if let Some(pmems) = &self.pmem {
+             for pmem in pmems {
+                 pmem.validate(self)?;
+@@ -2600,6 +2688,15 @@ impl VmConfig {
+             fs = Some(fs_config_list);
+         }
+ 
++        let mut gpu: Option<Vec<GpuConfig>> = None;
++        if let Some(gpu_list) = &vm_params.gpu {
++            let mut gpu_config_list = Vec::new();
++            for item in gpu_list.iter() {
++                gpu_config_list.push(GpuConfig::parse(item)?);
++            }
++            gpu = Some(gpu_config_list);
++        }
++
+         let mut pmem: Option<Vec<PmemConfig>> = None;
+         if let Some(pmem_list) = &vm_params.pmem {
+             let mut pmem_config_list = Vec::new();
+@@ -2704,6 +2801,7 @@ impl VmConfig {
+             rng,
+             balloon,
+             fs,
++            gpu,
+             pmem,
+             serial,
+             console,
+@@ -3078,6 +3176,21 @@ mod tests {
+         Ok(())
+     }
+ 
++    #[test]
++    fn test_parse_gpu() -> Result<()> {
++        // "socket" must be supplied
++        assert!(GpuConfig::parse("").is_err());
++        assert_eq!(
++            GpuConfig::parse("socket=/tmp/sock")?,
++            GpuConfig {
++                socket: PathBuf::from("/tmp/sock"),
++                ..Default::default()
++            }
++        );
++
++        Ok(())
++    }
++
+     #[test]
+     fn test_pmem_parsing() -> Result<()> {
+         // Must always give a file and size
+@@ -3303,6 +3416,7 @@ mod tests {
+             },
+             balloon: None,
+             fs: None,
++            gpu: None,
+             pmem: None,
+             serial: ConsoleConfig {
+                 file: None,
+@@ -3457,6 +3571,15 @@ mod tests {
+             Err(ValidationError::VhostUserRequiresSharedMemory)
+         );
+ 
++        let mut invalid_config = valid_config.clone();
++        invalid_config.gpu = Some(vec![GpuConfig {
++            ..Default::default()
++        }]);
++        assert_eq!(
++            invalid_config.validate(),
++            Err(ValidationError::VhostUserRequiresSharedMemory)
++        );
++
+         let mut still_valid_config = valid_config.clone();
+         still_valid_config.memory.shared = true;
+         assert!(still_valid_config.validate().is_ok());
+diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs
+index 19ce15be..81a28446 100644
+--- a/vmm/src/device_manager.rs
++++ b/vmm/src/device_manager.rs
+@@ -10,8 +10,8 @@
+ //
+ 
+ use crate::config::{
+-    ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, UserDeviceConfig,
+-    VdpaConfig, VhostMode, VmConfig, VsockConfig,
++    ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, GpuConfig, NetConfig, PmemConfig,
++    UserDeviceConfig, VdpaConfig, VhostMode, VmConfig, VsockConfig,
+ };
+ use crate::device_tree::{DeviceNode, DeviceTree};
+ use crate::interrupt::LegacyUserspaceInterruptManager;
+@@ -68,6 +68,7 @@ use std::collections::{BTreeSet, HashMap};
+ use std::convert::TryInto;
+ use std::fs::{read_link, File, OpenOptions};
+ use std::io::{self, stdout, Seek, SeekFrom};
++use std::iter::once;
+ use std::mem::zeroed;
+ use std::num::Wrapping;
+ use std::os::unix::fs::OpenOptionsExt;
+@@ -77,11 +78,13 @@ use std::result;
+ use std::sync::{Arc, Mutex};
+ use std::time::Instant;
+ use vfio_ioctls::{VfioContainer, VfioDevice, VfioDeviceFd};
++use virtio_bindings::virtio_gpu::virtio_gpu_shm_id_VIRTIO_GPU_SHM_ID_HOST_VISIBLE as VIRTIO_GPU_SHM_ID_HOST_VISIBLE;
+ use virtio_devices::transport::VirtioTransport;
+ use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator};
+ use virtio_devices::vhost_user::VhostUserConfig;
+ use virtio_devices::{
+     AccessPlatformMapping, ActivateError, VdpaDmaMapping, VirtioMemMappingSource,
++    VirtioSharedMemory, VirtioSharedMemoryList,
+ };
+ use virtio_devices::{Endpoint, IommuMapping};
+ use vm_allocator::{AddressAllocator, SystemAllocator};
+@@ -124,6 +127,7 @@ const CONSOLE_DEVICE_NAME: &str = "__console";
+ // identifiers if the user doesn't give one
+ const DISK_DEVICE_NAME_PREFIX: &str = "_disk";
+ const FS_DEVICE_NAME_PREFIX: &str = "_fs";
++const GPU_DEVICE_NAME_PREFIX: &str = "_gpu";
+ const NET_DEVICE_NAME_PREFIX: &str = "_net";
+ const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem";
+ const VDPA_DEVICE_NAME_PREFIX: &str = "_vdpa";
+@@ -160,9 +164,15 @@ pub enum DeviceManagerError {
+     /// Cannot create virtio-fs device
+     CreateVirtioFs(virtio_devices::vhost_user::Error),
+ 
++    /// Cannot create virtio-gpu device
++    CreateVirtioGpu(virtio_devices::vhost_user::Error),
++
+     /// Virtio-fs device was created without a socket.
+     NoVirtioFsSock,
+ 
++    /// Virtio-gpu device was created without a socket.
++    NoVirtioGpuSock,
++
+     /// Cannot create vhost-user-blk device
+     CreateVhostUserBlk(virtio_devices::vhost_user::Error),
+ 
+@@ -244,6 +254,9 @@ pub enum DeviceManagerError {
+     /// Cannot find a memory range for virtio-fs
+     FsRangeAllocation,
+ 
++    /// Cannot find a memory range for virtio-gpu
++    GpuRangeAllocation,
++
+     /// Error creating serial output file
+     SerialOutputFileOpen(io::Error),
+ 
+@@ -2064,6 +2077,9 @@ impl DeviceManager {
+         // Add virtio-fs if required
+         devices.append(&mut self.make_virtio_fs_devices()?);
+ 
++        // Add virtio-gpu if required
++        devices.append(&mut self.make_virtio_gpu_devices()?);
++
+         // Add virtio-pmem if required
+         devices.append(&mut self.make_virtio_pmem_devices()?);
+ 
+@@ -2514,6 +2530,119 @@ impl DeviceManager {
+         Ok(devices)
+     }
+ 
++    fn make_virtio_gpu_device(
++        &mut self,
++        gpu_cfg: &mut GpuConfig,
++    ) -> DeviceManagerResult<MetaVirtioDevice> {
++        let id = if let Some(id) = &gpu_cfg.id {
++            id.clone()
++        } else {
++            let id = self.next_device_name(GPU_DEVICE_NAME_PREFIX)?;
++            gpu_cfg.id = Some(id.clone());
++            id
++        };
++
++        info!("Creating virtio-gpu device: {:?}", gpu_cfg);
++
++        let mut node = device_node!(id);
++
++        if let Some(gpu_socket) = gpu_cfg.socket.to_str() {
++            let cache_size = gpu_cfg.cache_size;
++            // In crosvm, the 8 GiB bar is 8 GiB-aligned.
++            let cache_base = self.pci_segments[gpu_cfg.pci_segment as usize]
++                .allocator
++                .lock()
++                .unwrap()
++                .allocate(None, cache_size as GuestUsize, Some(cache_size))
++                .ok_or(DeviceManagerError::GpuRangeAllocation)?
++                .raw_value();
++
++            // Update the node with correct resource information.
++            node.resources.push(Resource::MmioAddressRange {
++                base: cache_base,
++                size: cache_size,
++            });
++
++            let mmap_region = MmapRegion::build(
++                None,
++                cache_size as usize,
++                libc::PROT_NONE,
++                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
++            )
++            .map_err(DeviceManagerError::NewMmapRegion)?;
++            let host_addr: u64 = mmap_region.as_ptr() as u64;
++
++            let mem_slot = self
++                .memory_manager
++                .lock()
++                .unwrap()
++                .create_userspace_mapping(cache_base, cache_size, host_addr, false, false, false)
++                .map_err(DeviceManagerError::MemoryManager)?;
++
++            let region_list = once((
++                VIRTIO_GPU_SHM_ID_HOST_VISIBLE as u8,
++                VirtioSharedMemory {
++                    offset: 0,
++                    len: cache_size,
++                },
++            ))
++            .collect();
++
++            let cache = Some((
++                VirtioSharedMemoryList {
++                    host_addr,
++                    mem_slot,
++                    addr: GuestAddress(cache_base),
++                    len: cache_size as GuestUsize,
++                    region_list,
++                },
++                mmap_region,
++            ));
++
++            let virtio_gpu_device = Arc::new(Mutex::new(
++                virtio_devices::vhost_user::Gpu::new(
++                    id.clone(),
++                    gpu_socket,
++                    cache,
++                    self.seccomp_action.clone(),
++                    self.restoring,
++                    self.exit_evt
++                        .try_clone()
++                        .map_err(DeviceManagerError::EventFd)?,
++                    self.force_iommu,
++                )
++                .map_err(DeviceManagerError::CreateVirtioGpu)?,
++            ));
++
++            self.device_tree.lock().unwrap().insert(id.clone(), node);
++
++            Ok(MetaVirtioDevice {
++                virtio_device: Arc::clone(&virtio_gpu_device)
++                    as Arc<Mutex<dyn virtio_devices::VirtioDevice>>,
++                iommu: false,
++                id,
++                pci_segment: gpu_cfg.pci_segment,
++                dma_handler: None,
++            })
++        } else {
++            Err(DeviceManagerError::NoVirtioGpuSock)
++        }
++    }
++
++    fn make_virtio_gpu_devices(&mut self) -> DeviceManagerResult<Vec<MetaVirtioDevice>> {
++        let mut devices = Vec::new();
++
++        let mut gpu_devices = self.config.lock().unwrap().gpu.clone();
++        if let Some(gpu_list_cfg) = &mut gpu_devices {
++            for gpu_cfg in gpu_list_cfg.iter_mut() {
++                devices.push(self.make_virtio_gpu_device(gpu_cfg)?);
++            }
++        }
++        self.config.lock().unwrap().gpu = gpu_devices;
++
++        Ok(devices)
++    }
++
+     fn make_virtio_pmem_device(
+         &mut self,
+         pmem_cfg: &mut PmemConfig,
+@@ -4004,6 +4133,13 @@ impl DeviceManager {
+         self.hotplug_virtio_pci_device(device)
+     }
+ 
++    pub fn add_gpu(&mut self, gpu_cfg: &mut GpuConfig) -> DeviceManagerResult<PciDeviceInfo> {
++        self.validate_identifier(&gpu_cfg.id)?;
++
++        let device = self.make_virtio_gpu_device(gpu_cfg)?;
++        self.hotplug_virtio_pci_device(device)
++    }
++
+     pub fn add_pmem(&mut self, pmem_cfg: &mut PmemConfig) -> DeviceManagerResult<PciDeviceInfo> {
+         self.validate_identifier(&pmem_cfg.id)?;
+ 
+diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs
+index a114488b..5baaa29f 100644
+--- a/vmm/src/lib.rs
++++ b/vmm/src/lib.rs
+@@ -26,6 +26,7 @@ use crate::migration::{recv_vm_config, recv_vm_state};
+ use crate::seccomp_filters::{get_seccomp_filter, Thread};
+ use crate::vm::{Error as VmError, Vm, VmState};
+ use anyhow::anyhow;
++use config::GpuConfig;
+ use libc::{EFD_NONBLOCK, SIGINT, SIGTERM};
+ use memory_manager::MemoryManagerSnapshotData;
+ use pci::PciBdf;
+@@ -969,6 +970,32 @@ impl Vmm {
+         }
+     }
+ 
++    fn vm_add_gpu(&mut self, gpu_cfg: GpuConfig) -> result::Result<Option<Vec<u8>>, VmError> {
++        self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
++
++        {
++            // Validate the configuration change in a cloned configuration
++            let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
++            add_to_config(&mut config.gpu, gpu_cfg.clone());
++            config.validate().map_err(VmError::ConfigValidation)?;
++        }
++
++        if let Some(ref mut vm) = self.vm {
++            let info = vm.add_gpu(gpu_cfg).map_err(|e| {
++                error!("Error when adding new gpu to the VM: {:?}", e);
++                e
++            })?;
++            serde_json::to_vec(&info)
++                .map(Some)
++                .map_err(VmError::SerializeJson)
++        } else {
++            // Update VmConfig by adding the new device.
++            let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
++            add_to_config(&mut config.gpu, gpu_cfg);
++            Ok(None)
++        }
++    }
++
+     fn vm_add_pmem(&mut self, pmem_cfg: PmemConfig) -> result::Result<Option<Vec<u8>>, VmError> {
+         self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
+ 
+@@ -1858,6 +1885,13 @@ impl Vmm {
+                                         .map(ApiResponsePayload::VmAction);
+                                     sender.send(response).map_err(Error::ApiResponseSend)?;
+                                 }
++                                ApiRequest::VmAddGpu(add_gpu_data, sender) => {
++                                    let response = self
++                                        .vm_add_gpu(add_gpu_data.as_ref().clone())
++                                        .map_err(ApiError::VmAddGpu)
++                                        .map(ApiResponsePayload::VmAction);
++                                    sender.send(response).map_err(Error::ApiResponseSend)?;
++                                }
+                                 ApiRequest::VmAddPmem(add_pmem_data, sender) => {
+                                     let response = self
+                                         .vm_add_pmem(add_pmem_data.as_ref().clone())
+@@ -2027,6 +2061,7 @@ mod unit_tests {
+             },
+             balloon: None,
+             fs: None,
++            gpu: None,
+             pmem: None,
+             serial: ConsoleConfig {
+                 file: None,
+@@ -2253,6 +2288,54 @@ mod unit_tests {
+         );
+     }
+ 
++    #[test]
++    fn test_vmm_vm_cold_add_gpu() {
++        let mut vmm = create_dummy_vmm();
++        let gpu_config = GpuConfig::parse("socket=/tmp/sock").unwrap();
++
++        assert!(matches!(
++            vmm.vm_add_gpu(gpu_config.clone()),
++            Err(VmError::VmNotCreated)
++        ));
++
++        let _ = vmm.vm_create(create_dummy_vm_config());
++        assert!(vmm
++            .vm_config
++            .as_ref()
++            .unwrap()
++            .lock()
++            .unwrap()
++            .gpu
++            .is_none());
++
++        let result = vmm.vm_add_gpu(gpu_config.clone());
++        assert!(result.is_ok());
++        assert!(result.unwrap().is_none());
++        assert_eq!(
++            vmm.vm_config
++                .as_ref()
++                .unwrap()
++                .lock()
++                .unwrap()
++                .gpu
++                .clone()
++                .unwrap()
++                .len(),
++            1
++        );
++        assert_eq!(
++            vmm.vm_config
++                .as_ref()
++                .unwrap()
++                .lock()
++                .unwrap()
++                .gpu
++                .clone()
++                .unwrap()[0],
++            gpu_config
++        );
++    }
++
+     #[test]
+     fn test_vmm_vm_cold_add_pmem() {
+         let mut vmm = create_dummy_vmm();
+diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs
+index 87278d5c..30a0c896 100644
+--- a/vmm/src/vm.rs
++++ b/vmm/src/vm.rs
+@@ -12,8 +12,8 @@
+ //
+ 
+ use crate::config::{
+-    add_to_config, DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig,
+-    UserDeviceConfig, ValidationError, VdpaConfig, VmConfig, VsockConfig,
++    add_to_config, DeviceConfig, DiskConfig, FsConfig, GpuConfig, HotplugMethod, NetConfig,
++    PmemConfig, UserDeviceConfig, ValidationError, VdpaConfig, VmConfig, VsockConfig,
+ };
+ use crate::config::{NumaConfig, PayloadConfig};
+ #[cfg(feature = "guest_debug")]
+@@ -1555,6 +1555,11 @@ impl Vm {
+             fs.retain(|dev| dev.id.as_ref() != Some(&id));
+         }
+ 
++        // Remove if gpu device
++        if let Some(gpu) = config.gpu.as_mut() {
++            gpu.retain(|dev| dev.id.as_ref() != Some(&id));
++        }
++
+         // Remove if net device
+         if let Some(net) = config.net.as_mut() {
+             net.retain(|dev| dev.id.as_ref() != Some(&id));
+@@ -1633,6 +1638,30 @@ impl Vm {
+         Ok(pci_device_info)
+     }
+ 
++    pub fn add_gpu(&mut self, mut gpu_cfg: GpuConfig) -> Result<PciDeviceInfo> {
++        let pci_device_info = self
++            .device_manager
++            .lock()
++            .unwrap()
++            .add_gpu(&mut gpu_cfg)
++            .map_err(Error::DeviceManager)?;
++
++        // Update VmConfig by adding the new device. This is important to
++        // ensure the device would be created in case of a reboot.
++        {
++            let mut config = self.config.lock().unwrap();
++            add_to_config(&mut config.gpu, gpu_cfg);
++        }
++
++        self.device_manager
++            .lock()
++            .unwrap()
++            .notify_hotplug(AcpiNotificationFlags::PCI_DEVICES_CHANGED)
++            .map_err(Error::DeviceManager)?;
++
++        Ok(pci_device_info)
++    }
++
+     pub fn add_pmem(&mut self, mut pmem_cfg: PmemConfig) -> Result<PciDeviceInfo> {
+         let pci_device_info = self
+             .device_manager
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0004-virtio-bindings-regenerate-with-Linux-5.19.patch b/pkgs/applications/virtualization/cloud-hypervisor/0004-virtio-bindings-regenerate-with-Linux-5.19.patch
new file mode 100644
index 00000000000..92129dc52bd
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0004-virtio-bindings-regenerate-with-Linux-5.19.patch
@@ -0,0 +1,1067 @@
+From b7806189fb4407221f33ea8869b89bbaa997f4b1 Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 31 Aug 2022 17:10:30 +0000
+Subject: [PATCH 4/5] virtio-bindings: regenerate with Linux 5.19
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/virtio-bindings/src/virtio_blk.rs  |  61 +-
+ crates/virtio-bindings/src/virtio_net.rs  | 749 ++++++++++++++++++++--
+ crates/virtio-bindings/src/virtio_ring.rs |  13 +-
+ 3 files changed, 765 insertions(+), 58 deletions(-)
+
+diff --git a/crates/virtio-bindings/src/virtio_blk.rs b/crates/virtio-bindings/src/virtio_blk.rs
+index 94daca3..71151a3 100644
+--- a/crates/virtio-bindings/src/virtio_blk.rs
++++ b/crates/virtio-bindings/src/virtio_blk.rs
+@@ -7,15 +7,47 @@ pub const VIRTIO_ID_BLOCK: u32 = 2;
+ pub const VIRTIO_ID_CONSOLE: u32 = 3;
+ pub const VIRTIO_ID_RNG: u32 = 4;
+ pub const VIRTIO_ID_BALLOON: u32 = 5;
++pub const VIRTIO_ID_IOMEM: u32 = 6;
+ pub const VIRTIO_ID_RPMSG: u32 = 7;
+ pub const VIRTIO_ID_SCSI: u32 = 8;
+ pub const VIRTIO_ID_9P: u32 = 9;
++pub const VIRTIO_ID_MAC80211_WLAN: u32 = 10;
+ pub const VIRTIO_ID_RPROC_SERIAL: u32 = 11;
+ pub const VIRTIO_ID_CAIF: u32 = 12;
++pub const VIRTIO_ID_MEMORY_BALLOON: u32 = 13;
+ pub const VIRTIO_ID_GPU: u32 = 16;
++pub const VIRTIO_ID_CLOCK: u32 = 17;
+ pub const VIRTIO_ID_INPUT: u32 = 18;
+ pub const VIRTIO_ID_VSOCK: u32 = 19;
+ pub const VIRTIO_ID_CRYPTO: u32 = 20;
++pub const VIRTIO_ID_SIGNAL_DIST: u32 = 21;
++pub const VIRTIO_ID_PSTORE: u32 = 22;
++pub const VIRTIO_ID_IOMMU: u32 = 23;
++pub const VIRTIO_ID_MEM: u32 = 24;
++pub const VIRTIO_ID_SOUND: u32 = 25;
++pub const VIRTIO_ID_FS: u32 = 26;
++pub const VIRTIO_ID_PMEM: u32 = 27;
++pub const VIRTIO_ID_RPMB: u32 = 28;
++pub const VIRTIO_ID_MAC80211_HWSIM: u32 = 29;
++pub const VIRTIO_ID_VIDEO_ENCODER: u32 = 30;
++pub const VIRTIO_ID_VIDEO_DECODER: u32 = 31;
++pub const VIRTIO_ID_SCMI: u32 = 32;
++pub const VIRTIO_ID_NITRO_SEC_MOD: u32 = 33;
++pub const VIRTIO_ID_I2C_ADAPTER: u32 = 34;
++pub const VIRTIO_ID_WATCHDOG: u32 = 35;
++pub const VIRTIO_ID_CAN: u32 = 36;
++pub const VIRTIO_ID_DMABUF: u32 = 37;
++pub const VIRTIO_ID_PARAM_SERV: u32 = 38;
++pub const VIRTIO_ID_AUDIO_POLICY: u32 = 39;
++pub const VIRTIO_ID_BT: u32 = 40;
++pub const VIRTIO_ID_GPIO: u32 = 41;
++pub const VIRTIO_TRANS_ID_NET: u32 = 4096;
++pub const VIRTIO_TRANS_ID_BLOCK: u32 = 4097;
++pub const VIRTIO_TRANS_ID_BALLOON: u32 = 4098;
++pub const VIRTIO_TRANS_ID_CONSOLE: u32 = 4099;
++pub const VIRTIO_TRANS_ID_SCSI: u32 = 4100;
++pub const VIRTIO_TRANS_ID_RNG: u32 = 4101;
++pub const VIRTIO_TRANS_ID_9P: u32 = 4105;
+ pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: u32 = 1;
+ pub const VIRTIO_CONFIG_S_DRIVER: u32 = 2;
+ pub const VIRTIO_CONFIG_S_DRIVER_OK: u32 = 4;
+@@ -27,8 +59,10 @@ pub const VIRTIO_TRANSPORT_F_END: u32 = 38;
+ pub const VIRTIO_F_NOTIFY_ON_EMPTY: u32 = 24;
+ pub const VIRTIO_F_ANY_LAYOUT: u32 = 27;
+ pub const VIRTIO_F_VERSION_1: u32 = 32;
++pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
+ pub const VIRTIO_F_IOMMU_PLATFORM: u32 = 33;
+ pub const VIRTIO_F_RING_PACKED: u32 = 34;
++pub const VIRTIO_F_IN_ORDER: u32 = 35;
+ pub const VIRTIO_F_ORDER_PLATFORM: u32 = 36;
+ pub const VIRTIO_F_SR_IOV: u32 = 37;
+ pub const VIRTIO_BLK_F_SIZE_MAX: u32 = 1;
+@@ -160,6 +194,7 @@ fn bindgen_test_layout___kernel_fsid_t() {
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
++pub type __kernel_old_time_t = __kernel_long_t;
+ pub type __kernel_time_t = __kernel_long_t;
+ pub type __kernel_time64_t = ::std::os::raw::c_longlong;
+ pub type __kernel_clock_t = __kernel_long_t;
+@@ -183,30 +218,30 @@ pub type __virtio64 = __u64;
+ #[repr(C, packed)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+ pub struct virtio_blk_config {
+-    pub capacity: __u64,
+-    pub size_max: __u32,
+-    pub seg_max: __u32,
++    pub capacity: __virtio64,
++    pub size_max: __virtio32,
++    pub seg_max: __virtio32,
+     pub geometry: virtio_blk_config_virtio_blk_geometry,
+-    pub blk_size: __u32,
++    pub blk_size: __virtio32,
+     pub physical_block_exp: __u8,
+     pub alignment_offset: __u8,
+-    pub min_io_size: __u16,
+-    pub opt_io_size: __u32,
++    pub min_io_size: __virtio16,
++    pub opt_io_size: __virtio32,
+     pub wce: __u8,
+     pub unused: __u8,
+-    pub num_queues: __u16,
+-    pub max_discard_sectors: __u32,
+-    pub max_discard_seg: __u32,
+-    pub discard_sector_alignment: __u32,
+-    pub max_write_zeroes_sectors: __u32,
+-    pub max_write_zeroes_seg: __u32,
++    pub num_queues: __virtio16,
++    pub max_discard_sectors: __virtio32,
++    pub max_discard_seg: __virtio32,
++    pub discard_sector_alignment: __virtio32,
++    pub max_write_zeroes_sectors: __virtio32,
++    pub max_write_zeroes_seg: __virtio32,
+     pub write_zeroes_may_unmap: __u8,
+     pub unused1: [__u8; 3usize],
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+ pub struct virtio_blk_config_virtio_blk_geometry {
+-    pub cylinders: __u16,
++    pub cylinders: __virtio16,
+     pub heads: __u8,
+     pub sectors: __u8,
+ }
+diff --git a/crates/virtio-bindings/src/virtio_net.rs b/crates/virtio-bindings/src/virtio_net.rs
+index 5707375..f66f69a 100644
+--- a/crates/virtio-bindings/src/virtio_net.rs
++++ b/crates/virtio-bindings/src/virtio_net.rs
+@@ -37,15 +37,47 @@ pub const VIRTIO_ID_BLOCK: u32 = 2;
+ pub const VIRTIO_ID_CONSOLE: u32 = 3;
+ pub const VIRTIO_ID_RNG: u32 = 4;
+ pub const VIRTIO_ID_BALLOON: u32 = 5;
++pub const VIRTIO_ID_IOMEM: u32 = 6;
+ pub const VIRTIO_ID_RPMSG: u32 = 7;
+ pub const VIRTIO_ID_SCSI: u32 = 8;
+ pub const VIRTIO_ID_9P: u32 = 9;
++pub const VIRTIO_ID_MAC80211_WLAN: u32 = 10;
+ pub const VIRTIO_ID_RPROC_SERIAL: u32 = 11;
+ pub const VIRTIO_ID_CAIF: u32 = 12;
++pub const VIRTIO_ID_MEMORY_BALLOON: u32 = 13;
+ pub const VIRTIO_ID_GPU: u32 = 16;
++pub const VIRTIO_ID_CLOCK: u32 = 17;
+ pub const VIRTIO_ID_INPUT: u32 = 18;
+ pub const VIRTIO_ID_VSOCK: u32 = 19;
+ pub const VIRTIO_ID_CRYPTO: u32 = 20;
++pub const VIRTIO_ID_SIGNAL_DIST: u32 = 21;
++pub const VIRTIO_ID_PSTORE: u32 = 22;
++pub const VIRTIO_ID_IOMMU: u32 = 23;
++pub const VIRTIO_ID_MEM: u32 = 24;
++pub const VIRTIO_ID_SOUND: u32 = 25;
++pub const VIRTIO_ID_FS: u32 = 26;
++pub const VIRTIO_ID_PMEM: u32 = 27;
++pub const VIRTIO_ID_RPMB: u32 = 28;
++pub const VIRTIO_ID_MAC80211_HWSIM: u32 = 29;
++pub const VIRTIO_ID_VIDEO_ENCODER: u32 = 30;
++pub const VIRTIO_ID_VIDEO_DECODER: u32 = 31;
++pub const VIRTIO_ID_SCMI: u32 = 32;
++pub const VIRTIO_ID_NITRO_SEC_MOD: u32 = 33;
++pub const VIRTIO_ID_I2C_ADAPTER: u32 = 34;
++pub const VIRTIO_ID_WATCHDOG: u32 = 35;
++pub const VIRTIO_ID_CAN: u32 = 36;
++pub const VIRTIO_ID_DMABUF: u32 = 37;
++pub const VIRTIO_ID_PARAM_SERV: u32 = 38;
++pub const VIRTIO_ID_AUDIO_POLICY: u32 = 39;
++pub const VIRTIO_ID_BT: u32 = 40;
++pub const VIRTIO_ID_GPIO: u32 = 41;
++pub const VIRTIO_TRANS_ID_NET: u32 = 4096;
++pub const VIRTIO_TRANS_ID_BLOCK: u32 = 4097;
++pub const VIRTIO_TRANS_ID_BALLOON: u32 = 4098;
++pub const VIRTIO_TRANS_ID_CONSOLE: u32 = 4099;
++pub const VIRTIO_TRANS_ID_SCSI: u32 = 4100;
++pub const VIRTIO_TRANS_ID_RNG: u32 = 4101;
++pub const VIRTIO_TRANS_ID_9P: u32 = 4105;
+ pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: u32 = 1;
+ pub const VIRTIO_CONFIG_S_DRIVER: u32 = 2;
+ pub const VIRTIO_CONFIG_S_DRIVER_OK: u32 = 4;
+@@ -57,8 +89,10 @@ pub const VIRTIO_TRANSPORT_F_END: u32 = 38;
+ pub const VIRTIO_F_NOTIFY_ON_EMPTY: u32 = 24;
+ pub const VIRTIO_F_ANY_LAYOUT: u32 = 27;
+ pub const VIRTIO_F_VERSION_1: u32 = 32;
++pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33;
+ pub const VIRTIO_F_IOMMU_PLATFORM: u32 = 33;
+ pub const VIRTIO_F_RING_PACKED: u32 = 34;
++pub const VIRTIO_F_IN_ORDER: u32 = 35;
+ pub const VIRTIO_F_ORDER_PLATFORM: u32 = 36;
+ pub const VIRTIO_F_SR_IOV: u32 = 37;
+ pub const ETH_ALEN: u32 = 6;
+@@ -109,17 +143,23 @@ pub const ETH_P_PPP_SES: u32 = 34916;
+ pub const ETH_P_LINK_CTL: u32 = 34924;
+ pub const ETH_P_ATMFATE: u32 = 34948;
+ pub const ETH_P_PAE: u32 = 34958;
++pub const ETH_P_PROFINET: u32 = 34962;
++pub const ETH_P_REALTEK: u32 = 34969;
+ pub const ETH_P_AOE: u32 = 34978;
++pub const ETH_P_ETHERCAT: u32 = 34980;
+ pub const ETH_P_8021AD: u32 = 34984;
+ pub const ETH_P_802_EX1: u32 = 34997;
+ pub const ETH_P_PREAUTH: u32 = 35015;
+ pub const ETH_P_TIPC: u32 = 35018;
++pub const ETH_P_LLDP: u32 = 35020;
++pub const ETH_P_MRP: u32 = 35043;
+ pub const ETH_P_MACSEC: u32 = 35045;
+ pub const ETH_P_8021AH: u32 = 35047;
+ pub const ETH_P_MVRP: u32 = 35061;
+ pub const ETH_P_1588: u32 = 35063;
+ pub const ETH_P_NCSI: u32 = 35064;
+ pub const ETH_P_PRP: u32 = 35067;
++pub const ETH_P_CFM: u32 = 35074;
+ pub const ETH_P_FCOE: u32 = 35078;
+ pub const ETH_P_IBOE: u32 = 35093;
+ pub const ETH_P_TDLS: u32 = 35085;
+@@ -132,6 +172,7 @@ pub const ETH_P_QINQ1: u32 = 37120;
+ pub const ETH_P_QINQ2: u32 = 37376;
+ pub const ETH_P_QINQ3: u32 = 37632;
+ pub const ETH_P_EDSA: u32 = 56026;
++pub const ETH_P_DSA_8021Q: u32 = 56027;
+ pub const ETH_P_IFE: u32 = 60734;
+ pub const ETH_P_AF_IUCV: u32 = 64507;
+ pub const ETH_P_802_3_MIN: u32 = 1536;
+@@ -161,6 +202,7 @@ pub const ETH_P_IEEE802154: u32 = 246;
+ pub const ETH_P_CAIF: u32 = 247;
+ pub const ETH_P_XDSA: u32 = 248;
+ pub const ETH_P_MAP: u32 = 249;
++pub const ETH_P_MCTP: u32 = 250;
+ pub const __UAPI_DEF_ETHHDR: u32 = 1;
+ pub const VIRTIO_NET_F_CSUM: u32 = 0;
+ pub const VIRTIO_NET_F_GUEST_CSUM: u32 = 1;
+@@ -184,18 +226,41 @@ pub const VIRTIO_NET_F_CTRL_RX_EXTRA: u32 = 20;
+ pub const VIRTIO_NET_F_GUEST_ANNOUNCE: u32 = 21;
+ pub const VIRTIO_NET_F_MQ: u32 = 22;
+ pub const VIRTIO_NET_F_CTRL_MAC_ADDR: u32 = 23;
++pub const VIRTIO_NET_F_HASH_REPORT: u32 = 57;
++pub const VIRTIO_NET_F_RSS: u32 = 60;
++pub const VIRTIO_NET_F_RSC_EXT: u32 = 61;
+ pub const VIRTIO_NET_F_STANDBY: u32 = 62;
+ pub const VIRTIO_NET_F_SPEED_DUPLEX: u32 = 63;
+ pub const VIRTIO_NET_F_GSO: u32 = 6;
+ pub const VIRTIO_NET_S_LINK_UP: u32 = 1;
+ pub const VIRTIO_NET_S_ANNOUNCE: u32 = 2;
++pub const VIRTIO_NET_RSS_HASH_TYPE_IPv4: u32 = 1;
++pub const VIRTIO_NET_RSS_HASH_TYPE_TCPv4: u32 = 2;
++pub const VIRTIO_NET_RSS_HASH_TYPE_UDPv4: u32 = 4;
++pub const VIRTIO_NET_RSS_HASH_TYPE_IPv6: u32 = 8;
++pub const VIRTIO_NET_RSS_HASH_TYPE_TCPv6: u32 = 16;
++pub const VIRTIO_NET_RSS_HASH_TYPE_UDPv6: u32 = 32;
++pub const VIRTIO_NET_RSS_HASH_TYPE_IP_EX: u32 = 64;
++pub const VIRTIO_NET_RSS_HASH_TYPE_TCP_EX: u32 = 128;
++pub const VIRTIO_NET_RSS_HASH_TYPE_UDP_EX: u32 = 256;
+ pub const VIRTIO_NET_HDR_F_NEEDS_CSUM: u32 = 1;
+ pub const VIRTIO_NET_HDR_F_DATA_VALID: u32 = 2;
++pub const VIRTIO_NET_HDR_F_RSC_INFO: u32 = 4;
+ pub const VIRTIO_NET_HDR_GSO_NONE: u32 = 0;
+ pub const VIRTIO_NET_HDR_GSO_TCPV4: u32 = 1;
+ pub const VIRTIO_NET_HDR_GSO_UDP: u32 = 3;
+ pub const VIRTIO_NET_HDR_GSO_TCPV6: u32 = 4;
+ pub const VIRTIO_NET_HDR_GSO_ECN: u32 = 128;
++pub const VIRTIO_NET_HASH_REPORT_NONE: u32 = 0;
++pub const VIRTIO_NET_HASH_REPORT_IPv4: u32 = 1;
++pub const VIRTIO_NET_HASH_REPORT_TCPv4: u32 = 2;
++pub const VIRTIO_NET_HASH_REPORT_UDPv4: u32 = 3;
++pub const VIRTIO_NET_HASH_REPORT_IPv6: u32 = 4;
++pub const VIRTIO_NET_HASH_REPORT_TCPv6: u32 = 5;
++pub const VIRTIO_NET_HASH_REPORT_UDPv6: u32 = 6;
++pub const VIRTIO_NET_HASH_REPORT_IPv6_EX: u32 = 7;
++pub const VIRTIO_NET_HASH_REPORT_TCPv6_EX: u32 = 8;
++pub const VIRTIO_NET_HASH_REPORT_UDPv6_EX: u32 = 9;
+ pub const VIRTIO_NET_OK: u32 = 0;
+ pub const VIRTIO_NET_ERR: u32 = 1;
+ pub const VIRTIO_NET_CTRL_RX: u32 = 0;
+@@ -217,6 +282,8 @@ pub const VIRTIO_NET_CTRL_MQ: u32 = 4;
+ pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET: u32 = 0;
+ pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN: u32 = 1;
+ pub const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX: u32 = 32768;
++pub const VIRTIO_NET_CTRL_MQ_RSS_CONFIG: u32 = 1;
++pub const VIRTIO_NET_CTRL_MQ_HASH_CONFIG: u32 = 2;
+ pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS: u32 = 5;
+ pub const VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET: u32 = 0;
+ pub type __s8 = ::std::os::raw::c_schar;
+@@ -321,6 +388,7 @@ fn bindgen_test_layout___kernel_fsid_t() {
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
++pub type __kernel_old_time_t = __kernel_long_t;
+ pub type __kernel_time_t = __kernel_long_t;
+ pub type __kernel_time64_t = ::std::os::raw::c_longlong;
+ pub type __kernel_clock_t = __kernel_long_t;
+@@ -416,17 +484,20 @@ fn bindgen_test_layout_ethhdr() {
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+ pub struct virtio_net_config {
+     pub mac: [__u8; 6usize],
+-    pub status: __u16,
+-    pub max_virtqueue_pairs: __u16,
+-    pub mtu: __u16,
+-    pub speed: __u32,
++    pub status: __virtio16,
++    pub max_virtqueue_pairs: __virtio16,
++    pub mtu: __virtio16,
++    pub speed: __le32,
+     pub duplex: __u8,
++    pub rss_max_key_size: __u8,
++    pub rss_max_indirection_table_length: __le16,
++    pub supported_hash_types: __le32,
+ }
+ #[test]
+ fn bindgen_test_layout_virtio_net_config() {
+     assert_eq!(
+         ::std::mem::size_of::<virtio_net_config>(),
+-        17usize,
++        24usize,
+         concat!("Size of: ", stringify!(virtio_net_config))
+     );
+     assert_eq!(
+@@ -536,17 +607,308 @@ fn bindgen_test_layout_virtio_net_config() {
+         );
+     }
+     test_field_duplex();
++    fn test_field_rss_max_key_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).rss_max_key_size) as usize - ptr as usize
++            },
++            17usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(rss_max_key_size)
++            )
++        );
++    }
++    test_field_rss_max_key_size();
++    fn test_field_rss_max_indirection_table_length() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).rss_max_indirection_table_length) as usize
++                    - ptr as usize
++            },
++            18usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(rss_max_indirection_table_length)
++            )
++        );
++    }
++    test_field_rss_max_indirection_table_length();
++    fn test_field_supported_hash_types() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).supported_hash_types) as usize - ptr as usize
++            },
++            20usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_config),
++                "::",
++                stringify!(supported_hash_types)
++            )
++        );
++    }
++    test_field_supported_hash_types();
+ }
+ #[repr(C)]
+-#[derive(Debug, Default, Copy, Clone, PartialEq)]
++#[derive(Copy, Clone)]
+ pub struct virtio_net_hdr_v1 {
+     pub flags: __u8,
+     pub gso_type: __u8,
+     pub hdr_len: __virtio16,
+     pub gso_size: __virtio16,
++    pub __bindgen_anon_1: virtio_net_hdr_v1__bindgen_ty_1,
++    pub num_buffers: __virtio16,
++}
++#[repr(C)]
++#[derive(Copy, Clone)]
++pub union virtio_net_hdr_v1__bindgen_ty_1 {
++    pub __bindgen_anon_1: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1,
++    pub csum: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2,
++    pub rsc: virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3,
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1 {
+     pub csum_start: __virtio16,
+     pub csum_offset: __virtio16,
+-    pub num_buffers: __virtio16,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1>(),
++        4usize,
++        concat!(
++            "Size of: ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1)
++        )
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1>(),
++        2usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1)
++        )
++    );
++    fn test_field_csum_start() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_start) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1),
++                "::",
++                stringify!(csum_start)
++            )
++        );
++    }
++    test_field_csum_start();
++    fn test_field_csum_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum_offset) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1),
++                "::",
++                stringify!(csum_offset)
++            )
++        );
++    }
++    test_field_csum_offset();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2 {
++    pub start: __virtio16,
++    pub offset: __virtio16,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2>(),
++        4usize,
++        concat!(
++            "Size of: ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2)
++        )
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2>(),
++        2usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2)
++        )
++    );
++    fn test_field_start() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).start) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2),
++                "::",
++                stringify!(start)
++            )
++        );
++    }
++    test_field_start();
++    fn test_field_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2),
++                "::",
++                stringify!(offset)
++            )
++        );
++    }
++    test_field_offset();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3 {
++    pub segments: __le16,
++    pub dup_acks: __le16,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3>(),
++        4usize,
++        concat!(
++            "Size of: ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3)
++        )
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3>(),
++        2usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3)
++        )
++    );
++    fn test_field_segments() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).segments) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3),
++                "::",
++                stringify!(segments)
++            )
++        );
++    }
++    test_field_segments();
++    fn test_field_dup_acks() {
++        assert_eq!(
++            unsafe {
++                let uninit = :: std :: mem :: MaybeUninit :: < virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3 > :: uninit () ;
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).dup_acks) as usize - ptr as usize
++            },
++            2usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3),
++                "::",
++                stringify!(dup_acks)
++            )
++        );
++    }
++    test_field_dup_acks();
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hdr_v1__bindgen_ty_1() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hdr_v1__bindgen_ty_1>(),
++        4usize,
++        concat!("Size of: ", stringify!(virtio_net_hdr_v1__bindgen_ty_1))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hdr_v1__bindgen_ty_1>(),
++        2usize,
++        concat!("Alignment of ", stringify!(virtio_net_hdr_v1__bindgen_ty_1))
++    );
++    fn test_field_csum() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1__bindgen_ty_1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).csum) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1),
++                "::",
++                stringify!(csum)
++            )
++        );
++    }
++    test_field_csum();
++    fn test_field_rsc() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1__bindgen_ty_1>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).rsc) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1__bindgen_ty_1),
++                "::",
++                stringify!(rsc)
++            )
++        );
++    }
++    test_field_rsc();
++}
++impl Default for virtio_net_hdr_v1__bindgen_ty_1 {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
+ }
+ #[test]
+ fn bindgen_test_layout_virtio_net_hdr_v1() {
+@@ -628,40 +990,6 @@ fn bindgen_test_layout_virtio_net_hdr_v1() {
+         );
+     }
+     test_field_gso_size();
+-    fn test_field_csum_start() {
+-        assert_eq!(
+-            unsafe {
+-                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
+-                let ptr = uninit.as_ptr();
+-                ::std::ptr::addr_of!((*ptr).csum_start) as usize - ptr as usize
+-            },
+-            6usize,
+-            concat!(
+-                "Offset of field: ",
+-                stringify!(virtio_net_hdr_v1),
+-                "::",
+-                stringify!(csum_start)
+-            )
+-        );
+-    }
+-    test_field_csum_start();
+-    fn test_field_csum_offset() {
+-        assert_eq!(
+-            unsafe {
+-                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1>::uninit();
+-                let ptr = uninit.as_ptr();
+-                ::std::ptr::addr_of!((*ptr).csum_offset) as usize - ptr as usize
+-            },
+-            8usize,
+-            concat!(
+-                "Offset of field: ",
+-                stringify!(virtio_net_hdr_v1),
+-                "::",
+-                stringify!(csum_offset)
+-            )
+-        );
+-    }
+-    test_field_csum_offset();
+     fn test_field_num_buffers() {
+         assert_eq!(
+             unsafe {
+@@ -680,6 +1008,113 @@ fn bindgen_test_layout_virtio_net_hdr_v1() {
+     }
+     test_field_num_buffers();
+ }
++impl Default for virtio_net_hdr_v1 {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
++}
++#[repr(C)]
++#[derive(Copy, Clone)]
++pub struct virtio_net_hdr_v1_hash {
++    pub hdr: virtio_net_hdr_v1,
++    pub hash_value: __le32,
++    pub hash_report: __le16,
++    pub padding: __le16,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hdr_v1_hash() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hdr_v1_hash>(),
++        20usize,
++        concat!("Size of: ", stringify!(virtio_net_hdr_v1_hash))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hdr_v1_hash>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_net_hdr_v1_hash))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1_hash>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1_hash),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_hash_value() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1_hash>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_value) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1_hash),
++                "::",
++                stringify!(hash_value)
++            )
++        );
++    }
++    test_field_hash_value();
++    fn test_field_hash_report() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1_hash>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_report) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1_hash),
++                "::",
++                stringify!(hash_report)
++            )
++        );
++    }
++    test_field_hash_report();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hdr_v1_hash>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            18usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hdr_v1_hash),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++impl Default for virtio_net_hdr_v1_hash {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
++}
+ #[repr(C)]
+ #[derive(Debug, Default, Copy, Clone, PartialEq)]
+ pub struct virtio_net_hdr {
+@@ -1008,3 +1443,235 @@ fn bindgen_test_layout_virtio_net_ctrl_mq() {
+     }
+     test_field_virtqueue_pairs();
+ }
++#[repr(C)]
++#[derive(Debug, Default)]
++pub struct virtio_net_rss_config {
++    pub hash_types: __le32,
++    pub indirection_table_mask: __le16,
++    pub unclassified_queue: __le16,
++    pub indirection_table: [__le16; 1usize],
++    pub max_tx_vq: __le16,
++    pub hash_key_length: __u8,
++    pub hash_key_data: __IncompleteArrayField<__u8>,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_rss_config() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_rss_config>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_net_rss_config))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_rss_config>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_net_rss_config))
++    );
++    fn test_field_hash_types() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_types) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(hash_types)
++            )
++        );
++    }
++    test_field_hash_types();
++    fn test_field_indirection_table_mask() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).indirection_table_mask) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(indirection_table_mask)
++            )
++        );
++    }
++    test_field_indirection_table_mask();
++    fn test_field_unclassified_queue() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).unclassified_queue) as usize - ptr as usize
++            },
++            6usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(unclassified_queue)
++            )
++        );
++    }
++    test_field_unclassified_queue();
++    fn test_field_indirection_table() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).indirection_table) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(indirection_table)
++            )
++        );
++    }
++    test_field_indirection_table();
++    fn test_field_max_tx_vq() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).max_tx_vq) as usize - ptr as usize
++            },
++            10usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(max_tx_vq)
++            )
++        );
++    }
++    test_field_max_tx_vq();
++    fn test_field_hash_key_length() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_key_length) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(hash_key_length)
++            )
++        );
++    }
++    test_field_hash_key_length();
++    fn test_field_hash_key_data() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_rss_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_key_data) as usize - ptr as usize
++            },
++            13usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_rss_config),
++                "::",
++                stringify!(hash_key_data)
++            )
++        );
++    }
++    test_field_hash_key_data();
++}
++#[repr(C)]
++#[derive(Debug, Default)]
++pub struct virtio_net_hash_config {
++    pub hash_types: __le32,
++    pub reserved: [__le16; 4usize],
++    pub hash_key_length: __u8,
++    pub hash_key_data: __IncompleteArrayField<__u8>,
++}
++#[test]
++fn bindgen_test_layout_virtio_net_hash_config() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_net_hash_config>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_net_hash_config))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_net_hash_config>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_net_hash_config))
++    );
++    fn test_field_hash_types() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hash_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_types) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hash_config),
++                "::",
++                stringify!(hash_types)
++            )
++        );
++    }
++    test_field_hash_types();
++    fn test_field_reserved() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hash_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hash_config),
++                "::",
++                stringify!(reserved)
++            )
++        );
++    }
++    test_field_reserved();
++    fn test_field_hash_key_length() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hash_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_key_length) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hash_config),
++                "::",
++                stringify!(hash_key_length)
++            )
++        );
++    }
++    test_field_hash_key_length();
++    fn test_field_hash_key_data() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_net_hash_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hash_key_data) as usize - ptr as usize
++            },
++            13usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_net_hash_config),
++                "::",
++                stringify!(hash_key_data)
++            )
++        );
++    }
++    test_field_hash_key_data();
++}
+diff --git a/crates/virtio-bindings/src/virtio_ring.rs b/crates/virtio-bindings/src/virtio_ring.rs
+index 60b84ab..20b4545 100644
+--- a/crates/virtio-bindings/src/virtio_ring.rs
++++ b/crates/virtio-bindings/src/virtio_ring.rs
+@@ -359,6 +359,7 @@ fn bindgen_test_layout___kernel_fsid_t() {
+ }
+ pub type __kernel_off_t = __kernel_long_t;
+ pub type __kernel_loff_t = ::std::os::raw::c_longlong;
++pub type __kernel_old_time_t = __kernel_long_t;
+ pub type __kernel_time_t = __kernel_long_t;
+ pub type __kernel_time64_t = ::std::os::raw::c_longlong;
+ pub type __kernel_clock_t = __kernel_long_t;
+@@ -592,12 +593,13 @@ fn bindgen_test_layout_vring_used_elem() {
+     }
+     test_field_len();
+ }
++pub type vring_used_elem_t = vring_used_elem;
+ #[repr(C)]
+ #[derive(Debug, Default)]
+ pub struct vring_used {
+     pub flags: __virtio16,
+     pub idx: __virtio16,
+-    pub ring: __IncompleteArrayField<vring_used_elem>,
++    pub ring: __IncompleteArrayField<vring_used_elem_t>,
+ }
+ #[test]
+ fn bindgen_test_layout_vring_used() {
+@@ -663,13 +665,16 @@ fn bindgen_test_layout_vring_used() {
+     }
+     test_field_ring();
+ }
++pub type vring_desc_t = vring_desc;
++pub type vring_avail_t = vring_avail;
++pub type vring_used_t = vring_used;
+ #[repr(C)]
+ #[derive(Debug, Copy, Clone, PartialEq)]
+ pub struct vring {
+     pub num: ::std::os::raw::c_uint,
+-    pub desc: *mut vring_desc,
+-    pub avail: *mut vring_avail,
+-    pub used: *mut vring_used,
++    pub desc: *mut vring_desc_t,
++    pub avail: *mut vring_avail_t,
++    pub used: *mut vring_used_t,
+ }
+ #[test]
+ fn bindgen_test_layout_vring() {
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0005-virtio-bindings-add-virtio-gpu-bindings.patch b/pkgs/applications/virtualization/cloud-hypervisor/0005-virtio-bindings-add-virtio-gpu-bindings.patch
new file mode 100644
index 00000000000..6747399d670
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0005-virtio-bindings-add-virtio-gpu-bindings.patch
@@ -0,0 +1,3587 @@
+From ffd586ecc6762da0e1ea870e0858391f9c158d8b Mon Sep 17 00:00:00 2001
+From: Alyssa Ross <alyssa.ross@unikie.com>
+Date: Wed, 31 Aug 2022 17:11:12 +0000
+Subject: [PATCH 5/5] virtio-bindings: add virtio-gpu bindings
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ crates/virtio-bindings/CONTRIBUTING.md   |    8 +-
+ crates/virtio-bindings/src/lib.rs        |    1 +
+ crates/virtio-bindings/src/virtio_gpu.rs | 3532 ++++++++++++++++++++++
+ 3 files changed, 3537 insertions(+), 4 deletions(-)
+ create mode 100644 crates/virtio-bindings/src/virtio_gpu.rs
+
+diff --git a/crates/virtio-bindings/CONTRIBUTING.md b/crates/virtio-bindings/CONTRIBUTING.md
+index 1b3da2f..d435078 100644
+--- a/crates/virtio-bindings/CONTRIBUTING.md
++++ b/crates/virtio-bindings/CONTRIBUTING.md
+@@ -30,12 +30,12 @@ git checkout v5.0
+ 
+ # Step 2: Generate the bindings from the kernel headers. We need to
+ # generate a file for each one of the virtio headers we're interested on.
+-# For the moment, we're generating "virtio_blk", "virtio_net" and
+-# "virtio_ring". Feel free to add additional header files if you need them
+-# for your project.
++# For the moment, we're generating "virtio_blk", "virtio_gpu", "virtio_net"
++# and "virtio_ring". Feel free to add additional header files if you need
++# them for your project.
+ make headers_install INSTALL_HDR_PATH=v5_0_headers
+ cd v5_0_headers
+-for i in virtio_blk virtio_net virtio_ring ; do \
++for i in virtio_blk virtio_gpu virtio_net virtio_ring ; do \
+     bindgen include/linux/$i.h -o $i.rs \
+     --with-derive-default \
+     --with-derive-partialeq \
+diff --git a/crates/virtio-bindings/src/lib.rs b/crates/virtio-bindings/src/lib.rs
+index 9702f17..543f630 100644
+--- a/crates/virtio-bindings/src/lib.rs
++++ b/crates/virtio-bindings/src/lib.rs
+@@ -7,6 +7,7 @@
+ #![allow(non_snake_case)]
+ 
+ pub mod virtio_blk;
++pub mod virtio_gpu;
+ pub mod virtio_net;
+ pub mod virtio_ring;
+ 
+diff --git a/crates/virtio-bindings/src/virtio_gpu.rs b/crates/virtio-bindings/src/virtio_gpu.rs
+new file mode 100644
+index 0000000..b1f9e5f
+--- /dev/null
++++ b/crates/virtio-bindings/src/virtio_gpu.rs
+@@ -0,0 +1,3532 @@
++/* automatically generated by rust-bindgen 0.60.1 */
++
++#[repr(C)]
++#[derive(Default)]
++pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
++impl<T> __IncompleteArrayField<T> {
++    #[inline]
++    pub const fn new() -> Self {
++        __IncompleteArrayField(::std::marker::PhantomData, [])
++    }
++    #[inline]
++    pub fn as_ptr(&self) -> *const T {
++        self as *const _ as *const T
++    }
++    #[inline]
++    pub fn as_mut_ptr(&mut self) -> *mut T {
++        self as *mut _ as *mut T
++    }
++    #[inline]
++    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
++        ::std::slice::from_raw_parts(self.as_ptr(), len)
++    }
++    #[inline]
++    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
++        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
++    }
++}
++impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
++    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
++        fmt.write_str("__IncompleteArrayField")
++    }
++}
++pub const __BITS_PER_LONG: u32 = 64;
++pub const __FD_SETSIZE: u32 = 1024;
++pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
++pub const VIRTIO_GPU_F_EDID: u32 = 1;
++pub const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
++pub const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
++pub const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
++pub const VIRTIO_GPU_FLAG_FENCE: u32 = 1;
++pub const VIRTIO_GPU_FLAG_INFO_RING_IDX: u32 = 2;
++pub const VIRTIO_GPU_MAX_SCANOUTS: u32 = 16;
++pub const VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP: u32 = 1;
++pub const VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 255;
++pub const VIRTIO_GPU_CAPSET_VIRGL: u32 = 1;
++pub const VIRTIO_GPU_CAPSET_VIRGL2: u32 = 2;
++pub const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1;
++pub const VIRTIO_GPU_BLOB_MEM_GUEST: u32 = 1;
++pub const VIRTIO_GPU_BLOB_MEM_HOST3D: u32 = 2;
++pub const VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST: u32 = 3;
++pub const VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE: u32 = 1;
++pub const VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE: u32 = 2;
++pub const VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE: u32 = 4;
++pub const VIRTIO_GPU_MAP_CACHE_MASK: u32 = 15;
++pub const VIRTIO_GPU_MAP_CACHE_NONE: u32 = 0;
++pub const VIRTIO_GPU_MAP_CACHE_CACHED: u32 = 1;
++pub const VIRTIO_GPU_MAP_CACHE_UNCACHED: u32 = 2;
++pub const VIRTIO_GPU_MAP_CACHE_WC: u32 = 3;
++pub type __s8 = ::std::os::raw::c_schar;
++pub type __u8 = ::std::os::raw::c_uchar;
++pub type __s16 = ::std::os::raw::c_short;
++pub type __u16 = ::std::os::raw::c_ushort;
++pub type __s32 = ::std::os::raw::c_int;
++pub type __u32 = ::std::os::raw::c_uint;
++pub type __s64 = ::std::os::raw::c_longlong;
++pub type __u64 = ::std::os::raw::c_ulonglong;
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct __kernel_fd_set {
++    pub fds_bits: [::std::os::raw::c_ulong; 16usize],
++}
++#[test]
++fn bindgen_test_layout___kernel_fd_set() {
++    assert_eq!(
++        ::std::mem::size_of::<__kernel_fd_set>(),
++        128usize,
++        concat!("Size of: ", stringify!(__kernel_fd_set))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<__kernel_fd_set>(),
++        8usize,
++        concat!("Alignment of ", stringify!(__kernel_fd_set))
++    );
++    fn test_field_fds_bits() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fd_set>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).fds_bits) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fd_set),
++                "::",
++                stringify!(fds_bits)
++            )
++        );
++    }
++    test_field_fds_bits();
++}
++pub type __kernel_sighandler_t =
++    ::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
++pub type __kernel_key_t = ::std::os::raw::c_int;
++pub type __kernel_mqd_t = ::std::os::raw::c_int;
++pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
++pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
++pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
++pub type __kernel_long_t = ::std::os::raw::c_long;
++pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
++pub type __kernel_ino_t = __kernel_ulong_t;
++pub type __kernel_mode_t = ::std::os::raw::c_uint;
++pub type __kernel_pid_t = ::std::os::raw::c_int;
++pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
++pub type __kernel_uid_t = ::std::os::raw::c_uint;
++pub type __kernel_gid_t = ::std::os::raw::c_uint;
++pub type __kernel_suseconds_t = __kernel_long_t;
++pub type __kernel_daddr_t = ::std::os::raw::c_int;
++pub type __kernel_uid32_t = ::std::os::raw::c_uint;
++pub type __kernel_gid32_t = ::std::os::raw::c_uint;
++pub type __kernel_size_t = __kernel_ulong_t;
++pub type __kernel_ssize_t = __kernel_long_t;
++pub type __kernel_ptrdiff_t = __kernel_long_t;
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct __kernel_fsid_t {
++    pub val: [::std::os::raw::c_int; 2usize],
++}
++#[test]
++fn bindgen_test_layout___kernel_fsid_t() {
++    assert_eq!(
++        ::std::mem::size_of::<__kernel_fsid_t>(),
++        8usize,
++        concat!("Size of: ", stringify!(__kernel_fsid_t))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<__kernel_fsid_t>(),
++        4usize,
++        concat!("Alignment of ", stringify!(__kernel_fsid_t))
++    );
++    fn test_field_val() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<__kernel_fsid_t>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).val) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(__kernel_fsid_t),
++                "::",
++                stringify!(val)
++            )
++        );
++    }
++    test_field_val();
++}
++pub type __kernel_off_t = __kernel_long_t;
++pub type __kernel_loff_t = ::std::os::raw::c_longlong;
++pub type __kernel_old_time_t = __kernel_long_t;
++pub type __kernel_time_t = __kernel_long_t;
++pub type __kernel_time64_t = ::std::os::raw::c_longlong;
++pub type __kernel_clock_t = __kernel_long_t;
++pub type __kernel_timer_t = ::std::os::raw::c_int;
++pub type __kernel_clockid_t = ::std::os::raw::c_int;
++pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
++pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
++pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
++pub type __le16 = __u16;
++pub type __be16 = __u16;
++pub type __le32 = __u32;
++pub type __be32 = __u32;
++pub type __le64 = __u64;
++pub type __be64 = __u64;
++pub type __sum16 = __u16;
++pub type __wsum = __u32;
++pub type __poll_t = ::std::os::raw::c_uint;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_UNDEFINED: virtio_gpu_ctrl_type = 0;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_GET_DISPLAY_INFO: virtio_gpu_ctrl_type = 256;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: virtio_gpu_ctrl_type = 257;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_UNREF: virtio_gpu_ctrl_type = 258;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_SET_SCANOUT: virtio_gpu_ctrl_type = 259;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_FLUSH: virtio_gpu_ctrl_type = 260;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: virtio_gpu_ctrl_type = 261;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: virtio_gpu_ctrl_type = 262;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: virtio_gpu_ctrl_type = 263;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_GET_CAPSET_INFO: virtio_gpu_ctrl_type = 264;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_GET_CAPSET: virtio_gpu_ctrl_type = 265;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_GET_EDID: virtio_gpu_ctrl_type = 266;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID: virtio_gpu_ctrl_type = 267;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB: virtio_gpu_ctrl_type = 268;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_SET_SCANOUT_BLOB: virtio_gpu_ctrl_type = 269;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_CTX_CREATE: virtio_gpu_ctrl_type = 512;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_CTX_DESTROY: virtio_gpu_ctrl_type = 513;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: virtio_gpu_ctrl_type = 514;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: virtio_gpu_ctrl_type = 515;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: virtio_gpu_ctrl_type = 516;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: virtio_gpu_ctrl_type = 517;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: virtio_gpu_ctrl_type = 518;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_SUBMIT_3D: virtio_gpu_ctrl_type = 519;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB: virtio_gpu_ctrl_type = 520;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB: virtio_gpu_ctrl_type = 521;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_UPDATE_CURSOR: virtio_gpu_ctrl_type = 768;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_CMD_MOVE_CURSOR: virtio_gpu_ctrl_type = 769;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_NODATA: virtio_gpu_ctrl_type = 4352;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_DISPLAY_INFO: virtio_gpu_ctrl_type = 4353;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_CAPSET_INFO: virtio_gpu_ctrl_type = 4354;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_CAPSET: virtio_gpu_ctrl_type = 4355;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_EDID: virtio_gpu_ctrl_type = 4356;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_RESOURCE_UUID: virtio_gpu_ctrl_type = 4357;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_OK_MAP_INFO: virtio_gpu_ctrl_type = 4358;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_UNSPEC: virtio_gpu_ctrl_type = 4608;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY: virtio_gpu_ctrl_type = 4609;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID: virtio_gpu_ctrl_type = 4610;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID: virtio_gpu_ctrl_type = 4611;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID: virtio_gpu_ctrl_type = 4612;
++pub const virtio_gpu_ctrl_type_VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER: virtio_gpu_ctrl_type = 4613;
++pub type virtio_gpu_ctrl_type = ::std::os::raw::c_uint;
++pub const virtio_gpu_shm_id_VIRTIO_GPU_SHM_ID_UNDEFINED: virtio_gpu_shm_id = 0;
++pub const virtio_gpu_shm_id_VIRTIO_GPU_SHM_ID_HOST_VISIBLE: virtio_gpu_shm_id = 1;
++pub type virtio_gpu_shm_id = ::std::os::raw::c_uint;
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_ctrl_hdr {
++    pub type_: __le32,
++    pub flags: __le32,
++    pub fence_id: __le64,
++    pub ctx_id: __le32,
++    pub ring_idx: __u8,
++    pub padding: [__u8; 3usize],
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_ctrl_hdr() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_ctrl_hdr>(),
++        24usize,
++        concat!("Size of: ", stringify!(virtio_gpu_ctrl_hdr))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_ctrl_hdr>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_ctrl_hdr))
++    );
++    fn test_field_type() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(type_)
++            )
++        );
++    }
++    test_field_type();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_fence_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).fence_id) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(fence_id)
++            )
++        );
++    }
++    test_field_fence_id();
++    fn test_field_ctx_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).ctx_id) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(ctx_id)
++            )
++        );
++    }
++    test_field_ctx_id();
++    fn test_field_ring_idx() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).ring_idx) as usize - ptr as usize
++            },
++            20usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(ring_idx)
++            )
++        );
++    }
++    test_field_ring_idx();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctrl_hdr>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            21usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctrl_hdr),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_cursor_pos {
++    pub scanout_id: __le32,
++    pub x: __le32,
++    pub y: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_cursor_pos() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_cursor_pos>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_gpu_cursor_pos))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_cursor_pos>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_cursor_pos))
++    );
++    fn test_field_scanout_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cursor_pos>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).scanout_id) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cursor_pos),
++                "::",
++                stringify!(scanout_id)
++            )
++        );
++    }
++    test_field_scanout_id();
++    fn test_field_x() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cursor_pos>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cursor_pos),
++                "::",
++                stringify!(x)
++            )
++        );
++    }
++    test_field_x();
++    fn test_field_y() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cursor_pos>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cursor_pos),
++                "::",
++                stringify!(y)
++            )
++        );
++    }
++    test_field_y();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cursor_pos>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cursor_pos),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_update_cursor {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub pos: virtio_gpu_cursor_pos,
++    pub resource_id: __le32,
++    pub hot_x: __le32,
++    pub hot_y: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_update_cursor() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_update_cursor>(),
++        56usize,
++        concat!("Size of: ", stringify!(virtio_gpu_update_cursor))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_update_cursor>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_update_cursor))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_pos() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).pos) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(pos)
++            )
++        );
++    }
++    test_field_pos();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_hot_x() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hot_x) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(hot_x)
++            )
++        );
++    }
++    test_field_hot_x();
++    fn test_field_hot_y() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hot_y) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(hot_y)
++            )
++        );
++    }
++    test_field_hot_y();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_update_cursor>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            52usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_update_cursor),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_rect {
++    pub x: __le32,
++    pub y: __le32,
++    pub width: __le32,
++    pub height: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_rect() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_rect>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_gpu_rect))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_rect>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_rect))
++    );
++    fn test_field_x() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_rect>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_rect),
++                "::",
++                stringify!(x)
++            )
++        );
++    }
++    test_field_x();
++    fn test_field_y() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_rect>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_rect),
++                "::",
++                stringify!(y)
++            )
++        );
++    }
++    test_field_y();
++    fn test_field_width() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_rect>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_rect),
++                "::",
++                stringify!(width)
++            )
++        );
++    }
++    test_field_width();
++    fn test_field_height() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_rect>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_rect),
++                "::",
++                stringify!(height)
++            )
++        );
++    }
++    test_field_height();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_unref {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_unref() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_unref>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_unref))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_unref>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_unref))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unref>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unref),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unref>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unref),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unref>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unref),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_create_2d {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub format: __le32,
++    pub width: __le32,
++    pub height: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_create_2d() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_create_2d>(),
++        40usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_create_2d))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_create_2d>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_create_2d))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_2d),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_2d),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_format() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_2d),
++                "::",
++                stringify!(format)
++            )
++        );
++    }
++    test_field_format();
++    fn test_field_width() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_2d),
++                "::",
++                stringify!(width)
++            )
++        );
++    }
++    test_field_width();
++    fn test_field_height() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize
++            },
++            36usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_2d),
++                "::",
++                stringify!(height)
++            )
++        );
++    }
++    test_field_height();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_set_scanout {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub r: virtio_gpu_rect,
++    pub scanout_id: __le32,
++    pub resource_id: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_set_scanout() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_set_scanout>(),
++        48usize,
++        concat!("Size of: ", stringify!(virtio_gpu_set_scanout))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_set_scanout>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_set_scanout))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_r() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout),
++                "::",
++                stringify!(r)
++            )
++        );
++    }
++    test_field_r();
++    fn test_field_scanout_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).scanout_id) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout),
++                "::",
++                stringify!(scanout_id)
++            )
++        );
++    }
++    test_field_scanout_id();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_flush {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub r: virtio_gpu_rect,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_flush() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_flush>(),
++        48usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_flush))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_flush>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_flush))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_flush>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_flush),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_r() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_flush>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_flush),
++                "::",
++                stringify!(r)
++            )
++        );
++    }
++    test_field_r();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_flush>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_flush),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_flush>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_flush),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_transfer_to_host_2d {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub r: virtio_gpu_rect,
++    pub offset: __le64,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_transfer_to_host_2d() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_transfer_to_host_2d>(),
++        56usize,
++        concat!("Size of: ", stringify!(virtio_gpu_transfer_to_host_2d))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_transfer_to_host_2d>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_transfer_to_host_2d))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_to_host_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_to_host_2d),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_r() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_to_host_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_to_host_2d),
++                "::",
++                stringify!(r)
++            )
++        );
++    }
++    test_field_r();
++    fn test_field_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_to_host_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_to_host_2d),
++                "::",
++                stringify!(offset)
++            )
++        );
++    }
++    test_field_offset();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_to_host_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_to_host_2d),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_to_host_2d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            52usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_to_host_2d),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_mem_entry {
++    pub addr: __le64,
++    pub length: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_mem_entry() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_mem_entry>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_gpu_mem_entry))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_mem_entry>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_mem_entry))
++    );
++    fn test_field_addr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_mem_entry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).addr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_mem_entry),
++                "::",
++                stringify!(addr)
++            )
++        );
++    }
++    test_field_addr();
++    fn test_field_length() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_mem_entry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).length) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_mem_entry),
++                "::",
++                stringify!(length)
++            )
++        );
++    }
++    test_field_length();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_mem_entry>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_mem_entry),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_attach_backing {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub nr_entries: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_attach_backing() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_attach_backing>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_attach_backing))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_attach_backing>(),
++        8usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_gpu_resource_attach_backing)
++        )
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_attach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_attach_backing),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_attach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_attach_backing),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_nr_entries() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_attach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).nr_entries) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_attach_backing),
++                "::",
++                stringify!(nr_entries)
++            )
++        );
++    }
++    test_field_nr_entries();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_detach_backing {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_detach_backing() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_detach_backing>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_detach_backing))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_detach_backing>(),
++        8usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_gpu_resource_detach_backing)
++        )
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_detach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_detach_backing),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_detach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_detach_backing),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit =
++                    ::std::mem::MaybeUninit::<virtio_gpu_resource_detach_backing>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_detach_backing),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_display_info {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub pmodes: [virtio_gpu_resp_display_info_virtio_gpu_display_one; 16usize],
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_display_info_virtio_gpu_display_one {
++    pub r: virtio_gpu_rect,
++    pub enabled: __le32,
++    pub flags: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_display_info_virtio_gpu_display_one() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_display_info_virtio_gpu_display_one>(),
++        24usize,
++        concat!(
++            "Size of: ",
++            stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one)
++        )
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_display_info_virtio_gpu_display_one>(),
++        4usize,
++        concat!(
++            "Alignment of ",
++            stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one)
++        )
++    );
++    fn test_field_r() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<
++                    virtio_gpu_resp_display_info_virtio_gpu_display_one,
++                >::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one),
++                "::",
++                stringify!(r)
++            )
++        );
++    }
++    test_field_r();
++    fn test_field_enabled() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<
++                    virtio_gpu_resp_display_info_virtio_gpu_display_one,
++                >::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one),
++                "::",
++                stringify!(enabled)
++            )
++        );
++    }
++    test_field_enabled();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<
++                    virtio_gpu_resp_display_info_virtio_gpu_display_one,
++                >::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            20usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_display_info() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_display_info>(),
++        408usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_display_info))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_display_info>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_display_info))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_display_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_display_info),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_pmodes() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_display_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).pmodes) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_display_info),
++                "::",
++                stringify!(pmodes)
++            )
++        );
++    }
++    test_field_pmodes();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_box {
++    pub x: __le32,
++    pub y: __le32,
++    pub z: __le32,
++    pub w: __le32,
++    pub h: __le32,
++    pub d: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_box() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_box>(),
++        24usize,
++        concat!("Size of: ", stringify!(virtio_gpu_box))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_box>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_box))
++    );
++    fn test_field_x() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(x)
++            )
++        );
++    }
++    test_field_x();
++    fn test_field_y() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(y)
++            )
++        );
++    }
++    test_field_y();
++    fn test_field_z() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).z) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(z)
++            )
++        );
++    }
++    test_field_z();
++    fn test_field_w() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).w) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(w)
++            )
++        );
++    }
++    test_field_w();
++    fn test_field_h() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).h) as usize - ptr as usize
++            },
++            16usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(h)
++            )
++        );
++    }
++    test_field_h();
++    fn test_field_d() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_box>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).d) as usize - ptr as usize
++            },
++            20usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_box),
++                "::",
++                stringify!(d)
++            )
++        );
++    }
++    test_field_d();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_transfer_host_3d {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub box_: virtio_gpu_box,
++    pub offset: __le64,
++    pub resource_id: __le32,
++    pub level: __le32,
++    pub stride: __le32,
++    pub layer_stride: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_transfer_host_3d() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_transfer_host_3d>(),
++        72usize,
++        concat!("Size of: ", stringify!(virtio_gpu_transfer_host_3d))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_transfer_host_3d>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_transfer_host_3d))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_box() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).box_) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(box_)
++            )
++        );
++    }
++    test_field_box();
++    fn test_field_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(offset)
++            )
++        );
++    }
++    test_field_offset();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            56usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_level() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).level) as usize - ptr as usize
++            },
++            60usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(level)
++            )
++        );
++    }
++    test_field_level();
++    fn test_field_stride() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).stride) as usize - ptr as usize
++            },
++            64usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(stride)
++            )
++        );
++    }
++    test_field_stride();
++    fn test_field_layer_stride() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_transfer_host_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).layer_stride) as usize - ptr as usize
++            },
++            68usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_transfer_host_3d),
++                "::",
++                stringify!(layer_stride)
++            )
++        );
++    }
++    test_field_layer_stride();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_create_3d {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub target: __le32,
++    pub format: __le32,
++    pub bind: __le32,
++    pub width: __le32,
++    pub height: __le32,
++    pub depth: __le32,
++    pub array_size: __le32,
++    pub last_level: __le32,
++    pub nr_samples: __le32,
++    pub flags: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_create_3d() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_create_3d>(),
++        72usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_create_3d))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_create_3d>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_create_3d))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_target() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).target) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(target)
++            )
++        );
++    }
++    test_field_target();
++    fn test_field_format() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(format)
++            )
++        );
++    }
++    test_field_format();
++    fn test_field_bind() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).bind) as usize - ptr as usize
++            },
++            36usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(bind)
++            )
++        );
++    }
++    test_field_bind();
++    fn test_field_width() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(width)
++            )
++        );
++    }
++    test_field_width();
++    fn test_field_height() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(height)
++            )
++        );
++    }
++    test_field_height();
++    fn test_field_depth() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).depth) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(depth)
++            )
++        );
++    }
++    test_field_depth();
++    fn test_field_array_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).array_size) as usize - ptr as usize
++            },
++            52usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(array_size)
++            )
++        );
++    }
++    test_field_array_size();
++    fn test_field_last_level() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).last_level) as usize - ptr as usize
++            },
++            56usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(last_level)
++            )
++        );
++    }
++    test_field_last_level();
++    fn test_field_nr_samples() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).nr_samples) as usize - ptr as usize
++            },
++            60usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(nr_samples)
++            )
++        );
++    }
++    test_field_nr_samples();
++    fn test_field_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize
++            },
++            64usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(flags)
++            )
++        );
++    }
++    test_field_flags();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_3d>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            68usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_3d),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_ctx_create {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub nlen: __le32,
++    pub context_init: __le32,
++    pub debug_name: [::std::os::raw::c_char; 64usize],
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_ctx_create() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_ctx_create>(),
++        96usize,
++        concat!("Size of: ", stringify!(virtio_gpu_ctx_create))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_ctx_create>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_ctx_create))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_create>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_create),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_nlen() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_create>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).nlen) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_create),
++                "::",
++                stringify!(nlen)
++            )
++        );
++    }
++    test_field_nlen();
++    fn test_field_context_init() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_create>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).context_init) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_create),
++                "::",
++                stringify!(context_init)
++            )
++        );
++    }
++    test_field_context_init();
++    fn test_field_debug_name() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_create>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).debug_name) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_create),
++                "::",
++                stringify!(debug_name)
++            )
++        );
++    }
++    test_field_debug_name();
++}
++impl Default for virtio_gpu_ctx_create {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_ctx_destroy {
++    pub hdr: virtio_gpu_ctrl_hdr,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_ctx_destroy() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_ctx_destroy>(),
++        24usize,
++        concat!("Size of: ", stringify!(virtio_gpu_ctx_destroy))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_ctx_destroy>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_ctx_destroy))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_destroy>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_destroy),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_ctx_resource {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_ctx_resource() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_ctx_resource>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_ctx_resource))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_ctx_resource>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_ctx_resource))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_resource>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_resource),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_resource>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_resource),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_ctx_resource>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_ctx_resource),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_cmd_submit {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub size: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_cmd_submit() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_cmd_submit>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_cmd_submit))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_cmd_submit>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_cmd_submit))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_submit>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_submit),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_submit>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_submit),
++                "::",
++                stringify!(size)
++            )
++        );
++    }
++    test_field_size();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_submit>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_submit),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_get_capset_info {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub capset_index: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_get_capset_info() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_get_capset_info>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_get_capset_info))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_get_capset_info>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_get_capset_info))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset_info),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_capset_index() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_index) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset_info),
++                "::",
++                stringify!(capset_index)
++            )
++        );
++    }
++    test_field_capset_index();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset_info),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_capset_info {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub capset_id: __le32,
++    pub capset_max_version: __le32,
++    pub capset_max_size: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_capset_info() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_capset_info>(),
++        40usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_capset_info))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_capset_info>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_capset_info))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset_info),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_capset_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset_info),
++                "::",
++                stringify!(capset_id)
++            )
++        );
++    }
++    test_field_capset_id();
++    fn test_field_capset_max_version() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_max_version) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset_info),
++                "::",
++                stringify!(capset_max_version)
++            )
++        );
++    }
++    test_field_capset_max_version();
++    fn test_field_capset_max_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_max_size) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset_info),
++                "::",
++                stringify!(capset_max_size)
++            )
++        );
++    }
++    test_field_capset_max_size();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            36usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset_info),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_get_capset {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub capset_id: __le32,
++    pub capset_version: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_get_capset() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_get_capset>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_get_capset))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_get_capset>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_get_capset))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_capset_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset),
++                "::",
++                stringify!(capset_id)
++            )
++        );
++    }
++    test_field_capset_id();
++    fn test_field_capset_version() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_get_capset>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_version) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_get_capset),
++                "::",
++                stringify!(capset_version)
++            )
++        );
++    }
++    test_field_capset_version();
++}
++#[repr(C)]
++#[derive(Debug, Default)]
++pub struct virtio_gpu_resp_capset {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub capset_data: __IncompleteArrayField<__u8>,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_capset() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_capset>(),
++        24usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_capset))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_capset>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_capset))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_capset_data() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_capset>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).capset_data) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_capset),
++                "::",
++                stringify!(capset_data)
++            )
++        );
++    }
++    test_field_capset_data();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_cmd_get_edid {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub scanout: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_cmd_get_edid() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_cmd_get_edid>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_cmd_get_edid))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_cmd_get_edid>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_cmd_get_edid))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_get_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_get_edid),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_scanout() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_get_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).scanout) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_get_edid),
++                "::",
++                stringify!(scanout)
++            )
++        );
++    }
++    test_field_scanout();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_cmd_get_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_cmd_get_edid),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_edid {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub size: __le32,
++    pub padding: __le32,
++    pub edid: [__u8; 1024usize],
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_edid() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_edid>(),
++        1056usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_edid))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_edid>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_edid))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_edid),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_edid),
++                "::",
++                stringify!(size)
++            )
++        );
++    }
++    test_field_size();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_edid),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++    fn test_field_edid() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_edid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).edid) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_edid),
++                "::",
++                stringify!(edid)
++            )
++        );
++    }
++    test_field_edid();
++}
++impl Default for virtio_gpu_resp_edid {
++    fn default() -> Self {
++        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
++        unsafe {
++            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
++            s.assume_init()
++        }
++    }
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_config {
++    pub events_read: __le32,
++    pub events_clear: __le32,
++    pub num_scanouts: __le32,
++    pub num_capsets: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_config() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_config>(),
++        16usize,
++        concat!("Size of: ", stringify!(virtio_gpu_config))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_config>(),
++        4usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_config))
++    );
++    fn test_field_events_read() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).events_read) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_config),
++                "::",
++                stringify!(events_read)
++            )
++        );
++    }
++    test_field_events_read();
++    fn test_field_events_clear() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).events_clear) as usize - ptr as usize
++            },
++            4usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_config),
++                "::",
++                stringify!(events_clear)
++            )
++        );
++    }
++    test_field_events_clear();
++    fn test_field_num_scanouts() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_scanouts) as usize - ptr as usize
++            },
++            8usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_config),
++                "::",
++                stringify!(num_scanouts)
++            )
++        );
++    }
++    test_field_num_scanouts();
++    fn test_field_num_capsets() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_config>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).num_capsets) as usize - ptr as usize
++            },
++            12usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_config),
++                "::",
++                stringify!(num_capsets)
++            )
++        );
++    }
++    test_field_num_capsets();
++}
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: virtio_gpu_formats = 1;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: virtio_gpu_formats = 2;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: virtio_gpu_formats = 3;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: virtio_gpu_formats = 4;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: virtio_gpu_formats = 67;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: virtio_gpu_formats = 68;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: virtio_gpu_formats = 121;
++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: virtio_gpu_formats = 134;
++pub type virtio_gpu_formats = ::std::os::raw::c_uint;
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_assign_uuid {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_assign_uuid() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_assign_uuid>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_assign_uuid))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_assign_uuid>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_assign_uuid))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_assign_uuid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_assign_uuid),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_assign_uuid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_assign_uuid),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_assign_uuid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_assign_uuid),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_resource_uuid {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub uuid: [__u8; 16usize],
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_resource_uuid() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_resource_uuid>(),
++        40usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_resource_uuid))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_resource_uuid>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_resource_uuid))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_resource_uuid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_resource_uuid),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_uuid() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_resource_uuid>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).uuid) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_resource_uuid),
++                "::",
++                stringify!(uuid)
++            )
++        );
++    }
++    test_field_uuid();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_create_blob {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub blob_mem: __le32,
++    pub blob_flags: __le32,
++    pub nr_entries: __le32,
++    pub blob_id: __le64,
++    pub size: __le64,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_create_blob() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_create_blob>(),
++        56usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_create_blob))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_create_blob>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_create_blob))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_blob_mem() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).blob_mem) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(blob_mem)
++            )
++        );
++    }
++    test_field_blob_mem();
++    fn test_field_blob_flags() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).blob_flags) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(blob_flags)
++            )
++        );
++    }
++    test_field_blob_flags();
++    fn test_field_nr_entries() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).nr_entries) as usize - ptr as usize
++            },
++            36usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(nr_entries)
++            )
++        );
++    }
++    test_field_nr_entries();
++    fn test_field_blob_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).blob_id) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(blob_id)
++            )
++        );
++    }
++    test_field_blob_id();
++    fn test_field_size() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_create_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_create_blob),
++                "::",
++                stringify!(size)
++            )
++        );
++    }
++    test_field_size();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_set_scanout_blob {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub r: virtio_gpu_rect,
++    pub scanout_id: __le32,
++    pub resource_id: __le32,
++    pub width: __le32,
++    pub height: __le32,
++    pub format: __le32,
++    pub padding: __le32,
++    pub strides: [__le32; 4usize],
++    pub offsets: [__le32; 4usize],
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_set_scanout_blob() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_set_scanout_blob>(),
++        96usize,
++        concat!("Size of: ", stringify!(virtio_gpu_set_scanout_blob))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_set_scanout_blob>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_set_scanout_blob))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_r() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(r)
++            )
++        );
++    }
++    test_field_r();
++    fn test_field_scanout_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).scanout_id) as usize - ptr as usize
++            },
++            40usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(scanout_id)
++            )
++        );
++    }
++    test_field_scanout_id();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            44usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_width() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize
++            },
++            48usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(width)
++            )
++        );
++    }
++    test_field_width();
++    fn test_field_height() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize
++            },
++            52usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(height)
++            )
++        );
++    }
++    test_field_height();
++    fn test_field_format() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize
++            },
++            56usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(format)
++            )
++        );
++    }
++    test_field_format();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            60usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++    fn test_field_strides() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).strides) as usize - ptr as usize
++            },
++            64usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(strides)
++            )
++        );
++    }
++    test_field_strides();
++    fn test_field_offsets() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_set_scanout_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).offsets) as usize - ptr as usize
++            },
++            80usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_set_scanout_blob),
++                "::",
++                stringify!(offsets)
++            )
++        );
++    }
++    test_field_offsets();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_map_blob {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++    pub offset: __le64,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_map_blob() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_map_blob>(),
++        40usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_map_blob))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_map_blob>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_map_blob))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_map_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_map_blob),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_map_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_map_blob),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_map_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_map_blob),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++    fn test_field_offset() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_map_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize
++            },
++            32usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_map_blob),
++                "::",
++                stringify!(offset)
++            )
++        );
++    }
++    test_field_offset();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resp_map_info {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub map_info: __u32,
++    pub padding: __u32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resp_map_info() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resp_map_info>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resp_map_info))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resp_map_info>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resp_map_info))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_map_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_map_info),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_map_info() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_map_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).map_info) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_map_info),
++                "::",
++                stringify!(map_info)
++            )
++        );
++    }
++    test_field_map_info();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resp_map_info>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resp_map_info),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
++#[repr(C)]
++#[derive(Debug, Default, Copy, Clone, PartialEq)]
++pub struct virtio_gpu_resource_unmap_blob {
++    pub hdr: virtio_gpu_ctrl_hdr,
++    pub resource_id: __le32,
++    pub padding: __le32,
++}
++#[test]
++fn bindgen_test_layout_virtio_gpu_resource_unmap_blob() {
++    assert_eq!(
++        ::std::mem::size_of::<virtio_gpu_resource_unmap_blob>(),
++        32usize,
++        concat!("Size of: ", stringify!(virtio_gpu_resource_unmap_blob))
++    );
++    assert_eq!(
++        ::std::mem::align_of::<virtio_gpu_resource_unmap_blob>(),
++        8usize,
++        concat!("Alignment of ", stringify!(virtio_gpu_resource_unmap_blob))
++    );
++    fn test_field_hdr() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unmap_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).hdr) as usize - ptr as usize
++            },
++            0usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unmap_blob),
++                "::",
++                stringify!(hdr)
++            )
++        );
++    }
++    test_field_hdr();
++    fn test_field_resource_id() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unmap_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize
++            },
++            24usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unmap_blob),
++                "::",
++                stringify!(resource_id)
++            )
++        );
++    }
++    test_field_resource_id();
++    fn test_field_padding() {
++        assert_eq!(
++            unsafe {
++                let uninit = ::std::mem::MaybeUninit::<virtio_gpu_resource_unmap_blob>::uninit();
++                let ptr = uninit.as_ptr();
++                ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize
++            },
++            28usize,
++            concat!(
++                "Offset of field: ",
++                stringify!(virtio_gpu_resource_unmap_blob),
++                "::",
++                stringify!(padding)
++            )
++        );
++    }
++    test_field_padding();
++}
+-- 
+2.37.1
+
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/default.nix b/pkgs/applications/virtualization/cloud-hypervisor/default.nix
index 2fb2836a6c0..cbef9798f53 100644
--- a/pkgs/applications/virtualization/cloud-hypervisor/default.nix
+++ b/pkgs/applications/virtualization/cloud-hypervisor/default.nix
@@ -1,4 +1,6 @@
-{ lib, stdenv, fetchFromGitHub, rustPlatform, pkg-config, dtc, openssl }:
+{ lib, stdenv, fetchCrate, fetchFromGitHub, fetchpatch, rustPlatform
+, pkg-config, dtc, openssl
+}:
 
 rustPlatform.buildRustPackage rec {
   pname = "cloud-hypervisor";
@@ -11,10 +13,68 @@ rustPlatform.buildRustPackage rec {
     sha256 = "sha256-choTT20TVp42nN/vS6xCDA7Mbf1ZuAE1tFQZn49g9ak=";
   };
 
+  vhost = fetchCrate {
+    pname = "vhost";
+    version = "0.4.0";
+    sha256 = "sha256-72tvycgdTI3pK1EpGoBEI0WajX7SYZvTI0lbU8ybdsc=";
+  };
+
+  vm-virtio = fetchFromGitHub {
+    owner = "rust-vmm";
+    repo = "vm-virtio";
+    rev = "7e203db6ed044217acd80dec5967c15d979491f8";
+    sha256 = "sha256-QLukQCPeWpletbKqhIruvevLMEepnQ4fKWVH42H7QM8=";
+  };
+
+  postUnpack = ''
+    unpackFile ${vhost}
+    mv vhost-* vhost
+
+    unpackFile ${vm-virtio}/crates/virtio-bindings
+
+    chmod -R +w vhost virtio-bindings
+  '';
+
+  cargoPatches = [
+    ./0001-build-use-local-vhost.patch
+    ./0002-build-use-local-virtio-bindings.patch
+    ./0003-virtio-devices-add-a-GPU-device.patch
+  ];
+
+  vhostPatches = [
+    ./vhost-vhost_user-add-shared-memory-region-support.patch
+  ];
+
+  virtioBindingsPatches = [
+    # https://github.com/rust-vmm/vm-virtio/pull/194
+    ./0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch
+    ./0002-virtio-bindings-remove-workaround-for-old-bindgen.patch
+    ./0003-virtio-bindings-regenerate-with-Glibc-2.36.patch
+    ./0004-virtio-bindings-regenerate-with-Linux-5.19.patch
+
+    ./0005-virtio-bindings-add-virtio-gpu-bindings.patch
+  ];
+
+  postPatch = ''
+    pushd ../vhost
+    for patch in $vhostPatches; do
+        echo applying patch $patch
+        patch -p1 < $patch
+    done
+    popd
+
+    pushd ../virtio-bindings
+    for patch in $virtioBindingsPatches; do
+        echo applying patch $patch
+        patch -p3 < $patch
+    done
+    popd
+  '';
+
   nativeBuildInputs = [ pkg-config ];
   buildInputs = [ openssl ] ++ lib.optional stdenv.isAarch64 dtc;
 
-  cargoSha256 = "sha256-mmyaT24he33wLI3zLOOKhVtzrPRyWzKgXUvc37suy5E=";
+  cargoSha256 = "164vr9xxrlpllac5db69ggasczq5vqb9zv60dkwbqabn8qm5cr1x";
 
   OPENSSL_NO_VENDOR = true;
 
diff --git a/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch b/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch
new file mode 100644
index 00000000000..728399548f8
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch
@@ -0,0 +1,724 @@
+From b72b87aed5542df7d912750f9745f9854c9cf482 Mon Sep 17 00:00:00 2001
+From: David Stevens <stevensd@chromium.org>
+Date: Wed, 15 Jun 2022 16:45:12 +0900
+Subject: [PATCH] vhost_user: add shared memory region support
+
+Add support for shared memory regions to vhost-user. This is adding
+support for a front-end message to query for necessary shared memory
+regions plus back-end message to support mapping/unmapping files from
+the shared memory region.
+
+go/vvu-shared-memory
+
+BUG=b:201745804
+TEST=compiles
+
+Change-Id: I35c5d260ee09175b68f6778b81883e0070ee0265
+Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3716344
+Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
+Commit-Queue: David Stevens <stevensd@chromium.org>
+Reviewed-by: Alexandre Courbot <acourbot@chromium.org>
+Tested-by: kokoro <noreply+kokoro@google.com>
+(cherry-picked from commit f436e2706011fa5f34dc415972434aa3299ebc43)
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.com>
+---
+ src/vhost_user/dummy_slave.rs        |   4 +
+ src/vhost_user/master.rs             |  24 +++++
+ src/vhost_user/master_req_handler.rs |  78 ++++++++++++---
+ src/vhost_user/message.rs            | 140 +++++++++++++++++++++++++--
+ src/vhost_user/mod.rs                |   2 +-
+ src/vhost_user/slave_fs_cache.rs     |  67 ++++++++-----
+ src/vhost_user/slave_req_handler.rs  |  27 +++++-
+ 7 files changed, 292 insertions(+), 50 deletions(-)
+
+diff --git a/src/vhost_user/dummy_slave.rs b/src/vhost_user/dummy_slave.rs
+index 222a5bb3..5389e3fb 100644
+--- a/src/vhost_user/dummy_slave.rs
++++ b/src/vhost_user/dummy_slave.rs
+@@ -271,4 +271,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
+     fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> {
+         Ok(())
+     }
++
++    fn get_shared_memory_regions(&mut self) -> Result<Vec<VhostSharedMemoryRegion>> {
++        Ok(Vec::new())
++    }
+ }
+diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs
+index 711b6739..1ad47aaa 100644
+--- a/src/vhost_user/master.rs
++++ b/src/vhost_user/master.rs
+@@ -72,6 +72,9 @@ pub trait VhostUserMaster: VhostBackend {
+ 
+     /// Remove a guest memory mapping from vhost.
+     fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>;
++
++    /// Gets the shared memory regions used by the device.
++    fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ fn error_code<T>(err: VhostUserError) -> Result<T> {
+@@ -552,6 +555,27 @@ impl VhostUserMaster for Master {
+         let hdr = node.send_request_with_body(MasterReq::REM_MEM_REG, &body, None)?;
+         node.wait_for_ack(&hdr).map_err(|e| e.into())
+     }
++
++    fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>> {
++        let mut node = self.node();
++        let hdr = node.send_request_header(MasterReq::GET_SHARED_MEMORY_REGIONS, None)?;
++        let (body_reply, buf_reply, rfds) = node.recv_reply_with_payload::<VhostUserU64>(&hdr)?;
++        let struct_size = mem::size_of::<VhostSharedMemoryRegion>();
++        if rfds.is_some() || buf_reply.len() != body_reply.value as usize * struct_size {
++            return error_code(VhostUserError::InvalidMessage);
++        }
++        let mut regions = Vec::new();
++        let mut offset = 0;
++        for _ in 0..body_reply.value {
++            regions.push(
++                // Can't fail because the input is the correct size.
++                VhostSharedMemoryRegion::from_slice(&buf_reply[offset..(offset + struct_size)])
++                    .unwrap().clone(),
++            );
++            offset += struct_size;
++        }
++        Ok(regions)
++    }
+ }
+ 
+ impl AsRawFd for Master {
+diff --git a/src/vhost_user/master_req_handler.rs b/src/vhost_user/master_req_handler.rs
+index 0ecda4e3..d0d6529b 100644
+--- a/src/vhost_user/master_req_handler.rs
++++ b/src/vhost_user/master_req_handler.rs
+@@ -17,7 +17,7 @@ use super::{Error, HandlerResult, Result};
+ /// request services from masters. The [VhostUserMasterReqHandler] trait defines services provided
+ /// by masters, and it's used both on the master side and slave side.
+ /// - on the slave side, a stub forwarder implementing [VhostUserMasterReqHandler] will proxy
+-///   service requests to masters. The [SlaveFsCacheReq] is an example stub forwarder.
++///   service requests to masters. The [Slave] is an example stub forwarder.
+ /// - on the master side, the [MasterReqHandler] will forward service requests to a handler
+ ///   implementing [VhostUserMasterReqHandler].
+ ///
+@@ -26,13 +26,27 @@ use super::{Error, HandlerResult, Result};
+ ///
+ /// [VhostUserMasterReqHandler]: trait.VhostUserMasterReqHandler.html
+ /// [MasterReqHandler]: struct.MasterReqHandler.html
+-/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html
++/// [Slave]: struct.Slave.html
+ pub trait VhostUserMasterReqHandler {
+     /// Handle device configuration change notifications.
+     fn handle_config_change(&self) -> HandlerResult<u64> {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+     }
+ 
++    /// Handle shared memory region mapping requests.
++    fn shmem_map(
++        &self,
++        _req: &VhostUserShmemMapMsg,
++        _fd: &dyn AsRawFd,
++    ) -> HandlerResult<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
++    /// Handle shared memory region unmapping requests.
++    fn shmem_unmap(&self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
+     /// Handle virtio-fs map file requests.
+     fn fs_slave_map(&self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult<u64> {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+@@ -66,6 +80,20 @@ pub trait VhostUserMasterReqHandlerMut {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+     }
+ 
++    /// Handle shared memory region mapping requests.
++    fn shmem_map(
++        &mut self,
++        _req: &VhostUserShmemMapMsg,
++        _fd: &dyn AsRawFd,
++    ) -> HandlerResult<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
++    /// Handle shared memory region unmapping requests.
++    fn shmem_unmap(&mut self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
++    }
++
+     /// Handle virtio-fs map file requests.
+     fn fs_slave_map(&mut self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult<u64> {
+         Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
+@@ -95,6 +123,18 @@ impl<S: VhostUserMasterReqHandlerMut> VhostUserMasterReqHandler for Mutex<S> {
+         self.lock().unwrap().handle_config_change()
+     }
+ 
++    fn shmem_map(
++        &self,
++        req: &VhostUserShmemMapMsg,
++        fd: &dyn AsRawFd,
++    ) -> HandlerResult<u64> {
++        self.lock().unwrap().shmem_map(req, fd)
++    }
++
++    fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        self.lock().unwrap().shmem_unmap(req)
++    }
++
+     fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
+         self.lock().unwrap().fs_slave_map(fs, fd)
+     }
+@@ -222,6 +262,19 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+                     .handle_config_change()
+                     .map_err(Error::ReqHandlerError)
+             }
++            SlaveReq::SHMEM_MAP => {
++                let msg = self.extract_msg_body::<VhostUserShmemMapMsg>(&hdr, size, &buf)?;
++                // check_attached_files() has validated files
++                self.backend
++                    .shmem_map(&msg, &files.unwrap()[0])
++                    .map_err(Error::ReqHandlerError)
++            }
++            SlaveReq::SHMEM_UNMAP => {
++                let msg = self.extract_msg_body::<VhostUserShmemUnmapMsg>(&hdr, size, &buf)?;
++                self.backend
++                    .shmem_unmap(&msg)
++                    .map_err(Error::ReqHandlerError)
++            }
+             SlaveReq::FS_MAP => {
+                 let msg = self.extract_msg_body::<VhostUserFSSlaveMsg>(&hdr, size, &buf)?;
+                 // check_attached_files() has validated files
+@@ -251,7 +304,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+             _ => Err(Error::InvalidMessage),
+         };
+ 
+-        self.send_ack_message(&hdr, &res)?;
++        self.send_reply(&hdr, &res)?;
+ 
+         res
+     }
+@@ -285,7 +338,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+         files: &Option<Vec<File>>,
+     ) -> Result<()> {
+         match hdr.get_code() {
+-            SlaveReq::FS_MAP | SlaveReq::FS_IO => {
++            SlaveReq::SHMEM_MAP | SlaveReq::FS_MAP | SlaveReq::FS_IO => {
+                 // Expect a single file is passed.
+                 match files {
+                     Some(files) if files.len() == 1 => Ok(()),
+@@ -326,12 +379,11 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
+         ))
+     }
+ 
+-    fn send_ack_message(
+-        &mut self,
+-        req: &VhostUserMsgHeader<SlaveReq>,
+-        res: &Result<u64>,
+-    ) -> Result<()> {
+-        if self.reply_ack_negotiated && req.is_need_reply() {
++    fn send_reply(&mut self, req: &VhostUserMsgHeader<SlaveReq>, res: &Result<u64>) -> Result<()> {
++        if req.get_code() == SlaveReq::SHMEM_MAP
++            || req.get_code() == SlaveReq::SHMEM_UNMAP
++            || (self.reply_ack_negotiated && req.is_need_reply())
++        {
+             let hdr = self.new_reply_header::<VhostUserU64>(req)?;
+             let def_err = libc::EINVAL;
+             let val = match res {
+@@ -362,7 +414,7 @@ mod tests {
+     use super::*;
+ 
+     #[cfg(feature = "vhost-user-slave")]
+-    use crate::vhost_user::SlaveFsCacheReq;
++    use crate::vhost_user::Slave;
+     #[cfg(feature = "vhost-user-slave")]
+     use std::os::unix::io::FromRawFd;
+ 
+@@ -410,7 +462,7 @@ mod tests {
+             panic!("failed to duplicated tx fd!");
+         }
+         let stream = unsafe { UnixStream::from_raw_fd(fd) };
+-        let fs_cache = SlaveFsCacheReq::from_stream(stream);
++        let fs_cache = Slave::from_stream(stream);
+ 
+         std::thread::spawn(move || {
+             let res = handler.handle_request().unwrap();
+@@ -440,7 +492,7 @@ mod tests {
+             panic!("failed to duplicated tx fd!");
+         }
+         let stream = unsafe { UnixStream::from_raw_fd(fd) };
+-        let fs_cache = SlaveFsCacheReq::from_stream(stream);
++        let fs_cache = Slave::from_stream(stream);
+ 
+         std::thread::spawn(move || {
+             let res = handler.handle_request().unwrap();
+diff --git a/src/vhost_user/message.rs b/src/vhost_user/message.rs
+index d61c17a1..66139972 100644
+--- a/src/vhost_user/message.rs
++++ b/src/vhost_user/message.rs
+@@ -139,8 +139,10 @@ pub enum MasterReq {
+     /// Query the backend for its device status as defined in the VIRTIO
+     /// specification.
+     GET_STATUS = 40,
++    /// Get a list of the device's shared memory regions.
++    GET_SHARED_MEMORY_REGIONS = 41,
+     /// Upper bound of valid commands.
+-    MAX_CMD = 41,
++    MAX_CMD = 42,
+ }
+ 
+ impl From<MasterReq> for u32 {
+@@ -171,16 +173,20 @@ pub enum SlaveReq {
+     VRING_CALL = 4,
+     /// Indicate that an error occurred on the specific vring.
+     VRING_ERR = 5,
++    /// Indicates a request to map a fd into a shared memory region.
++    SHMEM_MAP = 6,
++    /// Indicates a request to unmap part of a shared memory region.
++    SHMEM_UNMAP = 7,
+     /// Virtio-fs draft: map file content into the window.
+-    FS_MAP = 6,
++    FS_MAP = 8,
+     /// Virtio-fs draft: unmap file content from the window.
+-    FS_UNMAP = 7,
++    FS_UNMAP = 9,
+     /// Virtio-fs draft: sync file content.
+-    FS_SYNC = 8,
++    FS_SYNC = 10,
+     /// Virtio-fs draft: perform a read/write from an fd directly to GPA.
+-    FS_IO = 9,
++    FS_IO = 11,
+     /// Upper bound of valid commands.
+-    MAX_CMD = 10,
++    MAX_CMD = 12,
+ }
+ 
+ impl From<SlaveReq> for u32 {
+@@ -817,7 +823,7 @@ pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8;
+ 
+ /// Slave request message to update the MMIO window.
+ #[repr(packed)]
+-#[derive(Default)]
++#[derive(Clone, Copy, Default)]
+ pub struct VhostUserFSSlaveMsg {
+     /// File offset.
+     pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES],
+@@ -828,6 +834,8 @@ pub struct VhostUserFSSlaveMsg {
+     /// Flags for the mmap operation
+     pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES],
+ }
++// Safe because it only has data and has no implicit padding.
++unsafe impl ByteValued for VhostUserFSSlaveMsg {}
+ 
+ impl VhostUserMsgValidator for VhostUserFSSlaveMsg {
+     fn is_valid(&self) -> bool {
+@@ -843,6 +851,99 @@ impl VhostUserMsgValidator for VhostUserFSSlaveMsg {
+     }
+ }
+ 
++bitflags! {
++    #[derive(Default)]
++    /// Flags for SHMEM_MAP messages.
++    pub struct VhostUserShmemMapMsgFlags: u8 {
++        /// Empty permission.
++        const EMPTY = 0x0;
++        /// Read permission.
++        const MAP_R = 0x1;
++        /// Write permission.
++        const MAP_W = 0x2;
++    }
++}
++
++/// Slave request message to map a file into a shared memory region.
++#[repr(C, packed)]
++#[derive(Default, Copy, Clone)]
++pub struct VhostUserShmemMapMsg {
++    /// Flags for the mmap operation
++    pub flags: VhostUserShmemMapMsgFlags,
++    /// Shared memory region id.
++    pub shmid: u8,
++    padding: [u8; 6],
++    /// Offset into the shared memory region.
++    pub shm_offset: u64,
++    /// File offset.
++    pub fd_offset: u64,
++    /// Size of region to map.
++    pub len: u64,
++}
++// Safe because it only has data and has no implicit padding.
++unsafe impl ByteValued for VhostUserShmemMapMsg {}
++
++impl VhostUserMsgValidator for VhostUserShmemMapMsg {
++    fn is_valid(&self) -> bool {
++        (self.flags.bits() & !VhostUserFSSlaveMsgFlags::all().bits() as u8) == 0
++            && self.fd_offset.checked_add(self.len).is_some()
++            && self.shm_offset.checked_add(self.len).is_some()
++    }
++}
++
++impl VhostUserShmemMapMsg {
++    /// New instance of VhostUserShmemMapMsg struct
++    pub fn new(
++        shmid: u8,
++        shm_offset: u64,
++        fd_offset: u64,
++        len: u64,
++        flags: VhostUserShmemMapMsgFlags,
++    ) -> Self {
++        Self {
++            flags,
++            shmid,
++            padding: [0; 6],
++            shm_offset,
++            fd_offset,
++            len,
++        }
++    }
++}
++
++/// Slave request message to unmap part of a shared memory region.
++#[repr(C, packed)]
++#[derive(Default, Copy, Clone)]
++pub struct VhostUserShmemUnmapMsg {
++    /// Shared memory region id.
++    pub shmid: u8,
++    padding: [u8; 7],
++    /// Offset into the shared memory region.
++    pub shm_offset: u64,
++    /// Size of region to unmap.
++    pub len: u64,
++}
++// Safe because it only has data and has no implicit padding.
++unsafe impl ByteValued for VhostUserShmemUnmapMsg {}
++
++impl VhostUserMsgValidator for VhostUserShmemUnmapMsg {
++    fn is_valid(&self) -> bool {
++        self.shm_offset.checked_add(self.len).is_some()
++    }
++}
++
++impl VhostUserShmemUnmapMsg {
++    /// New instance of VhostUserShmemUnmapMsg struct
++    pub fn new(shmid: u8, shm_offset: u64, len: u64) -> Self {
++        Self {
++            shmid,
++            padding: [0; 7],
++            shm_offset,
++            len,
++        }
++    }
++}
++
+ /// Inflight I/O descriptor state for split virtqueues
+ #[repr(packed)]
+ #[derive(Clone, Copy, Default)]
+@@ -974,6 +1075,31 @@ impl QueueRegionPacked {
+     }
+ }
+ 
++/// Virtio shared memory descriptor.
++#[repr(packed)]
++#[derive(Default, Copy, Clone)]
++pub struct VhostSharedMemoryRegion {
++    /// The shared memory region's shmid.
++    pub id: u8,
++    /// Padding
++    padding: [u8; 7],
++    /// The length of the shared memory region.
++    pub length: u64,
++}
++// Safe because it only has data and has no implicit padding.
++unsafe impl ByteValued for VhostSharedMemoryRegion {}
++
++impl VhostSharedMemoryRegion {
++    /// New instance of VhostSharedMemoryRegion struct
++    pub fn new(id: u8, length: u64) -> Self {
++        VhostSharedMemoryRegion {
++            id,
++            padding: [0; 7],
++            length,
++        }
++    }
++}
++
+ #[cfg(test)]
+ mod tests {
+     use super::*;
+diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs
+index 6b1afb8c..a2f0af88 100644
+--- a/src/vhost_user/mod.rs
++++ b/src/vhost_user/mod.rs
+@@ -50,7 +50,7 @@ pub use self::slave_req_handler::{
+ #[cfg(feature = "vhost-user-slave")]
+ mod slave_fs_cache;
+ #[cfg(feature = "vhost-user-slave")]
+-pub use self::slave_fs_cache::SlaveFsCacheReq;
++pub use self::slave_fs_cache::Slave;
+ 
+ /// Errors for vhost-user operations
+ #[derive(Debug)]
+diff --git a/src/vhost_user/slave_fs_cache.rs b/src/vhost_user/slave_fs_cache.rs
+index e9ad7cf6..369d682a 100644
+--- a/src/vhost_user/slave_fs_cache.rs
++++ b/src/vhost_user/slave_fs_cache.rs
+@@ -7,11 +7,13 @@ use std::os::unix::io::{AsRawFd, RawFd};
+ use std::os::unix::net::UnixStream;
+ use std::sync::{Arc, Mutex, MutexGuard};
+ 
++use vm_memory::ByteValued;
++
+ use super::connection::Endpoint;
+ use super::message::*;
+ use super::{Error, HandlerResult, Result, VhostUserMasterReqHandler};
+ 
+-struct SlaveFsCacheReqInternal {
++struct SlaveInternal {
+     sock: Endpoint<SlaveReq>,
+ 
+     // Protocol feature VHOST_USER_PROTOCOL_F_REPLY_ACK has been negotiated.
+@@ -21,7 +23,7 @@ struct SlaveFsCacheReqInternal {
+     error: Option<i32>,
+ }
+ 
+-impl SlaveFsCacheReqInternal {
++impl SlaveInternal {
+     fn check_state(&self) -> Result<u64> {
+         match self.error {
+             Some(e) => Err(Error::SocketBroken(std::io::Error::from_raw_os_error(e))),
+@@ -29,27 +31,30 @@ impl SlaveFsCacheReqInternal {
+         }
+     }
+ 
+-    fn send_message(
++    fn send_message<T: ByteValued>(
+         &mut self,
+         request: SlaveReq,
+-        fs: &VhostUserFSSlaveMsg,
++        msg: &T,
+         fds: Option<&[RawFd]>,
+     ) -> Result<u64> {
+         self.check_state()?;
+ 
+-        let len = mem::size_of::<VhostUserFSSlaveMsg>();
++        let len = mem::size_of::<T>();
+         let mut hdr = VhostUserMsgHeader::new(request, 0, len as u32);
+         if self.reply_ack_negotiated {
+             hdr.set_need_reply(true);
+         }
+-        self.sock.send_message(&hdr, fs, fds)?;
++        self.sock.send_message(&hdr, msg, fds)?;
+ 
+-        self.wait_for_ack(&hdr)
++        self.wait_for_reply(&hdr)
+     }
+ 
+-    fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
++    fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
+         self.check_state()?;
+-        if !self.reply_ack_negotiated {
++        if hdr.get_code() != SlaveReq::SHMEM_MAP
++            && hdr.get_code() != SlaveReq::SHMEM_UNMAP
++            && !self.reply_ack_negotiated
++        {
+             return Ok(0);
+         }
+ 
+@@ -68,22 +73,22 @@ impl SlaveFsCacheReqInternal {
+ /// Request proxy to send vhost-user-fs slave requests to the master through the slave
+ /// communication channel.
+ ///
+-/// The [SlaveFsCacheReq] acts as a message proxy to forward vhost-user-fs slave requests to the
++/// The [Slave] acts as a message proxy to forward vhost-user-fs slave requests to the
+ /// master through the vhost-user slave communication channel. The forwarded messages will be
+ /// handled by the [MasterReqHandler] server.
+ ///
+-/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html
++/// [Slave]: struct.Slave.html
+ /// [MasterReqHandler]: struct.MasterReqHandler.html
+ #[derive(Clone)]
+-pub struct SlaveFsCacheReq {
++pub struct Slave {
+     // underlying Unix domain socket for communication
+-    node: Arc<Mutex<SlaveFsCacheReqInternal>>,
++    node: Arc<Mutex<SlaveInternal>>,
+ }
+ 
+-impl SlaveFsCacheReq {
++impl Slave {
+     fn new(ep: Endpoint<SlaveReq>) -> Self {
+-        SlaveFsCacheReq {
+-            node: Arc::new(Mutex::new(SlaveFsCacheReqInternal {
++        Slave {
++            node: Arc::new(Mutex::new(SlaveInternal {
+                 sock: ep,
+                 reply_ack_negotiated: false,
+                 error: None,
+@@ -91,18 +96,18 @@ impl SlaveFsCacheReq {
+         }
+     }
+ 
+-    fn node(&self) -> MutexGuard<SlaveFsCacheReqInternal> {
++    fn node(&self) -> MutexGuard<SlaveInternal> {
+         self.node.lock().unwrap()
+     }
+ 
+-    fn send_message(
++    fn send_message<T: ByteValued>(
+         &self,
+         request: SlaveReq,
+-        fs: &VhostUserFSSlaveMsg,
++        msg: &T,
+         fds: Option<&[RawFd]>,
+     ) -> io::Result<u64> {
+         self.node()
+-            .send_message(request, fs, fds)
++            .send_message(request, msg, fds)
+             .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))
+     }
+ 
+@@ -126,7 +131,21 @@ impl SlaveFsCacheReq {
+     }
+ }
+ 
+-impl VhostUserMasterReqHandler for SlaveFsCacheReq {
++impl VhostUserMasterReqHandler for Slave {
++    /// Handle shared memory region mapping requests.
++    fn shmem_map(
++        &self,
++        req: &VhostUserShmemMapMsg,
++        fd: &dyn AsRawFd,
++    ) -> HandlerResult<u64> {
++        self.send_message(SlaveReq::SHMEM_MAP, req, Some(&[fd.as_raw_fd()]))
++    }
++
++    /// Handle shared memory region unmapping requests.
++    fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> {
++        self.send_message(SlaveReq::SHMEM_UNMAP, req, None)
++    }
++
+     /// Forward vhost-user-fs map file requests to the slave.
+     fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult<u64> {
+         self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd.as_raw_fd()]))
+@@ -147,7 +166,7 @@ mod tests {
+     #[test]
+     fn test_slave_fs_cache_req_set_failed() {
+         let (p1, _p2) = UnixStream::pair().unwrap();
+-        let fs_cache = SlaveFsCacheReq::from_stream(p1);
++        let fs_cache = Slave::from_stream(p1);
+ 
+         assert!(fs_cache.node().error.is_none());
+         fs_cache.set_failed(libc::EAGAIN);
+@@ -157,7 +176,7 @@ mod tests {
+     #[test]
+     fn test_slave_fs_cache_send_failure() {
+         let (p1, p2) = UnixStream::pair().unwrap();
+-        let fs_cache = SlaveFsCacheReq::from_stream(p1);
++        let fs_cache = Slave::from_stream(p1);
+ 
+         fs_cache.set_failed(libc::ECONNRESET);
+         fs_cache
+@@ -172,7 +191,7 @@ mod tests {
+     #[test]
+     fn test_slave_fs_cache_recv_negative() {
+         let (p1, p2) = UnixStream::pair().unwrap();
+-        let fs_cache = SlaveFsCacheReq::from_stream(p1);
++        let fs_cache = Slave::from_stream(p1);
+         let mut master = Endpoint::<SlaveReq>::from_stream(p2);
+ 
+         let len = mem::size_of::<VhostUserFSSlaveMsg>();
+diff --git a/src/vhost_user/slave_req_handler.rs b/src/vhost_user/slave_req_handler.rs
+index f43159ad..ee313ffd 100644
+--- a/src/vhost_user/slave_req_handler.rs
++++ b/src/vhost_user/slave_req_handler.rs
+@@ -8,9 +8,11 @@ use std::os::unix::net::UnixStream;
+ use std::slice;
+ use std::sync::{Arc, Mutex};
+ 
++use vm_memory::ByteValued;
++
+ use super::connection::Endpoint;
+ use super::message::*;
+-use super::slave_fs_cache::SlaveFsCacheReq;
++use super::slave_fs_cache::Slave;
+ use super::{take_single_file, Error, Result};
+ 
+ /// Services provided to the master by the slave with interior mutability.
+@@ -62,12 +64,13 @@ pub trait VhostUserSlaveReqHandler {
+     fn set_vring_enable(&self, index: u32, enable: bool) -> Result<()>;
+     fn get_config(&self, offset: u32, size: u32, flags: VhostUserConfigFlags) -> Result<Vec<u8>>;
+     fn set_config(&self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>;
+-    fn set_slave_req_fd(&self, _vu_req: SlaveFsCacheReq) {}
++    fn set_slave_req_fd(&self, _vu_req: Slave) {}
+     fn get_inflight_fd(&self, inflight: &VhostUserInflight) -> Result<(VhostUserInflight, File)>;
+     fn set_inflight_fd(&self, inflight: &VhostUserInflight, file: File) -> Result<()>;
+     fn get_max_mem_slots(&self) -> Result<u64>;
+     fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
+     fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
++    fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ /// Services provided to the master by the slave without interior mutability.
+@@ -107,7 +110,7 @@ pub trait VhostUserSlaveReqHandlerMut {
+         flags: VhostUserConfigFlags,
+     ) -> Result<Vec<u8>>;
+     fn set_config(&mut self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>;
+-    fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {}
++    fn set_slave_req_fd(&mut self, _vu_req: Slave) {}
+     fn get_inflight_fd(
+         &mut self,
+         inflight: &VhostUserInflight,
+@@ -116,6 +119,7 @@ pub trait VhostUserSlaveReqHandlerMut {
+     fn get_max_mem_slots(&mut self) -> Result<u64>;
+     fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
+     fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
++    fn get_shared_memory_regions(&mut self) -> Result<Vec<VhostSharedMemoryRegion>>;
+ }
+ 
+ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
+@@ -201,7 +205,7 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
+         self.lock().unwrap().set_config(offset, buf, flags)
+     }
+ 
+-    fn set_slave_req_fd(&self, vu_req: SlaveFsCacheReq) {
++    fn set_slave_req_fd(&self, vu_req: Slave) {
+         self.lock().unwrap().set_slave_req_fd(vu_req)
+     }
+ 
+@@ -224,6 +228,10 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
+     fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> {
+         self.lock().unwrap().remove_mem_region(region)
+     }
++
++    fn get_shared_memory_regions(&self) -> Result<Vec<VhostSharedMemoryRegion>> {
++        self.lock().unwrap().get_shared_memory_regions()
++    }
+ }
+ 
+ /// Server to handle service requests from masters from the master communication channel.
+@@ -528,6 +536,15 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
+                 let res = self.backend.remove_mem_region(&msg);
+                 self.send_ack_message(&hdr, res)?;
+             }
++            MasterReq::GET_SHARED_MEMORY_REGIONS => {
++                let regions = self.backend.get_shared_memory_regions()?;
++                let mut buf = Vec::new();
++                let msg = VhostUserU64::new(regions.len() as u64);
++                for r in regions {
++                    buf.extend_from_slice(r.as_slice())
++                }
++                self.send_reply_with_payload(&hdr, &msg, buf.as_slice())?;
++            }
+             _ => {
+                 return Err(Error::InvalidMessage);
+             }
+@@ -641,7 +658,7 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
+     fn set_slave_req_fd(&mut self, files: Option<Vec<File>>) -> Result<()> {
+         let file = take_single_file(files).ok_or(Error::InvalidMessage)?;
+         let sock = unsafe { UnixStream::from_raw_fd(file.into_raw_fd()) };
+-        let vu_req = SlaveFsCacheReq::from_stream(sock);
++        let vu_req = Slave::from_stream(sock);
+         self.backend.set_slave_req_fd(vu_req);
+         Ok(())
+     }
+-- 
+2.37.1
+
-- 
2.37.1



  parent reply	other threads:[~2022-09-30 21:10 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-30 21:08 [RFC PATCH nixpkgs v2 0/9] virtio-gpu with crosvm and cloud-hypervisor Alyssa Ross
2022-09-30 21:08 ` [RFC PATCH nixpkgs v2 1/9] crosvm: switch back to old git repo URL Alyssa Ross
2022-09-30 21:08 ` [RFC PATCH nixpkgs v2 2/9] crosvm.updateScript: update release branch format Alyssa Ross
2022-09-30 21:09 ` [RFC PATCH nixpkgs v2 3/9] crosvm: 104.0 -> 106.2 Alyssa Ross
2022-09-30 21:09 ` [RFC PATCH nixpkgs v2 4/9] crosvm.updateScript: don't vendor Cargo.lock Alyssa Ross
2022-09-30 21:09 ` [RFC PATCH nixpkgs v2 5/9] crosvm: add fixes for cloud-hypervisor virtio-gpu Alyssa Ross
2022-09-30 21:09 ` [RFC PATCH nixpkgs v2 6/9] rustPlatform: forward unpack hooks to cargo fetch Alyssa Ross
2022-09-30 21:09 ` Alyssa Ross [this message]
2022-09-30 21:09 ` [RFC PATCH nixpkgs v2 8/9] ocamlPackages.wayland: 1.0 -> 1.1 Alyssa Ross
2022-09-30 21:12 ` [RFC PATCH nixpkgs v2 9/9] wayland-proxy-virtwl: unstable-2021-12-05 -> unstable-2022-09-22 Alyssa Ross

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220930210906.1696349-8-alyssa.ross@unikie.com \
    --to=alyssa.ross@unikie.com \
    --cc=devel@spectrum-os.org \
    --cc=puck@puckipedia.com \
    --cc=ville.ilvonen@unikie.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://spectrum-os.org/git/crosvm
	https://spectrum-os.org/git/doc
	https://spectrum-os.org/git/mktuntap
	https://spectrum-os.org/git/nixpkgs
	https://spectrum-os.org/git/spectrum
	https://spectrum-os.org/git/ucspi-vsock
	https://spectrum-os.org/git/www

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).