vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)

{

    unsigned int i, head, max;

    VuVirtqElement *elem;

    unsigned out_num, in_num;

    struct iovec iov[VIRTQUEUE_MAX_SIZE];

    struct vring_desc *desc;

    int rc;



    if (unlikely(dev->broken)) {

        return NULL;

    }



    if (vu_queue_empty(dev, vq)) {

        return NULL;

    }

    /* Needed after virtio_queue_empty(), see comment in

     * virtqueue_num_heads(). */

    smp_rmb();



    /* When we start there are none of either input nor output. */

    out_num = in_num = 0;



    max = vq->vring.num;

    if (vq->inuse >= vq->vring.num) {

        vu_panic(dev, "Virtqueue size exceeded");

        return NULL;

    }



    if (!virtqueue_get_head(dev, vq, vq->last_avail_idx++, &head)) {

        return NULL;

    }



    if (vu_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {

        vring_set_avail_event(vq, vq->last_avail_idx);

    }



    i = head;

    desc = vq->vring.desc;

    if (desc[i].flags & VRING_DESC_F_INDIRECT) {

        if (desc[i].len % sizeof(struct vring_desc)) {

            vu_panic(dev, "Invalid size for indirect buffer table");

        }



        /* loop over the indirect descriptor table */

        max = desc[i].len / sizeof(struct vring_desc);

        desc = vu_gpa_to_va(dev, desc[i].addr);

        i = 0;

    }



    /* Collect all the descriptors */

    do {

        if (desc[i].flags & VRING_DESC_F_WRITE) {

            virtqueue_map_desc(dev, &in_num, iov + out_num,

                               VIRTQUEUE_MAX_SIZE - out_num, true,

                               desc[i].addr, desc[i].len);

        } else {

            if (in_num) {

                vu_panic(dev, "Incorrect order for descriptors");

                return NULL;

            }

            virtqueue_map_desc(dev, &out_num, iov,

                               VIRTQUEUE_MAX_SIZE, false,

                               desc[i].addr, desc[i].len);

        }



        /* If we've got too many, that implies a descriptor loop. */

        if ((in_num + out_num) > max) {

            vu_panic(dev, "Looped descriptor");

        }

        rc = virtqueue_read_next_desc(dev, desc, i, max, &i);

    } while (rc == VIRTQUEUE_READ_DESC_MORE);



    if (rc == VIRTQUEUE_READ_DESC_ERROR) {

        return NULL;

    }



    /* Now copy what we have collected and mapped */

    elem = virtqueue_alloc_element(sz, out_num, in_num);

    elem->index = head;

    for (i = 0; i < out_num; i++) {

        elem->out_sg[i] = iov[i];

    }

    for (i = 0; i < in_num; i++) {

        elem->in_sg[i] = iov[out_num + i];

    }



    vq->inuse++;



    return elem;

}

vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz)

