Merge with upstream 2025-06-08 2/2

7083e31d2 rutabaga_gfx: ffi: fix windows build
175474738 rutagaba: add the missing import for cfg(goldfish)
0c1f69de2 Roll recipe dependencies (trivial).
f047d43c0 Roll recipe dependencies (trivial).
8c50e5ba9 Roll recipe dependencies (trivial).
d8e388a6b Roll recipe dependencies (trivial).
9ed0cca78 Roll recipe dependencies (trivial).
754973f3a rutabaga: add host-host transfer support
4287898ca Roll recipe dependencies (trivial).
a1c0254c8 tools/testvm: Uprev testvm

https://chromium.googlesource.com/crosvm/crosvm/+log/4299752ed4614afc1593aaa536fac803eee28d53..7083e31d219cdcd57866c70144e1b39ddc008f0f

BUG=422984461

Change-Id: Idca79151eab1da3cd01db1984f96f43644ac8117
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/6629430
Bot-Commit: crosvm LUCI CI <crosvm-luci-ci-builder@crosvm-infra.iam.gserviceaccount.com>
Commit-Queue: Yuan Yao <yuanyaogoog@chromium.org>
diff --git a/devices/src/virtio/gpu/virtio_gpu.rs b/devices/src/virtio/gpu/virtio_gpu.rs
index 892bd92..d31acb4 100644
--- a/devices/src/virtio/gpu/virtio_gpu.rs
+++ b/devices/src/virtio/gpu/virtio_gpu.rs
@@ -1014,7 +1014,7 @@
         transfer: Transfer3D,
     ) -> VirtioGpuResult {
         self.rutabaga
-            .transfer_write(ctx_id, resource_id, transfer)?;
+            .transfer_write(ctx_id, resource_id, transfer, None)?;
         Ok(OkNoData)
     }
 
