cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

grant-dma-ops.c (8360B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Xen grant DMA-mapping layer - contains special DMA-mapping routines
      4 * for providing grant references as DMA addresses to be used by frontends
      5 * (e.g. virtio) in Xen guests
      6 *
      7 * Copyright (c) 2021, Juergen Gross <jgross@suse.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/dma-map-ops.h>
     12#include <linux/of.h>
     13#include <linux/pfn.h>
     14#include <linux/xarray.h>
     15#include <xen/xen.h>
     16#include <xen/xen-ops.h>
     17#include <xen/grant_table.h>
     18
     19struct xen_grant_dma_data {
     20	/* The ID of backend domain */
     21	domid_t backend_domid;
     22	/* Is device behaving sane? */
     23	bool broken;
     24};
     25
     26static DEFINE_XARRAY(xen_grant_dma_devices);
     27
     28#define XEN_GRANT_DMA_ADDR_OFF	(1ULL << 63)
     29
     30static inline dma_addr_t grant_to_dma(grant_ref_t grant)
     31{
     32	return XEN_GRANT_DMA_ADDR_OFF | ((dma_addr_t)grant << PAGE_SHIFT);
     33}
     34
     35static inline grant_ref_t dma_to_grant(dma_addr_t dma)
     36{
     37	return (grant_ref_t)((dma & ~XEN_GRANT_DMA_ADDR_OFF) >> PAGE_SHIFT);
     38}
     39
     40static struct xen_grant_dma_data *find_xen_grant_dma_data(struct device *dev)
     41{
     42	struct xen_grant_dma_data *data;
     43
     44	xa_lock(&xen_grant_dma_devices);
     45	data = xa_load(&xen_grant_dma_devices, (unsigned long)dev);
     46	xa_unlock(&xen_grant_dma_devices);
     47
     48	return data;
     49}
     50
     51/*
     52 * DMA ops for Xen frontends (e.g. virtio).
     53 *
     54 * Used to act as a kind of software IOMMU for Xen guests by using grants as
     55 * DMA addresses.
     56 * Such a DMA address is formed by using the grant reference as a frame
     57 * number and setting the highest address bit (this bit is for the backend
     58 * to be able to distinguish it from e.g. a mmio address).
     59 */
     60static void *xen_grant_dma_alloc(struct device *dev, size_t size,
     61				 dma_addr_t *dma_handle, gfp_t gfp,
     62				 unsigned long attrs)
     63{
     64	struct xen_grant_dma_data *data;
     65	unsigned int i, n_pages = PFN_UP(size);
     66	unsigned long pfn;
     67	grant_ref_t grant;
     68	void *ret;
     69
     70	data = find_xen_grant_dma_data(dev);
     71	if (!data)
     72		return NULL;
     73
     74	if (unlikely(data->broken))
     75		return NULL;
     76
     77	ret = alloc_pages_exact(n_pages * PAGE_SIZE, gfp);
     78	if (!ret)
     79		return NULL;
     80
     81	pfn = virt_to_pfn(ret);
     82
     83	if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) {
     84		free_pages_exact(ret, n_pages * PAGE_SIZE);
     85		return NULL;
     86	}
     87
     88	for (i = 0; i < n_pages; i++) {
     89		gnttab_grant_foreign_access_ref(grant + i, data->backend_domid,
     90				pfn_to_gfn(pfn + i), 0);
     91	}
     92
     93	*dma_handle = grant_to_dma(grant);
     94
     95	return ret;
     96}
     97
     98static void xen_grant_dma_free(struct device *dev, size_t size, void *vaddr,
     99			       dma_addr_t dma_handle, unsigned long attrs)
    100{
    101	struct xen_grant_dma_data *data;
    102	unsigned int i, n_pages = PFN_UP(size);
    103	grant_ref_t grant;
    104
    105	data = find_xen_grant_dma_data(dev);
    106	if (!data)
    107		return;
    108
    109	if (unlikely(data->broken))
    110		return;
    111
    112	grant = dma_to_grant(dma_handle);
    113
    114	for (i = 0; i < n_pages; i++) {
    115		if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) {
    116			dev_alert(dev, "Grant still in use by backend domain, disabled for further use\n");
    117			data->broken = true;
    118			return;
    119		}
    120	}
    121
    122	gnttab_free_grant_reference_seq(grant, n_pages);
    123
    124	free_pages_exact(vaddr, n_pages * PAGE_SIZE);
    125}
    126
    127static struct page *xen_grant_dma_alloc_pages(struct device *dev, size_t size,
    128					      dma_addr_t *dma_handle,
    129					      enum dma_data_direction dir,
    130					      gfp_t gfp)
    131{
    132	void *vaddr;
    133
    134	vaddr = xen_grant_dma_alloc(dev, size, dma_handle, gfp, 0);
    135	if (!vaddr)
    136		return NULL;
    137
    138	return virt_to_page(vaddr);
    139}
    140
    141static void xen_grant_dma_free_pages(struct device *dev, size_t size,
    142				     struct page *vaddr, dma_addr_t dma_handle,
    143				     enum dma_data_direction dir)
    144{
    145	xen_grant_dma_free(dev, size, page_to_virt(vaddr), dma_handle, 0);
    146}
    147
    148static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
    149					 unsigned long offset, size_t size,
    150					 enum dma_data_direction dir,
    151					 unsigned long attrs)
    152{
    153	struct xen_grant_dma_data *data;
    154	unsigned int i, n_pages = PFN_UP(size);
    155	grant_ref_t grant;
    156	dma_addr_t dma_handle;
    157
    158	if (WARN_ON(dir == DMA_NONE))
    159		return DMA_MAPPING_ERROR;
    160
    161	data = find_xen_grant_dma_data(dev);
    162	if (!data)
    163		return DMA_MAPPING_ERROR;
    164
    165	if (unlikely(data->broken))
    166		return DMA_MAPPING_ERROR;
    167
    168	if (gnttab_alloc_grant_reference_seq(n_pages, &grant))
    169		return DMA_MAPPING_ERROR;
    170
    171	for (i = 0; i < n_pages; i++) {
    172		gnttab_grant_foreign_access_ref(grant + i, data->backend_domid,
    173				xen_page_to_gfn(page) + i, dir == DMA_TO_DEVICE);
    174	}
    175
    176	dma_handle = grant_to_dma(grant) + offset;
    177
    178	return dma_handle;
    179}
    180
    181static void xen_grant_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
    182				     size_t size, enum dma_data_direction dir,
    183				     unsigned long attrs)
    184{
    185	struct xen_grant_dma_data *data;
    186	unsigned int i, n_pages = PFN_UP(size);
    187	grant_ref_t grant;
    188
    189	if (WARN_ON(dir == DMA_NONE))
    190		return;
    191
    192	data = find_xen_grant_dma_data(dev);
    193	if (!data)
    194		return;
    195
    196	if (unlikely(data->broken))
    197		return;
    198
    199	grant = dma_to_grant(dma_handle);
    200
    201	for (i = 0; i < n_pages; i++) {
    202		if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) {
    203			dev_alert(dev, "Grant still in use by backend domain, disabled for further use\n");
    204			data->broken = true;
    205			return;
    206		}
    207	}
    208
    209	gnttab_free_grant_reference_seq(grant, n_pages);
    210}
    211
    212static void xen_grant_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
    213				   int nents, enum dma_data_direction dir,
    214				   unsigned long attrs)
    215{
    216	struct scatterlist *s;
    217	unsigned int i;
    218
    219	if (WARN_ON(dir == DMA_NONE))
    220		return;
    221
    222	for_each_sg(sg, s, nents, i)
    223		xen_grant_dma_unmap_page(dev, s->dma_address, sg_dma_len(s), dir,
    224				attrs);
    225}
    226
    227static int xen_grant_dma_map_sg(struct device *dev, struct scatterlist *sg,
    228				int nents, enum dma_data_direction dir,
    229				unsigned long attrs)
    230{
    231	struct scatterlist *s;
    232	unsigned int i;
    233
    234	if (WARN_ON(dir == DMA_NONE))
    235		return -EINVAL;
    236
    237	for_each_sg(sg, s, nents, i) {
    238		s->dma_address = xen_grant_dma_map_page(dev, sg_page(s), s->offset,
    239				s->length, dir, attrs);
    240		if (s->dma_address == DMA_MAPPING_ERROR)
    241			goto out;
    242
    243		sg_dma_len(s) = s->length;
    244	}
    245
    246	return nents;
    247
    248out:
    249	xen_grant_dma_unmap_sg(dev, sg, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC);
    250	sg_dma_len(sg) = 0;
    251
    252	return -EIO;
    253}
    254
    255static int xen_grant_dma_supported(struct device *dev, u64 mask)
    256{
    257	return mask == DMA_BIT_MASK(64);
    258}
    259
    260static const struct dma_map_ops xen_grant_dma_ops = {
    261	.alloc = xen_grant_dma_alloc,
    262	.free = xen_grant_dma_free,
    263	.alloc_pages = xen_grant_dma_alloc_pages,
    264	.free_pages = xen_grant_dma_free_pages,
    265	.mmap = dma_common_mmap,
    266	.get_sgtable = dma_common_get_sgtable,
    267	.map_page = xen_grant_dma_map_page,
    268	.unmap_page = xen_grant_dma_unmap_page,
    269	.map_sg = xen_grant_dma_map_sg,
    270	.unmap_sg = xen_grant_dma_unmap_sg,
    271	.dma_supported = xen_grant_dma_supported,
    272};
    273
    274bool xen_is_grant_dma_device(struct device *dev)
    275{
    276	struct device_node *iommu_np;
    277	bool has_iommu;
    278
    279	/* XXX Handle only DT devices for now */
    280	if (!dev->of_node)
    281		return false;
    282
    283	iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
    284	has_iommu = iommu_np && of_device_is_compatible(iommu_np, "xen,grant-dma");
    285	of_node_put(iommu_np);
    286
    287	return has_iommu;
    288}
    289
    290void xen_grant_setup_dma_ops(struct device *dev)
    291{
    292	struct xen_grant_dma_data *data;
    293	struct of_phandle_args iommu_spec;
    294
    295	data = find_xen_grant_dma_data(dev);
    296	if (data) {
    297		dev_err(dev, "Xen grant DMA data is already created\n");
    298		return;
    299	}
    300
    301	/* XXX ACPI device unsupported for now */
    302	if (!dev->of_node)
    303		goto err;
    304
    305	if (of_parse_phandle_with_args(dev->of_node, "iommus", "#iommu-cells",
    306			0, &iommu_spec)) {
    307		dev_err(dev, "Cannot parse iommus property\n");
    308		goto err;
    309	}
    310
    311	if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") ||
    312			iommu_spec.args_count != 1) {
    313		dev_err(dev, "Incompatible IOMMU node\n");
    314		of_node_put(iommu_spec.np);
    315		goto err;
    316	}
    317
    318	of_node_put(iommu_spec.np);
    319
    320	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    321	if (!data)
    322		goto err;
    323
    324	/*
    325	 * The endpoint ID here means the ID of the domain where the corresponding
    326	 * backend is running
    327	 */
    328	data->backend_domid = iommu_spec.args[0];
    329
    330	if (xa_err(xa_store(&xen_grant_dma_devices, (unsigned long)dev, data,
    331			GFP_KERNEL))) {
    332		dev_err(dev, "Cannot store Xen grant DMA data\n");
    333		goto err;
    334	}
    335
    336	dev->dma_ops = &xen_grant_dma_ops;
    337
    338	return;
    339
    340err:
    341	dev_err(dev, "Cannot set up Xen grant DMA ops, retain platform DMA ops\n");
    342}
    343
    344MODULE_DESCRIPTION("Xen grant DMA-mapping layer");
    345MODULE_AUTHOR("Juergen Gross <jgross@suse.com>");
    346MODULE_LICENSE("GPL");