diff options
author | John Levon <john.levon@nutanix.com> | 2021-03-31 16:49:52 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-31 16:49:52 +0100 |
commit | 14b237fc80473bf4419a2bccda4cf7e7d382c174 (patch) | |
tree | 959e0cc1c4d2557f624df6fa5c189a8cdc92993f /include/libvfio-user.h | |
parent | 0ae00cbb9edcc3879b1276cd61479d668a7f1ec9 (diff) | |
download | libvfio-user-14b237fc80473bf4419a2bccda4cf7e7d382c174.zip libvfio-user-14b237fc80473bf4419a2bccda4cf7e7d382c174.tar.gz libvfio-user-14b237fc80473bf4419a2bccda4cf7e7d382c174.tar.bz2 |
rework DMA callbacks (#396)
This fixes a number of issues with how DMA is handled, based on some changes by
Thanos Makatos:
- rename callbacks to register/unregister, as there is not necessarily
any mapping
- provide the (large) page-aligned mapped start and size, the page size used,
as well as the protection flags: some API users need these
- for convenience, provide the virtual address separately that corresponds to
the mapped region
- we should only require a DMA controller to use vfu_addr_to_sg(),
not an unregister callback
- the callbacks should return errno not -errno
- region removal was incorrectly updating the region array
- various other cleanups and clarifications
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'include/libvfio-user.h')
-rw-r--r-- | include/libvfio-user.h | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h index 7b9532b..1048236 100644 --- a/include/libvfio-user.h +++ b/include/libvfio-user.h @@ -60,12 +60,12 @@ extern "C" { #define VFU_DMA_REGIONS 0x10 -// FIXME: too common a name? -typedef uint64_t dma_addr_t; +/* DMA addresses cannot be directly de-referenced. */ +typedef void *vfu_dma_addr_t; typedef struct { - dma_addr_t dma_addr; - int region; /* TODO replace region and length with struct iovec */ + vfu_dma_addr_t *dma_addr; + int region; int length; uint64_t offset; bool mappable; @@ -313,40 +313,95 @@ int vfu_setup_device_reset_cb(vfu_ctx_t *vfu_ctx, vfu_reset_cb_t *reset); /* - * Function that is called when the guest maps a DMA region. Optional. + * Info for a guest DMA region. @iova is always valid; the other parameters + * will only be set if the guest DMA region is VFIO_USER_F_DMA_REGION_MAPPABLE, + * and a file descriptor has been passed across the vfio-user socket. + * + * @iova: guest DMA range. This is the guest physical range (as we don't + * support vIOMMU) that the guest registers for DMA, via a VFIO_USER_DMA_MAP + * message, and is the address space used as input to vfu_addr_to_sg(). + * @vaddr: if the range is mapped into this process, this is the virtual address + * of the start of the region. + * @mapping: if @vaddr is non-NULL, this range represents the actual range + * mmap()ed into the process. This might be (large) page aligned, and + * therefore be different from @vaddr + @iova.iov_len. + * @page_size: if @vaddr is non-NULL, page size of the mapping (e.g. 2MB) + * @prot: if @vaddr is non-NULL, protection settings of the mapping as per + * mmap(2) + * + * For a real example, using the gpio sample server, and a qemu configured to + * use huge pages and share its memory: + * + * gpio: mapped DMA region iova=[0xf0000-0x10000000) vaddr=0x2aaaab0f0000 + * page_size=0x200000 mapping=[0x2aaaab000000-0x2aaabb000000) + * + * 0xf0000 0x10000000 + * | | + * v v + * +-----------------------------------+ + * | Guest IOVA (DMA) space | + * +--+-----------------------------------+--+ + * | | | | + * | +-----------------------------------+ | + * | ^ libvfio-user server address space | + * +--|--------------------------------------+ + * ^ vaddr=0x2aaaab0f0000 ^ + * | | + * 0x2aaaab000000 0x2aaabb000000 + * + * This region can be directly accessed at 0x2aaaab0f0000, but the underlying + * large page mapping is in the range [0x2aaaab000000-0x2aaabb000000). + */ +typedef struct vfu_dma_info { + struct iovec iova; + void *vaddr; + struct iovec mapping; + size_t page_size; + uint32_t prot; +} vfu_dma_info_t; + +/* + * Called when a guest registers one of its DMA regions via a VFIO_USER_DMA_MAP + * message. * * @vfu_ctx: the libvfio-user context - * @iova: iova address - * @len: length - * @prot: memory protection used to map region as defined in <sys/mman.h> + * @info: the DMA info */ -typedef void (vfu_map_dma_cb_t)(vfu_ctx_t *vfu_ctx, - uint64_t iova, uint64_t len, uint32_t prot); +typedef void (vfu_dma_register_cb_t)(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info); /* - * Function that is called when the guest unmaps a DMA region. The device + * Function that is called when the guest unregisters a DMA region. The device * must release all references to that region before the callback returns. - * This is required if you want to be able to access guest memory. + * This is required if you want to be able to access guest memory directly via + * a mapping. + * + * The callback should return 0 on success, errno on failure (although + * unregister should not fail: this will not stop a guest from unregistering the + * region). * * @vfu_ctx: the libvfio-user context - * @iova: iova address - * @len: length + * @info: the DMA info */ -typedef int (vfu_unmap_dma_cb_t)(vfu_ctx_t *vfu_ctx, - uint64_t iova, uint64_t len); +typedef int (vfu_dma_unregister_cb_t)(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info); /** - * Setup device DMA map/unmap callbacks. This will also enable bookkeeping of - * DMA regions received from client, otherwise they will be just acknowledged. + * Setup device DMA registration callbacks. When libvfio-user is notified of a + * DMA range addition or removal, these callbacks will be invoked. + * + * If this function is not called, guest DMA regions are not accessible via + * vfu_addr_to_sg(). + * + * To directly access this DMA memory via a local mapping with vfu_map_sg(), at + * least @dma_unregister must be provided. * * @vfu_ctx: the libvfio-user context - * @map_dma: DMA region map callback (optional) - * @unmap_dma: DMA region unmap callback (optional) + * @dma_register: DMA region registration callback (optional) + * @dma_unregister: DMA region unregistration callback (optional) */ int -vfu_setup_device_dma_cb(vfu_ctx_t *vfu_ctx, vfu_map_dma_cb_t *map_dma, - vfu_unmap_dma_cb_t *unmap_dma); +vfu_setup_device_dma(vfu_ctx_t *vfu_ctx, vfu_dma_register_cb_t *dma_register, + vfu_dma_unregister_cb_t *dma_unregister); enum vfu_dev_irq_type { VFU_DEV_INTX_IRQ, @@ -481,7 +536,7 @@ typedef struct { * to client accesses of the migration region; the migration region read/write * callbacks are not called after this function call. Offsets in callbacks are * relative to @data_offset. - * + * * @vfu_ctx: the libvfio-user context * @callbacks: migration callbacks * @data_offset: offset in the migration region where data begins. @@ -512,8 +567,8 @@ vfu_irq_trigger(vfu_ctx_t *vfu_ctx, uint32_t subindex); * than can be individually mapped in the program's virtual memory. A single * linear guest physical address span may need to be split into multiple * scatter/gather regions due to limitations of how memory can be mapped. - * Field unmap_dma must have been provided at context creation time in order - * to use this function. + * + * vfu_setup_device_dma() must have been called prior to using this function. * * @vfu_ctx: the libvfio-user context * @dma_addr: the guest physical address @@ -530,15 +585,16 @@ vfu_irq_trigger(vfu_ctx_t *vfu_ctx, uint32_t subindex); * entries necessary to complete this request (errno=0). */ int -vfu_addr_to_sg(vfu_ctx_t *vfu_ctx, dma_addr_t dma_addr, uint32_t len, +vfu_addr_to_sg(vfu_ctx_t *vfu_ctx, vfu_dma_addr_t dma_addr, size_t len, dma_sg_t *sg, int max_sg, int prot); /** * Maps a list scatter/gather entries from the guest's physical address space * to the program's virtual memory. It is the caller's responsibility to remove - * the mappings by calling vfu_unmap_sg. - * Field unmap_dma must have been provided at context creation time in order - * to use this function. + * the mappings by calling vfu_unmap_sg(). + * + * This is only supported when a @dma_unregister callback is provided to + * vfu_setup_device_dma(). * * @vfu_ctx: the libvfio-user context * @sg: array of scatter/gather entries returned by vfu_addr_to_sg @@ -553,10 +609,8 @@ vfu_map_sg(vfu_ctx_t *vfu_ctx, const dma_sg_t *sg, struct iovec *iov, int cnt); /** - * Unmaps a list scatter/gather entries (previously mapped by vfu_map_sg) from + * Unmaps a list scatter/gather entries (previously mapped by vfu_map_sg()) from * the program's virtual memory. - * Field unmap_dma must have been provided at context creation time in order - * to use this function. * * @vfu_ctx: the libvfio-user context * @sg: array of scatter/gather entries to unmap |