Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/virtio.c
Show First 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | vi_vq_init(struct virtio_softc *vs, uint32_t pfn) | ||||
vq->vq_save_used = 0; | vq->vq_save_used = 0; | ||||
} | } | ||||
/* | /* | ||||
* Helper inline for vq_getchain(): record the i'th "real" | * Helper inline for vq_getchain(): record the i'th "real" | ||||
* descriptor. | * descriptor. | ||||
*/ | */ | ||||
static inline void | static inline void | ||||
_vq_record(int i, volatile struct vring_desc *vd, struct vmctx *ctx, | _vq_record(struct virtio_softc *vs, int i, volatile struct vring_desc *vd, | ||||
afedorov: “vs” argument is unused. | |||||
struct iovec *iov, int n_iov, uint16_t *flags) { | struct vmctx *ctx, struct iovec *iov, int n_iov, | ||||
struct vi_req *reqp) { | |||||
if (i >= n_iov) | if (i >= n_iov) | ||||
return; | return; | ||||
iov[i].iov_base = paddr_guest2host(ctx, vd->addr, vd->len); | iov[i].iov_base = paddr_guest2host(ctx, vd->addr, vd->len); | ||||
iov[i].iov_len = vd->len; | iov[i].iov_len = vd->len; | ||||
if (flags != NULL) | if ((vd->flags & VRING_DESC_F_WRITE) == 0) | ||||
flags[i] = vd->flags; | reqp->readable++; | ||||
else | |||||
reqp->writable++; | |||||
} | } | ||||
#define VQ_MAX_DESCRIPTORS 512 /* see below */ | #define VQ_MAX_DESCRIPTORS 512 /* see below */ | ||||
/* | /* | ||||
* Examine the chain of descriptors starting at the "next one" to | * Examine the chain of descriptors starting at the "next one" to | ||||
* make sure that they describe a sensible request. If so, return | * make sure that they describe a sensible request. If so, return | ||||
* the number of "real" descriptors that would be needed/used in | * the number of "real" descriptors that would be needed/used in | ||||
* acting on this request. This may be smaller than the number of | * acting on this request. This may be smaller than the number of | ||||
Show All 15 Lines | |||||
* array (of the given size). If the array overflows, we stop | * array (of the given size). If the array overflows, we stop | ||||
* placing values into the array but keep processing descriptors, | * placing values into the array but keep processing descriptors, | ||||
* up to VQ_MAX_DESCRIPTORS, before giving up and returning -1. | * up to VQ_MAX_DESCRIPTORS, before giving up and returning -1. | ||||
* So you, the caller, must not assume that iov[] is as big as the | * So you, the caller, must not assume that iov[] is as big as the | ||||
* return value (you can process the same thing twice to allocate | * return value (you can process the same thing twice to allocate | ||||
* a larger iov array if needed, or supply a zero length to find | * a larger iov array if needed, or supply a zero length to find | ||||
* out how much space is needed). | * out how much space is needed). | ||||
* | * | ||||
* If you want to verify the WRITE flag on each descriptor, pass a | |||||
* non-NULL "flags" pointer to an array of "uint16_t" of the same size | |||||
* as n_iov and we'll copy each "flags" field after unwinding any | |||||
* indirects. | |||||
* | |||||
* If some descriptor(s) are invalid, this prints a diagnostic message | * If some descriptor(s) are invalid, this prints a diagnostic message | ||||
* and returns -1. If no descriptors are ready now it simply returns 0. | * and returns -1. If no descriptors are ready now it simply returns 0. | ||||
* | * | ||||
* You are assumed to have done a vq_ring_ready() if needed (note | * You are assumed to have done a vq_ring_ready() if needed (note | ||||
* that vq_has_descs() does one). | * that vq_has_descs() does one). | ||||
*/ | */ | ||||
int | int | ||||
vq_getchain(struct vqueue_info *vq, uint16_t *pidx, | vq_getchain(struct vqueue_info *vq, struct iovec *iov, int niov, | ||||
struct iovec *iov, int n_iov, uint16_t *flags) | struct vi_req *reqp) | ||||
{ | { | ||||
int i; | int i; | ||||
u_int ndesc, n_indir; | u_int ndesc, n_indir; | ||||
u_int idx, next; | u_int idx, next; | ||||
struct vi_req req; | |||||
Not Done Inline ActionsIt would look very slightly neater to initialise this further down, rather than where it's declared. None of the other stack variables are initialised at the top of this function. philip: It would look very slightly neater to initialise this further down, rather than where it's… | |||||
volatile struct vring_desc *vdir, *vindir, *vp; | volatile struct vring_desc *vdir, *vindir, *vp; | ||||
struct vmctx *ctx; | struct vmctx *ctx; | ||||
struct virtio_softc *vs; | struct virtio_softc *vs; | ||||
const char *name; | const char *name; | ||||
vs = vq->vq_vs; | vs = vq->vq_vs; | ||||
name = vs->vs_vc->vc_name; | name = vs->vs_vc->vc_name; | ||||
memset(&req, 0, sizeof(req)); | |||||
Not Done Inline ActionsE.g. initialise req = { 0 }; here. philip: E.g. initialise `req = { 0 };` here. | |||||
/* | /* | ||||
* Note: it's the responsibility of the guest not to | * Note: it's the responsibility of the guest not to | ||||
* update vq->vq_avail->idx until all of the descriptors | * update vq->vq_avail->idx until all of the descriptors | ||||
* the guest has written are valid (including all their | * the guest has written are valid (including all their | ||||
* "next" fields and "flags"). | * "next" fields and "flags"). | ||||
* | * | ||||
* Compute (vq_avail->idx - last_avail) in integers mod 2**16. This is | * Compute (vq_avail->idx - last_avail) in integers mod 2**16. This is | ||||
* the number of descriptors the device has made available | * the number of descriptors the device has made available | ||||
Show All 18 Lines | vq_getchain(struct vqueue_info *vq, struct iovec *iov, int niov, | ||||
* Now count/parse "involved" descriptors starting from | * Now count/parse "involved" descriptors starting from | ||||
* the head of the chain. | * the head of the chain. | ||||
* | * | ||||
* To prevent loops, we could be more complicated and | * To prevent loops, we could be more complicated and | ||||
* check whether we're re-visiting a previously visited | * check whether we're re-visiting a previously visited | ||||
* index, but we just abort if the count gets excessive. | * index, but we just abort if the count gets excessive. | ||||
*/ | */ | ||||
ctx = vs->vs_pi->pi_vmctx; | ctx = vs->vs_pi->pi_vmctx; | ||||
*pidx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)]; | req.idx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)]; | ||||
vq->vq_last_avail++; | vq->vq_last_avail++; | ||||
for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->next) { | for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->next) { | ||||
if (next >= vq->vq_qsize) { | if (next >= vq->vq_qsize) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: descriptor index %u out of range, " | "%s: descriptor index %u out of range, " | ||||
"driver confused?", | "driver confused?", | ||||
name, next); | name, next); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
vdir = &vq->vq_desc[next]; | vdir = &vq->vq_desc[next]; | ||||
if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) { | if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) { | ||||
_vq_record(i, vdir, ctx, iov, n_iov, flags); | _vq_record(vs, i, vdir, ctx, iov, niov, &req); | ||||
i++; | i++; | ||||
} else if ((vs->vs_vc->vc_hv_caps & | } else if ((vs->vs_vc->vc_hv_caps & | ||||
VIRTIO_RING_F_INDIRECT_DESC) == 0) { | VIRTIO_RING_F_INDIRECT_DESC) == 0) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: descriptor has forbidden INDIRECT flag, " | "%s: descriptor has forbidden INDIRECT flag, " | ||||
"driver confused?", | "driver confused?", | ||||
name); | name); | ||||
return (-1); | return (-1); | ||||
Show All 20 Lines | if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) { | ||||
vp = &vindir[next]; | vp = &vindir[next]; | ||||
if (vp->flags & VRING_DESC_F_INDIRECT) { | if (vp->flags & VRING_DESC_F_INDIRECT) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: indirect desc has INDIR flag," | "%s: indirect desc has INDIR flag," | ||||
" driver confused?", | " driver confused?", | ||||
name); | name); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
_vq_record(i, vp, ctx, iov, n_iov, flags); | _vq_record(vs, i, vp, ctx, iov, niov, &req); | ||||
if (++i > VQ_MAX_DESCRIPTORS) | if (++i > VQ_MAX_DESCRIPTORS) | ||||
goto loopy; | goto loopy; | ||||
if ((vp->flags & VRING_DESC_F_NEXT) == 0) | if ((vp->flags & VRING_DESC_F_NEXT) == 0) | ||||
break; | break; | ||||
next = vp->next; | next = vp->next; | ||||
if (next >= n_indir) { | if (next >= n_indir) { | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: invalid next %u > %u, " | "%s: invalid next %u > %u, " | ||||
"driver confused?", | "driver confused?", | ||||
name, (u_int)next, n_indir); | name, (u_int)next, n_indir); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if ((vdir->flags & VRING_DESC_F_NEXT) == 0) | if ((vdir->flags & VRING_DESC_F_NEXT) == 0) | ||||
return (i); | goto done; | ||||
} | } | ||||
loopy: | loopy: | ||||
EPRINTLN( | EPRINTLN( | ||||
"%s: descriptor loop? count > %d - driver confused?", | "%s: descriptor loop? count > %d - driver confused?", | ||||
name, i); | name, i); | ||||
return (-1); | return (-1); | ||||
done: | |||||
*reqp = req; | |||||
return (i); | |||||
} | } | ||||
/* | /* | ||||
* Return the first n_chain request chains back to the available queue. | * Return the first n_chain request chains back to the available queue. | ||||
* | * | ||||
* (These chains are the ones you handled when you called vq_getchain() | * (These chains are the ones you handled when you called vq_getchain() | ||||
* and used its positive return value.) | * and used its positive return value.) | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 554 Lines • Show Last 20 Lines |
“vs” argument is unused.