8c773d53fb
This implements an MMU-based software IOTLB to support mapping kernel dma buffer into userspace dynamically. The basic idea behind it is treating MMU (VA->PA) as IOMMU (IOVA->PA). The software IOTLB will set up MMU mapping instead of IOMMU mapping for the DMA transfer so that the userspace process is able to use its virtual address to access the dma buffer in kernel. To avoid security issue, a bounce-buffering mechanism is introduced to prevent userspace accessing the original buffer directly which may contain other kernel data. During the mapping, unmapping, the software IOTLB will copy the data from the original buffer to the bounce buffer and back, depending on the direction of the transfer. And the bounce-buffer addresses will be mapped into the user address space instead of the original one. Signed-off-by: Xie Yongji <xieyongji@bytedance.com> Acked-by: Jason Wang <jasowang@redhat.com> Link: https://lore.kernel.org/r/20210831103634.33-12-xieyongji@bytedance.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
74 lines
1.9 KiB
C
74 lines
1.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* MMU-based software IOTLB.
|
|
*
|
|
* Copyright (C) 2020-2021 Bytedance Inc. and/or its affiliates. All rights reserved.
|
|
*
|
|
* Author: Xie Yongji <xieyongji@bytedance.com>
|
|
*
|
|
*/
|
|
|
|
#ifndef _VDUSE_IOVA_DOMAIN_H
|
|
#define _VDUSE_IOVA_DOMAIN_H
|
|
|
|
#include <linux/iova.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/vhost_iotlb.h>
|
|
|
|
#define IOVA_START_PFN 1
|
|
|
|
#define INVALID_PHYS_ADDR (~(phys_addr_t)0)
|
|
|
|
struct vduse_bounce_map {
|
|
struct page *bounce_page;
|
|
u64 orig_phys;
|
|
};
|
|
|
|
struct vduse_iova_domain {
|
|
struct iova_domain stream_iovad;
|
|
struct iova_domain consistent_iovad;
|
|
struct vduse_bounce_map *bounce_maps;
|
|
size_t bounce_size;
|
|
unsigned long iova_limit;
|
|
int bounce_map;
|
|
struct vhost_iotlb *iotlb;
|
|
spinlock_t iotlb_lock;
|
|
struct file *file;
|
|
};
|
|
|
|
int vduse_domain_set_map(struct vduse_iova_domain *domain,
|
|
struct vhost_iotlb *iotlb);
|
|
|
|
void vduse_domain_clear_map(struct vduse_iova_domain *domain,
|
|
struct vhost_iotlb *iotlb);
|
|
|
|
dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
|
|
struct page *page, unsigned long offset,
|
|
size_t size, enum dma_data_direction dir,
|
|
unsigned long attrs);
|
|
|
|
void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
|
|
dma_addr_t dma_addr, size_t size,
|
|
enum dma_data_direction dir, unsigned long attrs);
|
|
|
|
void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
|
|
size_t size, dma_addr_t *dma_addr,
|
|
gfp_t flag, unsigned long attrs);
|
|
|
|
void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
|
|
void *vaddr, dma_addr_t dma_addr,
|
|
unsigned long attrs);
|
|
|
|
void vduse_domain_reset_bounce_map(struct vduse_iova_domain *domain);
|
|
|
|
void vduse_domain_destroy(struct vduse_iova_domain *domain);
|
|
|
|
struct vduse_iova_domain *vduse_domain_create(unsigned long iova_limit,
|
|
size_t bounce_size);
|
|
|
|
int vduse_domain_init(void);
|
|
|
|
void vduse_domain_exit(void);
|
|
|
|
#endif /* _VDUSE_IOVA_DOMAIN_H */
|