From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on atuin.qyliss.net X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.6 Received: from atuin.qyliss.net (localhost [IPv6:::1]) by atuin.qyliss.net (Postfix) with ESMTP id 5D40072330; Fri, 30 Sep 2022 21:10:09 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 496) id CE5E6722A3; Fri, 30 Sep 2022 21:10:05 +0000 (UTC) Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by atuin.qyliss.net (Postfix) with ESMTPS id 99E0472231 for ; Fri, 30 Sep 2022 21:09:58 +0000 (UTC) Received: by mail-ed1-x535.google.com with SMTP id y100so7006278ede.6 for ; Fri, 30 Sep 2022 14:09:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=unikie.com; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date; bh=yPl08wRYvpIdwpT7EUixxQWDotP1t3+owM1TH4oRMLg=; b=FdQyJcRcL6EMY8iVc9/HHd5tzyXckqsWqhFM76NnDAAqC+95f7Ad2Fh09kB35Chxhk 8tkMckJfijSQ+zXKSPdHz6a6ayUnX1yX2hCqZn7W7CoCuj+XlB+thRW1ZpPwVwEvd07g cWfP8+mlXoEsMNLgjRVOdbQ4n3GdUjlE5j6gcAV8zqGFKjBVf+FidR2Uh/58P9WxSZTu Asb3PQnMx9fU4IYf7P7RFaAIr5W5cl3vUe2LERHOQSsi4pPpcADQ56kHF6UlT4NQcVAX /vZQNxq8C4abEvNitBpobo2b1c1pekuoH+cp4IWR+Mhi0I5mLSYCxe307ZpmCqXE3C+a PI6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=yPl08wRYvpIdwpT7EUixxQWDotP1t3+owM1TH4oRMLg=; b=M+CteMf513eU+jiyB2fgpj2ycUPR+QMvu3dFsa2tUV2YdKtbJ0X4cBB8TUZJOZTZvT jr1JjnewmSBDfVboMYPFPh93K1u/t9VehnyE2dhGlEFqPStMNNRk3oVAfH2CBiyQ3J+h UlxxFYxiquCIHT2eBStKZTQ3ovQGaYNSHL27cv3/TGh1XykRJYMH5I83rqaCFrMsrpXC 1R0iNB77IuBKdS3XWYEHzeCEYdWiBk59OGsZD7dUtFocBeR/P+8sRmVTuxD4L7DM03Ba bdSzzSfZkDrqZaVGyD0QO8Nmz6c97cy4dxK5vtMtwfnmnF0I0agOSorzMNsl9ciQ1i3d bPIQ== X-Gm-Message-State: ACrzQf01+Tm2mVY4YiZwf0VTGNNqyhlcSV6fKDn2Gcm6HtdM0B31a33q 3lLXV0SmhmnzXBqQorKqskSX8g== X-Google-Smtp-Source: AMsMyM6Y1BUsyvjh0+XjMKhgdB2VzHevMO8sxPLcGzbeOZhRBuQyW84T2p6VOq+IMLWGc84bbi9Jaw== X-Received: by 2002:a05:6402:204a:b0:456:eed5:5f2c with SMTP id bc10-20020a056402204a00b00456eed55f2cmr9373366edb.200.1664572197205; Fri, 30 Sep 2022 14:09:57 -0700 (PDT) Received: from x220.qyliss.net (p200300ed67079c010000000000000003.dip0.t-ipconnect.de. [2003:ed:6707:9c01::3]) by smtp.gmail.com with ESMTPSA id t13-20020a50d70d000000b00452878cba5bsm2208321edi.97.2022.09.30.14.09.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Sep 2022 14:09:56 -0700 (PDT) Received: by x220.qyliss.net (Postfix, from userid 1000) id 1D4D2685; Fri, 30 Sep 2022 21:09:56 +0000 (UTC) From: Alyssa Ross To: devel@spectrum-os.org Subject: [RFC PATCH nixpkgs v2 7/9] cloud-hypervisor: add virtio-gpu support Date: Fri, 30 Sep 2022 21:09:04 +0000 Message-Id: <20220930210906.1696349-8-alyssa.ross@unikie.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220930210906.1696349-1-alyssa.ross@unikie.com> References: <20220930210906.1696349-1-alyssa.ross@unikie.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: 4AUM2SZZYAE3ABPY6PSOSBCYVNLV42CG X-Message-ID-Hash: 4AUM2SZZYAE3ABPY6PSOSBCYVNLV42CG X-MailFrom: alyssa.ross@unikie.com X-Mailman-Rule-Hits: header-match-devel.spectrum-os.org-0 X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1 CC: Puck Meerburg , Ville Ilvonen X-Mailman-Version: 3.3.5 Precedence: list List-Id: Patches and low-level development discussion Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 ++ ...0003-virtio-devices-add-a-GPU-device.patch | 1279 ++++++ ...-bindings-regenerate-with-Linux-5.19.patch | 1067 +++++ ...tio-bindings-add-virtio-gpu-bindings.patch | 3587 +++++++++++++++++ .../cloud-hypervisor/default.nix | 64 +- ...ser-add-shared-memory-region-support.patch | 724 ++++ 10 files changed, 9661 insertions(+), 2 deletions(-) create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0002-build-use-local-virtio-bindings.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0002-virtio-bindings-remove-workaround-for-old-bindgen.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-bindings-regenerate-with-Glibc-2.36.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0004-virtio-bindings-regenerate-with-Linux-5.19.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/0005-virtio-bindings-add-virtio-gpu-bindings.patch create mode 100644 pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch diff --git a/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch b/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch new file mode 100644 index 00000000000..c4152ae3504 --- /dev/null +++ b/pkgs/applications/virtualization/cloud-hypervisor/0001-build-use-local-vhost.patch @@ -0,0 +1,39 @@ +From 53848d798c617110c5c3f975db47a9555bc276f4 Mon Sep 17 00:00:00 2001 +From: Alyssa Ross +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(::std::marker::PhantomData, [T; 0]); + impl __IncompleteArrayField { + #[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 ::std::fmt::Debug for __IncompleteArrayField { + fmt.write_str("__IncompleteArrayField") + } + } +-impl ::std::clone::Clone for __IncompleteArrayField { +- #[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::())).h_dest as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(ethhdr), +- "::", +- stringify!(h_dest) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).h_source as *const _ as usize }, +- 6usize, +- concat!( +- "Offset of field: ", +- stringify!(ethhdr), +- "::", +- stringify!(h_source) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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(::std::marker::PhantomData, [T; 0]); + impl __IncompleteArrayField { + #[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 ::std::fmt::Debug for __IncompleteArrayField { + fmt.write_str("__IncompleteArrayField") + } + } +-impl ::std::clone::Clone for __IncompleteArrayField { +- #[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::())).num as *const _ as usize }, +- 0usize, +- concat!( +- "Offset of field: ", +- stringify!(vring), +- "::", +- stringify!(num) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).desc as *const _ as usize }, +- 8usize, +- concat!( +- "Offset of field: ", +- stringify!(vring), +- "::", +- stringify!(desc) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).avail as *const _ as usize }, +- 16usize, +- concat!( +- "Offset of field: ", +- stringify!(vring), +- "::", +- stringify!(avail) +- ) +- ); +- assert_eq!( +- unsafe { &(*(::std::ptr::null::())).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::::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::::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::::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::::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::::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 ::std::fmt::Debug for __IncompleteArrayField { + 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-GPU-device.patch b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch new file mode 100644 index 00000000000..20b1f9da3af --- /dev/null +++ b/pkgs/applications/virtualization/cloud-hypervisor/0003-virtio-devices-add-a-GPU-device.patch @@ -0,0 +1,1279 @@ +From cadce3914276387389d10fd2d180c85c46d77f20 Mon Sep 17 00:00:00 2001 +From: Alyssa Ross +Date: Wed, 7 Sep 2022 14:16:29 +0000 +Subject: [PATCH 3/3] virtio-devices: add a GPU device + +This adds support for exposing a virtio-gpu device to guest by +implementing a vhost-user frontend compatible with crosvm's GPU device +backend. + +Note that this is not the same as the "vhost-user-gpu" protocol +implemented by QEMU. + +Adding a GPU device from the command line looks like this: + + --gpu socket=/path/to/crosvm-gpu-vhost-user.sock + +As a workaround, We fall back to trying to map shared memory as +read-only if it can't be mapped read-write, because wlroots' keymaps +are read-only, and crosvm does not properly handle this, causing +cloud-hypervisor to crash. + +Signed-off-by: Alyssa Ross +Co-authored-by: Puck Meerburg +Signed-off-by: Puck Meerburg +--- + Cargo.lock | 1 + + src/main.rs | 9 + + virtio-devices/src/device.rs | 8 +- + virtio-devices/src/lib.rs | 2 + + virtio-devices/src/seccomp_filters.rs | 10 + + virtio-devices/src/transport/pci_device.rs | 4 +- + virtio-devices/src/vhost_user/gpu.rs | 372 ++++++++++++++++++ + virtio-devices/src/vhost_user/mod.rs | 2 + + .../src/vhost_user/vu_common_ctrl.rs | 14 +- + vmm/Cargo.toml | 1 + + vmm/src/api/mod.rs | 7 + + vmm/src/config.rs | 123 ++++++ + vmm/src/device_manager.rs | 140 ++++++- + vmm/src/lib.rs | 83 ++++ + vmm/src/vm.rs | 33 +- + 15 files changed, 793 insertions(+), 16 deletions(-) + create mode 100644 virtio-devices/src/vhost_user/gpu.rs + +diff --git a/Cargo.lock b/Cargo.lock +index d119f28e..c8a20cef 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -1463,6 +1463,7 @@ dependencies = [ + "vfio-ioctls", + "vfio_user", + "vhdx", ++ "virtio-bindings", + "virtio-devices", + "virtio-queue", + "vm-allocator", +diff --git a/src/main.rs b/src/main.rs +index 8725129a..eac7a126 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -263,6 +263,14 @@ fn create_app<'a>( + .min_values(1) + .group("vm-config"), + ) ++ .arg( ++ Arg::new("gpu") ++ .long("gpu") ++ .help(config::GpuConfig::SYNTAX) ++ .takes_value(true) ++ .min_values(1) ++ .group("vm-config"), ++ ) + .arg( + Arg::new("pmem") + .long("pmem") +@@ -724,6 +732,7 @@ mod unit_tests { + }, + balloon: None, + fs: None, ++ gpu: None, + pmem: None, + serial: ConsoleConfig { + file: None, +diff --git a/virtio-devices/src/device.rs b/virtio-devices/src/device.rs +index c09adbb2..8bdbb7b9 100644 +--- a/virtio-devices/src/device.rs ++++ b/virtio-devices/src/device.rs +@@ -11,7 +11,7 @@ use crate::{ + VIRTIO_F_RING_INDIRECT_DESC, + }; + use libc::EFD_NONBLOCK; +-use std::collections::HashMap; ++use std::collections::{BTreeMap, HashMap}; + use std::io::Write; + use std::num::Wrapping; + use std::sync::{ +@@ -47,19 +47,19 @@ pub struct UserspaceMapping { + pub mergeable: bool, + } + +-#[derive(Clone)] ++#[derive(Clone, Debug)] + pub struct VirtioSharedMemory { + pub offset: u64, + pub len: u64, + } + +-#[derive(Clone)] ++#[derive(Clone, Debug)] + pub struct VirtioSharedMemoryList { + pub host_addr: u64, + pub mem_slot: u32, + pub addr: GuestAddress, + pub len: GuestUsize, +- pub region_list: Vec, ++ 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..a1ec89d8 100644 +--- a/virtio-devices/src/seccomp_filters.rs ++++ b/virtio-devices/src/seccomp_filters.rs +@@ -22,6 +22,7 @@ pub enum Thread { + VirtioRng, + VirtioVhostBlock, + VirtioVhostFs, ++ VirtioVhostGpu, + VirtioVhostNet, + VirtioVhostNetCtl, + VirtioVsock, +@@ -168,6 +169,14 @@ fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec)> { + ] + } + ++fn virtio_vhost_gpu_thread_rules() -> Vec<(i64, Vec)> { ++ vec![ ++ (libc::SYS_getcwd, vec![]), ++ (libc::SYS_recvmsg, vec![]), ++ (libc::SYS_sendmsg, vec![]), ++ ] ++} ++ + fn virtio_vhost_net_ctl_thread_rules() -> Vec<(i64, Vec)> { + vec![] + } +@@ -230,6 +239,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec)> { + Thread::VirtioRng => virtio_rng_thread_rules(), + Thread::VirtioVhostBlock => virtio_vhost_block_thread_rules(), + Thread::VirtioVhostFs => virtio_vhost_fs_thread_rules(), ++ Thread::VirtioVhostGpu => virtio_vhost_gpu_thread_rules(), + Thread::VirtioVhostNet => virtio_vhost_net_thread_rules(), + Thread::VirtioVhostNetCtl => virtio_vhost_net_ctl_thread_rules(), + Thread::VirtioVsock => virtio_vsock_thread_rules(), +diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs +index 748d4328..6b0d0daa 100644 +--- a/virtio-devices/src/transport/pci_device.rs ++++ b/virtio-devices/src/transport/pci_device.rs +@@ -949,11 +949,11 @@ impl PciDevice for VirtioPciDevice { + + bars.push(bar); + +- for (idx, shm) in shm_list.region_list.iter().enumerate() { ++ for (shmid, shm) in shm_list.region_list.iter() { + let shm_cap = VirtioPciCap64::new( + PciCapabilityType::SharedMemoryConfig, + VIRTIO_SHM_BAR_INDEX as u8, +- idx as u8, ++ *shmid, + shm.offset, + shm.len, + ); +diff --git a/virtio-devices/src/vhost_user/gpu.rs b/virtio-devices/src/vhost_user/gpu.rs +new file mode 100644 +index 00000000..2eb18445 +--- /dev/null ++++ b/virtio-devices/src/vhost_user/gpu.rs +@@ -0,0 +1,372 @@ ++// Copyright 2019 Intel Corporation. All Rights Reserved. ++// Copyright 2022 Unikie ++// Copyright 2022 Puck Meerburg ++// SPDX-License-Identifier: Apache-2.0 ++ ++use crate::seccomp_filters::Thread; ++use crate::thread_helper::spawn_virtio_thread; ++use crate::vhost_user::vu_common_ctrl::VhostUserHandle; ++use crate::vhost_user::{Error, Result, VhostUserCommon}; ++use crate::{ ++ ActivateError, ActivateResult, GuestMemoryMmap, GuestRegionMmap, MmapRegion, UserspaceMapping, ++ VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterrupt, VirtioSharedMemoryList, ++ VIRTIO_F_VERSION_1, ++}; ++use seccompiler::SeccompAction; ++use std::io::{self, Write}; ++use std::os::unix::prelude::AsRawFd; ++use std::sync::{Arc, Barrier, Mutex}; ++use std::thread; ++use vhost::vhost_user::message::{ ++ VhostUserConfigFlags, VhostUserProtocolFeatures, VhostUserShmemMapMsg, VhostUserShmemUnmapMsg, ++ VhostUserVirtioFeatures, ++}; ++use vhost::vhost_user::{ ++ HandlerResult, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler, ++}; ++use virtio_bindings::virtio_gpu::{ ++ VIRTIO_GPU_F_CONTEXT_INIT, VIRTIO_GPU_F_RESOURCE_BLOB, VIRTIO_GPU_F_RESOURCE_UUID, ++ VIRTIO_GPU_F_VIRGL, ++}; ++use virtio_queue::Queue; ++use vm_memory::GuestMemoryAtomic; ++use vm_migration::Pausable; ++use vmm_sys_util::eventfd::EventFd; ++ ++const QUEUE_SIZES: &[u16] = &[256, 16]; ++const NUM_QUEUES: u16 = QUEUE_SIZES.len() as _; ++ ++struct SlaveReqHandler { ++ cache_size: u64, ++ mmap_cache_addr: u64, ++} ++ ++impl SlaveReqHandler { ++ // Make sure request is within cache range ++ fn is_req_valid(&self, offset: u64, len: u64) -> bool { ++ let end = match offset.checked_add(len) { ++ Some(n) => n, ++ None => return false, ++ }; ++ ++ !(offset >= self.cache_size || end > self.cache_size) ++ } ++} ++ ++impl VhostUserMasterReqHandler for SlaveReqHandler { ++ fn shmem_map(&self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawFd) -> HandlerResult { ++ if !self.is_req_valid(req.shm_offset, req.len) { ++ return Err(io::Error::from_raw_os_error(libc::EINVAL)); ++ } ++ ++ let addr = self.mmap_cache_addr + req.shm_offset; ++ let mut ret = unsafe { ++ libc::mmap( ++ addr as *mut libc::c_void, ++ req.len as usize, ++ req.flags.bits() as i32, ++ libc::MAP_SHARED | libc::MAP_FIXED, ++ fd.as_raw_fd(), ++ req.fd_offset as libc::off_t, ++ ) ++ }; ++ ++ if ret == libc::MAP_FAILED { ++ ret = unsafe { ++ libc::mmap( ++ addr as *mut libc::c_void, ++ req.len as usize, ++ (req.flags.bits() as i32) & !libc::PROT_WRITE, ++ libc::MAP_SHARED | libc::MAP_FIXED, ++ fd.as_raw_fd(), ++ req.fd_offset as libc::off_t, ++ ) ++ }; ++ } ++ ++ if ret == libc::MAP_FAILED { ++ return Err(io::Error::last_os_error()); ++ } ++ ++ Ok(0) ++ } ++ ++ fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult { ++ 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 { ++ 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, ++ interrupt_cb: Arc, ++ 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 { ++ // 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, ++ ) -> std::result::Result<(), crate::Error> { ++ todo!("add_memory_region({:?})", region) ++ } ++ ++ fn userspace_mappings(&self) -> Vec { ++ 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, Sender), + ++ /// Add a gpu to the VM. ++ VmAddGpu(Arc, Sender), ++ + /// Add a pmem device to the VM. + VmAddPmem(Arc, Sender), + +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, ++ 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 { ++ 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::("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, + 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 { ++ 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 { ++ 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 { + 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 { ++ 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 { + 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::::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::::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::::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(::std::marker::PhantomData, [T; 0]); ++impl __IncompleteArrayField { ++ #[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 ::std::fmt::Debug for __IncompleteArrayField { ++ 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::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_update_cursor), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_hot_x() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).hot_x) as usize - ptr as usize ++ }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_update_cursor), ++ "::", ++ stringify!(hot_x) ++ ) ++ ); ++ } ++ test_field_hot_x(); ++ fn test_field_hot_y() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).hot_y) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_update_cursor), ++ "::", ++ stringify!(hot_y) ++ ) ++ ); ++ } ++ test_field_hot_y(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 52usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_update_cursor), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_rect { ++ pub x: __le32, ++ pub y: __le32, ++ pub width: __le32, ++ pub height: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_rect() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(virtio_gpu_rect)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_rect)) ++ ); ++ 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 ++ }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_rect), ++ "::", ++ stringify!(x) ++ ) ++ ); ++ } ++ test_field_x(); ++ fn test_field_y() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize ++ }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_rect), ++ "::", ++ stringify!(y) ++ ) ++ ); ++ } ++ test_field_y(); ++ fn test_field_width() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize ++ }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_rect), ++ "::", ++ stringify!(width) ++ ) ++ ); ++ } ++ test_field_width(); ++ fn test_field_height() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize ++ }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_rect), ++ "::", ++ stringify!(height) ++ ) ++ ); ++ } ++ test_field_height(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_unref { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_unref() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_unref)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_unref)) ++ ); ++ 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_resource_unref), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_unref), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_unref), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_create_2d { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub format: __le32, ++ pub width: __le32, ++ pub height: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_create_2d() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_create_2d)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_create_2d)) ++ ); ++ 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_resource_create_2d), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_2d), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_format() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_2d), ++ "::", ++ stringify!(format) ++ ) ++ ); ++ } ++ test_field_format(); ++ fn test_field_width() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_2d), ++ "::", ++ stringify!(width) ++ ) ++ ); ++ } ++ test_field_width(); ++ fn test_field_height() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize ++ }, ++ 36usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_2d), ++ "::", ++ stringify!(height) ++ ) ++ ); ++ } ++ test_field_height(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_set_scanout { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub r: virtio_gpu_rect, ++ pub scanout_id: __le32, ++ pub resource_id: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_set_scanout() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(virtio_gpu_set_scanout)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_set_scanout)) ++ ); ++ 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_set_scanout), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_r() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout), ++ "::", ++ stringify!(r) ++ ) ++ ); ++ } ++ test_field_r(); ++ fn test_field_scanout_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).scanout_id) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout), ++ "::", ++ stringify!(scanout_id) ++ ) ++ ); ++ } ++ test_field_scanout_id(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_flush { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub r: virtio_gpu_rect, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_flush() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 48usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_flush)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_flush)) ++ ); ++ 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_resource_flush), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_r() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_flush), ++ "::", ++ stringify!(r) ++ ) ++ ); ++ } ++ test_field_r(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_flush), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_flush), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_transfer_to_host_2d { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub r: virtio_gpu_rect, ++ pub offset: __le64, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_transfer_to_host_2d() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(virtio_gpu_transfer_to_host_2d)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_transfer_to_host_2d)) ++ ); ++ 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_transfer_to_host_2d), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_r() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_to_host_2d), ++ "::", ++ stringify!(r) ++ ) ++ ); ++ } ++ test_field_r(); ++ fn test_field_offset() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_to_host_2d), ++ "::", ++ stringify!(offset) ++ ) ++ ); ++ } ++ test_field_offset(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_to_host_2d), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 52usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_to_host_2d), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_mem_entry { ++ pub addr: __le64, ++ pub length: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_mem_entry() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(virtio_gpu_mem_entry)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_mem_entry)) ++ ); ++ 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!(virtio_gpu_mem_entry), ++ "::", ++ stringify!(addr) ++ ) ++ ); ++ } ++ test_field_addr(); ++ fn test_field_length() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).length) as usize - ptr as usize ++ }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_mem_entry), ++ "::", ++ stringify!(length) ++ ) ++ ); ++ } ++ test_field_length(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_mem_entry), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_attach_backing { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub nr_entries: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_attach_backing() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_attach_backing)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(virtio_gpu_resource_attach_backing) ++ ) ++ ); ++ 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_resource_attach_backing), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ++ ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_attach_backing), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_nr_entries() { ++ assert_eq!( ++ unsafe { ++ let uninit = ++ ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).nr_entries) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_attach_backing), ++ "::", ++ stringify!(nr_entries) ++ ) ++ ); ++ } ++ test_field_nr_entries(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_detach_backing { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_detach_backing() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_detach_backing)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!( ++ "Alignment of ", ++ stringify!(virtio_gpu_resource_detach_backing) ++ ) ++ ); ++ 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_resource_detach_backing), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ++ ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_detach_backing), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ++ ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_detach_backing), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_display_info { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub pmodes: [virtio_gpu_resp_display_info_virtio_gpu_display_one; 16usize], ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_display_info_virtio_gpu_display_one { ++ pub r: virtio_gpu_rect, ++ pub enabled: __le32, ++ pub flags: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_display_info_virtio_gpu_display_one() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!( ++ "Size of: ", ++ stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one) ++ ) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!( ++ "Alignment of ", ++ stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one) ++ ) ++ ); ++ fn test_field_r() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::< ++ virtio_gpu_resp_display_info_virtio_gpu_display_one, ++ >::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize ++ }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one), ++ "::", ++ stringify!(r) ++ ) ++ ); ++ } ++ test_field_r(); ++ fn test_field_enabled() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::< ++ virtio_gpu_resp_display_info_virtio_gpu_display_one, ++ >::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).enabled) as usize - ptr as usize ++ }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one), ++ "::", ++ stringify!(enabled) ++ ) ++ ); ++ } ++ test_field_enabled(); ++ fn test_field_flags() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::< ++ virtio_gpu_resp_display_info_virtio_gpu_display_one, ++ >::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize ++ }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_display_info_virtio_gpu_display_one), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ } ++ test_field_flags(); ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_display_info() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 408usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_display_info)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_display_info)) ++ ); ++ 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_resp_display_info), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_pmodes() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).pmodes) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_display_info), ++ "::", ++ stringify!(pmodes) ++ ) ++ ); ++ } ++ test_field_pmodes(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_box { ++ pub x: __le32, ++ pub y: __le32, ++ pub z: __le32, ++ pub w: __le32, ++ pub h: __le32, ++ pub d: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_box() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(virtio_gpu_box)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_box)) ++ ); ++ 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 ++ }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(x) ++ ) ++ ); ++ } ++ test_field_x(); ++ fn test_field_y() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).y) as usize - ptr as usize ++ }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(y) ++ ) ++ ); ++ } ++ test_field_y(); ++ fn test_field_z() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).z) as usize - ptr as usize ++ }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(z) ++ ) ++ ); ++ } ++ test_field_z(); ++ fn test_field_w() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).w) as usize - ptr as usize ++ }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(w) ++ ) ++ ); ++ } ++ test_field_w(); ++ fn test_field_h() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).h) as usize - ptr as usize ++ }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(h) ++ ) ++ ); ++ } ++ test_field_h(); ++ fn test_field_d() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).d) as usize - ptr as usize ++ }, ++ 20usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_box), ++ "::", ++ stringify!(d) ++ ) ++ ); ++ } ++ test_field_d(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_transfer_host_3d { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub box_: virtio_gpu_box, ++ pub offset: __le64, ++ pub resource_id: __le32, ++ pub level: __le32, ++ pub stride: __le32, ++ pub layer_stride: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_transfer_host_3d() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(virtio_gpu_transfer_host_3d)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_transfer_host_3d)) ++ ); ++ 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_transfer_host_3d), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_box() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).box_) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(box_) ++ ) ++ ); ++ } ++ test_field_box(); ++ fn test_field_offset() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(offset) ++ ) ++ ); ++ } ++ test_field_offset(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_level() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).level) as usize - ptr as usize ++ }, ++ 60usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(level) ++ ) ++ ); ++ } ++ test_field_level(); ++ fn test_field_stride() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).stride) as usize - ptr as usize ++ }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(stride) ++ ) ++ ); ++ } ++ test_field_stride(); ++ fn test_field_layer_stride() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).layer_stride) as usize - ptr as usize ++ }, ++ 68usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_transfer_host_3d), ++ "::", ++ stringify!(layer_stride) ++ ) ++ ); ++ } ++ test_field_layer_stride(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_create_3d { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub target: __le32, ++ pub format: __le32, ++ pub bind: __le32, ++ pub width: __le32, ++ pub height: __le32, ++ pub depth: __le32, ++ pub array_size: __le32, ++ pub last_level: __le32, ++ pub nr_samples: __le32, ++ pub flags: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_create_3d() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 72usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_create_3d)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_create_3d)) ++ ); ++ 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_resource_create_3d), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_target() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).target) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(target) ++ ) ++ ); ++ } ++ test_field_target(); ++ fn test_field_format() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(format) ++ ) ++ ); ++ } ++ test_field_format(); ++ fn test_field_bind() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).bind) as usize - ptr as usize ++ }, ++ 36usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(bind) ++ ) ++ ); ++ } ++ test_field_bind(); ++ fn test_field_width() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(width) ++ ) ++ ); ++ } ++ test_field_width(); ++ fn test_field_height() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize ++ }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(height) ++ ) ++ ); ++ } ++ test_field_height(); ++ fn test_field_depth() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).depth) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(depth) ++ ) ++ ); ++ } ++ test_field_depth(); ++ fn test_field_array_size() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).array_size) as usize - ptr as usize ++ }, ++ 52usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(array_size) ++ ) ++ ); ++ } ++ test_field_array_size(); ++ fn test_field_last_level() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).last_level) as usize - ptr as usize ++ }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(last_level) ++ ) ++ ); ++ } ++ test_field_last_level(); ++ fn test_field_nr_samples() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).nr_samples) as usize - ptr as usize ++ }, ++ 60usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(nr_samples) ++ ) ++ ); ++ } ++ test_field_nr_samples(); ++ fn test_field_flags() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize ++ }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(flags) ++ ) ++ ); ++ } ++ test_field_flags(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 68usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_3d), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_ctx_create { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub nlen: __le32, ++ pub context_init: __le32, ++ pub debug_name: [::std::os::raw::c_char; 64usize], ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_ctx_create() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 96usize, ++ concat!("Size of: ", stringify!(virtio_gpu_ctx_create)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_ctx_create)) ++ ); ++ 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_ctx_create), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_nlen() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).nlen) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_ctx_create), ++ "::", ++ stringify!(nlen) ++ ) ++ ); ++ } ++ test_field_nlen(); ++ fn test_field_context_init() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).context_init) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_ctx_create), ++ "::", ++ stringify!(context_init) ++ ) ++ ); ++ } ++ test_field_context_init(); ++ fn test_field_debug_name() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).debug_name) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_ctx_create), ++ "::", ++ stringify!(debug_name) ++ ) ++ ); ++ } ++ test_field_debug_name(); ++} ++impl Default for virtio_gpu_ctx_create { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_ctx_destroy { ++ pub hdr: virtio_gpu_ctrl_hdr, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_ctx_destroy() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(virtio_gpu_ctx_destroy)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_ctx_destroy)) ++ ); ++ 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_ctx_destroy), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_ctx_resource { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_ctx_resource() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_ctx_resource)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_ctx_resource)) ++ ); ++ 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_ctx_resource), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_ctx_resource), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_ctx_resource), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_cmd_submit { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub size: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_cmd_submit() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_cmd_submit)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_cmd_submit)) ++ ); ++ 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_cmd_submit), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_size() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_cmd_submit), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ } ++ test_field_size(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_cmd_submit), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_get_capset_info { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub capset_index: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_get_capset_info() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_get_capset_info)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_get_capset_info)) ++ ); ++ 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_get_capset_info), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_capset_index() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_index) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_get_capset_info), ++ "::", ++ stringify!(capset_index) ++ ) ++ ); ++ } ++ test_field_capset_index(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_get_capset_info), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_capset_info { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub capset_id: __le32, ++ pub capset_max_version: __le32, ++ pub capset_max_size: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_capset_info() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_capset_info)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_capset_info)) ++ ); ++ 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_resp_capset_info), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_capset_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_capset_info), ++ "::", ++ stringify!(capset_id) ++ ) ++ ); ++ } ++ test_field_capset_id(); ++ fn test_field_capset_max_version() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_max_version) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_capset_info), ++ "::", ++ stringify!(capset_max_version) ++ ) ++ ); ++ } ++ test_field_capset_max_version(); ++ fn test_field_capset_max_size() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_max_size) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_capset_info), ++ "::", ++ stringify!(capset_max_size) ++ ) ++ ); ++ } ++ test_field_capset_max_size(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 36usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_capset_info), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_get_capset { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub capset_id: __le32, ++ pub capset_version: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_get_capset() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_get_capset)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_get_capset)) ++ ); ++ 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_get_capset), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_capset_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_get_capset), ++ "::", ++ stringify!(capset_id) ++ ) ++ ); ++ } ++ test_field_capset_id(); ++ fn test_field_capset_version() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_version) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_get_capset), ++ "::", ++ stringify!(capset_version) ++ ) ++ ); ++ } ++ test_field_capset_version(); ++} ++#[repr(C)] ++#[derive(Debug, Default)] ++pub struct virtio_gpu_resp_capset { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub capset_data: __IncompleteArrayField<__u8>, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_capset() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 24usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_capset)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_capset)) ++ ); ++ 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_resp_capset), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_capset_data() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).capset_data) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_capset), ++ "::", ++ stringify!(capset_data) ++ ) ++ ); ++ } ++ test_field_capset_data(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_cmd_get_edid { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub scanout: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_cmd_get_edid() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_cmd_get_edid)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_cmd_get_edid)) ++ ); ++ 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_cmd_get_edid), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_scanout() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).scanout) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_cmd_get_edid), ++ "::", ++ stringify!(scanout) ++ ) ++ ); ++ } ++ test_field_scanout(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_cmd_get_edid), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_edid { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub size: __le32, ++ pub padding: __le32, ++ pub edid: [__u8; 1024usize], ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_edid() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 1056usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_edid)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_edid)) ++ ); ++ 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_resp_edid), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_size() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_edid), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ } ++ test_field_size(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_edid), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++ fn test_field_edid() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).edid) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_edid), ++ "::", ++ stringify!(edid) ++ ) ++ ); ++ } ++ test_field_edid(); ++} ++impl Default for virtio_gpu_resp_edid { ++ fn default() -> Self { ++ let mut s = ::std::mem::MaybeUninit::::uninit(); ++ unsafe { ++ ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); ++ s.assume_init() ++ } ++ } ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_config { ++ pub events_read: __le32, ++ pub events_clear: __le32, ++ pub num_scanouts: __le32, ++ pub num_capsets: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_config() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(virtio_gpu_config)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_config)) ++ ); ++ fn test_field_events_read() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).events_read) as usize - ptr as usize ++ }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_config), ++ "::", ++ stringify!(events_read) ++ ) ++ ); ++ } ++ test_field_events_read(); ++ fn test_field_events_clear() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).events_clear) as usize - ptr as usize ++ }, ++ 4usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_config), ++ "::", ++ stringify!(events_clear) ++ ) ++ ); ++ } ++ test_field_events_clear(); ++ fn test_field_num_scanouts() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).num_scanouts) as usize - ptr as usize ++ }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_config), ++ "::", ++ stringify!(num_scanouts) ++ ) ++ ); ++ } ++ test_field_num_scanouts(); ++ fn test_field_num_capsets() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).num_capsets) as usize - ptr as usize ++ }, ++ 12usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_config), ++ "::", ++ stringify!(num_capsets) ++ ) ++ ); ++ } ++ test_field_num_capsets(); ++} ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: virtio_gpu_formats = 1; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: virtio_gpu_formats = 2; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: virtio_gpu_formats = 3; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: virtio_gpu_formats = 4; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: virtio_gpu_formats = 67; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: virtio_gpu_formats = 68; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: virtio_gpu_formats = 121; ++pub const virtio_gpu_formats_VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: virtio_gpu_formats = 134; ++pub type virtio_gpu_formats = ::std::os::raw::c_uint; ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_assign_uuid { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_assign_uuid() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_assign_uuid)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_assign_uuid)) ++ ); ++ 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_resource_assign_uuid), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_assign_uuid), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_assign_uuid), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_resource_uuid { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub uuid: [__u8; 16usize], ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_resource_uuid() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_resource_uuid)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_resource_uuid)) ++ ); ++ 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_resp_resource_uuid), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_uuid() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).uuid) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_resource_uuid), ++ "::", ++ stringify!(uuid) ++ ) ++ ); ++ } ++ test_field_uuid(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_create_blob { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub blob_mem: __le32, ++ pub blob_flags: __le32, ++ pub nr_entries: __le32, ++ pub blob_id: __le64, ++ pub size: __le64, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_create_blob() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 56usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_create_blob)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_create_blob)) ++ ); ++ 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_resource_create_blob), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_blob_mem() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).blob_mem) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(blob_mem) ++ ) ++ ); ++ } ++ test_field_blob_mem(); ++ fn test_field_blob_flags() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).blob_flags) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(blob_flags) ++ ) ++ ); ++ } ++ test_field_blob_flags(); ++ fn test_field_nr_entries() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).nr_entries) as usize - ptr as usize ++ }, ++ 36usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(nr_entries) ++ ) ++ ); ++ } ++ test_field_nr_entries(); ++ fn test_field_blob_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).blob_id) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(blob_id) ++ ) ++ ); ++ } ++ test_field_blob_id(); ++ fn test_field_size() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_create_blob), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ } ++ test_field_size(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_set_scanout_blob { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub r: virtio_gpu_rect, ++ pub scanout_id: __le32, ++ pub resource_id: __le32, ++ pub width: __le32, ++ pub height: __le32, ++ pub format: __le32, ++ pub padding: __le32, ++ pub strides: [__le32; 4usize], ++ pub offsets: [__le32; 4usize], ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_set_scanout_blob() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 96usize, ++ concat!("Size of: ", stringify!(virtio_gpu_set_scanout_blob)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_set_scanout_blob)) ++ ); ++ 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_set_scanout_blob), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_r() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).r) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(r) ++ ) ++ ); ++ } ++ test_field_r(); ++ fn test_field_scanout_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).scanout_id) as usize - ptr as usize ++ }, ++ 40usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(scanout_id) ++ ) ++ ); ++ } ++ test_field_scanout_id(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 44usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_width() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).width) as usize - ptr as usize ++ }, ++ 48usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(width) ++ ) ++ ); ++ } ++ test_field_width(); ++ fn test_field_height() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).height) as usize - ptr as usize ++ }, ++ 52usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(height) ++ ) ++ ); ++ } ++ test_field_height(); ++ fn test_field_format() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).format) as usize - ptr as usize ++ }, ++ 56usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(format) ++ ) ++ ); ++ } ++ test_field_format(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 60usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++ fn test_field_strides() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).strides) as usize - ptr as usize ++ }, ++ 64usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(strides) ++ ) ++ ); ++ } ++ test_field_strides(); ++ fn test_field_offsets() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).offsets) as usize - ptr as usize ++ }, ++ 80usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_set_scanout_blob), ++ "::", ++ stringify!(offsets) ++ ) ++ ); ++ } ++ test_field_offsets(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_map_blob { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++ pub offset: __le64, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_map_blob() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 40usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_map_blob)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_map_blob)) ++ ); ++ 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_resource_map_blob), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_map_blob), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_map_blob), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++ fn test_field_offset() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize ++ }, ++ 32usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_map_blob), ++ "::", ++ stringify!(offset) ++ ) ++ ); ++ } ++ test_field_offset(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resp_map_info { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub map_info: __u32, ++ pub padding: __u32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resp_map_info() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resp_map_info)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resp_map_info)) ++ ); ++ 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_resp_map_info), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_map_info() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).map_info) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_map_info), ++ "::", ++ stringify!(map_info) ++ ) ++ ); ++ } ++ test_field_map_info(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resp_map_info), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} ++#[repr(C)] ++#[derive(Debug, Default, Copy, Clone, PartialEq)] ++pub struct virtio_gpu_resource_unmap_blob { ++ pub hdr: virtio_gpu_ctrl_hdr, ++ pub resource_id: __le32, ++ pub padding: __le32, ++} ++#[test] ++fn bindgen_test_layout_virtio_gpu_resource_unmap_blob() { ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(virtio_gpu_resource_unmap_blob)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(virtio_gpu_resource_unmap_blob)) ++ ); ++ 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_resource_unmap_blob), ++ "::", ++ stringify!(hdr) ++ ) ++ ); ++ } ++ test_field_hdr(); ++ fn test_field_resource_id() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).resource_id) as usize - ptr as usize ++ }, ++ 24usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_unmap_blob), ++ "::", ++ stringify!(resource_id) ++ ) ++ ); ++ } ++ test_field_resource_id(); ++ fn test_field_padding() { ++ assert_eq!( ++ unsafe { ++ let uninit = ::std::mem::MaybeUninit::::uninit(); ++ let ptr = uninit.as_ptr(); ++ ::std::ptr::addr_of!((*ptr).padding) as usize - ptr as usize ++ }, ++ 28usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(virtio_gpu_resource_unmap_blob), ++ "::", ++ stringify!(padding) ++ ) ++ ); ++ } ++ test_field_padding(); ++} +-- +2.37.1 + diff --git a/pkgs/applications/virtualization/cloud-hypervisor/default.nix b/pkgs/applications/virtualization/cloud-hypervisor/default.nix index 2fb2836a6c0..cbef9798f53 100644 --- a/pkgs/applications/virtualization/cloud-hypervisor/default.nix +++ b/pkgs/applications/virtualization/cloud-hypervisor/default.nix @@ -1,4 +1,6 @@ -{ lib, stdenv, fetchFromGitHub, rustPlatform, pkg-config, dtc, openssl }: +{ lib, stdenv, fetchCrate, fetchFromGitHub, fetchpatch, rustPlatform +, pkg-config, dtc, openssl +}: rustPlatform.buildRustPackage rec { pname = "cloud-hypervisor"; @@ -11,10 +13,68 @@ rustPlatform.buildRustPackage rec { sha256 = "sha256-choTT20TVp42nN/vS6xCDA7Mbf1ZuAE1tFQZn49g9ak="; }; + vhost = fetchCrate { + pname = "vhost"; + version = "0.4.0"; + sha256 = "sha256-72tvycgdTI3pK1EpGoBEI0WajX7SYZvTI0lbU8ybdsc="; + }; + + vm-virtio = fetchFromGitHub { + owner = "rust-vmm"; + repo = "vm-virtio"; + rev = "7e203db6ed044217acd80dec5967c15d979491f8"; + sha256 = "sha256-QLukQCPeWpletbKqhIruvevLMEepnQ4fKWVH42H7QM8="; + }; + + postUnpack = '' + unpackFile ${vhost} + mv vhost-* vhost + + unpackFile ${vm-virtio}/crates/virtio-bindings + + chmod -R +w vhost virtio-bindings + ''; + + cargoPatches = [ + ./0001-build-use-local-vhost.patch + ./0002-build-use-local-virtio-bindings.patch + ./0003-virtio-devices-add-a-GPU-device.patch + ]; + + vhostPatches = [ + ./vhost-vhost_user-add-shared-memory-region-support.patch + ]; + + virtioBindingsPatches = [ + # https://github.com/rust-vmm/vm-virtio/pull/194 + ./0001-virtio-bindings-regenerate-with-bindgen-0.60.1.patch + ./0002-virtio-bindings-remove-workaround-for-old-bindgen.patch + ./0003-virtio-bindings-regenerate-with-Glibc-2.36.patch + ./0004-virtio-bindings-regenerate-with-Linux-5.19.patch + + ./0005-virtio-bindings-add-virtio-gpu-bindings.patch + ]; + + postPatch = '' + pushd ../vhost + for patch in $vhostPatches; do + echo applying patch $patch + patch -p1 < $patch + done + popd + + pushd ../virtio-bindings + for patch in $virtioBindingsPatches; do + echo applying patch $patch + patch -p3 < $patch + done + popd + ''; + nativeBuildInputs = [ pkg-config ]; buildInputs = [ openssl ] ++ lib.optional stdenv.isAarch64 dtc; - cargoSha256 = "sha256-mmyaT24he33wLI3zLOOKhVtzrPRyWzKgXUvc37suy5E="; + cargoSha256 = "164vr9xxrlpllac5db69ggasczq5vqb9zv60dkwbqabn8qm5cr1x"; OPENSSL_NO_VENDOR = true; diff --git a/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch b/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch new file mode 100644 index 00000000000..728399548f8 --- /dev/null +++ b/pkgs/applications/virtualization/cloud-hypervisor/vhost-vhost_user-add-shared-memory-region-support.patch @@ -0,0 +1,724 @@ +From b72b87aed5542df7d912750f9745f9854c9cf482 Mon Sep 17 00:00:00 2001 +From: David Stevens +Date: Wed, 15 Jun 2022 16:45:12 +0900 +Subject: [PATCH] vhost_user: add shared memory region support + +Add support for shared memory regions to vhost-user. This is adding +support for a front-end message to query for necessary shared memory +regions plus back-end message to support mapping/unmapping files from +the shared memory region. + +go/vvu-shared-memory + +BUG=b:201745804 +TEST=compiles + +Change-Id: I35c5d260ee09175b68f6778b81883e0070ee0265 +Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3716344 +Reviewed-by: Keiichi Watanabe +Commit-Queue: David Stevens +Reviewed-by: Alexandre Courbot +Tested-by: kokoro +(cherry-picked from commit f436e2706011fa5f34dc415972434aa3299ebc43) +Signed-off-by: Alyssa Ross +--- + src/vhost_user/dummy_slave.rs | 4 + + src/vhost_user/master.rs | 24 +++++ + src/vhost_user/master_req_handler.rs | 78 ++++++++++++--- + src/vhost_user/message.rs | 140 +++++++++++++++++++++++++-- + src/vhost_user/mod.rs | 2 +- + src/vhost_user/slave_fs_cache.rs | 67 ++++++++----- + src/vhost_user/slave_req_handler.rs | 27 +++++- + 7 files changed, 292 insertions(+), 50 deletions(-) + +diff --git a/src/vhost_user/dummy_slave.rs b/src/vhost_user/dummy_slave.rs +index 222a5bb3..5389e3fb 100644 +--- a/src/vhost_user/dummy_slave.rs ++++ b/src/vhost_user/dummy_slave.rs +@@ -271,4 +271,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler { + fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> { + Ok(()) + } ++ ++ fn get_shared_memory_regions(&mut self) -> Result> { ++ Ok(Vec::new()) ++ } + } +diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs +index 711b6739..1ad47aaa 100644 +--- a/src/vhost_user/master.rs ++++ b/src/vhost_user/master.rs +@@ -72,6 +72,9 @@ pub trait VhostUserMaster: VhostBackend { + + /// Remove a guest memory mapping from vhost. + fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>; ++ ++ /// Gets the shared memory regions used by the device. ++ fn get_shared_memory_regions(&self) -> Result>; + } + + fn error_code(err: VhostUserError) -> Result { +@@ -552,6 +555,27 @@ impl VhostUserMaster for Master { + let hdr = node.send_request_with_body(MasterReq::REM_MEM_REG, &body, None)?; + node.wait_for_ack(&hdr).map_err(|e| e.into()) + } ++ ++ fn get_shared_memory_regions(&self) -> Result> { ++ let mut node = self.node(); ++ let hdr = node.send_request_header(MasterReq::GET_SHARED_MEMORY_REGIONS, None)?; ++ let (body_reply, buf_reply, rfds) = node.recv_reply_with_payload::(&hdr)?; ++ let struct_size = mem::size_of::(); ++ if rfds.is_some() || buf_reply.len() != body_reply.value as usize * struct_size { ++ return error_code(VhostUserError::InvalidMessage); ++ } ++ let mut regions = Vec::new(); ++ let mut offset = 0; ++ for _ in 0..body_reply.value { ++ regions.push( ++ // Can't fail because the input is the correct size. ++ VhostSharedMemoryRegion::from_slice(&buf_reply[offset..(offset + struct_size)]) ++ .unwrap().clone(), ++ ); ++ offset += struct_size; ++ } ++ Ok(regions) ++ } + } + + impl AsRawFd for Master { +diff --git a/src/vhost_user/master_req_handler.rs b/src/vhost_user/master_req_handler.rs +index 0ecda4e3..d0d6529b 100644 +--- a/src/vhost_user/master_req_handler.rs ++++ b/src/vhost_user/master_req_handler.rs +@@ -17,7 +17,7 @@ use super::{Error, HandlerResult, Result}; + /// request services from masters. The [VhostUserMasterReqHandler] trait defines services provided + /// by masters, and it's used both on the master side and slave side. + /// - on the slave side, a stub forwarder implementing [VhostUserMasterReqHandler] will proxy +-/// service requests to masters. The [SlaveFsCacheReq] is an example stub forwarder. ++/// service requests to masters. The [Slave] is an example stub forwarder. + /// - on the master side, the [MasterReqHandler] will forward service requests to a handler + /// implementing [VhostUserMasterReqHandler]. + /// +@@ -26,13 +26,27 @@ use super::{Error, HandlerResult, Result}; + /// + /// [VhostUserMasterReqHandler]: trait.VhostUserMasterReqHandler.html + /// [MasterReqHandler]: struct.MasterReqHandler.html +-/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html ++/// [Slave]: struct.Slave.html + pub trait VhostUserMasterReqHandler { + /// Handle device configuration change notifications. + fn handle_config_change(&self) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + ++ /// Handle shared memory region mapping requests. ++ fn shmem_map( ++ &self, ++ _req: &VhostUserShmemMapMsg, ++ _fd: &dyn AsRawFd, ++ ) -> HandlerResult { ++ Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) ++ } ++ ++ /// Handle shared memory region unmapping requests. ++ fn shmem_unmap(&self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult { ++ Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) ++ } ++ + /// Handle virtio-fs map file requests. + fn fs_slave_map(&self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) +@@ -66,6 +80,20 @@ pub trait VhostUserMasterReqHandlerMut { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) + } + ++ /// Handle shared memory region mapping requests. ++ fn shmem_map( ++ &mut self, ++ _req: &VhostUserShmemMapMsg, ++ _fd: &dyn AsRawFd, ++ ) -> HandlerResult { ++ Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) ++ } ++ ++ /// Handle shared memory region unmapping requests. ++ fn shmem_unmap(&mut self, _req: &VhostUserShmemUnmapMsg) -> HandlerResult { ++ Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) ++ } ++ + /// Handle virtio-fs map file requests. + fn fs_slave_map(&mut self, _fs: &VhostUserFSSlaveMsg, _fd: &dyn AsRawFd) -> HandlerResult { + Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) +@@ -95,6 +123,18 @@ impl VhostUserMasterReqHandler for Mutex { + self.lock().unwrap().handle_config_change() + } + ++ fn shmem_map( ++ &self, ++ req: &VhostUserShmemMapMsg, ++ fd: &dyn AsRawFd, ++ ) -> HandlerResult { ++ self.lock().unwrap().shmem_map(req, fd) ++ } ++ ++ fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult { ++ self.lock().unwrap().shmem_unmap(req) ++ } ++ + fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult { + self.lock().unwrap().fs_slave_map(fs, fd) + } +@@ -222,6 +262,19 @@ impl MasterReqHandler { + .handle_config_change() + .map_err(Error::ReqHandlerError) + } ++ SlaveReq::SHMEM_MAP => { ++ let msg = self.extract_msg_body::(&hdr, size, &buf)?; ++ // check_attached_files() has validated files ++ self.backend ++ .shmem_map(&msg, &files.unwrap()[0]) ++ .map_err(Error::ReqHandlerError) ++ } ++ SlaveReq::SHMEM_UNMAP => { ++ let msg = self.extract_msg_body::(&hdr, size, &buf)?; ++ self.backend ++ .shmem_unmap(&msg) ++ .map_err(Error::ReqHandlerError) ++ } + SlaveReq::FS_MAP => { + let msg = self.extract_msg_body::(&hdr, size, &buf)?; + // check_attached_files() has validated files +@@ -251,7 +304,7 @@ impl MasterReqHandler { + _ => Err(Error::InvalidMessage), + }; + +- self.send_ack_message(&hdr, &res)?; ++ self.send_reply(&hdr, &res)?; + + res + } +@@ -285,7 +338,7 @@ impl MasterReqHandler { + files: &Option>, + ) -> Result<()> { + match hdr.get_code() { +- SlaveReq::FS_MAP | SlaveReq::FS_IO => { ++ SlaveReq::SHMEM_MAP | SlaveReq::FS_MAP | SlaveReq::FS_IO => { + // Expect a single file is passed. + match files { + Some(files) if files.len() == 1 => Ok(()), +@@ -326,12 +379,11 @@ impl MasterReqHandler { + )) + } + +- fn send_ack_message( +- &mut self, +- req: &VhostUserMsgHeader, +- res: &Result, +- ) -> Result<()> { +- if self.reply_ack_negotiated && req.is_need_reply() { ++ fn send_reply(&mut self, req: &VhostUserMsgHeader, res: &Result) -> Result<()> { ++ if req.get_code() == SlaveReq::SHMEM_MAP ++ || req.get_code() == SlaveReq::SHMEM_UNMAP ++ || (self.reply_ack_negotiated && req.is_need_reply()) ++ { + let hdr = self.new_reply_header::(req)?; + let def_err = libc::EINVAL; + let val = match res { +@@ -362,7 +414,7 @@ mod tests { + use super::*; + + #[cfg(feature = "vhost-user-slave")] +- use crate::vhost_user::SlaveFsCacheReq; ++ use crate::vhost_user::Slave; + #[cfg(feature = "vhost-user-slave")] + use std::os::unix::io::FromRawFd; + +@@ -410,7 +462,7 @@ mod tests { + panic!("failed to duplicated tx fd!"); + } + let stream = unsafe { UnixStream::from_raw_fd(fd) }; +- let fs_cache = SlaveFsCacheReq::from_stream(stream); ++ let fs_cache = Slave::from_stream(stream); + + std::thread::spawn(move || { + let res = handler.handle_request().unwrap(); +@@ -440,7 +492,7 @@ mod tests { + panic!("failed to duplicated tx fd!"); + } + let stream = unsafe { UnixStream::from_raw_fd(fd) }; +- let fs_cache = SlaveFsCacheReq::from_stream(stream); ++ let fs_cache = Slave::from_stream(stream); + + std::thread::spawn(move || { + let res = handler.handle_request().unwrap(); +diff --git a/src/vhost_user/message.rs b/src/vhost_user/message.rs +index d61c17a1..66139972 100644 +--- a/src/vhost_user/message.rs ++++ b/src/vhost_user/message.rs +@@ -139,8 +139,10 @@ pub enum MasterReq { + /// Query the backend for its device status as defined in the VIRTIO + /// specification. + GET_STATUS = 40, ++ /// Get a list of the device's shared memory regions. ++ GET_SHARED_MEMORY_REGIONS = 41, + /// Upper bound of valid commands. +- MAX_CMD = 41, ++ MAX_CMD = 42, + } + + impl From for u32 { +@@ -171,16 +173,20 @@ pub enum SlaveReq { + VRING_CALL = 4, + /// Indicate that an error occurred on the specific vring. + VRING_ERR = 5, ++ /// Indicates a request to map a fd into a shared memory region. ++ SHMEM_MAP = 6, ++ /// Indicates a request to unmap part of a shared memory region. ++ SHMEM_UNMAP = 7, + /// Virtio-fs draft: map file content into the window. +- FS_MAP = 6, ++ FS_MAP = 8, + /// Virtio-fs draft: unmap file content from the window. +- FS_UNMAP = 7, ++ FS_UNMAP = 9, + /// Virtio-fs draft: sync file content. +- FS_SYNC = 8, ++ FS_SYNC = 10, + /// Virtio-fs draft: perform a read/write from an fd directly to GPA. +- FS_IO = 9, ++ FS_IO = 11, + /// Upper bound of valid commands. +- MAX_CMD = 10, ++ MAX_CMD = 12, + } + + impl From for u32 { +@@ -817,7 +823,7 @@ pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8; + + /// Slave request message to update the MMIO window. + #[repr(packed)] +-#[derive(Default)] ++#[derive(Clone, Copy, Default)] + pub struct VhostUserFSSlaveMsg { + /// File offset. + pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], +@@ -828,6 +834,8 @@ pub struct VhostUserFSSlaveMsg { + /// Flags for the mmap operation + pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES], + } ++// Safe because it only has data and has no implicit padding. ++unsafe impl ByteValued for VhostUserFSSlaveMsg {} + + impl VhostUserMsgValidator for VhostUserFSSlaveMsg { + fn is_valid(&self) -> bool { +@@ -843,6 +851,99 @@ impl VhostUserMsgValidator for VhostUserFSSlaveMsg { + } + } + ++bitflags! { ++ #[derive(Default)] ++ /// Flags for SHMEM_MAP messages. ++ pub struct VhostUserShmemMapMsgFlags: u8 { ++ /// Empty permission. ++ const EMPTY = 0x0; ++ /// Read permission. ++ const MAP_R = 0x1; ++ /// Write permission. ++ const MAP_W = 0x2; ++ } ++} ++ ++/// Slave request message to map a file into a shared memory region. ++#[repr(C, packed)] ++#[derive(Default, Copy, Clone)] ++pub struct VhostUserShmemMapMsg { ++ /// Flags for the mmap operation ++ pub flags: VhostUserShmemMapMsgFlags, ++ /// Shared memory region id. ++ pub shmid: u8, ++ padding: [u8; 6], ++ /// Offset into the shared memory region. ++ pub shm_offset: u64, ++ /// File offset. ++ pub fd_offset: u64, ++ /// Size of region to map. ++ pub len: u64, ++} ++// Safe because it only has data and has no implicit padding. ++unsafe impl ByteValued for VhostUserShmemMapMsg {} ++ ++impl VhostUserMsgValidator for VhostUserShmemMapMsg { ++ fn is_valid(&self) -> bool { ++ (self.flags.bits() & !VhostUserFSSlaveMsgFlags::all().bits() as u8) == 0 ++ && self.fd_offset.checked_add(self.len).is_some() ++ && self.shm_offset.checked_add(self.len).is_some() ++ } ++} ++ ++impl VhostUserShmemMapMsg { ++ /// New instance of VhostUserShmemMapMsg struct ++ pub fn new( ++ shmid: u8, ++ shm_offset: u64, ++ fd_offset: u64, ++ len: u64, ++ flags: VhostUserShmemMapMsgFlags, ++ ) -> Self { ++ Self { ++ flags, ++ shmid, ++ padding: [0; 6], ++ shm_offset, ++ fd_offset, ++ len, ++ } ++ } ++} ++ ++/// Slave request message to unmap part of a shared memory region. ++#[repr(C, packed)] ++#[derive(Default, Copy, Clone)] ++pub struct VhostUserShmemUnmapMsg { ++ /// Shared memory region id. ++ pub shmid: u8, ++ padding: [u8; 7], ++ /// Offset into the shared memory region. ++ pub shm_offset: u64, ++ /// Size of region to unmap. ++ pub len: u64, ++} ++// Safe because it only has data and has no implicit padding. ++unsafe impl ByteValued for VhostUserShmemUnmapMsg {} ++ ++impl VhostUserMsgValidator for VhostUserShmemUnmapMsg { ++ fn is_valid(&self) -> bool { ++ self.shm_offset.checked_add(self.len).is_some() ++ } ++} ++ ++impl VhostUserShmemUnmapMsg { ++ /// New instance of VhostUserShmemUnmapMsg struct ++ pub fn new(shmid: u8, shm_offset: u64, len: u64) -> Self { ++ Self { ++ shmid, ++ padding: [0; 7], ++ shm_offset, ++ len, ++ } ++ } ++} ++ + /// Inflight I/O descriptor state for split virtqueues + #[repr(packed)] + #[derive(Clone, Copy, Default)] +@@ -974,6 +1075,31 @@ impl QueueRegionPacked { + } + } + ++/// Virtio shared memory descriptor. ++#[repr(packed)] ++#[derive(Default, Copy, Clone)] ++pub struct VhostSharedMemoryRegion { ++ /// The shared memory region's shmid. ++ pub id: u8, ++ /// Padding ++ padding: [u8; 7], ++ /// The length of the shared memory region. ++ pub length: u64, ++} ++// Safe because it only has data and has no implicit padding. ++unsafe impl ByteValued for VhostSharedMemoryRegion {} ++ ++impl VhostSharedMemoryRegion { ++ /// New instance of VhostSharedMemoryRegion struct ++ pub fn new(id: u8, length: u64) -> Self { ++ VhostSharedMemoryRegion { ++ id, ++ padding: [0; 7], ++ length, ++ } ++ } ++} ++ + #[cfg(test)] + mod tests { + use super::*; +diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs +index 6b1afb8c..a2f0af88 100644 +--- a/src/vhost_user/mod.rs ++++ b/src/vhost_user/mod.rs +@@ -50,7 +50,7 @@ pub use self::slave_req_handler::{ + #[cfg(feature = "vhost-user-slave")] + mod slave_fs_cache; + #[cfg(feature = "vhost-user-slave")] +-pub use self::slave_fs_cache::SlaveFsCacheReq; ++pub use self::slave_fs_cache::Slave; + + /// Errors for vhost-user operations + #[derive(Debug)] +diff --git a/src/vhost_user/slave_fs_cache.rs b/src/vhost_user/slave_fs_cache.rs +index e9ad7cf6..369d682a 100644 +--- a/src/vhost_user/slave_fs_cache.rs ++++ b/src/vhost_user/slave_fs_cache.rs +@@ -7,11 +7,13 @@ use std::os::unix::io::{AsRawFd, RawFd}; + use std::os::unix::net::UnixStream; + use std::sync::{Arc, Mutex, MutexGuard}; + ++use vm_memory::ByteValued; ++ + use super::connection::Endpoint; + use super::message::*; + use super::{Error, HandlerResult, Result, VhostUserMasterReqHandler}; + +-struct SlaveFsCacheReqInternal { ++struct SlaveInternal { + sock: Endpoint, + + // Protocol feature VHOST_USER_PROTOCOL_F_REPLY_ACK has been negotiated. +@@ -21,7 +23,7 @@ struct SlaveFsCacheReqInternal { + error: Option, + } + +-impl SlaveFsCacheReqInternal { ++impl SlaveInternal { + fn check_state(&self) -> Result { + match self.error { + Some(e) => Err(Error::SocketBroken(std::io::Error::from_raw_os_error(e))), +@@ -29,27 +31,30 @@ impl SlaveFsCacheReqInternal { + } + } + +- fn send_message( ++ fn send_message( + &mut self, + request: SlaveReq, +- fs: &VhostUserFSSlaveMsg, ++ msg: &T, + fds: Option<&[RawFd]>, + ) -> Result { + self.check_state()?; + +- let len = mem::size_of::(); ++ let len = mem::size_of::(); + let mut hdr = VhostUserMsgHeader::new(request, 0, len as u32); + if self.reply_ack_negotiated { + hdr.set_need_reply(true); + } +- self.sock.send_message(&hdr, fs, fds)?; ++ self.sock.send_message(&hdr, msg, fds)?; + +- self.wait_for_ack(&hdr) ++ self.wait_for_reply(&hdr) + } + +- fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader) -> Result { ++ fn wait_for_reply(&mut self, hdr: &VhostUserMsgHeader) -> Result { + self.check_state()?; +- if !self.reply_ack_negotiated { ++ if hdr.get_code() != SlaveReq::SHMEM_MAP ++ && hdr.get_code() != SlaveReq::SHMEM_UNMAP ++ && !self.reply_ack_negotiated ++ { + return Ok(0); + } + +@@ -68,22 +73,22 @@ impl SlaveFsCacheReqInternal { + /// Request proxy to send vhost-user-fs slave requests to the master through the slave + /// communication channel. + /// +-/// The [SlaveFsCacheReq] acts as a message proxy to forward vhost-user-fs slave requests to the ++/// The [Slave] acts as a message proxy to forward vhost-user-fs slave requests to the + /// master through the vhost-user slave communication channel. The forwarded messages will be + /// handled by the [MasterReqHandler] server. + /// +-/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html ++/// [Slave]: struct.Slave.html + /// [MasterReqHandler]: struct.MasterReqHandler.html + #[derive(Clone)] +-pub struct SlaveFsCacheReq { ++pub struct Slave { + // underlying Unix domain socket for communication +- node: Arc>, ++ node: Arc>, + } + +-impl SlaveFsCacheReq { ++impl Slave { + fn new(ep: Endpoint) -> Self { +- SlaveFsCacheReq { +- node: Arc::new(Mutex::new(SlaveFsCacheReqInternal { ++ Slave { ++ node: Arc::new(Mutex::new(SlaveInternal { + sock: ep, + reply_ack_negotiated: false, + error: None, +@@ -91,18 +96,18 @@ impl SlaveFsCacheReq { + } + } + +- fn node(&self) -> MutexGuard { ++ fn node(&self) -> MutexGuard { + self.node.lock().unwrap() + } + +- fn send_message( ++ fn send_message( + &self, + request: SlaveReq, +- fs: &VhostUserFSSlaveMsg, ++ msg: &T, + fds: Option<&[RawFd]>, + ) -> io::Result { + self.node() +- .send_message(request, fs, fds) ++ .send_message(request, msg, fds) + .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e))) + } + +@@ -126,7 +131,21 @@ impl SlaveFsCacheReq { + } + } + +-impl VhostUserMasterReqHandler for SlaveFsCacheReq { ++impl VhostUserMasterReqHandler for Slave { ++ /// Handle shared memory region mapping requests. ++ fn shmem_map( ++ &self, ++ req: &VhostUserShmemMapMsg, ++ fd: &dyn AsRawFd, ++ ) -> HandlerResult { ++ self.send_message(SlaveReq::SHMEM_MAP, req, Some(&[fd.as_raw_fd()])) ++ } ++ ++ /// Handle shared memory region unmapping requests. ++ fn shmem_unmap(&self, req: &VhostUserShmemUnmapMsg) -> HandlerResult { ++ self.send_message(SlaveReq::SHMEM_UNMAP, req, None) ++ } ++ + /// Forward vhost-user-fs map file requests to the slave. + fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: &dyn AsRawFd) -> HandlerResult { + self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd.as_raw_fd()])) +@@ -147,7 +166,7 @@ mod tests { + #[test] + fn test_slave_fs_cache_req_set_failed() { + let (p1, _p2) = UnixStream::pair().unwrap(); +- let fs_cache = SlaveFsCacheReq::from_stream(p1); ++ let fs_cache = Slave::from_stream(p1); + + assert!(fs_cache.node().error.is_none()); + fs_cache.set_failed(libc::EAGAIN); +@@ -157,7 +176,7 @@ mod tests { + #[test] + fn test_slave_fs_cache_send_failure() { + let (p1, p2) = UnixStream::pair().unwrap(); +- let fs_cache = SlaveFsCacheReq::from_stream(p1); ++ let fs_cache = Slave::from_stream(p1); + + fs_cache.set_failed(libc::ECONNRESET); + fs_cache +@@ -172,7 +191,7 @@ mod tests { + #[test] + fn test_slave_fs_cache_recv_negative() { + let (p1, p2) = UnixStream::pair().unwrap(); +- let fs_cache = SlaveFsCacheReq::from_stream(p1); ++ let fs_cache = Slave::from_stream(p1); + let mut master = Endpoint::::from_stream(p2); + + let len = mem::size_of::(); +diff --git a/src/vhost_user/slave_req_handler.rs b/src/vhost_user/slave_req_handler.rs +index f43159ad..ee313ffd 100644 +--- a/src/vhost_user/slave_req_handler.rs ++++ b/src/vhost_user/slave_req_handler.rs +@@ -8,9 +8,11 @@ use std::os::unix::net::UnixStream; + use std::slice; + use std::sync::{Arc, Mutex}; + ++use vm_memory::ByteValued; ++ + use super::connection::Endpoint; + use super::message::*; +-use super::slave_fs_cache::SlaveFsCacheReq; ++use super::slave_fs_cache::Slave; + use super::{take_single_file, Error, Result}; + + /// Services provided to the master by the slave with interior mutability. +@@ -62,12 +64,13 @@ pub trait VhostUserSlaveReqHandler { + fn set_vring_enable(&self, index: u32, enable: bool) -> Result<()>; + fn get_config(&self, offset: u32, size: u32, flags: VhostUserConfigFlags) -> Result>; + fn set_config(&self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; +- fn set_slave_req_fd(&self, _vu_req: SlaveFsCacheReq) {} ++ fn set_slave_req_fd(&self, _vu_req: Slave) {} + fn get_inflight_fd(&self, inflight: &VhostUserInflight) -> Result<(VhostUserInflight, File)>; + fn set_inflight_fd(&self, inflight: &VhostUserInflight, file: File) -> Result<()>; + fn get_max_mem_slots(&self) -> Result; + fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>; + fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>; ++ fn get_shared_memory_regions(&self) -> Result>; + } + + /// Services provided to the master by the slave without interior mutability. +@@ -107,7 +110,7 @@ pub trait VhostUserSlaveReqHandlerMut { + flags: VhostUserConfigFlags, + ) -> Result>; + fn set_config(&mut self, offset: u32, buf: &[u8], flags: VhostUserConfigFlags) -> Result<()>; +- fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {} ++ fn set_slave_req_fd(&mut self, _vu_req: Slave) {} + fn get_inflight_fd( + &mut self, + inflight: &VhostUserInflight, +@@ -116,6 +119,7 @@ pub trait VhostUserSlaveReqHandlerMut { + fn get_max_mem_slots(&mut self) -> Result; + fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>; + fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>; ++ fn get_shared_memory_regions(&mut self) -> Result>; + } + + impl VhostUserSlaveReqHandler for Mutex { +@@ -201,7 +205,7 @@ impl VhostUserSlaveReqHandler for Mutex { + self.lock().unwrap().set_config(offset, buf, flags) + } + +- fn set_slave_req_fd(&self, vu_req: SlaveFsCacheReq) { ++ fn set_slave_req_fd(&self, vu_req: Slave) { + self.lock().unwrap().set_slave_req_fd(vu_req) + } + +@@ -224,6 +228,10 @@ impl VhostUserSlaveReqHandler for Mutex { + fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> { + self.lock().unwrap().remove_mem_region(region) + } ++ ++ fn get_shared_memory_regions(&self) -> Result> { ++ self.lock().unwrap().get_shared_memory_regions() ++ } + } + + /// Server to handle service requests from masters from the master communication channel. +@@ -528,6 +536,15 @@ impl SlaveReqHandler { + let res = self.backend.remove_mem_region(&msg); + self.send_ack_message(&hdr, res)?; + } ++ MasterReq::GET_SHARED_MEMORY_REGIONS => { ++ let regions = self.backend.get_shared_memory_regions()?; ++ let mut buf = Vec::new(); ++ let msg = VhostUserU64::new(regions.len() as u64); ++ for r in regions { ++ buf.extend_from_slice(r.as_slice()) ++ } ++ self.send_reply_with_payload(&hdr, &msg, buf.as_slice())?; ++ } + _ => { + return Err(Error::InvalidMessage); + } +@@ -641,7 +658,7 @@ impl SlaveReqHandler { + fn set_slave_req_fd(&mut self, files: Option>) -> Result<()> { + let file = take_single_file(files).ok_or(Error::InvalidMessage)?; + let sock = unsafe { UnixStream::from_raw_fd(file.into_raw_fd()) }; +- let vu_req = SlaveFsCacheReq::from_stream(sock); ++ let vu_req = Slave::from_stream(sock); + self.backend.set_slave_req_fd(vu_req); + Ok(()) + } +-- +2.37.1 + -- 2.37.1