These helpers do a full transfer from an in-memory buffer to target memory, with full support for MMIO areas. It will be used to store the reply of an emulated command into a QEMUSGList provided by the adapter.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- cutils.c | 8 +++--- dma-helpers.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dma.h | 5 ++++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/cutils.c b/cutils.c index f9a7e36..969fd2e 100644 --- a/cutils.c +++ b/cutils.c @@ -215,14 +215,14 @@ void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size) void qemu_iovec_destroy(QEMUIOVector *qiov) { - assert(qiov->nalloc != -1); - - qemu_free(qiov->iov); + if (qiov->nalloc != -1) { + qemu_free(qiov->iov); + } } void qemu_iovec_reset(QEMUIOVector *qiov) { - assert(qiov->nalloc != -1); + assert(qiov->nalloc != -1 || qiov->niov == 0); qiov->niov = 0; qiov->size = 0; diff --git a/dma-helpers.c b/dma-helpers.c index 4469ce2..10dc8ca 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -84,6 +84,7 @@ struct DMAAIOCB { BlockDriverAIOCB common; union { BlockDriverState *bs; + uint8_t *ptr; } u; BlockDriverAIOCB *acb; QEMUSGList *sg; @@ -245,3 +246,65 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, { return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1); } + + +static int dma_copy_cb(DMAAIOCB *dbs, int ret) +{ + void *mem; + target_phys_addr_t cur_len; + + assert(ret == 0); + + /* sector_num is the residual number of bytes to copy. */ + while (dbs->sector_num > 0 && + (mem = qemu_sglist_map_segment(dbs->sg, &cur_len, + !dbs->is_write)) != NULL) { + if (dbs->is_write) { + memcpy(dbs->u.ptr, mem, cur_len); + } else { + memcpy(mem, dbs->u.ptr, cur_len); + } + cpu_physical_memory_unmap(mem, cur_len, !dbs->is_write, cur_len); + dbs->u.ptr += cur_len; + dbs->sector_num -= cur_len; + } + + if (dbs->sg->resid > 0) { + cpu_register_map_client(dbs, continue_after_map_failure); + return -EAGAIN; + } + + return 0; +} + +static BlockDriverAIOCB *dma_copy( + uint8_t *ptr, int32_t len, QEMUSGList *sg, + void (*cb)(void *opaque, int ret), void *opaque, int is_write) +{ + DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, NULL, cb, opaque); + + dbs->acb = NULL; + dbs->u.ptr = ptr; + dbs->sg = sg; + dbs->sector_num = MIN(len, sg->size); + dbs->is_write = is_write; + dbs->bh = NULL; + dbs->cb = dma_copy_cb; + qemu_iovec_init_external(&dbs->iov, NULL, 0); + qemu_sglist_rewind(sg); + return dma_continue(dbs, 0); +} + +BlockDriverAIOCB *dma_buf_read( + uint8_t *ptr, int32_t len, QEMUSGList *sg, + void (*cb)(void *opaque, int ret), void *opaque) +{ + return dma_copy(ptr, len, sg, cb, opaque, 0); +} + +BlockDriverAIOCB *dma_buf_write( + uint8_t *ptr, int32_t len, QEMUSGList *sg, + void (*cb)(void *opaque, int ret), void *opaque) +{ + return dma_copy(ptr, len, sg, cb, opaque, 1); +} diff --git a/dma.h b/dma.h index 363e932..6bf51ee 100644 --- a/dma.h +++ b/dma.h @@ -58,4 +58,9 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs, BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, QEMUSGList *sg, uint64_t sector, BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg, + BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg, + BlockDriverCompletionFunc *cb, void *opaque); + #endif -- 1.7.6