Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/virtio/random/virtio_random.c
Show First 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
vtrnd_harvest(struct vtrnd_softc *sc, void *buf, size_t *sz) | vtrnd_harvest(struct vtrnd_softc *sc, void *buf, size_t *sz) | ||||
{ | { | ||||
struct sglist_seg segs[1]; | struct sglist_seg segs[1]; | ||||
struct sglist sg; | struct sglist sg; | ||||
struct virtqueue *vq; | struct virtqueue *vq; | ||||
void *cookie; | |||||
uint32_t value[HARVESTSIZE] __aligned(sizeof(uint32_t) * HARVESTSIZE); | uint32_t value[HARVESTSIZE] __aligned(sizeof(uint32_t) * HARVESTSIZE); | ||||
uint32_t rdlen; | uint32_t rdlen; | ||||
int error; | int error; | ||||
_Static_assert(sizeof(value) < PAGE_SIZE, "sglist assumption"); | _Static_assert(sizeof(value) < PAGE_SIZE, "sglist assumption"); | ||||
sglist_init(&sg, 1, segs); | sglist_init(&sg, 1, segs); | ||||
error = sglist_append(&sg, value, *sz); | error = sglist_append(&sg, value, *sz); | ||||
if (error != 0) | if (error != 0) | ||||
panic("%s: sglist_append error=%d", __func__, error); | panic("%s: sglist_append error=%d", __func__, error); | ||||
vq = sc->vtrnd_vq; | vq = sc->vtrnd_vq; | ||||
KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__)); | KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__)); | ||||
error = virtqueue_enqueue(vq, buf, &sg, 0, 1); | error = virtqueue_enqueue(vq, buf, &sg, 0, 1); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Poll for the response, but the command is likely already | * Poll for the response, but the command is likely already | ||||
* done when we return from the notify. | * done when we return from the notify. | ||||
*/ | */ | ||||
virtqueue_notify(vq); | virtqueue_notify(vq); | ||||
virtqueue_poll(vq, &rdlen); | cookie = virtqueue_poll(vq, &rdlen); | ||||
/* Almost trivially true, but could indicate something bad. */ | |||||
KASSERT(cookie == buf, ("inconsistent virtqueue state")); | |||||
if (rdlen > *sz) | if (rdlen > *sz) | ||||
panic("%s: random device wrote %zu bytes beyond end of provided" | panic("%s: random device wrote %zu bytes beyond end of provided" | ||||
" buffer %p:%zu", __func__, (size_t)rdlen - *sz, | " buffer %p:%zu", __func__, (size_t)rdlen - *sz, | ||||
(void *)value, *sz); | (void *)value, *sz); | ||||
else if (rdlen == 0) | else if (rdlen == 0) | ||||
return (EAGAIN); | return (EAGAIN); | ||||
*sz = MIN(rdlen, *sz); | *sz = MIN(rdlen, *sz); | ||||
Show All 23 Lines |