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
