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

xen-front-pgdir-shbuf.c (14558B)


      1// SPDX-License-Identifier: GPL-2.0 OR MIT
      2
      3/*
      4 * Xen frontend/backend page directory based shared buffer
      5 * helper module.
      6 *
      7 * Copyright (C) 2018 EPAM Systems Inc.
      8 *
      9 * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/errno.h>
     14#include <linux/mm.h>
     15
     16#include <asm/xen/hypervisor.h>
     17#include <xen/balloon.h>
     18#include <xen/xen.h>
     19#include <xen/xenbus.h>
     20#include <xen/interface/io/ring.h>
     21
     22#include <xen/xen-front-pgdir-shbuf.h>
     23
     24/**
     25 * This structure represents the structure of a shared page
     26 * that contains grant references to the pages of the shared
     27 * buffer. This structure is common to many Xen para-virtualized
     28 * protocols at include/xen/interface/io/
     29 */
     30struct xen_page_directory {
     31	grant_ref_t gref_dir_next_page;
     32#define XEN_GREF_LIST_END	0
     33	grant_ref_t gref[1]; /* Variable length */
     34};
     35
     36/**
     37 * Shared buffer ops which are differently implemented
     38 * depending on the allocation mode, e.g. if the buffer
     39 * is allocated by the corresponding backend or frontend.
     40 * Some of the operations.
     41 */
     42struct xen_front_pgdir_shbuf_ops {
     43	/*
     44	 * Calculate number of grefs required to handle this buffer,
     45	 * e.g. if grefs are required for page directory only or the buffer
     46	 * pages as well.
     47	 */
     48	void (*calc_num_grefs)(struct xen_front_pgdir_shbuf *buf);
     49
     50	/* Fill page directory according to para-virtual display protocol. */
     51	void (*fill_page_dir)(struct xen_front_pgdir_shbuf *buf);
     52
     53	/* Claim grant references for the pages of the buffer. */
     54	int (*grant_refs_for_buffer)(struct xen_front_pgdir_shbuf *buf,
     55				     grant_ref_t *priv_gref_head, int gref_idx);
     56
     57	/* Map grant references of the buffer. */
     58	int (*map)(struct xen_front_pgdir_shbuf *buf);
     59
     60	/* Unmap grant references of the buffer. */
     61	int (*unmap)(struct xen_front_pgdir_shbuf *buf);
     62};
     63
     64/**
     65 * Get granted reference to the very first page of the
     66 * page directory. Usually this is passed to the backend,
     67 * so it can find/fill the grant references to the buffer's
     68 * pages.
     69 *
     70 * \param buf shared buffer which page directory is of interest.
     71 * \return granted reference to the very first page of the
     72 * page directory.
     73 */
     74grant_ref_t
     75xen_front_pgdir_shbuf_get_dir_start(struct xen_front_pgdir_shbuf *buf)
     76{
     77	if (!buf->grefs)
     78		return INVALID_GRANT_REF;
     79
     80	return buf->grefs[0];
     81}
     82EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_get_dir_start);
     83
     84/**
     85 * Map granted references of the shared buffer.
     86 *
     87 * Depending on the shared buffer mode of allocation
     88 * (be_alloc flag) this can either do nothing (for buffers
     89 * shared by the frontend itself) or map the provided granted
     90 * references onto the backing storage (buf->pages).
     91 *
     92 * \param buf shared buffer which grants to be maped.
     93 * \return zero on success or a negative number on failure.
     94 */
     95int xen_front_pgdir_shbuf_map(struct xen_front_pgdir_shbuf *buf)
     96{
     97	if (buf->ops && buf->ops->map)
     98		return buf->ops->map(buf);
     99
    100	/* No need to map own grant references. */
    101	return 0;
    102}
    103EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_map);
    104
    105/**
    106 * Unmap granted references of the shared buffer.
    107 *
    108 * Depending on the shared buffer mode of allocation
    109 * (be_alloc flag) this can either do nothing (for buffers
    110 * shared by the frontend itself) or unmap the provided granted
    111 * references.
    112 *
    113 * \param buf shared buffer which grants to be unmaped.
    114 * \return zero on success or a negative number on failure.
    115 */
    116int xen_front_pgdir_shbuf_unmap(struct xen_front_pgdir_shbuf *buf)
    117{
    118	if (buf->ops && buf->ops->unmap)
    119		return buf->ops->unmap(buf);
    120
    121	/* No need to unmap own grant references. */
    122	return 0;
    123}
    124EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_unmap);
    125
    126/**
    127 * Free all the resources of the shared buffer.
    128 *
    129 * \param buf shared buffer which resources to be freed.
    130 */
    131void xen_front_pgdir_shbuf_free(struct xen_front_pgdir_shbuf *buf)
    132{
    133	if (buf->grefs) {
    134		int i;
    135
    136		for (i = 0; i < buf->num_grefs; i++)
    137			if (buf->grefs[i] != INVALID_GRANT_REF)
    138				gnttab_end_foreign_access(buf->grefs[i], NULL);
    139	}
    140	kfree(buf->grefs);
    141	kfree(buf->directory);
    142}
    143EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_free);
    144
    145/*
    146 * Number of grefs a page can hold with respect to the
    147 * struct xen_page_directory header.
    148 */
    149#define XEN_NUM_GREFS_PER_PAGE ((PAGE_SIZE - \
    150				 offsetof(struct xen_page_directory, \
    151					  gref)) / sizeof(grant_ref_t))
    152
    153/**
    154 * Get the number of pages the page directory consumes itself.
    155 *
    156 * \param buf shared buffer.
    157 */
    158static int get_num_pages_dir(struct xen_front_pgdir_shbuf *buf)
    159{
    160	return DIV_ROUND_UP(buf->num_pages, XEN_NUM_GREFS_PER_PAGE);
    161}
    162
    163/**
    164 * Calculate the number of grant references needed to share the buffer
    165 * and its pages when backend allocates the buffer.
    166 *
    167 * \param buf shared buffer.
    168 */
    169static void backend_calc_num_grefs(struct xen_front_pgdir_shbuf *buf)
    170{
    171	/* Only for pages the page directory consumes itself. */
    172	buf->num_grefs = get_num_pages_dir(buf);
    173}
    174
    175/**
    176 * Calculate the number of grant references needed to share the buffer
    177 * and its pages when frontend allocates the buffer.
    178 *
    179 * \param buf shared buffer.
    180 */
    181static void guest_calc_num_grefs(struct xen_front_pgdir_shbuf *buf)
    182{
    183	/*
    184	 * Number of pages the page directory consumes itself
    185	 * plus grefs for the buffer pages.
    186	 */
    187	buf->num_grefs = get_num_pages_dir(buf) + buf->num_pages;
    188}
    189
    190#define xen_page_to_vaddr(page) \
    191	((uintptr_t)pfn_to_kaddr(page_to_xen_pfn(page)))
    192
    193/**
    194 * Unmap the buffer previously mapped with grant references
    195 * provided by the backend.
    196 *
    197 * \param buf shared buffer.
    198 * \return zero on success or a negative number on failure.
    199 */
    200static int backend_unmap(struct xen_front_pgdir_shbuf *buf)
    201{
    202	struct gnttab_unmap_grant_ref *unmap_ops;
    203	int i, ret;
    204
    205	if (!buf->pages || !buf->backend_map_handles || !buf->grefs)
    206		return 0;
    207
    208	unmap_ops = kcalloc(buf->num_pages, sizeof(*unmap_ops),
    209			    GFP_KERNEL);
    210	if (!unmap_ops)
    211		return -ENOMEM;
    212
    213	for (i = 0; i < buf->num_pages; i++) {
    214		phys_addr_t addr;
    215
    216		addr = xen_page_to_vaddr(buf->pages[i]);
    217		gnttab_set_unmap_op(&unmap_ops[i], addr, GNTMAP_host_map,
    218				    buf->backend_map_handles[i]);
    219	}
    220
    221	ret = gnttab_unmap_refs(unmap_ops, NULL, buf->pages,
    222				buf->num_pages);
    223
    224	for (i = 0; i < buf->num_pages; i++) {
    225		if (unlikely(unmap_ops[i].status != GNTST_okay))
    226			dev_err(&buf->xb_dev->dev,
    227				"Failed to unmap page %d: %d\n",
    228				i, unmap_ops[i].status);
    229	}
    230
    231	if (ret)
    232		dev_err(&buf->xb_dev->dev,
    233			"Failed to unmap grant references, ret %d", ret);
    234
    235	kfree(unmap_ops);
    236	kfree(buf->backend_map_handles);
    237	buf->backend_map_handles = NULL;
    238	return ret;
    239}
    240
    241/**
    242 * Map the buffer with grant references provided by the backend.
    243 *
    244 * \param buf shared buffer.
    245 * \return zero on success or a negative number on failure.
    246 */
    247static int backend_map(struct xen_front_pgdir_shbuf *buf)
    248{
    249	struct gnttab_map_grant_ref *map_ops = NULL;
    250	unsigned char *ptr;
    251	int ret, cur_gref, cur_dir_page, cur_page, grefs_left;
    252
    253	map_ops = kcalloc(buf->num_pages, sizeof(*map_ops), GFP_KERNEL);
    254	if (!map_ops)
    255		return -ENOMEM;
    256
    257	buf->backend_map_handles = kcalloc(buf->num_pages,
    258					   sizeof(*buf->backend_map_handles),
    259					   GFP_KERNEL);
    260	if (!buf->backend_map_handles) {
    261		kfree(map_ops);
    262		return -ENOMEM;
    263	}
    264
    265	/*
    266	 * Read page directory to get grefs from the backend: for external
    267	 * buffer we only allocate buf->grefs for the page directory,
    268	 * so buf->num_grefs has number of pages in the page directory itself.
    269	 */
    270	ptr = buf->directory;
    271	grefs_left = buf->num_pages;
    272	cur_page = 0;
    273	for (cur_dir_page = 0; cur_dir_page < buf->num_grefs; cur_dir_page++) {
    274		struct xen_page_directory *page_dir =
    275			(struct xen_page_directory *)ptr;
    276		int to_copy = XEN_NUM_GREFS_PER_PAGE;
    277
    278		if (to_copy > grefs_left)
    279			to_copy = grefs_left;
    280
    281		for (cur_gref = 0; cur_gref < to_copy; cur_gref++) {
    282			phys_addr_t addr;
    283
    284			addr = xen_page_to_vaddr(buf->pages[cur_page]);
    285			gnttab_set_map_op(&map_ops[cur_page], addr,
    286					  GNTMAP_host_map,
    287					  page_dir->gref[cur_gref],
    288					  buf->xb_dev->otherend_id);
    289			cur_page++;
    290		}
    291
    292		grefs_left -= to_copy;
    293		ptr += PAGE_SIZE;
    294	}
    295	ret = gnttab_map_refs(map_ops, NULL, buf->pages, buf->num_pages);
    296
    297	/* Save handles even if error, so we can unmap. */
    298	for (cur_page = 0; cur_page < buf->num_pages; cur_page++) {
    299		if (likely(map_ops[cur_page].status == GNTST_okay)) {
    300			buf->backend_map_handles[cur_page] =
    301				map_ops[cur_page].handle;
    302		} else {
    303			buf->backend_map_handles[cur_page] =
    304				INVALID_GRANT_HANDLE;
    305			if (!ret)
    306				ret = -ENXIO;
    307			dev_err(&buf->xb_dev->dev,
    308				"Failed to map page %d: %d\n",
    309				cur_page, map_ops[cur_page].status);
    310		}
    311	}
    312
    313	if (ret) {
    314		dev_err(&buf->xb_dev->dev,
    315			"Failed to map grant references, ret %d", ret);
    316		backend_unmap(buf);
    317	}
    318
    319	kfree(map_ops);
    320	return ret;
    321}
    322
    323/**
    324 * Fill page directory with grant references to the pages of the
    325 * page directory itself.
    326 *
    327 * The grant references to the buffer pages are provided by the
    328 * backend in this case.
    329 *
    330 * \param buf shared buffer.
    331 */
    332static void backend_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
    333{
    334	struct xen_page_directory *page_dir;
    335	unsigned char *ptr;
    336	int i, num_pages_dir;
    337
    338	ptr = buf->directory;
    339	num_pages_dir = get_num_pages_dir(buf);
    340
    341	/* Fill only grefs for the page directory itself. */
    342	for (i = 0; i < num_pages_dir - 1; i++) {
    343		page_dir = (struct xen_page_directory *)ptr;
    344
    345		page_dir->gref_dir_next_page = buf->grefs[i + 1];
    346		ptr += PAGE_SIZE;
    347	}
    348	/* Last page must say there is no more pages. */
    349	page_dir = (struct xen_page_directory *)ptr;
    350	page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
    351}
    352
    353/**
    354 * Fill page directory with grant references to the pages of the
    355 * page directory and the buffer we share with the backend.
    356 *
    357 * \param buf shared buffer.
    358 */
    359static void guest_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
    360{
    361	unsigned char *ptr;
    362	int cur_gref, grefs_left, to_copy, i, num_pages_dir;
    363
    364	ptr = buf->directory;
    365	num_pages_dir = get_num_pages_dir(buf);
    366
    367	/*
    368	 * While copying, skip grefs at start, they are for pages
    369	 * granted for the page directory itself.
    370	 */
    371	cur_gref = num_pages_dir;
    372	grefs_left = buf->num_pages;
    373	for (i = 0; i < num_pages_dir; i++) {
    374		struct xen_page_directory *page_dir =
    375			(struct xen_page_directory *)ptr;
    376
    377		if (grefs_left <= XEN_NUM_GREFS_PER_PAGE) {
    378			to_copy = grefs_left;
    379			page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
    380		} else {
    381			to_copy = XEN_NUM_GREFS_PER_PAGE;
    382			page_dir->gref_dir_next_page = buf->grefs[i + 1];
    383		}
    384		memcpy(&page_dir->gref, &buf->grefs[cur_gref],
    385		       to_copy * sizeof(grant_ref_t));
    386		ptr += PAGE_SIZE;
    387		grefs_left -= to_copy;
    388		cur_gref += to_copy;
    389	}
    390}
    391
    392/**
    393 * Grant references to the frontend's buffer pages.
    394 *
    395 * These will be shared with the backend, so it can
    396 * access the buffer's data.
    397 *
    398 * \param buf shared buffer.
    399 * \return zero on success or a negative number on failure.
    400 */
    401static int guest_grant_refs_for_buffer(struct xen_front_pgdir_shbuf *buf,
    402				       grant_ref_t *priv_gref_head,
    403				       int gref_idx)
    404{
    405	int i, cur_ref, otherend_id;
    406
    407	otherend_id = buf->xb_dev->otherend_id;
    408	for (i = 0; i < buf->num_pages; i++) {
    409		cur_ref = gnttab_claim_grant_reference(priv_gref_head);
    410		if (cur_ref < 0)
    411			return cur_ref;
    412
    413		gnttab_grant_foreign_access_ref(cur_ref, otherend_id,
    414						xen_page_to_gfn(buf->pages[i]),
    415						0);
    416		buf->grefs[gref_idx++] = cur_ref;
    417	}
    418	return 0;
    419}
    420
    421/**
    422 * Grant all the references needed to share the buffer.
    423 *
    424 * Grant references to the page directory pages and, if
    425 * needed, also to the pages of the shared buffer data.
    426 *
    427 * \param buf shared buffer.
    428 * \return zero on success or a negative number on failure.
    429 */
    430static int grant_references(struct xen_front_pgdir_shbuf *buf)
    431{
    432	grant_ref_t priv_gref_head;
    433	int ret, i, j, cur_ref;
    434	int otherend_id, num_pages_dir;
    435
    436	ret = gnttab_alloc_grant_references(buf->num_grefs, &priv_gref_head);
    437	if (ret < 0) {
    438		dev_err(&buf->xb_dev->dev,
    439			"Cannot allocate grant references\n");
    440		return ret;
    441	}
    442
    443	otherend_id = buf->xb_dev->otherend_id;
    444	j = 0;
    445	num_pages_dir = get_num_pages_dir(buf);
    446	for (i = 0; i < num_pages_dir; i++) {
    447		unsigned long frame;
    448
    449		cur_ref = gnttab_claim_grant_reference(&priv_gref_head);
    450		if (cur_ref < 0)
    451			return cur_ref;
    452
    453		frame = xen_page_to_gfn(virt_to_page(buf->directory +
    454						     PAGE_SIZE * i));
    455		gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0);
    456		buf->grefs[j++] = cur_ref;
    457	}
    458
    459	if (buf->ops->grant_refs_for_buffer) {
    460		ret = buf->ops->grant_refs_for_buffer(buf, &priv_gref_head, j);
    461		if (ret)
    462			return ret;
    463	}
    464
    465	gnttab_free_grant_references(priv_gref_head);
    466	return 0;
    467}
    468
    469/**
    470 * Allocate all required structures to mange shared buffer.
    471 *
    472 * \param buf shared buffer.
    473 * \return zero on success or a negative number on failure.
    474 */
    475static int alloc_storage(struct xen_front_pgdir_shbuf *buf)
    476{
    477	buf->grefs = kcalloc(buf->num_grefs, sizeof(*buf->grefs), GFP_KERNEL);
    478	if (!buf->grefs)
    479		return -ENOMEM;
    480
    481	buf->directory = kcalloc(get_num_pages_dir(buf), PAGE_SIZE, GFP_KERNEL);
    482	if (!buf->directory)
    483		return -ENOMEM;
    484
    485	return 0;
    486}
    487
    488/*
    489 * For backend allocated buffers we don't need grant_refs_for_buffer
    490 * as those grant references are allocated at backend side.
    491 */
    492static const struct xen_front_pgdir_shbuf_ops backend_ops = {
    493	.calc_num_grefs = backend_calc_num_grefs,
    494	.fill_page_dir = backend_fill_page_dir,
    495	.map = backend_map,
    496	.unmap = backend_unmap
    497};
    498
    499/*
    500 * For locally granted references we do not need to map/unmap
    501 * the references.
    502 */
    503static const struct xen_front_pgdir_shbuf_ops local_ops = {
    504	.calc_num_grefs = guest_calc_num_grefs,
    505	.fill_page_dir = guest_fill_page_dir,
    506	.grant_refs_for_buffer = guest_grant_refs_for_buffer,
    507};
    508
    509/**
    510 * Allocate a new instance of a shared buffer.
    511 *
    512 * \param cfg configuration to be used while allocating a new shared buffer.
    513 * \return zero on success or a negative number on failure.
    514 */
    515int xen_front_pgdir_shbuf_alloc(struct xen_front_pgdir_shbuf_cfg *cfg)
    516{
    517	struct xen_front_pgdir_shbuf *buf = cfg->pgdir;
    518	int ret;
    519
    520	if (cfg->be_alloc)
    521		buf->ops = &backend_ops;
    522	else
    523		buf->ops = &local_ops;
    524	buf->xb_dev = cfg->xb_dev;
    525	buf->num_pages = cfg->num_pages;
    526	buf->pages = cfg->pages;
    527
    528	buf->ops->calc_num_grefs(buf);
    529
    530	ret = alloc_storage(buf);
    531	if (ret)
    532		goto fail;
    533
    534	ret = grant_references(buf);
    535	if (ret)
    536		goto fail;
    537
    538	buf->ops->fill_page_dir(buf);
    539
    540	return 0;
    541
    542fail:
    543	xen_front_pgdir_shbuf_free(buf);
    544	return ret;
    545}
    546EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_alloc);
    547
    548MODULE_DESCRIPTION("Xen frontend/backend page directory based "
    549		   "shared buffer handling");
    550MODULE_AUTHOR("Oleksandr Andrushchenko");
    551MODULE_LICENSE("GPL");