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
---
.../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
+Date: Wed, 28 Sep 2022 12:18:19 +0000
+Subject: [PATCH 1/3] build: use local vhost
+
+Signed-off-by: Alyssa Ross
+---
+ 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
+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
+---
+ 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;
+@@ -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::())).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::())).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::())).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::::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::::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::::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::())).capacity as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(capacity)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).size_max as *const _ as usize },
+- 8usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(size_max)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).seg_max as *const _ as usize },
+- 12usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(seg_max)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).geometry as *const _ as usize },
+- 16usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(geometry)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).blk_size as *const _ as usize },
+- 20usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(blk_size)
+- )
+- );
+- assert_eq!(
+- unsafe {
+- &(*(::std::ptr::null::())).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::())).alignment_offset as *const _ as usize
+- },
+- 25usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(alignment_offset)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::())).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::())).wce as *const _ as usize },
+- 32usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(wce)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).unused as *const _ as usize },
+- 33usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(unused)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).num_queues as *const _ as usize },
+- 34usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_config),
+- "::",
+- stringify!(num_queues)
+- )
+- );
+- assert_eq!(
+- unsafe {
+- &(*(::std::ptr::null::())).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::())).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::())).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::())).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::())).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::())).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::())).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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::::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::())).type_ as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_outhdr),
+- "::",
+- stringify!(type_)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).ioprio as *const _ as usize },
+- 4usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_outhdr),
+- "::",
+- stringify!(ioprio)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::())).sector as *const _ as usize
+- },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_blk_discard_write_zeroes),
+- "::",
+- stringify!(sector)
+- )
+- );
+- assert_eq!(
+- unsafe {
+- &(*(::std::ptr::null::())).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::())).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::::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::::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::::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::())).errors as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_scsi_inhdr),
+- "::",
+- stringify!(errors)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).data_len as *const _ as usize },
+- 4usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_scsi_inhdr),
+- "::",
+- stringify!(data_len)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).sense_len as *const _ as usize },
+- 8usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_scsi_inhdr),
+- "::",
+- stringify!(sense_len)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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;
+@@ -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::())).mac as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_config),
+- "::",
+- stringify!(mac)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).status as *const _ as usize },
+- 6usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_config),
+- "::",
+- stringify!(status)
+- )
+- );
+- assert_eq!(
+- unsafe {
+- &(*(::std::ptr::null::())).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::())).mtu as *const _ as usize },
+- 10usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_config),
+- "::",
+- stringify!(mtu)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).speed as *const _ as usize },
+- 12usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_config),
+- "::",
+- stringify!(speed)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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::::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::::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::())).flags as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr_v1),
+- "::",
+- stringify!(flags)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::())).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::())).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::())).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::())).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::())).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::::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::::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::::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::::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::::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::::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::::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::())).flags as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr),
+- "::",
+- stringify!(flags)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).gso_type as *const _ as usize },
+- 1usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr),
+- "::",
+- stringify!(gso_type)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).hdr_len as *const _ as usize },
+- 2usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr),
+- "::",
+- stringify!(hdr_len)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).gso_size as *const _ as usize },
+- 4usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr),
+- "::",
+- stringify!(gso_size)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).csum_start as *const _ as usize },
+- 6usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr),
+- "::",
+- stringify!(csum_start)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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::::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::::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::())).hdr as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_hdr_mrg_rxbuf),
+- "::",
+- stringify!(hdr)
+- )
+- );
+- assert_eq!(
+- unsafe {
+- &(*(::std::ptr::null::())).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::::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::::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::())).class as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(virtio_net_ctrl_hdr),
+- "::",
+- stringify!(class)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::())).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::::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;
+@@ -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::())).addr as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_desc),
+- "::",
+- stringify!(addr)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize },
+- 8usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_desc),
+- "::",
+- stringify!(len)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).flags as *const _ as usize },
+- 12usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_desc),
+- "::",
+- stringify!(flags)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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::())).id as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_used_elem),
+- "::",
+- stringify!(id)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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,
+- 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::())).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::())).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::::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::::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::())).addr as *const _ as usize },
+- 0usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_packed_desc),
+- "::",
+- stringify!(addr)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).len as *const _ as usize },
+- 8usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_packed_desc),
+- "::",
+- stringify!(len)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).id as *const _ as usize },
+- 12usize,
+- concat!(
+- "Offset of field: ",
+- stringify!(vring_packed_desc),
+- "::",
+- stringify!(id)
+- )
+- );
+- assert_eq!(
+- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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
+Date: Wed, 28 Sep 2022 12:30:42 +0000
+Subject: [PATCH 2/3] build: use local virtio-bindings
+
+Signed-off-by: Alyssa Ross
+---
+ 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
+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
+---
+ 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
+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
+---
+ 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::::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::::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::::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::::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::::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::::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::::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::::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
+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
+---
+ 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,
+ }
+
+ /// 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>,
++ 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 {
++ // 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>,
++ pub gpu: Option>,
+ pub pmem: Option>,
+ 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> = args.values_of("fs").map(|x| x.collect());
++ let gpu: Option> = args.values_of("gpu").map(|x| x.collect());
+ let pmem: Option> = args.values_of("pmem").map(|x| x.collect());
+ let devices: Option> = args.values_of("device").map(|x| x.collect());
+ let user_devices: Option> = 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=,cache_size=,\
++ id=,pci_segment=\"";
++
++ 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,
++ pub gpu: Option,
+ pub pmem: Option,
+ #[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 = 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 = 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,
++ iommu: false,
++ id,
++ pci_segment: gpu_cfg.pci_segment,
++ dma_handler: None,
++ })
++ } else {
++ Err(DeviceManagerError::NoVirtioGpuSock)
++ }
++ }
++
++ fn make_virtio_gpu_devices(&mut self) -> DeviceManagerResult {
++ 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, 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 , 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
+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
+---
+ 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::(),
+- 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::::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::::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::::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::(),
++ 4usize,
++ concat!(
++ "Size of: ",
++ stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_1)
++ )
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 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::(),
++ 4usize,
++ concat!(
++ "Size of: ",
++ stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_2)
++ )
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 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::(),
++ 4usize,
++ concat!(
++ "Size of: ",
++ stringify!(virtio_net_hdr_v1__bindgen_ty_1__bindgen_ty_3)
++ )
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 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::(),
++ 4usize,
++ concat!("Size of: ", stringify!(virtio_net_hdr_v1__bindgen_ty_1))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 2usize,
++ concat!("Alignment of ", stringify!(virtio_net_hdr_v1__bindgen_ty_1))
++ );
++ fn test_field_csum() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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::(),
++ 20usize,
++ concat!("Size of: ", stringify!(virtio_net_hdr_v1_hash))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 4usize,
++ concat!("Alignment of ", stringify!(virtio_net_hdr_v1_hash))
++ );
++ fn test_field_hdr() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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::(),
++ 16usize,
++ concat!("Size of: ", stringify!(virtio_net_rss_config))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 4usize,
++ concat!("Alignment of ", stringify!(virtio_net_rss_config))
++ );
++ fn test_field_hash_types() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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::::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::::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::::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::(),
++ 16usize,
++ concat!("Size of: ", stringify!(virtio_net_hash_config))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 4usize,
++ concat!("Alignment of ", stringify!(virtio_net_hash_config))
++ );
++ fn test_field_hash_types() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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,
++ pub ring: __IncompleteArrayField,
+ }
+ #[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
+Date: Wed, 31 Aug 2022 17:11:12 +0000
+Subject: [PATCH 5/5] virtio-bindings: add virtio-gpu bindings
+
+Signed-off-by: Alyssa Ross
+---
+ 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;
++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::(),
++ 24usize,
++ concat!("Size of: ", stringify!(virtio_gpu_ctrl_hdr))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 8usize,
++ concat!("Alignment of ", stringify!(virtio_gpu_ctrl_hdr))
++ );
++ fn test_field_type() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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::::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::::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::(),
++ 16usize,
++ concat!("Size of: ", stringify!(virtio_gpu_cursor_pos))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 4usize,
++ concat!("Alignment of ", stringify!(virtio_gpu_cursor_pos))
++ );
++ fn test_field_scanout_id() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::::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::::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::(),
++ 56usize,
++ concat!("Size of: ", stringify!(virtio_gpu_update_cursor))
++ );
++ assert_eq!(
++ ::std::mem::align_of::(),
++ 8usize,
++ concat!("Alignment of ", stringify!(virtio_gpu_update_cursor))
++ );
++ fn test_field_hdr() {
++ assert_eq!(
++ unsafe {
++ let uninit = ::std::mem::MaybeUninit::::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::::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::