diff --git a/infra/README.recipes.md b/infra/README.recipes.md
index d3f464f..2d55991 100644
--- a/infra/README.recipes.md
+++ b/infra/README.recipes.md
@@ -199,20 +199,20 @@
 
 &mdash; **def [RunSteps](/infra/recipes/uprev_baguette_image.py#37)(api: RecipeApi, properties: UprevBaguetteImageProperties):**
 
-[depot_tools/recipe_modules/bot_update]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d2947264a99fb668d3bf1370c2c82ea817ab9e45/recipes/README.recipes.md#recipe_modules-bot_update
-[depot_tools/recipe_modules/depot_tools]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d2947264a99fb668d3bf1370c2c82ea817ab9e45/recipes/README.recipes.md#recipe_modules-depot_tools
-[depot_tools/recipe_modules/gclient]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d2947264a99fb668d3bf1370c2c82ea817ab9e45/recipes/README.recipes.md#recipe_modules-gclient
-[depot_tools/recipe_modules/git]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d2947264a99fb668d3bf1370c2c82ea817ab9e45/recipes/README.recipes.md#recipe_modules-git
-[depot_tools/recipe_modules/gsutil]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d2947264a99fb668d3bf1370c2c82ea817ab9e45/recipes/README.recipes.md#recipe_modules-gsutil
-[recipe_engine/recipe_modules/buildbucket]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-buildbucket
-[recipe_engine/recipe_modules/cipd]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-cipd
-[recipe_engine/recipe_modules/context]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-context
-[recipe_engine/recipe_modules/file]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-file
-[recipe_engine/recipe_modules/json]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-json
-[recipe_engine/recipe_modules/path]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-path
-[recipe_engine/recipe_modules/platform]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-platform
-[recipe_engine/recipe_modules/properties]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-properties
-[recipe_engine/recipe_modules/raw_io]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-raw_io
-[recipe_engine/recipe_modules/step]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-step
-[recipe_engine/recipe_modules/time]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/README.recipes.md#recipe_modules-time
-[recipe_engine/wkt/RecipeApi]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/d476abd7a60e0154d1432263bd147d1776badb8e/recipe_engine/recipe_api.py#433
+[depot_tools/recipe_modules/bot_update]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d255a8d41e7a2fdc6b50fee69e70014f875d47ef/recipes/README.recipes.md#recipe_modules-bot_update
+[depot_tools/recipe_modules/depot_tools]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d255a8d41e7a2fdc6b50fee69e70014f875d47ef/recipes/README.recipes.md#recipe_modules-depot_tools
+[depot_tools/recipe_modules/gclient]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d255a8d41e7a2fdc6b50fee69e70014f875d47ef/recipes/README.recipes.md#recipe_modules-gclient
+[depot_tools/recipe_modules/git]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d255a8d41e7a2fdc6b50fee69e70014f875d47ef/recipes/README.recipes.md#recipe_modules-git
+[depot_tools/recipe_modules/gsutil]: https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/d255a8d41e7a2fdc6b50fee69e70014f875d47ef/recipes/README.recipes.md#recipe_modules-gsutil
+[recipe_engine/recipe_modules/buildbucket]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-buildbucket
+[recipe_engine/recipe_modules/cipd]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-cipd
+[recipe_engine/recipe_modules/context]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-context
+[recipe_engine/recipe_modules/file]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-file
+[recipe_engine/recipe_modules/json]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-json
+[recipe_engine/recipe_modules/path]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-path
+[recipe_engine/recipe_modules/platform]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-platform
+[recipe_engine/recipe_modules/properties]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-properties
+[recipe_engine/recipe_modules/raw_io]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-raw_io
+[recipe_engine/recipe_modules/step]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-step
+[recipe_engine/recipe_modules/time]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/README.recipes.md#recipe_modules-time
+[recipe_engine/wkt/RecipeApi]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9/recipe_engine/recipe_api.py#433
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 4b6356b..7399963 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -18,12 +18,12 @@
   "deps": {
     "depot_tools": {
       "branch": "refs/heads/main",
-      "revision": "d2947264a99fb668d3bf1370c2c82ea817ab9e45",
+      "revision": "d255a8d41e7a2fdc6b50fee69e70014f875d47ef",
       "url": "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
     },
     "recipe_engine": {
       "branch": "refs/heads/main",
-      "revision": "d476abd7a60e0154d1432263bd147d1776badb8e",
+      "revision": "aac6da572b54b2caf24d6ae73c6b997ab1b1a6e9",
       "url": "https://chromium.googlesource.com/infra/luci/recipes-py.git"
     }
   },
diff --git a/rutabaga_gfx/ffi/build.rs b/rutabaga_gfx/ffi/build.rs
index 030ee69..bbdb299 100644
--- a/rutabaga_gfx/ffi/build.rs
+++ b/rutabaga_gfx/ffi/build.rs
@@ -9,7 +9,8 @@
 fn main() {
     let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
 
-    // Override prefix from environment variable (with a default)
+    println!("cargo::rustc-check-cfg=cfg(goldfish)"); // Silences warnings
+                                                      // Override prefix from environment variable (with a default)
     let prefix = format!(
         r##"prefix={prefix}"##,
         prefix = env::var("PREFIX").unwrap_or_else(|_| "/usr".to_string())
diff --git a/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi_goldfish.h b/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi_goldfish.h
new file mode 100644
index 0000000..e008e67
--- /dev/null
+++ b/rutabaga_gfx/ffi/src/include/rutabaga_gfx_ffi_goldfish.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef RUTABAGA_GFX_FFI_GOLDFISH_H
+#define RUTABAGA_GFX_FFI_GOLDFISH_H
+
+#include "rutabaga_gfx_ffi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int32_t rutabaga_resource_transfer_write_goldfish(struct rutabaga *ptr, uint32_t ctx_id,
+                                                  uint32_t resource_id,
+                                                  const struct rutabaga_transfer *transfer,
+                                                  const struct iovec *iovec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* RUTABAGA_GFX_FFI_GOLDFISH_H */
diff --git a/rutabaga_gfx/ffi/src/lib.rs b/rutabaga_gfx/ffi/src/lib.rs
index 16b0186..506a018 100644
--- a/rutabaga_gfx/ffi/src/lib.rs
+++ b/rutabaga_gfx/ffi/src/lib.rs
@@ -10,6 +10,8 @@
 use std::convert::TryInto;
 use std::ffi::CStr;
 use std::ffi::CString;
+#[cfg(goldfish)]
+use std::io::IoSlice;
 use std::io::IoSliceMut;
 use std::os::raw::c_char;
 use std::os::raw::c_void;
@@ -42,6 +44,7 @@
 use rutabaga_gfx::RutabagaImportData;
 use rutabaga_gfx::RutabagaIntoRawDescriptor;
 use rutabaga_gfx::RutabagaIovec;
+use rutabaga_gfx::RutabagaRawDescriptor;
 use rutabaga_gfx::RutabagaResult;
 use rutabaga_gfx::RutabagaWsi;
 use rutabaga_gfx::Transfer3D;
@@ -431,7 +434,7 @@
     catch_unwind(AssertUnwindSafe(|| {
         let internal_handle = RutabagaHandle {
             os_handle: RutabagaDescriptor::from_raw_descriptor(
-                import_handle.os_handle.try_into().unwrap(),
+                import_handle.os_handle as RutabagaRawDescriptor,
             ),
             handle_type: import_handle.handle_type,
         };
@@ -513,7 +516,31 @@
     transfer: &rutabaga_transfer,
 ) -> i32 {
     catch_unwind(AssertUnwindSafe(|| {
-        let result = ptr.transfer_write(ctx_id, resource_id, *transfer);
+        let result = ptr.transfer_write(ctx_id, resource_id, *transfer, None);
+        return_result(result)
+    }))
+    .unwrap_or(-ESRCH)
+}
+
+#[cfg(goldfish)]
+#[no_mangle]
+pub unsafe extern "C" fn rutabaga_resource_transfer_write_goldfish(
+    ptr: &mut rutabaga,
+    ctx_id: u32,
+    resource_id: u32,
+    transfer: &rutabaga_transfer,
+    buf: Option<&iovec>,
+) -> i32 {
+    catch_unwind(AssertUnwindSafe(|| {
+        let slice = match buf {
+            Some(iov) => Some(IoSlice::new(std::slice::from_raw_parts(
+                iov.iov_base as *mut u8,
+                iov.iov_len,
+            ))),
+            None => None,
+        };
+
+        let result = ptr.transfer_write(ctx_id, resource_id, *transfer, slice);
         return_result(result)
     }))
     .unwrap_or(-ESRCH)
@@ -557,11 +584,10 @@
 
         // Only needed on Unix, since there is no way to create a handle from guest memory on
         // Windows.
-        #[cfg(unix)]
         if let Some(hnd) = handle {
             handle_opt = Some(RutabagaHandle {
                 os_handle: RutabagaDescriptor::from_raw_descriptor(
-                    hnd.os_handle.try_into().unwrap(),
+                    hnd.os_handle as RutabagaRawDescriptor,
                 ),
                 handle_type: hnd.handle_type,
             });
diff --git a/rutabaga_gfx/src/gfxstream.rs b/rutabaga_gfx/src/gfxstream.rs
index 5e396a3..bf0f365 100644
--- a/rutabaga_gfx/src/gfxstream.rs
+++ b/rutabaga_gfx/src/gfxstream.rs
@@ -10,6 +10,7 @@
 
 use std::convert::TryInto;
 use std::ffi::CString;
+use std::io::IoSlice;
 use std::io::IoSliceMut;
 use std::mem::size_of;
 use std::os::raw::c_char;
@@ -704,6 +705,7 @@
         ctx_id: u32,
         resource: &mut RutabagaResource,
         transfer: Transfer3D,
+        buf: Option<IoSlice>,
     ) -> RutabagaResult<()> {
         if transfer.is_empty() {
             return Ok(());
@@ -721,6 +723,21 @@
         // SAFETY:
         // Safe because only stack variables of the appropriate type are used.
         let ret = unsafe {
+            let mut iov = RutabagaIovec {
+                base: null_mut(),
+                len: 0,
+            };
+
+            let (iovs_ptr, iovs_n) = match buf {
+                Some(slice) => {
+                    iov.base = slice.as_ptr() as *mut c_void;
+                    iov.len = slice.len();
+
+                    (&mut iov as *mut RutabagaIovec as *mut iovec, 1u32)
+                }
+                None => (null_mut(), 0u32),
+            };
+
             stream_renderer_transfer_write_iov(
                 resource.resource_id,
                 ctx_id,
@@ -729,8 +746,8 @@
                 transfer.layer_stride,
                 &mut transfer_box as *mut VirglBox as *mut stream_renderer_box,
                 transfer.offset,
-                null_mut(),
-                0,
+                iovs_ptr,
+                iovs_n,
             )
         };
         ret_to_res(ret)
diff --git a/rutabaga_gfx/src/rutabaga_2d.rs b/rutabaga_gfx/src/rutabaga_2d.rs
index 4098b88..6ff6d8b 100644
--- a/rutabaga_gfx/src/rutabaga_2d.rs
+++ b/rutabaga_gfx/src/rutabaga_2d.rs
@@ -7,6 +7,7 @@
 use std::cmp::max;
 use std::cmp::min;
 use std::cmp::Ordering;
+use std::io::IoSlice;
 use std::io::IoSliceMut;
 
 use anyhow::Context;
@@ -197,11 +198,16 @@
         _ctx_id: u32,
         resource: &mut RutabagaResource,
         transfer: Transfer3D,
+        buf: Option<IoSlice>,
     ) -> RutabagaResult<()> {
         if transfer.is_empty() {
             return Ok(());
         }
 
+        if buf.is_some() {
+            return Err(RutabagaErrorKind::Unsupported.into());
+        }
+
         let mut info_2d = resource
             .info_2d
             .take()
diff --git a/rutabaga_gfx/src/rutabaga_core.rs b/rutabaga_gfx/src/rutabaga_core.rs
index b7b07b0..319a2ea 100644
--- a/rutabaga_gfx/src/rutabaga_core.rs
+++ b/rutabaga_gfx/src/rutabaga_core.rs
@@ -5,6 +5,7 @@
 //! rutabaga_core: Cross-platform, Rust-based, Wayland and Vulkan centric GPU virtualization.
 use std::collections::BTreeMap as Map;
 use std::convert::TryInto;
+use std::io::IoSlice;
 use std::io::IoSliceMut;
 use std::path::Path;
 use std::sync::Arc;
@@ -233,6 +234,7 @@
         _ctx_id: u32,
         _resource: &mut RutabagaResource,
         _transfer: Transfer3D,
+        _buf: Option<IoSlice>,
     ) -> RutabagaResult<()> {
         Ok(())
     }
@@ -814,6 +816,7 @@
         ctx_id: u32,
         resource_id: u32,
         transfer: Transfer3D,
+        buf: Option<IoSlice>,
     ) -> RutabagaResult<()> {
         let component = self
             .components
@@ -825,7 +828,7 @@
             .get_mut(&resource_id)
             .ok_or(RutabagaErrorKind::InvalidResourceId)?;
 
-        component.transfer_write(ctx_id, resource, transfer)
+        component.transfer_write(ctx_id, resource, transfer, buf)
     }
 
     /// 1) If specified, copies to `buf` from the host resource.
diff --git a/rutabaga_gfx/src/virgl_renderer.rs b/rutabaga_gfx/src/virgl_renderer.rs
index 164d971..ec50fb7 100644
--- a/rutabaga_gfx/src/virgl_renderer.rs
+++ b/rutabaga_gfx/src/virgl_renderer.rs
@@ -9,6 +9,7 @@
 
 use std::cmp::min;
 use std::io::Error as SysError;
+use std::io::IoSlice;
 use std::io::IoSliceMut;
 use std::mem::size_of;
 use std::mem::transmute;
@@ -603,11 +604,16 @@
         ctx_id: u32,
         resource: &mut RutabagaResource,
         transfer: Transfer3D,
+        buf: Option<IoSlice>,
     ) -> RutabagaResult<()> {
         if transfer.is_empty() {
             return Ok(());
         }
 
+        if buf.is_some() {
+            return Err(RutabagaErrorKind::Unsupported.into());
+        }
+
         let mut transfer_box = VirglBox {
             x: transfer.x,
             y: transfer.y,
diff --git a/tools/impl/testvm/Makefile b/tools/impl/testvm/Makefile
index 82874e9..6de719d 100644
--- a/tools/impl/testvm/Makefile
+++ b/tools/impl/testvm/Makefile
@@ -12,7 +12,8 @@
 #   make ARCH=aarch64 upload
 #
 # You need write access to the crosvm-testvm storage bucket which is part of the
-# crosvm-packages cloud project.
+# crosvm-packages cloud project. Please browse the storage bucket to find the
+# current latest file version, it can be different than what's in the version file.
 #
 # Note: The locally built image is stored in the same place that testvm.py
 # expects. So the image can be tested directly:
diff --git a/tools/impl/testvm/version b/tools/impl/testvm/version
index 526a6d2..ea1d9dd 100644
--- a/tools/impl/testvm/version
+++ b/tools/impl/testvm/version
@@ -1 +1 @@
-r0014
+r0016