This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit c77c9818506e5886f1a549af15bbe20bf42f431a
Author: Ulaş Sertan Kemeç <[email protected]>
AuthorDate: Tue Aug 4 11:38:17 2026 +0300

    drivers/vhost: Add vhost_get_vq_buffers_pa().
    
    vhost_get_vq_buffers() converts descriptor addresses through the 
shared-memory
    I/O region, which truncates silently when the CPU cannot address all of the
    peer's memory -- a 32-bit remote core against a 64-bit host, where
    metal_phys_addr_t is 32-bit and Linux posts buffers above 4 GB.
    
    Returns the raw 64-bit address and length instead, so class drivers can
    translate through platform window hardware.  Completion is unchanged.
    
    Assisted-by: Claude Code:claude-fable-5
    Signed-off-by: Ulaş Sertan Kemeç <[email protected]>
---
 drivers/vhost/vhost.c       | 83 +++++++++++++++++++++++++++++++++++++++++++++
 include/nuttx/vhost/vhost.h | 17 ++++++++++
 2 files changed, 100 insertions(+)

diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 8a749baae0c..8136b48993f 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -31,6 +31,10 @@
 #include <nuttx/wqueue.h>
 #include <nuttx/vhost/vhost.h>
 
+#ifdef CONFIG_DRIVERS_VHOST_NET
+#  include "vhost-net.h"
+#endif
+
 #include "vhost-rng.h"
 #include "vhost-rpmsg.h"
 
@@ -210,6 +214,77 @@ int vhost_get_vq_buffers(FAR struct virtqueue *vq,
   return head;
 }
 
+/****************************************************************************
+ * Name: vhost_get_vq_buffers_pa
+ *
+ * Description:
+ *   Like vhost_get_vq_buffers(), but returns the untranslated 64-bit
+ *   descriptor addresses instead of CPU pointers.  Needed when the peer
+ *   driver posts buffers beyond the CPU's directly addressable range
+ *   (the pointer-based API would silently truncate the address).
+ *
+ *   The caller completes the chain with virtqueue_add_consumed_buffer()
+ *   using the returned head index, exactly as with the pointer API.
+ *
+ ****************************************************************************/
+
+int vhost_get_vq_buffers_pa(FAR struct virtqueue *vq,
+                            FAR struct vhost_buf_s *vb, size_t vbsize,
+                            FAR size_t *vbcnt)
+{
+  uint16_t head;
+  uint16_t idx;
+  size_t i = 0;
+
+  DEBUGASSERT(vb != NULL && vbsize >= 1 && vbcnt != NULL);
+
+  atomic_thread_fence(memory_order_acquire);
+
+  /* The avail ring is written by the peer driver.  On systems without
+   * hardware coherency between the two sides the vring memory must be
+   * mapped non-cacheable (or otherwise synchronized) for these reads to
+   * observe the peer's updates.
+   */
+
+  if (vq->vq_available_idx == vq->vq_ring.avail->idx)
+    {
+      return -ENOMEM;
+    }
+
+  head = vq->vq_ring.avail->ring[vq->vq_available_idx++ &
+                                 (vq->vq_nentries - 1)];
+
+  for (idx = head; ; )
+    {
+      if (i >= vbsize || i >= vq->vq_nentries)
+        {
+          /* Chain longer than the caller's array (or malformed and
+           * looping): complete it untouched so the ring slot returns to
+           * the peer rather than leaking, and report the drop.
+           */
+
+          vhosterr("descriptor chain exceeds vbsize %zu, dropped\n",
+                   vbsize);
+          virtqueue_add_consumed_buffer(vq, head, 0);
+          return -EINVAL;
+        }
+
+      vb[i].addr = vq->vq_ring.desc[idx].addr;
+      vb[i].len  = vq->vq_ring.desc[idx].len;
+      i++;
+
+      if (!(vq->vq_ring.desc[idx].flags & VRING_DESC_F_NEXT))
+        {
+          break;
+        }
+
+      idx = vq->vq_ring.desc[idx].next;
+    }
+
+  *vbcnt = i;
+  return head;
+}
+
 /****************************************************************************
  * Name: vhost_register_driver
  ****************************************************************************/
@@ -436,6 +511,14 @@ void vhost_register_drivers(void)
       vhosterr("metal_init failed, ret=%d\n", ret);
     }
 
+#ifdef CONFIG_DRIVERS_VHOST_NET
+  ret = vhost_register_net_driver();
+  if (ret < 0)
+    {
+      vhosterr("vhost_register_net_driver failed, ret=%d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_DRIVERS_VHOST_RNG
   ret = vhost_register_rng_driver();
   if (ret < 0)
diff --git a/include/nuttx/vhost/vhost.h b/include/nuttx/vhost/vhost.h
index bef97150861..60f32db1cc8 100644
--- a/include/nuttx/vhost/vhost.h
+++ b/include/nuttx/vhost/vhost.h
@@ -72,6 +72,20 @@ struct vhost_driver
   CODE void        (*remove)(FAR struct vhost_device *hdev);
 };
 
+/* Peer buffer described by its full 64-bit guest physical address.  On
+ * targets where the CPU cannot address all of the peer's memory directly
+ * (e.g. a 32-bit remote core with the driver side on a 64-bit host),
+ * vhost_get_vq_buffers() is unusable because converting the descriptor
+ * address to a CPU pointer truncates it; this variant hands the raw
+ * address to the class driver, which must map it appropriately.
+ */
+
+struct vhost_buf_s
+{
+  uint64_t addr;               /* Guest physical address from descriptor */
+  uint32_t len;                /* Descriptor length */
+};
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
@@ -91,6 +105,9 @@ int vhost_unregister_device(FAR struct vhost_device *hdev);
 int vhost_get_vq_buffers(FAR struct virtqueue *vq,
                          FAR struct virtqueue_buf *vb, size_t vbsize,
                          FAR size_t *vbcnt);
+int vhost_get_vq_buffers_pa(FAR struct virtqueue *vq,
+                            FAR struct vhost_buf_s *vb, size_t vbsize,
+                            FAR size_t *vbcnt);
 
 /****************************************************************************
  * Name: vhost_register_drivers

Reply via email to