{

    unsigned int i, head, max;

    VuVirtqElement *elem;

    unsigned out_num, in_num;

    struct iovec iov[VIRTQUEUE_MAX_SIZE];

    struct vring_desc *desc;

    int rc;



    if (unlikely(dev->broken)) {

        return NULL;

    }



    if (vu_queue_empty(dev, vq)) {

        return NULL;

    }

    



    smp_rmb();



    

    out_num = in_num = 0;



    max = vq->vring.num;

    if (vq->inuse >= vq->vring.num) {

        vu_panic(dev, "Virtqueue size exceeded");

        return NULL;

    }



    if (!virtqueue_get_head(dev, vq, vq->last_avail_idx++, &head)) {

        return NULL;

    }



    if (vu_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {

        vring_set_avail_event(vq, vq->last_avail_idx);

    }



    i = head;

    desc = vq->vring.desc;

    if (desc[i].flags & VRING_DESC_F_INDIRECT) {

        if (desc[i].len % sizeof(struct vring_desc)) {

            vu_panic(dev, "Invalid size for indirect buffer table");

        }



        

        max = desc[i].len / sizeof(struct vring_desc);

        desc = vu_gpa_to_va(dev, desc[i].addr);

        i = 0;

    }



    

    do {

        if (desc[i].flags & VRING_DESC_F_WRITE) {

            virtqueue_map_desc(dev, &in_num, iov + out_num,

                               VIRTQUEUE_MAX_SIZE - out_num, true,

                               desc[i].addr, desc[i].len);

        } else {

            if (in_num) {

                vu_panic(dev, "Incorrect order for descriptors");

                return NULL;

            }

            virtqueue_map_desc(dev, &out_num, iov,

                               VIRTQUEUE_MAX_SIZE, false,

                               desc[i].addr, desc[i].len);

        }



        

        if ((in_num + out_num) > max) {

            vu_panic(dev, "Looped descriptor");

        }

        rc = virtqueue_read_next_desc(dev, desc, i, max, &i);

    } while (rc == VIRTQUEUE_READ_DESC_MORE);



    if (rc == VIRTQUEUE_READ_DESC_ERROR) {

        return NULL;

    }



    

    elem = virtqueue_alloc_element(sz, out_num, in_num);

    elem->index = head;

    for (i = 0; i < out_num; i++) {

        elem->out_sg[i] = iov[i];

    }

    for (i = 0; i < in_num; i++) {

        elem->in_sg[i] = iov[out_num + i];

    }



    vq->inuse++;



    return elem;

}

    if (unlikely(dev->broken)) {     if (unlikely(dev->broken)) {     if (unlikely(dev->broken)) {     if (unlikely(dev->broken)) {
FUNC_0(VuDev *VAR_0, VuVirtq *VAR_1, size_t VAR_2)

{

    unsigned int VAR_3, VAR_4, VAR_5;

    VuVirtqElement *elem;

    unsigned VAR_6, VAR_7;

    struct iovec VAR_8[VIRTQUEUE_MAX_SIZE];

    struct vring_desc *VAR_9;

    int VAR_10;



    if (unlikely(VAR_0->broken)) {

        return NULL;

    }



    if (vu_queue_empty(VAR_0, VAR_1)) {

        return NULL;

    }

    



    smp_rmb();



    

    VAR_6 = VAR_7 = 0;



    VAR_5 = VAR_1->vring.num;

    if (VAR_1->inuse >= VAR_1->vring.num) {

        vu_panic(VAR_0, "Virtqueue size exceeded");

        return NULL;

    }



    if (!virtqueue_get_head(VAR_0, VAR_1, VAR_1->last_avail_idx++, &VAR_4)) {

        return NULL;

    }



    if (vu_has_feature(VAR_0, VIRTIO_RING_F_EVENT_IDX)) {

        vring_set_avail_event(VAR_1, VAR_1->last_avail_idx);

    }



    VAR_3 = VAR_4;

    VAR_9 = VAR_1->vring.VAR_9;

    if (VAR_9[VAR_3].flags & VRING_DESC_F_INDIRECT) {

        if (VAR_9[VAR_3].len % sizeof(struct vring_desc)) {

            vu_panic(VAR_0, "Invalid size for indirect buffer table");

        }



        

        VAR_5 = VAR_9[VAR_3].len / sizeof(struct vring_desc);

        VAR_9 = vu_gpa_to_va(VAR_0, VAR_9[VAR_3].addr);

        VAR_3 = 0;

    }



    

    do {

        if (VAR_9[VAR_3].flags & VRING_DESC_F_WRITE) {

            virtqueue_map_desc(VAR_0, &VAR_7, VAR_8 + VAR_6,

                               VIRTQUEUE_MAX_SIZE - VAR_6, true,

                               VAR_9[VAR_3].addr, VAR_9[VAR_3].len);

        } else {

            if (VAR_7) {

                vu_panic(VAR_0, "Incorrect order for descriptors");

                return NULL;

            }

            virtqueue_map_desc(VAR_0, &VAR_6, VAR_8,

                               VIRTQUEUE_MAX_SIZE, false,

                               VAR_9[VAR_3].addr, VAR_9[VAR_3].len);

        }



        

        if ((VAR_7 + VAR_6) > VAR_5) {

            vu_panic(VAR_0, "Looped descriptor");

        }

        VAR_10 = virtqueue_read_next_desc(VAR_0, VAR_9, VAR_3, VAR_5, &VAR_3);

    } while (VAR_10 == VIRTQUEUE_READ_DESC_MORE);



    if (VAR_10 == VIRTQUEUE_READ_DESC_ERROR) {

        return NULL;

    }



    

    elem = virtqueue_alloc_element(VAR_2, VAR_6, VAR_7);

    elem->index = VAR_4;

    for (VAR_3 = 0; VAR_3 < VAR_6; VAR_3++) {

        elem->out_sg[VAR_3] = VAR_8[VAR_3];

    }

    for (VAR_3 = 0; VAR_3 < VAR_7; VAR_3++) {

        elem->in_sg[VAR_3] = VAR_8[VAR_6 + VAR_3];

    }



    VAR_1->inuse++;



    return elem;

}

FUNC_0(VuDev *VAR_0, VuVirtq *VAR_1, size_t VAR_2)
{ unsigned int VAR_3, VAR_4, VAR_5; VuVirtqElement *elem; unsigned VAR_6, VAR_7; struct iovec VAR_8[VIRTQUEUE_MAX_SIZE]; struct vring_desc *VAR_9; int VAR_10; if (unlikely(VAR_0->broken)) { return NULL; } if (vu_queue_empty(VAR_0, VAR_1)) { return NULL; } smp_rmb(); VAR_6 = VAR_7 = 0; VAR_5 = VAR_1->vring.num; if (VAR_1->inuse >= VAR_1->vring.num) { vu_panic(VAR_0, "Virtqueue size exceeded"); return NULL; } if (!virtqueue_get_head(VAR_0, VAR_1, VAR_1->last_avail_idx++, &VAR_4)) { return NULL; } if (vu_has_feature(VAR_0, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(VAR_1, VAR_1->last_avail_idx); } VAR_3 = VAR_4; VAR_9 = VAR_1->vring.VAR_9; if (VAR_9[VAR_3].flags & VRING_DESC_F_INDIRECT) { if (VAR_9[VAR_3].len % sizeof(struct vring_desc)) { vu_panic(VAR_0, "Invalid size for indirect buffer table"); } VAR_5 = VAR_9[VAR_3].len / sizeof(struct vring_desc); VAR_9 = vu_gpa_to_va(VAR_0, VAR_9[VAR_3].addr); VAR_3 = 0; } do { if (VAR_9[VAR_3].flags & VRING_DESC_F_WRITE) { virtqueue_map_desc(VAR_0, &VAR_7, VAR_8 + VAR_6,
VIRTQUEUE_MAX_SIZE - VAR_6, true,
VAR_9[VAR_3].addr, VAR_9[VAR_3].len); } else { if (VAR_7) { vu_panic(VAR_0, "Incorrect order for descriptors"); return NULL; } virtqueue_map_desc(VAR_0, &VAR_6, VAR_8,
VIRTQUEUE_MAX_SIZE, false,
VAR_9[VAR_3].addr, VAR_9[VAR_3].len); } if ((VAR_7 + VAR_6) > VAR_5) { vu_panic(VAR_0, "Looped descriptor"); } VAR_10 = virtqueue_read_next_desc(VAR_0, VAR_9, VAR_3, VAR_5, &VAR_3); } while (VAR_10 == VIRTQUEUE_READ_DESC_MORE); if (VAR_10 == VIRTQUEUE_READ_DESC_ERROR) { return NULL; } elem = virtqueue_alloc_element(VAR_2, VAR_6, VAR_7); elem->index = VAR_4; for (VAR_3 = 0; VAR_3 < VAR_6; VAR_3++) { elem->out_sg[VAR_3] = VAR_8[VAR_3]; } for (VAR_3 = 0; VAR_3 < VAR_7; VAR_3++) { elem->in_sg[VAR_3] = VAR_8[VAR_6 + VAR_3]; } VAR_1->inuse++; return elem; }