[RFC PATCH nixpkgs 7/9] cloud-hypervisor: add virtio-gpu support

Alyssa Ross
2022-09-28T17:02:01Z

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 ++
...-devices-add-a-vhost-user-gpu-device.patch | 1253 ++++++
...-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, 9635 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-vhost-user-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-vhost-user-gpu-device.patch b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-vhost-user-gpu-device.patch
new file mode 100644
index 00000000000..a9f5ec543cb
--- /dev/null
+++ b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-vhost-user-gpu-device.patch
@@ -0,0 +1,1253 @@
+From 4430a440c3cc01aedbddd843b9ddcfba2253b4f3 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 vhost-user-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
+
+Signed-off-by: Alyssa Ross <alyssa.ross@unikie.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 | 6 +
+ virtio-devices/src/transport/pci_device.rs | 4 +-
+ virtio-devices/src/vhost_user/gpu.rs | 357 ++++++++++++++++++
+ 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, 774 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..45a27750 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,10 @@ 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![])]
++}
++
+ fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
+ vec![]
+ }
+@@ -230,6 +235,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..b0a9ee7c
+--- /dev/null
++++ b/virtio-devices/src/vhost_user/gpu.rs
+@@ -0,0 +1,357 @@
++// Copyright 2019 Intel Corporation. All Rights Reserved.
++// Copyright 2022 Unikie
++// 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 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 {
++ 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..d4fc8d46265 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-vhost-user-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 {
+ 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 {
+ .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 {
+ _ => Err(Error::InvalidMessage),
+ };
+
+- self.send_ack_message(&hdr, &res)?;
++ self.send_reply(&hdr, &res)?;
+
+ res
+ }
+@@ -285,7 +338,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler {
+ 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 {
+ ))
+ }
+
+- 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 {
+ 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 {
+ 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