Re: [RFC PATCH 01/60] hyper_dmabuf: initial working version of hyper_dmabuf drv

From: Dongwon Kim
Date: Wed Feb 14 2018 - 20:37:10 EST


Abandoning this series as a new version was submitted for the review

"[RFC PATCH v2 0/9] hyper_dmabuf: Hyper_DMABUF driver"

On Tue, Dec 19, 2017 at 11:29:17AM -0800, Kim, Dongwon wrote:
> Upload of intial version of hyper_DMABUF driver enabling
> DMA_BUF exchange between two different VMs in virtualized
> platform based on hypervisor such as KVM or XEN.
>
> Hyper_DMABUF drv's primary role is to import a DMA_BUF
> from originator then re-export it to another Linux VM
> so that it can be mapped and accessed by it.
>
> The functionality of this driver highly depends on
> Hypervisor's native page sharing mechanism and inter-VM
> communication support.
>
> This driver has two layers, one is main hyper_DMABUF
> framework for scatter-gather list management that handles
> actual import and export of DMA_BUF. Lower layer is about
> actual memory sharing and communication between two VMs,
> which is hypervisor-specific interface.
>
> This driver is initially designed to enable DMA_BUF
> sharing across VMs in Xen environment, so currently working
> with Xen only.
>
> This also adds Kernel configuration for hyper_DMABUF drv
> under Device Drivers->Xen driver support->hyper_dmabuf
> options.
>
> To give some brief information about each source file,
>
> hyper_dmabuf/hyper_dmabuf_conf.h
> : configuration info
>
> hyper_dmabuf/hyper_dmabuf_drv.c
> : driver interface and initialization
>
> hyper_dmabuf/hyper_dmabuf_imp.c
> : scatter-gather list generation and management. DMA_BUF
> ops for DMA_BUF reconstructed from hyper_DMABUF
>
> hyper_dmabuf/hyper_dmabuf_ioctl.c
> : IOCTLs calls for export/import and comm channel creation
> unexport.
>
> hyper_dmabuf/hyper_dmabuf_list.c
> : Database (linked-list) for exported and imported
> hyper_DMABUF
>
> hyper_dmabuf/hyper_dmabuf_msg.c
> : creation and management of messages between exporter and
> importer
>
> hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c
> : comm ch management and ISRs for incoming messages.
>
> hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c
> : Database (linked-list) for keeping information about
> existing comm channels among VMs
>
> Signed-off-by: Dongwon Kim <dongwon.kim@xxxxxxxxx>
> Signed-off-by: Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
> ---
> drivers/xen/Kconfig | 2 +
> drivers/xen/Makefile | 1 +
> drivers/xen/hyper_dmabuf/Kconfig | 14 +
> drivers/xen/hyper_dmabuf/Makefile | 34 +
> drivers/xen/hyper_dmabuf/hyper_dmabuf_conf.h | 2 +
> drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.c | 54 ++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.h | 101 +++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.c | 852 +++++++++++++++++++++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.h | 31 +
> drivers/xen/hyper_dmabuf/hyper_dmabuf_ioctl.c | 462 +++++++++++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_list.c | 119 +++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_list.h | 40 +
> drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.c | 212 +++++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.h | 45 ++
> drivers/xen/hyper_dmabuf/hyper_dmabuf_query.h | 16 +
> drivers/xen/hyper_dmabuf/hyper_dmabuf_struct.h | 70 ++
> .../xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c | 328 ++++++++
> .../xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.h | 62 ++
> .../hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c | 106 +++
> .../hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.h | 35 +
> 20 files changed, 2586 insertions(+)
> create mode 100644 drivers/xen/hyper_dmabuf/Kconfig
> create mode 100644 drivers/xen/hyper_dmabuf/Makefile
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_conf.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.c
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.c
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_ioctl.c
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_list.c
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_list.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.c
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_query.h
> create mode 100644 drivers/xen/hyper_dmabuf/hyper_dmabuf_struct.h
> create mode 100644 drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c
> create mode 100644 drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.h
> create mode 100644 drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c
> create mode 100644 drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.h
>
> diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
> index d8dd546..b59b0e3 100644
> --- a/drivers/xen/Kconfig
> +++ b/drivers/xen/Kconfig
> @@ -321,4 +321,6 @@ config XEN_SYMS
> config XEN_HAVE_VPMU
> bool
>
> +source "drivers/xen/hyper_dmabuf/Kconfig"
> +
> endmenu
> diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
> index 451e833..a6e253a 100644
> --- a/drivers/xen/Makefile
> +++ b/drivers/xen/Makefile
> @@ -4,6 +4,7 @@ obj-$(CONFIG_X86) += fallback.o
> obj-y += grant-table.o features.o balloon.o manage.o preempt.o time.o
> obj-y += events/
> obj-y += xenbus/
> +obj-y += hyper_dmabuf/
>
> nostackp := $(call cc-option, -fno-stack-protector)
> CFLAGS_features.o := $(nostackp)
> diff --git a/drivers/xen/hyper_dmabuf/Kconfig b/drivers/xen/hyper_dmabuf/Kconfig
> new file mode 100644
> index 0000000..75e1f96
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/Kconfig
> @@ -0,0 +1,14 @@
> +menu "hyper_dmabuf options"
> +
> +config HYPER_DMABUF
> + tristate "Enables hyper dmabuf driver"
> + default y
> +
> +config HYPER_DMABUF_XEN
> + bool "Configure hyper_dmabuf for XEN hypervisor"
> + default y
> + depends on HYPER_DMABUF
> + help
> + Configuring hyper_dmabuf driver for XEN hypervisor
> +
> +endmenu
> diff --git a/drivers/xen/hyper_dmabuf/Makefile b/drivers/xen/hyper_dmabuf/Makefile
> new file mode 100644
> index 0000000..0be7445
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/Makefile
> @@ -0,0 +1,34 @@
> +TARGET_MODULE:=hyper_dmabuf
> +
> +# If we running by kernel building system
> +ifneq ($(KERNELRELEASE),)
> + $(TARGET_MODULE)-objs := hyper_dmabuf_drv.o \
> + hyper_dmabuf_ioctl.o \
> + hyper_dmabuf_list.o \
> + hyper_dmabuf_imp.o \
> + hyper_dmabuf_msg.o \
> + xen/hyper_dmabuf_xen_comm.o \
> + xen/hyper_dmabuf_xen_comm_list.o
> +
> +obj-$(CONFIG_HYPER_DMABUF) := $(TARGET_MODULE).o
> +
> +# If we are running without kernel build system
> +else
> +BUILDSYSTEM_DIR?=../../../
> +PWD:=$(shell pwd)
> +
> +all :
> +# run kernel build system to make module
> +$(MAKE) -C $(BUILDSYSTEM_DIR) M=$(PWD) modules
> +
> +clean:
> +# run kernel build system to cleanup in current directory
> +$(MAKE) -C $(BUILDSYSTEM_DIR) M=$(PWD) clean
> +
> +load:
> + insmod ./$(TARGET_MODULE).ko
> +
> +unload:
> + rmmod ./$(TARGET_MODULE).ko
> +
> +endif
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_conf.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_conf.h
> new file mode 100644
> index 0000000..3d9b2d6
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_conf.h
> @@ -0,0 +1,2 @@
> +#define CURRENT_TARGET XEN
> +#define INTER_DOMAIN_DMABUF_SYNCHRONIZATION
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.c b/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.c
> new file mode 100644
> index 0000000..0698327
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.c
> @@ -0,0 +1,54 @@
> +#include <linux/init.h> /* module_init, module_exit */
> +#include <linux/module.h> /* version info, MODULE_LICENSE, MODULE_AUTHOR, printk() */
> +#include "hyper_dmabuf_conf.h"
> +#include "hyper_dmabuf_list.h"
> +#include "xen/hyper_dmabuf_xen_comm_list.h"
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_AUTHOR("IOTG-PED, INTEL");
> +
> +int register_device(void);
> +int unregister_device(void);
> +
> +/*===============================================================================================*/
> +static int hyper_dmabuf_drv_init(void)
> +{
> + int ret = 0;
> +
> + printk( KERN_NOTICE "hyper_dmabuf_starting: Initialization started" );
> +
> + ret = register_device();
> + if (ret < 0) {
> + return -EINVAL;
> + }
> +
> + printk( KERN_NOTICE "initializing database for imported/exported dmabufs\n");
> +
> + ret = hyper_dmabuf_table_init();
> + if (ret < 0) {
> + return -EINVAL;
> + }
> +
> + ret = hyper_dmabuf_ring_table_init();
> + if (ret < 0) {
> + return -EINVAL;
> + }
> +
> + /* interrupt for comm should be registered here: */
> + return ret;
> +}
> +
> +/*-----------------------------------------------------------------------------------------------*/
> +static void hyper_dmabuf_drv_exit(void)
> +{
> + /* hash tables for export/import entries and ring_infos */
> + hyper_dmabuf_table_destroy();
> + hyper_dmabuf_ring_table_init();
> +
> + printk( KERN_NOTICE "dma_buf-src_sink model: Exiting" );
> + unregister_device();
> +}
> +/*===============================================================================================*/
> +
> +module_init(hyper_dmabuf_drv_init);
> +module_exit(hyper_dmabuf_drv_exit);
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.h
> new file mode 100644
> index 0000000..2dad9a6
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_drv.h
> @@ -0,0 +1,101 @@
> +#ifndef __LINUX_PUBLIC_HYPER_DMABUF_DRV_H__
> +#define __LINUX_PUBLIC_HYPER_DMABUF_DRV_H__
> +
> +typedef int (*hyper_dmabuf_ioctl_t)(void *data);
> +
> +struct hyper_dmabuf_ioctl_desc {
> + unsigned int cmd;
> + int flags;
> + hyper_dmabuf_ioctl_t func;
> + const char *name;
> +};
> +
> +#define HYPER_DMABUF_IOCTL_DEF(ioctl, _func, _flags) \
> + [_IOC_NR(ioctl)] = { \
> + .cmd = ioctl, \
> + .func = _func, \
> + .flags = _flags, \
> + .name = #ioctl \
> + }
> +
> +#define IOCTL_HYPER_DMABUF_EXPORTER_RING_SETUP \
> +_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_hyper_dmabuf_exporter_ring_setup))
> +struct ioctl_hyper_dmabuf_exporter_ring_setup {
> + /* IN parameters */
> + /* Remote domain id */
> + uint32_t remote_domain;
> + grant_ref_t ring_refid; /* assigned by driver, copied to userspace after initialization */
> + uint32_t port; /* assigned by driver, copied to userspace after initialization */
> +};
> +
> +#define IOCTL_HYPER_DMABUF_IMPORTER_RING_SETUP \
> +_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_hyper_dmabuf_importer_ring_setup))
> +struct ioctl_hyper_dmabuf_importer_ring_setup {
> + /* IN parameters */
> + /* Source domain id */
> + uint32_t source_domain;
> + /* Ring shared page refid */
> + grant_ref_t ring_refid;
> + /* Port number */
> + uint32_t port;
> +};
> +
> +#define IOCTL_HYPER_DMABUF_EXPORT_REMOTE \
> +_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_hyper_dmabuf_export_remote))
> +struct ioctl_hyper_dmabuf_export_remote {
> + /* IN parameters */
> + /* DMA buf fd to be exported */
> + uint32_t dmabuf_fd;
> + /* Domain id to which buffer should be exported */
> + uint32_t remote_domain;
> + /* exported dma buf id */
> + uint32_t hyper_dmabuf_id;
> + uint32_t private[4];
> +};
> +
> +#define IOCTL_HYPER_DMABUF_EXPORT_FD \
> +_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_hyper_dmabuf_export_fd))
> +struct ioctl_hyper_dmabuf_export_fd {
> + /* IN parameters */
> + /* hyper dmabuf id to be imported */
> + uint32_t hyper_dmabuf_id;
> + /* flags */
> + uint32_t flags;
> + /* OUT parameters */
> + /* exported dma buf fd */
> + uint32_t fd;
> +};
> +
> +#define IOCTL_HYPER_DMABUF_DESTROY \
> +_IOC(_IOC_NONE, 'G', 4, sizeof(struct ioctl_hyper_dmabuf_destroy))
> +struct ioctl_hyper_dmabuf_destroy {
> + /* IN parameters */
> + /* hyper dmabuf id to be destroyed */
> + uint32_t hyper_dmabuf_id;
> + /* OUT parameters */
> + /* Status of request */
> + uint32_t status;
> +};
> +
> +#define IOCTL_HYPER_DMABUF_QUERY \
> +_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_hyper_dmabuf_query))
> +struct ioctl_hyper_dmabuf_query {
> + /* in parameters */
> + /* hyper dmabuf id to be queried */
> + uint32_t hyper_dmabuf_id;
> + /* item to be queried */
> + uint32_t item;
> + /* OUT parameters */
> + /* Value of queried item */
> + uint32_t info;
> +};
> +
> +#define IOCTL_HYPER_DMABUF_REMOTE_EXPORTER_RING_SETUP \
> +_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_hyper_dmabuf_remote_exporter_ring_setup))
> +struct ioctl_hyper_dmabuf_remote_exporter_ring_setup {
> + /* in parameters */
> + uint32_t rdomain; /* id of remote domain where exporter's ring need to be setup */
> + uint32_t info;
> +};
> +
> +#endif //__LINUX_PUBLIC_HYPER_DMABUF_DRV_H__
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.c b/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.c
> new file mode 100644
> index 0000000..faa5c1b
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.c
> @@ -0,0 +1,852 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/dma-buf.h>
> +#include <xen/grant_table.h>
> +#include <asm/xen/page.h>
> +#include "hyper_dmabuf_struct.h"
> +#include "hyper_dmabuf_imp.h"
> +#include "xen/hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_msg.h"
> +
> +#define REFS_PER_PAGE (PAGE_SIZE/sizeof(grant_ref_t))
> +
> +/* return total number of pages referecned by a sgt
> + * for pre-calculation of # of pages behind a given sgt
> + */
> +static int hyper_dmabuf_get_num_pgs(struct sg_table *sgt)
> +{
> + struct scatterlist *sgl;
> + int length, i;
> + /* at least one page */
> + int num_pages = 1;
> +
> + sgl = sgt->sgl;
> +
> + length = sgl->length - PAGE_SIZE + sgl->offset;
> + num_pages += ((length + PAGE_SIZE - 1)/PAGE_SIZE); /* round-up */
> +
> + for (i = 1; i < sgt->nents; i++) {
> + sgl = sg_next(sgl);
> + num_pages += ((sgl->length + PAGE_SIZE - 1) / PAGE_SIZE); /* round-up */
> + }
> +
> + return num_pages;
> +}
> +
> +/* extract pages directly from struct sg_table */
> +struct hyper_dmabuf_pages_info *hyper_dmabuf_ext_pgs(struct sg_table *sgt)
> +{
> + struct hyper_dmabuf_pages_info *pinfo;
> + int i, j;
> + int length;
> + struct scatterlist *sgl;
> +
> + pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
> + if (pinfo == NULL)
> + return NULL;
> +
> + pinfo->pages = kmalloc(sizeof(struct page *)*hyper_dmabuf_get_num_pgs(sgt), GFP_KERNEL);
> + if (pinfo->pages == NULL)
> + return NULL;
> +
> + sgl = sgt->sgl;
> +
> + pinfo->nents = 1;
> + pinfo->frst_ofst = sgl->offset;
> + pinfo->pages[0] = sg_page(sgl);
> + length = sgl->length - PAGE_SIZE + sgl->offset;
> + i=1;
> +
> + while (length > 0) {
> + pinfo->pages[i] = nth_page(sg_page(sgl), i);
> + length -= PAGE_SIZE;
> + pinfo->nents++;
> + i++;
> + }
> +
> + for (j = 1; j < sgt->nents; j++) {
> + sgl = sg_next(sgl);
> + pinfo->pages[i++] = sg_page(sgl);
> + length = sgl->length - PAGE_SIZE;
> + pinfo->nents++;
> +
> + while (length > 0) {
> + pinfo->pages[i] = nth_page(sg_page(sgl), i);
> + length -= PAGE_SIZE;
> + pinfo->nents++;
> + i++;
> + }
> + }
> +
> + /*
> + * lenght at that point will be 0 or negative,
> + * so to calculate last page size just add it to PAGE_SIZE
> + */
> + pinfo->last_len = PAGE_SIZE + length;
> +
> + return pinfo;
> +}
> +
> +/* create sg_table with given pages and other parameters */
> +struct sg_table* hyper_dmabuf_create_sgt(struct page **pages,
> + int frst_ofst, int last_len, int nents)
> +{
> + struct sg_table *sgt;
> + struct scatterlist *sgl;
> + int i, ret;
> +
> + sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
> + if (sgt == NULL) {
> + return NULL;
> + }
> +
> + ret = sg_alloc_table(sgt, nents, GFP_KERNEL);
> + if (ret) {
> + kfree(sgt);
> + return NULL;
> + }
> +
> + sgl = sgt->sgl;
> +
> + sg_set_page(sgl, pages[0], PAGE_SIZE-frst_ofst, frst_ofst);
> +
> + for (i=1; i<nents-1; i++) {
> + sgl = sg_next(sgl);
> + sg_set_page(sgl, pages[i], PAGE_SIZE, 0);
> + }
> +
> + if (i > 1) /* more than one page */ {
> + sgl = sg_next(sgl);
> + sg_set_page(sgl, pages[i], last_len, 0);
> + }
> +
> + return sgt;
> +}
> +
> +/*
> + * Creates 2 level page directory structure for referencing shared pages.
> + * Top level page is a single page that contains up to 1024 refids that
> + * point to 2nd level pages.
> + * Each 2nd level page contains up to 1024 refids that point to shared
> + * data pages.
> + * There will always be one top level page and number of 2nd level pages
> + * depends on number of shared data pages.
> + *
> + * Top level page 2nd level pages Data pages
> + * +-------------------------+ â>+--------------------+ â--->+------------+
> + * |2nd level page 0 refid |---â |Data page 0 refid |-â |Data page 0 |
> + * |2nd level page 1 refid |---â |Data page 1 refid |-â +------------+
> + * | ... | | | .... | |
> + * |2nd level page 1023 refid|-â | |Data page 1023 refid| â--->+------------+
> + * +-------------------------+ | | +--------------------+ |Data page 1 |
> + * | | +------------+
> + * | â>+--------------------+
> + * | |Data page 1024 refid|
> + * | |Data page 1025 refid|
> + * | | ... |
> + * | |Data page 2047 refid|
> + * | +--------------------+
> + * |
> + * | .....
> + * â-->+-----------------------+
> + * |Data page 1047552 refid|
> + * |Data page 1047553 refid|
> + * | ... |
> + * |Data page 1048575 refid|-->+------------------+
> + * +-----------------------+ |Data page 1048575 |
> + * +------------------+
> + *
> + * Using such 2 level structure it is possible to reference up to 4GB of
> + * shared data using single refid pointing to top level page.
> + *
> + * Returns refid of top level page.
> + */
> +grant_ref_t hyper_dmabuf_create_addressing_tables(grant_ref_t *data_refs, int nents, int rdomain,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info)
> +{
> + /*
> + * Calculate number of pages needed for 2nd level addresing:
> + */
> + int n_2nd_level_pages = (nents/REFS_PER_PAGE + ((nents % REFS_PER_PAGE) ? 1: 0));/* rounding */
> + int i;
> + unsigned long gref_page_start;
> + grant_ref_t *tmp_page;
> + grant_ref_t top_level_ref;
> + grant_ref_t * addr_refs;
> + addr_refs = kcalloc(sizeof(grant_ref_t), n_2nd_level_pages, GFP_KERNEL);
> +
> + gref_page_start = __get_free_pages(GFP_KERNEL, n_2nd_level_pages);
> + tmp_page = (grant_ref_t *)gref_page_start;
> +
> + /* Store 2nd level pages to be freed later */
> + shared_pages_info->addr_pages = tmp_page;
> +
> + /*TODO: make sure that allocated memory is filled with 0*/
> +
> + /* Share 2nd level addressing pages in readonly mode*/
> + for (i=0; i< n_2nd_level_pages; i++) {
> + addr_refs[i] = gnttab_grant_foreign_access(rdomain, virt_to_mfn((unsigned long)tmp_page+i*PAGE_SIZE ), 1);
> + }
> +
> + /*
> + * fill second level pages with data refs
> + */
> + for (i = 0; i < nents; i++) {
> + tmp_page[i] = data_refs[i];
> + }
> +
> +
> + /* allocate top level page */
> + gref_page_start = __get_free_pages(GFP_KERNEL, 1);
> + tmp_page = (grant_ref_t *)gref_page_start;
> +
> + /* Store top level page to be freed later */
> + shared_pages_info->top_level_page = tmp_page;
> +
> + /*
> + * fill top level page with reference numbers of second level pages refs.
> + */
> + for (i=0; i< n_2nd_level_pages; i++) {
> + tmp_page[i] = addr_refs[i];
> + }
> +
> + /* Share top level addressing page in readonly mode*/
> + top_level_ref = gnttab_grant_foreign_access(rdomain, virt_to_mfn((unsigned long)tmp_page), 1);
> +
> + kfree(addr_refs);
> +
> + return top_level_ref;
> +}
> +
> +/*
> + * Maps provided top level ref id and then return array of pages containing data refs.
> + */
> +struct page** hyper_dmabuf_get_data_refs(grant_ref_t top_level_ref, int domid, int nents,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info)
> +{
> + struct page *top_level_page;
> + struct page **level2_pages;
> +
> + grant_ref_t *top_level_refs;
> +
> + struct gnttab_map_grant_ref top_level_map_ops;
> + struct gnttab_unmap_grant_ref top_level_unmap_ops;
> +
> + struct gnttab_map_grant_ref *map_ops;
> + struct gnttab_unmap_grant_ref *unmap_ops;
> +
> + unsigned long addr;
> + int n_level2_refs = 0;
> + int i;
> +
> + n_level2_refs = (nents / REFS_PER_PAGE) + ((nents % REFS_PER_PAGE) ? 1 : 0);
> +
> + level2_pages = kcalloc(sizeof(struct page*), n_level2_refs, GFP_KERNEL);
> +
> + map_ops = kcalloc(sizeof(map_ops[0]), REFS_PER_PAGE, GFP_KERNEL);
> + unmap_ops = kcalloc(sizeof(unmap_ops[0]), REFS_PER_PAGE, GFP_KERNEL);
> +
> + /* Map top level addressing page */
> + if (gnttab_alloc_pages(1, &top_level_page)) {
> + printk("Cannot allocate pages\n");
> + return NULL;
> + }
> +
> + addr = (unsigned long)pfn_to_kaddr(page_to_pfn(top_level_page));
> + gnttab_set_map_op(&top_level_map_ops, addr, GNTMAP_host_map | GNTMAP_readonly, top_level_ref, domid);
> + gnttab_set_unmap_op(&top_level_unmap_ops, addr, GNTMAP_host_map | GNTMAP_readonly, -1);
> +
> + if (gnttab_map_refs(&top_level_map_ops, NULL, &top_level_page, 1)) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed");
> + return NULL;
> + }
> +
> + if (top_level_map_ops.status) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed status = %d",
> + top_level_map_ops.status);
> + return NULL;
> + } else {
> + top_level_unmap_ops.handle = top_level_map_ops.handle;
> + }
> +
> + /* Parse contents of top level addressing page to find how many second level pages is there*/
> + top_level_refs = pfn_to_kaddr(page_to_pfn(top_level_page));
> +
> + /* Map all second level pages */
> + if (gnttab_alloc_pages(n_level2_refs, level2_pages)) {
> + printk("Cannot allocate pages\n");
> + return NULL;
> + }
> +
> + for (i = 0; i < n_level2_refs; i++) {
> + addr = (unsigned long)pfn_to_kaddr(page_to_pfn(level2_pages[i]));
> + gnttab_set_map_op(&map_ops[i], addr, GNTMAP_host_map | GNTMAP_readonly, top_level_refs[i], domid);
> + gnttab_set_unmap_op(&unmap_ops[i], addr, GNTMAP_host_map | GNTMAP_readonly, -1);
> + }
> +
> + if (gnttab_map_refs(map_ops, NULL, level2_pages, n_level2_refs)) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed");
> + return NULL;
> + }
> +
> + /* Checks if pages were mapped correctly and at the same time is calculating total number of data refids*/
> + for (i = 0; i < n_level2_refs; i++) {
> + if (map_ops[i].status) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed status = %d",
> + map_ops[i].status);
> + return NULL;
> + } else {
> + unmap_ops[i].handle = map_ops[i].handle;
> + }
> + }
> +
> + /* Unmap top level page, as it won't be needed any longer */
> + if (gnttab_unmap_refs(&top_level_unmap_ops, NULL, &top_level_page, 1)) {
> + printk("\xen: cannot unmap top level page\n");
> + return NULL;
> + }
> +
> + gnttab_free_pages(1, &top_level_page);
> + kfree(map_ops);
> + shared_pages_info->unmap_ops = unmap_ops;
> +
> + return level2_pages;
> +}
> +
> +
> +/* This collects all reference numbers for 2nd level shared pages and create a table
> + * with those in 1st level shared pages then return reference numbers for this top level
> + * table. */
> +grant_ref_t hyper_dmabuf_create_gref_table(struct page **pages, int rdomain, int nents,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info)
> +{
> + int i = 0;
> + grant_ref_t *data_refs;
> + grant_ref_t top_level_ref;
> +
> + /* allocate temp array for refs of shared data pages */
> + data_refs = kcalloc(nents, sizeof(grant_ref_t), GFP_KERNEL);
> +
> + /* share data pages in rw mode*/
> + for (i=0; i<nents; i++) {
> + data_refs[i] = gnttab_grant_foreign_access(rdomain, pfn_to_mfn(page_to_pfn(pages[i])), 0);
> + }
> +
> + /* create additional shared pages with 2 level addressing of data pages */
> + top_level_ref = hyper_dmabuf_create_addressing_tables(data_refs, nents, rdomain,
> + shared_pages_info);
> +
> + /* Store exported pages refid to be unshared later */
> + shared_pages_info->data_refs = data_refs;
> + shared_pages_info->top_level_ref = top_level_ref;
> +
> + return top_level_ref;
> +}
> +
> +int hyper_dmabuf_cleanup_gref_table(struct hyper_dmabuf_sgt_info *sgt_info) {
> + uint32_t i = 0;
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info = &sgt_info->shared_pages_info;
> +
> + grant_ref_t *ref = shared_pages_info->top_level_page;
> + int n_2nd_level_pages = (sgt_info->sgt->nents/REFS_PER_PAGE + ((sgt_info->sgt->nents % REFS_PER_PAGE) ? 1: 0));/* rounding */
> +
> +
> + if (shared_pages_info->data_refs == NULL ||
> + shared_pages_info->addr_pages == NULL ||
> + shared_pages_info->top_level_page == NULL ||
> + shared_pages_info->top_level_ref == -1) {
> + printk("gref table for hyper_dmabuf already cleaned up\n");
> + return 0;
> + }
> +
> + /* End foreign access for 2nd level addressing pages */
> + while(ref[i] != 0 && i < n_2nd_level_pages) {
> + if (gnttab_query_foreign_access(ref[i])) {
> + printk("refid not shared !!\n");
> + }
> + if (!gnttab_end_foreign_access_ref(ref[i], 1)) {
> + printk("refid still in use!!!\n");
> + }
> + i++;
> + }
> + free_pages((unsigned long)shared_pages_info->addr_pages, i);
> +
> + /* End foreign access for top level addressing page */
> + if (gnttab_query_foreign_access(shared_pages_info->top_level_ref)) {
> + printk("refid not shared !!\n");
> + }
> + if (!gnttab_end_foreign_access_ref(shared_pages_info->top_level_ref, 1)) {
> + printk("refid still in use!!!\n");
> + }
> + gnttab_end_foreign_access_ref(shared_pages_info->top_level_ref, 1);
> + free_pages((unsigned long)shared_pages_info->top_level_page, 1);
> +
> + /* End foreign access for data pages, but do not free them */
> + for (i = 0; i < sgt_info->sgt->nents; i++) {
> + if (gnttab_query_foreign_access(shared_pages_info->data_refs[i])) {
> + printk("refid not shared !!\n");
> + }
> + gnttab_end_foreign_access_ref(shared_pages_info->data_refs[i], 0);
> + }
> +
> + kfree(shared_pages_info->data_refs);
> +
> + shared_pages_info->data_refs = NULL;
> + shared_pages_info->addr_pages = NULL;
> + shared_pages_info->top_level_page = NULL;
> + shared_pages_info->top_level_ref = -1;
> +
> + return 0;
> +}
> +
> +int hyper_dmabuf_cleanup_imported_pages(struct hyper_dmabuf_imported_sgt_info *sgt_info) {
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info = &sgt_info->shared_pages_info;
> +
> + if(shared_pages_info->unmap_ops == NULL || shared_pages_info->data_pages == NULL) {
> + printk("Imported pages already cleaned up or buffer was not imported yet\n");
> + return 0;
> + }
> +
> + if (gnttab_unmap_refs(shared_pages_info->unmap_ops, NULL, shared_pages_info->data_pages, sgt_info->nents) ) {
> + printk("Cannot unmap data pages\n");
> + return -EINVAL;
> + }
> +
> + gnttab_free_pages(sgt_info->nents, shared_pages_info->data_pages);
> + kfree(shared_pages_info->data_pages);
> + kfree(shared_pages_info->unmap_ops);
> + shared_pages_info->unmap_ops = NULL;
> + shared_pages_info->data_pages = NULL;
> +
> + return 0;
> +}
> +
> +/* map and construct sg_lists from reference numbers */
> +struct sg_table* hyper_dmabuf_map_pages(grant_ref_t top_level_gref, int frst_ofst, int last_len, int nents, int sdomain,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info)
> +{
> + struct sg_table *st;
> + struct page **pages;
> + struct gnttab_map_grant_ref *ops;
> + struct gnttab_unmap_grant_ref *unmap_ops;
> + unsigned long addr;
> + grant_ref_t *refs;
> + int i;
> + int n_level2_refs = (nents / REFS_PER_PAGE) + ((nents % REFS_PER_PAGE) ? 1 : 0);
> +
> + /* Get data refids */
> + struct page** refid_pages = hyper_dmabuf_get_data_refs(top_level_gref, sdomain, nents,
> + shared_pages_info);
> +
> + pages = kcalloc(sizeof(struct page*), nents, GFP_KERNEL);
> + if (pages == NULL) {
> + return NULL;
> + }
> +
> + /* allocate new pages that are mapped to shared pages via grant-table */
> + if (gnttab_alloc_pages(nents, pages)) {
> + printk("Cannot allocate pages\n");
> + return NULL;
> + }
> +
> + ops = (struct gnttab_map_grant_ref *)kcalloc(nents, sizeof(struct gnttab_map_grant_ref), GFP_KERNEL);
> + unmap_ops = (struct gnttab_unmap_grant_ref *)kcalloc(nents, sizeof(struct gnttab_unmap_grant_ref), GFP_KERNEL);
> +
> + for (i=0; i<nents; i++) {
> + addr = (unsigned long)pfn_to_kaddr(page_to_pfn(pages[i]));
> + refs = pfn_to_kaddr(page_to_pfn(refid_pages[i / REFS_PER_PAGE]));
> + gnttab_set_map_op(&ops[i], addr, GNTMAP_host_map | GNTMAP_readonly, refs[i % REFS_PER_PAGE], sdomain);
> + gnttab_set_unmap_op(&unmap_ops[i], addr, GNTMAP_host_map | GNTMAP_readonly, -1);
> + }
> +
> + if (gnttab_map_refs(ops, NULL, pages, nents)) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed\n");
> + return NULL;
> + }
> +
> + for (i=0; i<nents; i++) {
> + if (ops[i].status) {
> + printk("\nxen: dom0: HYPERVISOR map grant ref failed status = %d\n",
> + ops[0].status);
> + return NULL;
> + } else {
> + unmap_ops[i].handle = ops[i].handle;
> + }
> + }
> +
> + st = hyper_dmabuf_create_sgt(pages, frst_ofst, last_len, nents);
> +
> + if (gnttab_unmap_refs(shared_pages_info->unmap_ops, NULL, refid_pages, n_level2_refs) ) {
> + printk("Cannot unmap 2nd level refs\n");
> + return NULL;
> + }
> +
> + gnttab_free_pages(n_level2_refs, refid_pages);
> + kfree(refid_pages);
> +
> + kfree(shared_pages_info->unmap_ops);
> + shared_pages_info->unmap_ops = unmap_ops;
> + shared_pages_info->data_pages = pages;
> + kfree(ops);
> +
> + return st;
> +}
> +
> +inline int hyper_dmabuf_sync_request_and_wait(int id, int ops)
> +{
> + struct hyper_dmabuf_ring_rq *req;
> + int operands[2];
> + int ret;
> +
> + operands[0] = id;
> + operands[1] = ops;
> +
> + req = kcalloc(1, sizeof(*req), GFP_KERNEL);
> +
> + hyper_dmabuf_create_request(req, HYPER_DMABUF_OPS_TO_SOURCE, &operands[0]);
> +
> + /* send request */
> + ret = hyper_dmabuf_send_request(id, req);
> +
> + /* TODO: wait until it gets response.. or can we just move on? */
> +
> + kfree(req);
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_ops_attach(struct dma_buf* dmabuf, struct device* dev,
> + struct dma_buf_attachment *attach)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!attach->dmabuf->priv)
> + return -EINVAL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)attach->dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_ATTACH);
> +
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return ret;
> +}
> +
> +static void hyper_dmabuf_ops_detach(struct dma_buf* dmabuf, struct dma_buf_attachment *attach)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!attach->dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)attach->dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_DETACH);
> +
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static struct sg_table* hyper_dmabuf_ops_map(struct dma_buf_attachment *attachment,
> + enum dma_data_direction dir)
> +{
> + struct sg_table *st;
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + struct hyper_dmabuf_pages_info *page_info;
> + int ret;
> +
> + if (!attachment->dmabuf->priv)
> + return NULL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)attachment->dmabuf->priv;
> +
> + /* extract pages from sgt */
> + page_info = hyper_dmabuf_ext_pgs(sgt_info->sgt);
> +
> + /* create a new sg_table with extracted pages */
> + st = hyper_dmabuf_create_sgt(page_info->pages, page_info->frst_ofst,
> + page_info->last_len, page_info->nents);
> + if (st == NULL)
> + goto err_free_sg;
> +
> + if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
> + goto err_free_sg;
> + }
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_MAP);
> +
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return st;
> +
> +err_free_sg:
> + sg_free_table(st);
> + kfree(st);
> + return NULL;
> +}
> +
> +static void hyper_dmabuf_ops_unmap(struct dma_buf_attachment *attachment,
> + struct sg_table *sg,
> + enum dma_data_direction dir)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!attachment->dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)attachment->dmabuf->priv;
> +
> + dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
> +
> + sg_free_table(sg);
> + kfree(sg);
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_UNMAP);
> +
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static void hyper_dmabuf_ops_release(struct dma_buf *dmabuf)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_RELEASE);
> +
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static int hyper_dmabuf_ops_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return -EINVAL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_ops_end_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return -EINVAL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_END_CPU_ACCESS);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return 0;
> +}
> +
> +static void *hyper_dmabuf_ops_kmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return NULL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_KMAP_ATOMIC);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return NULL; /* for now NULL.. need to return the address of mapped region */
> +}
> +
> +static void hyper_dmabuf_ops_kunmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum, void *vaddr)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_KUNMAP_ATOMIC);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static void *hyper_dmabuf_ops_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return NULL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_KMAP);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return NULL; /* for now NULL.. need to return the address of mapped region */
> +}
> +
> +static void hyper_dmabuf_ops_kunmap(struct dma_buf *dmabuf, unsigned long pgnum, void *vaddr)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_KUNMAP);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static int hyper_dmabuf_ops_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return -EINVAL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_MMAP);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return ret;
> +}
> +
> +static void *hyper_dmabuf_ops_vmap(struct dma_buf *dmabuf)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return NULL;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_VMAP);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +
> + return NULL;
> +}
> +
> +static void hyper_dmabuf_ops_vunmap(struct dma_buf *dmabuf, void *vaddr)
> +{
> + struct hyper_dmabuf_imported_sgt_info *sgt_info;
> + int ret;
> +
> + if (!dmabuf->priv)
> + return;
> +
> + sgt_info = (struct hyper_dmabuf_imported_sgt_info *)dmabuf->priv;
> +
> + ret = hyper_dmabuf_sync_request_and_wait(HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(sgt_info->hyper_dmabuf_id),
> + HYPER_DMABUF_OPS_VUNMAP);
> + if (ret < 0) {
> + printk("send dmabuf sync request failed\n");
> + }
> +}
> +
> +static const struct dma_buf_ops hyper_dmabuf_ops = {
> + .attach = hyper_dmabuf_ops_attach,
> + .detach = hyper_dmabuf_ops_detach,
> + .map_dma_buf = hyper_dmabuf_ops_map,
> + .unmap_dma_buf = hyper_dmabuf_ops_unmap,
> + .release = hyper_dmabuf_ops_release,
> + .begin_cpu_access = (void*)hyper_dmabuf_ops_begin_cpu_access,
> + .end_cpu_access = (void*)hyper_dmabuf_ops_end_cpu_access,
> + .map_atomic = hyper_dmabuf_ops_kmap_atomic,
> + .unmap_atomic = hyper_dmabuf_ops_kunmap_atomic,
> + .map = hyper_dmabuf_ops_kmap,
> + .unmap = hyper_dmabuf_ops_kunmap,
> + .mmap = hyper_dmabuf_ops_mmap,
> + .vmap = hyper_dmabuf_ops_vmap,
> + .vunmap = hyper_dmabuf_ops_vunmap,
> +};
> +
> +/* exporting dmabuf as fd */
> +int hyper_dmabuf_export_fd(struct hyper_dmabuf_imported_sgt_info *dinfo, int flags)
> +{
> + int fd;
> +
> + struct dma_buf* dmabuf;
> +
> +/* call hyper_dmabuf_export_dmabuf and create and bind a handle for it
> + * then release */
> +
> + dmabuf = hyper_dmabuf_export_dma_buf(dinfo);
> +
> + fd = dma_buf_fd(dmabuf, flags);
> +
> + return fd;
> +}
> +
> +struct dma_buf* hyper_dmabuf_export_dma_buf(struct hyper_dmabuf_imported_sgt_info *dinfo)
> +{
> + DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
> +
> + exp_info.ops = &hyper_dmabuf_ops;
> + exp_info.size = dinfo->sgt->nents * PAGE_SIZE; /* multiple of PAGE_SIZE, not considering offset */
> + exp_info.flags = /* not sure about flag */0;
> + exp_info.priv = dinfo;
> +
> + return dma_buf_export(&exp_info);
> +};
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.h
> new file mode 100644
> index 0000000..003c158
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_imp.h
> @@ -0,0 +1,31 @@
> +#ifndef __HYPER_DMABUF_IMP_H__
> +#define __HYPER_DMABUF_IMP_H__
> +
> +#include "hyper_dmabuf_struct.h"
> +
> +/* extract pages directly from struct sg_table */
> +struct hyper_dmabuf_pages_info *hyper_dmabuf_ext_pgs(struct sg_table *sgt);
> +
> +/* create sg_table with given pages and other parameters */
> +struct sg_table* hyper_dmabuf_create_sgt(struct page **pages,
> + int frst_ofst, int last_len, int nents);
> +
> +grant_ref_t hyper_dmabuf_create_gref_table(struct page **pages, int rdomain, int nents,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info);
> +
> +int hyper_dmabuf_cleanup_gref_table(struct hyper_dmabuf_sgt_info *sgt_info);
> +
> +int hyper_dmabuf_cleanup_imported_pages(struct hyper_dmabuf_imported_sgt_info *sgt_info);
> +
> +/* map first level tables that contains reference numbers for actual shared pages */
> +grant_ref_t *hyper_dmabuf_map_gref_table(grant_ref_t *gref_table, int n_pages_table);
> +
> +/* map and construct sg_lists from reference numbers */
> +struct sg_table* hyper_dmabuf_map_pages(grant_ref_t gref, int frst_ofst, int last_len, int nents, int sdomain,
> + struct hyper_dmabuf_shared_pages_info *shared_pages_info);
> +
> +int hyper_dmabuf_export_fd(struct hyper_dmabuf_imported_sgt_info *dinfo, int flags);
> +
> +struct dma_buf* hyper_dmabuf_export_dma_buf(struct hyper_dmabuf_imported_sgt_info *dinfo);
> +
> +#endif /* __HYPER_DMABUF_IMP_H__ */
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_ioctl.c b/drivers/xen/hyper_dmabuf/hyper_dmabuf_ioctl.c
> new file mode 100644
> index 0000000..5e50908
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_ioctl.c
> @@ -0,0 +1,462 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/miscdevice.h>
> +#include <linux/uaccess.h>
> +#include <linux/dma-buf.h>
> +#include <linux/delay.h>
> +#include "hyper_dmabuf_struct.h"
> +#include "hyper_dmabuf_imp.h"
> +#include "hyper_dmabuf_list.h"
> +#include "hyper_dmabuf_drv.h"
> +#include "hyper_dmabuf_query.h"
> +#include "xen/hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_msg.h"
> +
> +struct hyper_dmabuf_private {
> + struct device *device;
> +} hyper_dmabuf_private;
> +
> +static uint32_t hyper_dmabuf_id_gen(void) {
> + /* TODO: add proper implementation */
> + static uint32_t id = 0;
> + static int32_t domid = -1;
> + if (domid == -1) {
> + domid = hyper_dmabuf_get_domid();
> + }
> + return HYPER_DMABUF_ID_IMPORTER(domid, id++);
> +}
> +
> +static int hyper_dmabuf_exporter_ring_setup(void *data)
> +{
> + struct ioctl_hyper_dmabuf_exporter_ring_setup *ring_attr;
> + int ret = 0;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -1;
> + }
> + ring_attr = (struct ioctl_hyper_dmabuf_exporter_ring_setup *)data;
> +
> + ret = hyper_dmabuf_exporter_ringbuf_init(ring_attr->remote_domain,
> + &ring_attr->ring_refid,
> + &ring_attr->port);
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_importer_ring_setup(void *data)
> +{
> + struct ioctl_hyper_dmabuf_importer_ring_setup *setup_imp_ring_attr;
> + int ret = 0;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -1;
> + }
> +
> + setup_imp_ring_attr = (struct ioctl_hyper_dmabuf_importer_ring_setup *)data;
> +
> + /* user need to provide a port number and ref # for the page used as ring buffer */
> + ret = hyper_dmabuf_importer_ringbuf_init(setup_imp_ring_attr->source_domain,
> + setup_imp_ring_attr->ring_refid,
> + setup_imp_ring_attr->port);
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_export_remote(void *data)
> +{
> + struct ioctl_hyper_dmabuf_export_remote *export_remote_attr;
> + struct dma_buf *dma_buf;
> + struct dma_buf_attachment *attachment;
> + struct sg_table *sgt;
> + struct hyper_dmabuf_pages_info *page_info;
> + struct hyper_dmabuf_sgt_info *sgt_info;
> + struct hyper_dmabuf_ring_rq *req;
> + int operands[9];
> + int ret = 0;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -1;
> + }
> +
> + export_remote_attr = (struct ioctl_hyper_dmabuf_export_remote *)data;
> +
> + dma_buf = dma_buf_get(export_remote_attr->dmabuf_fd);
> + if (!dma_buf) {
> + printk("Cannot get dma buf\n");
> + return -1;
> + }
> +
> + attachment = dma_buf_attach(dma_buf, hyper_dmabuf_private.device);
> + if (!attachment) {
> + printk("Cannot get attachment\n");
> + return -1;
> + }
> +
> + /* we check if this specific attachment was already exported
> + * to the same domain and if yes, it returns hyper_dmabuf_id
> + * of pre-exported sgt */
> + ret = hyper_dmabuf_find_id(attachment, export_remote_attr->remote_domain);
> + if (ret != -1) {
> + dma_buf_detach(dma_buf, attachment);
> + dma_buf_put(dma_buf);
> + export_remote_attr->hyper_dmabuf_id = ret;
> + return 0;
> + }
> + /* Clear ret, as that will cause whole ioctl to return failure to userspace, which is not true */
> + ret = 0;
> +
> + sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
> +
> + sgt_info = kmalloc(sizeof(*sgt_info), GFP_KERNEL);
> +
> + sgt_info->hyper_dmabuf_id = hyper_dmabuf_id_gen();
> + /* TODO: We might need to consider using port number on event channel? */
> + sgt_info->hyper_dmabuf_rdomain = export_remote_attr->remote_domain;
> + sgt_info->sgt = sgt;
> + sgt_info->attachment = attachment;
> + sgt_info->dma_buf = dma_buf;
> +
> + page_info = hyper_dmabuf_ext_pgs(sgt);
> + if (page_info == NULL)
> + goto fail_export;
> +
> + /* now register it to export list */
> + hyper_dmabuf_register_exported(sgt_info);
> +
> + page_info->hyper_dmabuf_rdomain = sgt_info->hyper_dmabuf_rdomain;
> + page_info->hyper_dmabuf_id = sgt_info->hyper_dmabuf_id; /* may not be needed */
> +
> + export_remote_attr->hyper_dmabuf_id = sgt_info->hyper_dmabuf_id;
> +
> + /* now create table of grefs for shared pages and */
> +
> + /* now create request for importer via ring */
> + operands[0] = page_info->hyper_dmabuf_id;
> + operands[1] = page_info->nents;
> + operands[2] = page_info->frst_ofst;
> + operands[3] = page_info->last_len;
> + operands[4] = hyper_dmabuf_create_gref_table(page_info->pages, export_remote_attr->remote_domain,
> + page_info->nents, &sgt_info->shared_pages_info);
> + /* driver/application specific private info, max 32 bytes */
> + operands[5] = export_remote_attr->private[0];
> + operands[6] = export_remote_attr->private[1];
> + operands[7] = export_remote_attr->private[2];
> + operands[8] = export_remote_attr->private[3];
> +
> + req = kcalloc(1, sizeof(*req), GFP_KERNEL);
> +
> + /* composing a message to the importer */
> + hyper_dmabuf_create_request(req, HYPER_DMABUF_EXPORT, &operands[0]);
> + if(hyper_dmabuf_send_request(export_remote_attr->remote_domain, req))
> + goto fail_send_request;
> +
> + /* free msg */
> + kfree(req);
> + /* free page_info */
> + kfree(page_info);
> +
> + return ret;
> +
> +fail_send_request:
> + kfree(req);
> + hyper_dmabuf_remove_exported(sgt_info->hyper_dmabuf_id);
> +
> +fail_export:
> + dma_buf_unmap_attachment(sgt_info->attachment, sgt_info->sgt, DMA_BIDIRECTIONAL);
> + dma_buf_detach(sgt_info->dma_buf, sgt_info->attachment);
> + dma_buf_put(sgt_info->dma_buf);
> +
> + return -EINVAL;
> +}
> +
> +static int hyper_dmabuf_export_fd_ioctl(void *data)
> +{
> + struct ioctl_hyper_dmabuf_export_fd *export_fd_attr;
> + struct hyper_dmabuf_imported_sgt_info *imported_sgt_info;
> + int ret = 0;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -1;
> + }
> +
> + export_fd_attr = (struct ioctl_hyper_dmabuf_export_fd *)data;
> +
> + /* look for dmabuf for the id */
> + imported_sgt_info = hyper_dmabuf_find_imported(export_fd_attr->hyper_dmabuf_id);
> + if (imported_sgt_info == NULL) /* can't find sgt from the table */
> + return -1;
> +
> + printk("%s Found buffer gref %d off %d last len %d nents %d domain %d\n", __func__,
> + imported_sgt_info->gref, imported_sgt_info->frst_ofst,
> + imported_sgt_info->last_len, imported_sgt_info->nents,
> + HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(imported_sgt_info->hyper_dmabuf_id));
> +
> + imported_sgt_info->sgt = hyper_dmabuf_map_pages(imported_sgt_info->gref,
> + imported_sgt_info->frst_ofst,
> + imported_sgt_info->last_len,
> + imported_sgt_info->nents,
> + HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(imported_sgt_info->hyper_dmabuf_id),
> + &imported_sgt_info->shared_pages_info);
> +
> + if (!imported_sgt_info->sgt) {
> + return -1;
> + }
> +
> + export_fd_attr->fd = hyper_dmabuf_export_fd(imported_sgt_info, export_fd_attr->flags);
> + if (export_fd_attr < 0) {
> + ret = export_fd_attr->fd;
> + }
> +
> + return ret;
> +}
> +
> +/* removing dmabuf from the database and send int req to the source domain
> +* to unmap it. */
> +static int hyper_dmabuf_destroy(void *data)
> +{
> + struct ioctl_hyper_dmabuf_destroy *destroy_attr;
> + struct hyper_dmabuf_sgt_info *sgt_info;
> + struct hyper_dmabuf_ring_rq *req;
> + int ret;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -EINVAL;
> + }
> +
> + destroy_attr = (struct ioctl_hyper_dmabuf_destroy *)data;
> +
> + /* find dmabuf in export list */
> + sgt_info = hyper_dmabuf_find_exported(destroy_attr->hyper_dmabuf_id);
> + if (sgt_info == NULL) { /* failed to find corresponding entry in export list */
> + destroy_attr->status = -EINVAL;
> + return -EFAULT;
> + }
> +
> + req = kcalloc(1, sizeof(*req), GFP_KERNEL);
> +
> + hyper_dmabuf_create_request(req, HYPER_DMABUF_DESTROY, &destroy_attr->hyper_dmabuf_id);
> +
> + /* now send destroy request to remote domain
> + * currently assuming there's only one importer exist */
> + ret = hyper_dmabuf_send_request(sgt_info->hyper_dmabuf_rdomain, req);
> + if (ret < 0) {
> + kfree(req);
> + return -EFAULT;
> + }
> +
> + /* free msg */
> + kfree(req);
> + destroy_attr->status = ret;
> +
> + /* Rest of cleanup will follow when importer will free it's buffer,
> + * current implementation assumes that there is only one importer
> + */
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_query(void *data)
> +{
> + struct ioctl_hyper_dmabuf_query *query_attr;
> + struct hyper_dmabuf_sgt_info *sgt_info;
> + struct hyper_dmabuf_imported_sgt_info *imported_sgt_info;
> + int ret = 0;
> +
> + if (!data) {
> + printk("user data is NULL\n");
> + return -EINVAL;
> + }
> +
> + query_attr = (struct ioctl_hyper_dmabuf_query *)data;
> +
> + sgt_info = hyper_dmabuf_find_exported(query_attr->hyper_dmabuf_id);
> + imported_sgt_info = hyper_dmabuf_find_imported(query_attr->hyper_dmabuf_id);
> +
> + /* if dmabuf can't be found in both lists, return */
> + if (!(sgt_info && imported_sgt_info)) {
> + printk("can't find entry anywhere\n");
> + return -EINVAL;
> + }
> +
> + /* not considering the case where a dmabuf is found on both queues
> + * in one domain */
> + switch (query_attr->item)
> + {
> + case DMABUF_QUERY_TYPE_LIST:
> + if (sgt_info) {
> + query_attr->info = EXPORTED;
> + } else {
> + query_attr->info = IMPORTED;
> + }
> + break;
> +
> + /* exporting domain of this specific dmabuf*/
> + case DMABUF_QUERY_EXPORTER:
> + if (sgt_info) {
> + query_attr->info = 0xFFFFFFFF; /* myself */
> + } else {
> + query_attr->info = (HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(imported_sgt_info->hyper_dmabuf_id));
> + }
> + break;
> +
> + /* importing domain of this specific dmabuf */
> + case DMABUF_QUERY_IMPORTER:
> + if (sgt_info) {
> + query_attr->info = sgt_info->hyper_dmabuf_rdomain;
> + } else {
> +#if 0 /* TODO: a global variable, current_domain does not exist yet*/
> + query_attr->info = current_domain;
> +#endif
> + }
> + break;
> +
> + /* size of dmabuf in byte */
> + case DMABUF_QUERY_SIZE:
> + if (sgt_info) {
> +#if 0 /* TODO: hyper_dmabuf_buf_size is not implemented yet */
> + query_attr->info = hyper_dmabuf_buf_size(sgt_info->sgt);
> +#endif
> + } else {
> + query_attr->info = imported_sgt_info->nents * 4096 -
> + imported_sgt_info->frst_ofst - 4096 +
> + imported_sgt_info->last_len;
> + }
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int hyper_dmabuf_remote_exporter_ring_setup(void *data)
> +{
> + struct ioctl_hyper_dmabuf_remote_exporter_ring_setup *remote_exporter_ring_setup;
> + struct hyper_dmabuf_ring_rq *req;
> +
> + remote_exporter_ring_setup = (struct ioctl_hyper_dmabuf_remote_exporter_ring_setup *)data;
> +
> + req = kcalloc(1, sizeof(*req), GFP_KERNEL);
> + hyper_dmabuf_create_request(req, HYPER_DMABUF_EXPORTER_RING_SETUP, NULL);
> +
> + /* requesting remote domain to set-up exporter's ring */
> + if(hyper_dmabuf_send_request(remote_exporter_ring_setup->rdomain, req) < 0) {
> + kfree(req);
> + return -EINVAL;
> + }
> +
> + kfree(req);
> + return 0;
> +}
> +
> +static const struct hyper_dmabuf_ioctl_desc hyper_dmabuf_ioctls[] = {
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_EXPORTER_RING_SETUP, hyper_dmabuf_exporter_ring_setup, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_IMPORTER_RING_SETUP, hyper_dmabuf_importer_ring_setup, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_EXPORT_REMOTE, hyper_dmabuf_export_remote, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_EXPORT_FD, hyper_dmabuf_export_fd_ioctl, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_DESTROY, hyper_dmabuf_destroy, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_QUERY, hyper_dmabuf_query, 0),
> + HYPER_DMABUF_IOCTL_DEF(IOCTL_HYPER_DMABUF_REMOTE_EXPORTER_RING_SETUP, hyper_dmabuf_remote_exporter_ring_setup, 0),
> +};
> +
> +static long hyper_dmabuf_ioctl(struct file *filp,
> + unsigned int cmd, unsigned long param)
> +{
> + const struct hyper_dmabuf_ioctl_desc *ioctl = NULL;
> + unsigned int nr = _IOC_NR(cmd);
> + int ret = -EINVAL;
> + hyper_dmabuf_ioctl_t func;
> + char *kdata;
> +
> + ioctl = &hyper_dmabuf_ioctls[nr];
> +
> + func = ioctl->func;
> +
> + if (unlikely(!func)) {
> + printk("no function\n");
> + return -EINVAL;
> + }
> +
> + kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
> + if (!kdata) {
> + printk("no memory\n");
> + return -ENOMEM;
> + }
> +
> + if (copy_from_user(kdata, (void __user *)param, _IOC_SIZE(cmd)) != 0) {
> + printk("failed to copy from user arguments\n");
> + return -EFAULT;
> + }
> +
> + ret = func(kdata);
> +
> + if (copy_to_user((void __user *)param, kdata, _IOC_SIZE(cmd)) != 0) {
> + printk("failed to copy to user arguments\n");
> + return -EFAULT;
> + }
> +
> + kfree(kdata);
> +
> + return ret;
> +}
> +
> +struct device_info {
> + int curr_domain;
> +};
> +
> +/*===============================================================================================*/
> +static struct file_operations hyper_dmabuf_driver_fops =
> +{
> + .owner = THIS_MODULE,
> + .unlocked_ioctl = hyper_dmabuf_ioctl,
> +};
> +
> +static struct miscdevice hyper_dmabuf_miscdev = {
> + .minor = MISC_DYNAMIC_MINOR,
> + .name = "xen/hyper_dmabuf",
> + .fops = &hyper_dmabuf_driver_fops,
> +};
> +
> +static const char device_name[] = "hyper_dmabuf";
> +
> +/*===============================================================================================*/
> +int register_device(void)
> +{
> + int result = 0;
> +
> + result = misc_register(&hyper_dmabuf_miscdev);
> +
> + if (result != 0) {
> + printk(KERN_WARNING "hyper_dmabuf: driver can't be registered\n");
> + return result;
> + }
> +
> + hyper_dmabuf_private.device = hyper_dmabuf_miscdev.this_device;
> +
> + /* TODO: Check if there is a different way to initialize dma mask nicely */
> + dma_coerce_mask_and_coherent(hyper_dmabuf_private.device, 0xFFFFFFFF);
> +
> + /* TODO find a way to provide parameters for below function or move that to ioctl */
> +/* err = bind_interdomain_evtchn_to_irqhandler(rdomain, evtchn,
> + src_sink_isr, PORT_NUM, "remote_domain", &info);
> + if (err < 0) {
> + printk("hyper_dmabuf: can't register interrupt handlers\n");
> + return -EFAULT;
> + }
> +
> + info.irq = err;
> +*/
> + return result;
> +}
> +
> +/*-----------------------------------------------------------------------------------------------*/
> +void unregister_device(void)
> +{
> + printk( KERN_NOTICE "hyper_dmabuf: unregister_device() is called" );
> + misc_deregister(&hyper_dmabuf_miscdev);
> +}
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.c b/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.c
> new file mode 100644
> index 0000000..77a7e65
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.c
> @@ -0,0 +1,119 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <asm/uaccess.h>
> +#include <linux/hashtable.h>
> +#include <linux/dma-buf.h>
> +#include "hyper_dmabuf_list.h"
> +
> +DECLARE_HASHTABLE(hyper_dmabuf_hash_imported, MAX_ENTRY_IMPORTED);
> +DECLARE_HASHTABLE(hyper_dmabuf_hash_exported, MAX_ENTRY_EXPORTED);
> +
> +int hyper_dmabuf_table_init()
> +{
> + hash_init(hyper_dmabuf_hash_imported);
> + hash_init(hyper_dmabuf_hash_exported);
> + return 0;
> +}
> +
> +int hyper_dmabuf_table_destroy()
> +{
> + /* TODO: cleanup hyper_dmabuf_hash_imported and hyper_dmabuf_hash_exported */
> + return 0;
> +}
> +
> +int hyper_dmabuf_register_exported(struct hyper_dmabuf_sgt_info *info)
> +{
> + struct hyper_dmabuf_info_entry_exported *info_entry;
> +
> + info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> + info_entry->info = info;
> +
> + hash_add(hyper_dmabuf_hash_exported, &info_entry->node,
> + info_entry->info->hyper_dmabuf_id);
> +
> + return 0;
> +}
> +
> +int hyper_dmabuf_register_imported(struct hyper_dmabuf_imported_sgt_info* info)
> +{
> + struct hyper_dmabuf_info_entry_imported *info_entry;
> +
> + info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> + info_entry->info = info;
> +
> + hash_add(hyper_dmabuf_hash_imported, &info_entry->node,
> + info_entry->info->hyper_dmabuf_id);
> +
> + return 0;
> +}
> +
> +struct hyper_dmabuf_sgt_info *hyper_dmabuf_find_exported(int id)
> +{
> + struct hyper_dmabuf_info_entry_exported *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_exported, bkt, info_entry, node)
> + if(info_entry->info->hyper_dmabuf_id == id)
> + return info_entry->info;
> +
> + return NULL;
> +}
> +
> +/* search for pre-exported sgt and return id of it if it exist */
> +int hyper_dmabuf_find_id(struct dma_buf_attachment *attach, int domid)
> +{
> + struct hyper_dmabuf_info_entry_exported *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_exported, bkt, info_entry, node)
> + if(info_entry->info->attachment == attach &&
> + info_entry->info->hyper_dmabuf_rdomain == domid)
> + return info_entry->info->hyper_dmabuf_id;
> +
> + return -1;
> +}
> +
> +struct hyper_dmabuf_imported_sgt_info *hyper_dmabuf_find_imported(int id)
> +{
> + struct hyper_dmabuf_info_entry_imported *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_imported, bkt, info_entry, node)
> + if(info_entry->info->hyper_dmabuf_id == id)
> + return info_entry->info;
> +
> + return NULL;
> +}
> +
> +int hyper_dmabuf_remove_exported(int id)
> +{
> + struct hyper_dmabuf_info_entry_exported *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_exported, bkt, info_entry, node)
> + if(info_entry->info->hyper_dmabuf_id == id) {
> + hash_del(&info_entry->node);
> + return 0;
> + }
> +
> + return -1;
> +}
> +
> +int hyper_dmabuf_remove_imported(int id)
> +{
> + struct hyper_dmabuf_info_entry_imported *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_imported, bkt, info_entry, node)
> + if(info_entry->info->hyper_dmabuf_id == id) {
> + hash_del(&info_entry->node);
> + return 0;
> + }
> +
> + return -1;
> +}
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.h
> new file mode 100644
> index 0000000..869cd9a
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_list.h
> @@ -0,0 +1,40 @@
> +#ifndef __HYPER_DMABUF_LIST_H__
> +#define __HYPER_DMABUF_LIST_H__
> +
> +#include "hyper_dmabuf_struct.h"
> +
> +/* number of bits to be used for exported dmabufs hash table */
> +#define MAX_ENTRY_EXPORTED 7
> +/* number of bits to be used for imported dmabufs hash table */
> +#define MAX_ENTRY_IMPORTED 7
> +
> +struct hyper_dmabuf_info_entry_exported {
> + struct hyper_dmabuf_sgt_info *info;
> + struct hlist_node node;
> +};
> +
> +struct hyper_dmabuf_info_entry_imported {
> + struct hyper_dmabuf_imported_sgt_info *info;
> + struct hlist_node node;
> +};
> +
> +int hyper_dmabuf_table_init(void);
> +
> +int hyper_dmabuf_table_destroy(void);
> +
> +int hyper_dmabuf_register_exported(struct hyper_dmabuf_sgt_info *info);
> +
> +/* search for pre-exported sgt and return id of it if it exist */
> +int hyper_dmabuf_find_id(struct dma_buf_attachment *attach, int domid);
> +
> +int hyper_dmabuf_register_imported(struct hyper_dmabuf_imported_sgt_info* info);
> +
> +struct hyper_dmabuf_sgt_info *hyper_dmabuf_find_exported(int id);
> +
> +struct hyper_dmabuf_imported_sgt_info *hyper_dmabuf_find_imported(int id);
> +
> +int hyper_dmabuf_remove_exported(int id);
> +
> +int hyper_dmabuf_remove_imported(int id);
> +
> +#endif // __HYPER_DMABUF_LIST_H__
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.c b/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.c
> new file mode 100644
> index 0000000..3237e50
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.c
> @@ -0,0 +1,212 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/dma-buf.h>
> +#include "hyper_dmabuf_imp.h"
> +//#include "hyper_dmabuf_remote_sync.h"
> +#include "xen/hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_msg.h"
> +#include "hyper_dmabuf_list.h"
> +
> +void hyper_dmabuf_create_request(struct hyper_dmabuf_ring_rq *request,
> + enum hyper_dmabuf_command command, int *operands)
> +{
> + int i;
> +
> + request->request_id = hyper_dmabuf_next_req_id_export();
> + request->status = HYPER_DMABUF_REQ_NOT_RESPONDED;
> + request->command = command;
> +
> + switch(command) {
> + /* as exporter, commands to importer */
> + case HYPER_DMABUF_EXPORT:
> + /* exporting pages for dmabuf */
> + /* command : HYPER_DMABUF_EXPORT,
> + * operands0 : hyper_dmabuf_id
> + * operands1 : number of pages to be shared
> + * operands2 : offset of data in the first page
> + * operands3 : length of data in the last page
> + * operands4 : top-level reference number for shared pages
> + * operands5~8 : Driver-specific private data (e.g. graphic buffer's meta info)
> + */
> + for (i=0; i < 8; i++)
> + request->operands[i] = operands[i];
> + break;
> +
> + case HYPER_DMABUF_DESTROY:
> + /* destroy sg_list for hyper_dmabuf_id on remote side */
> + /* command : DMABUF_DESTROY,
> + * operands0 : hyper_dmabuf_id
> + */
> + request->operands[0] = operands[0];
> + break;
> +
> + case HYPER_DMABUF_OPS_TO_REMOTE:
> + /* notifying dmabuf map/unmap to importer (probably not needed) */
> + /* for dmabuf synchronization */
> + break;
> +
> + /* as importer, command to exporter */
> + case HYPER_DMABUF_OPS_TO_SOURCE:
> + /* notifying dmabuf map/unmap to exporter, map will make the driver to do shadow mapping
> + * or unmapping for synchronization with original exporter (e.g. i915) */
> + /* command : DMABUF_OPS_TO_SOURCE.
> + * operands0 : hyper_dmabuf_id
> + * operands1 : map(=1)/unmap(=2)/attach(=3)/detach(=4)
> + */
> + for (i=0; i<2; i++)
> + request->operands[i] = operands[i];
> + break;
> +
> + /* requesting the other side to setup another ring channel for reverse direction */
> + case HYPER_DMABUF_EXPORTER_RING_SETUP:
> + /* command : HYPER_DMABUF_EXPORTER_RING_SETUP */
> + /* no operands needed */
> + break;
> +
> + default:
> + /* no command found */
> + return;
> + }
> +}
> +
> +int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_ring_rq *req)
> +{
> + uint32_t i, ret;
> + struct hyper_dmabuf_imported_sgt_info *imported_sgt_info;
> + struct hyper_dmabuf_sgt_info *sgt_info;
> +
> + /* make sure req is not NULL (may not be needed) */
> + if (!req) {
> + return -EINVAL;
> + }
> +
> + req->status = HYPER_DMABUF_REQ_PROCESSED;
> +
> + switch (req->command) {
> + case HYPER_DMABUF_EXPORT:
> + /* exporting pages for dmabuf */
> + /* command : HYPER_DMABUF_EXPORT,
> + * operands0 : hyper_dmabuf_id
> + * operands1 : number of pages to be shared
> + * operands2 : offset of data in the first page
> + * operands3 : length of data in the last page
> + * operands4 : top-level reference number for shared pages
> + * operands5~8 : Driver-specific private data (e.g. graphic buffer's meta info)
> + */
> + imported_sgt_info = (struct hyper_dmabuf_imported_sgt_info*)kcalloc(1, sizeof(*imported_sgt_info), GFP_KERNEL);
> + imported_sgt_info->hyper_dmabuf_id = req->operands[0];
> + imported_sgt_info->frst_ofst = req->operands[2];
> + imported_sgt_info->last_len = req->operands[3];
> + imported_sgt_info->nents = req->operands[1];
> + imported_sgt_info->gref = req->operands[4];
> +
> + printk("DMABUF was exported\n");
> + printk("\thyper_dmabuf_id %d\n", req->operands[0]);
> + printk("\tnents %d\n", req->operands[1]);
> + printk("\tfirst offset %d\n", req->operands[2]);
> + printk("\tlast len %d\n", req->operands[3]);
> + printk("\tgrefid %d\n", req->operands[4]);
> +
> + for (i=0; i<4; i++)
> + imported_sgt_info->private[i] = req->operands[5+i];
> +
> + hyper_dmabuf_register_imported(imported_sgt_info);
> + break;
> +
> + case HYPER_DMABUF_DESTROY:
> + /* destroy sg_list for hyper_dmabuf_id on remote side */
> + /* command : DMABUF_DESTROY,
> + * operands0 : hyper_dmabuf_id
> + */
> +
> + imported_sgt_info =
> + hyper_dmabuf_find_imported(req->operands[0]);
> +
> + if (imported_sgt_info) {
> + hyper_dmabuf_cleanup_imported_pages(imported_sgt_info);
> +
> + hyper_dmabuf_remove_imported(req->operands[0]);
> +
> + /* TODO: cleanup sgt on importer side etc */
> + }
> +
> + /* Notify exporter that buffer is freed and it can cleanup it */
> + req->status = HYPER_DMABUF_REQ_NEEDS_FOLLOW_UP;
> + req->command = HYPER_DMABUF_DESTROY_FINISH;
> +
> +#if 0 /* function is not implemented yet */
> +
> + ret = hyper_dmabuf_destroy_sgt(req->hyper_dmabuf_id);
> +#endif
> + break;
> +
> + case HYPER_DMABUF_DESTROY_FINISH:
> + /* destroy sg_list for hyper_dmabuf_id on local side */
> + /* command : DMABUF_DESTROY_FINISH,
> + * operands0 : hyper_dmabuf_id
> + */
> +
> + /* TODO: that should be done on workqueue, when received ack from all importers that buffer is no longer used */
> + sgt_info =
> + hyper_dmabuf_find_exported(req->operands[0]);
> +
> + if (sgt_info) {
> + hyper_dmabuf_cleanup_gref_table(sgt_info);
> +
> + /* unmap dmabuf */
> + dma_buf_unmap_attachment(sgt_info->attachment, sgt_info->sgt, DMA_BIDIRECTIONAL);
> + dma_buf_detach(sgt_info->dma_buf, sgt_info->attachment);
> + dma_buf_put(sgt_info->dma_buf);
> +
> + /* TODO: Rest of cleanup, sgt cleanup etc */
> + }
> +
> + break;
> +
> + case HYPER_DMABUF_OPS_TO_REMOTE:
> + /* notifying dmabuf map/unmap to importer (probably not needed) */
> + /* for dmabuf synchronization */
> + break;
> +
> + /* as importer, command to exporter */
> + case HYPER_DMABUF_OPS_TO_SOURCE:
> + /* notifying dmabuf map/unmap to exporter, map will make the driver to do shadow mapping
> + * or unmapping for synchronization with original exporter (e.g. i915) */
> + /* command : DMABUF_OPS_TO_SOURCE.
> + * operands0 : hyper_dmabuf_id
> + * operands1 : map(=1)/unmap(=2)/attach(=3)/detach(=4)
> + */
> + break;
> +
> + /* requesting the other side to setup another ring channel for reverse direction */
> + case HYPER_DMABUF_EXPORTER_RING_SETUP:
> + /* command: HYPER_DMABUF_EXPORTER_RING_SETUP
> + * no operands needed */
> + ret = hyper_dmabuf_exporter_ringbuf_init(domid, &req->operands[0], &req->operands[1]);
> + if (ret < 0) {
> + req->status = HYPER_DMABUF_REQ_ERROR;
> + return -EINVAL;
> + }
> +
> + req->status = HYPER_DMABUF_REQ_NEEDS_FOLLOW_UP;
> + req->command = HYPER_DMABUF_IMPORTER_RING_SETUP;
> + break;
> +
> + case HYPER_DMABUF_IMPORTER_RING_SETUP:
> + /* command: HYPER_DMABUF_IMPORTER_RING_SETUP */
> + /* no operands needed */
> + ret = hyper_dmabuf_importer_ringbuf_init(domid, req->operands[0], req->operands[1]);
> + if (ret < 0)
> + return -EINVAL;
> +
> + break;
> +
> + default:
> + /* no matched command, nothing to do.. just return error */
> + return -EINVAL;
> + }
> +
> + return req->command;
> +}
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.h
> new file mode 100644
> index 0000000..44bfb70
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_msg.h
> @@ -0,0 +1,45 @@
> +#ifndef __HYPER_DMABUF_MSG_H__
> +#define __HYPER_DMABUF_MSG_H__
> +
> +enum hyper_dmabuf_command {
> + HYPER_DMABUF_EXPORT = 0x10,
> + HYPER_DMABUF_DESTROY,
> + HYPER_DMABUF_DESTROY_FINISH,
> + HYPER_DMABUF_OPS_TO_REMOTE,
> + HYPER_DMABUF_OPS_TO_SOURCE,
> + HYPER_DMABUF_EXPORTER_RING_SETUP, /* requesting remote domain to set up exporter's ring */
> + HYPER_DMABUF_IMPORTER_RING_SETUP, /* requesting remote domain to set up importer's ring */
> +};
> +
> +enum hyper_dmabuf_ops {
> + HYPER_DMABUF_OPS_ATTACH = 0x1000,
> + HYPER_DMABUF_OPS_DETACH,
> + HYPER_DMABUF_OPS_MAP,
> + HYPER_DMABUF_OPS_UNMAP,
> + HYPER_DMABUF_OPS_RELEASE,
> + HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS,
> + HYPER_DMABUF_OPS_END_CPU_ACCESS,
> + HYPER_DMABUF_OPS_KMAP_ATOMIC,
> + HYPER_DMABUF_OPS_KUNMAP_ATOMIC,
> + HYPER_DMABUF_OPS_KMAP,
> + HYPER_DMABUF_OPS_KUNMAP,
> + HYPER_DMABUF_OPS_MMAP,
> + HYPER_DMABUF_OPS_VMAP,
> + HYPER_DMABUF_OPS_VUNMAP,
> +};
> +
> +enum hyper_dmabuf_req_feedback {
> + HYPER_DMABUF_REQ_PROCESSED = 0x100,
> + HYPER_DMABUF_REQ_NEEDS_FOLLOW_UP,
> + HYPER_DMABUF_REQ_ERROR,
> + HYPER_DMABUF_REQ_NOT_RESPONDED
> +};
> +
> +/* create a request packet with given command and operands */
> +void hyper_dmabuf_create_request(struct hyper_dmabuf_ring_rq *request,
> + enum hyper_dmabuf_command command, int *operands);
> +
> +/* parse incoming request packet (or response) and take appropriate actions for those */
> +int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_ring_rq *req);
> +
> +#endif // __HYPER_DMABUF_MSG_H__
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_query.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_query.h
> new file mode 100644
> index 0000000..a577167
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_query.h
> @@ -0,0 +1,16 @@
> +#ifndef __HYPER_DMABUF_QUERY_H__
> +#define __HYPER_DMABUF_QUERY_H__
> +
> +enum hyper_dmabuf_query {
> + DMABUF_QUERY_TYPE_LIST = 0x10,
> + DMABUF_QUERY_EXPORTER,
> + DMABUF_QUERY_IMPORTER,
> + DMABUF_QUERY_SIZE
> +};
> +
> +enum hyper_dmabuf_status {
> + EXPORTED = 0x01,
> + IMPORTED
> +};
> +
> +#endif /* __HYPER_DMABUF_QUERY_H__ */
> diff --git a/drivers/xen/hyper_dmabuf/hyper_dmabuf_struct.h b/drivers/xen/hyper_dmabuf/hyper_dmabuf_struct.h
> new file mode 100644
> index 0000000..c8a2f4d
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/hyper_dmabuf_struct.h
> @@ -0,0 +1,70 @@
> +#ifndef __HYPER_DMABUF_STRUCT_H__
> +#define __HYPER_DMABUF_STRUCT_H__
> +
> +#include <xen/interface/grant_table.h>
> +
> +/* Importer combine source domain id with given hyper_dmabuf_id
> + * to make it unique in case there are multiple exporters */
> +
> +#define HYPER_DMABUF_ID_IMPORTER(sdomain, id) \
> + ((((sdomain) & 0xFF) << 24) | ((id) & 0xFFFFFF))
> +
> +#define HYPER_DMABUF_ID_IMPORTER_GET_SDOMAIN_ID(id) \
> + (((id) >> 24) & 0xFF)
> +
> +/* each grant_ref_t is 4 bytes, so total 4096 grant_ref_t can be
> + * in this block meaning we can share 4KB*4096 = 16MB of buffer
> + * (needs to be increased for large buffer use-cases such as 4K
> + * frame buffer) */
> +#define MAX_ALLOWED_NUM_PAGES_FOR_GREF_NUM_ARRAYS 4
> +
> +struct hyper_dmabuf_shared_pages_info {
> + grant_ref_t *data_refs; /* table with shared buffer pages refid */
> + grant_ref_t *addr_pages; /* pages of 2nd level addressing */
> + grant_ref_t *top_level_page; /* page of top level addressing, it contains refids of 2nd level pages */
> + grant_ref_t top_level_ref; /* top level refid */
> + struct gnttab_unmap_grant_ref* unmap_ops; /* unmap ops for mapped pages */
> + struct page **data_pages; /* data pages to be unmapped */
> +};
> +
> +/* Exporter builds pages_info before sharing pages */
> +struct hyper_dmabuf_pages_info {
> + int hyper_dmabuf_id; /* unique id to reference dmabuf in source domain */
> + int hyper_dmabuf_rdomain; /* currenting considering just one remote domain access it */
> + int frst_ofst; /* offset of data in the first page */
> + int last_len; /* length of data in the last page */
> + int nents; /* # of pages */
> + struct page **pages; /* pages that contains reference numbers of shared pages*/
> +};
> +
> +/* Both importer and exporter use this structure to point to sg lists
> + *
> + * Exporter stores references to sgt in a hash table
> + * Exporter keeps these references for synchronization and tracking purposes
> + *
> + * Importer use this structure exporting to other drivers in the same domain */
> +struct hyper_dmabuf_sgt_info {
> + int hyper_dmabuf_id; /* unique id to reference dmabuf in remote domain */
> + int hyper_dmabuf_rdomain; /* domain importing this sgt */
> + struct sg_table *sgt; /* pointer to sgt */
> + struct dma_buf *dma_buf; /* needed to store this for freeing it later */
> + struct dma_buf_attachment *attachment; /* needed to store this for freeing this later */
> + struct hyper_dmabuf_shared_pages_info shared_pages_info;
> + int private[4]; /* device specific info (e.g. image's meta info?) */
> +};
> +
> +/* Importer store references (before mapping) on shared pages
> + * Importer store these references in the table and map it in
> + * its own memory map once userspace asks for reference for the buffer */
> +struct hyper_dmabuf_imported_sgt_info {
> + int hyper_dmabuf_id; /* unique id to reference dmabuf (HYPER_DMABUF_ID_IMPORTER(source domain id, exporter's hyper_dmabuf_id */
> + int frst_ofst; /* start offset in shared page #1 */
> + int last_len; /* length of data in the last shared page */
> + int nents; /* number of pages to be shared */
> + grant_ref_t gref; /* reference number of top level addressing page of shared pages */
> + struct sg_table *sgt; /* sgt pointer after importing buffer */
> + struct hyper_dmabuf_shared_pages_info shared_pages_info;
> + int private[4]; /* device specific info (e.g. image's meta info?) */
> +};
> +
> +#endif /* __HYPER_DMABUF_STRUCT_H__ */
> diff --git a/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c
> new file mode 100644
> index 0000000..22f2ef0
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.c
> @@ -0,0 +1,328 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <xen/grant_table.h>
> +#include <xen/events.h>
> +#include <xen/xenbus.h>
> +#include <asm/xen/page.h>
> +#include "hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_xen_comm_list.h"
> +#include "../hyper_dmabuf_imp.h"
> +#include "../hyper_dmabuf_list.h"
> +#include "../hyper_dmabuf_msg.h"
> +
> +static int export_req_id = 0;
> +static int import_req_id = 0;
> +
> +int32_t hyper_dmabuf_get_domid(void)
> +{
> + struct xenbus_transaction xbt;
> + int32_t domid;
> +
> + xenbus_transaction_start(&xbt);
> +
> + if (!xenbus_scanf(xbt, "domid","", "%d", &domid)) {
> + domid = -1;
> + }
> + xenbus_transaction_end(xbt, 0);
> +
> + return domid;
> +}
> +
> +int hyper_dmabuf_next_req_id_export(void)
> +{
> + export_req_id++;
> + return export_req_id;
> +}
> +
> +int hyper_dmabuf_next_req_id_import(void)
> +{
> + import_req_id++;
> + return import_req_id;
> +}
> +
> +/* For now cache latast rings as global variables TODO: keep them in list*/
> +static irqreturn_t hyper_dmabuf_front_ring_isr(int irq, void *dev_id);
> +static irqreturn_t hyper_dmabuf_back_ring_isr(int irq, void *dev_id);
> +
> +/* exporter needs to generated info for page sharing */
> +int hyper_dmabuf_exporter_ringbuf_init(int rdomain, grant_ref_t *refid, int *port)
> +{
> + struct hyper_dmabuf_ring_info_export *ring_info;
> + struct hyper_dmabuf_sring *sring;
> + struct evtchn_alloc_unbound alloc_unbound;
> + struct evtchn_close close;
> +
> + void *shared_ring;
> + int ret;
> +
> + ring_info = (struct hyper_dmabuf_ring_info_export*)
> + kmalloc(sizeof(*ring_info), GFP_KERNEL);
> +
> + /* from exporter to importer */
> + shared_ring = (void *)__get_free_pages(GFP_KERNEL, 1);
> + if (shared_ring == 0) {
> + return -EINVAL;
> + }
> +
> + sring = (struct hyper_dmabuf_sring *) shared_ring;
> +
> + SHARED_RING_INIT(sring);
> +
> + FRONT_RING_INIT(&(ring_info->ring_front), sring, PAGE_SIZE);
> +
> + ring_info->gref_ring = gnttab_grant_foreign_access(rdomain,
> + virt_to_mfn(shared_ring), 0);
> + if (ring_info->gref_ring < 0) {
> + return -EINVAL; /* fail to get gref */
> + }
> +
> + alloc_unbound.dom = DOMID_SELF;
> + alloc_unbound.remote_dom = rdomain;
> + ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound);
> + if (ret != 0) {
> + printk("Cannot allocate event channel\n");
> + return -EINVAL;
> + }
> +
> + /* setting up interrupt */
> + ret = bind_evtchn_to_irqhandler(alloc_unbound.port,
> + hyper_dmabuf_front_ring_isr, 0,
> + NULL, (void*) ring_info);
> +
> + if (ret < 0) {
> + printk("Failed to setup event channel\n");
> + close.port = alloc_unbound.port;
> + HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
> + gnttab_end_foreign_access(ring_info->gref_ring, 0, virt_to_mfn(shared_ring));
> + return -EINVAL;
> + }
> +
> + ring_info->rdomain = rdomain;
> + ring_info->irq = ret;
> + ring_info->port = alloc_unbound.port;
> +
> + /* store refid and port numbers for userspace's use */
> + *refid = ring_info->gref_ring;
> + *port = ring_info->port;
> +
> + printk("%s: allocated eventchannel gref %d port: %d irq: %d\n", __func__,
> + ring_info->gref_ring,
> + ring_info->port,
> + ring_info->irq);
> +
> + /* register ring info */
> + ret = hyper_dmabuf_register_exporter_ring(ring_info);
> +
> + return ret;
> +}
> +
> +/* importer needs to know about shared page and port numbers for ring buffer and event channel */
> +int hyper_dmabuf_importer_ringbuf_init(int sdomain, grant_ref_t gref, int port)
> +{
> + struct hyper_dmabuf_ring_info_import *ring_info;
> + struct hyper_dmabuf_sring *sring;
> +
> + struct page *shared_ring;
> +
> + struct gnttab_map_grant_ref *ops;
> + struct gnttab_unmap_grant_ref *unmap_ops;
> + int ret;
> +
> + ring_info = (struct hyper_dmabuf_ring_info_import *)
> + kmalloc(sizeof(*ring_info), GFP_KERNEL);
> +
> + ring_info->sdomain = sdomain;
> + ring_info->evtchn = port;
> +
> + ops = (struct gnttab_map_grant_ref*)kmalloc(sizeof(*ops), GFP_KERNEL);
> + unmap_ops = (struct gnttab_unmap_grant_ref*)kmalloc(sizeof(*unmap_ops), GFP_KERNEL);
> +
> + if (gnttab_alloc_pages(1, &shared_ring)) {
> + return -EINVAL;
> + }
> +
> + gnttab_set_map_op(&ops[0], (unsigned long)pfn_to_kaddr(page_to_pfn(shared_ring)),
> + GNTMAP_host_map, gref, sdomain);
> +
> + ret = gnttab_map_refs(ops, NULL, &shared_ring, 1);
> + if (ret < 0) {
> + printk("Cannot map ring\n");
> + return -EINVAL;
> + }
> +
> + if (ops[0].status) {
> + printk("Ring mapping failed\n");
> + return -EINVAL;
> + }
> +
> + sring = (struct hyper_dmabuf_sring*) pfn_to_kaddr(page_to_pfn(shared_ring));
> +
> + BACK_RING_INIT(&ring_info->ring_back, sring, PAGE_SIZE);
> +
> + ret = bind_interdomain_evtchn_to_irqhandler(sdomain, port, hyper_dmabuf_back_ring_isr, 0,
> + NULL, (void*)ring_info);
> + if (ret < 0) {
> + return -EINVAL;
> + }
> +
> + ring_info->irq = ret;
> +
> + printk("%s: bound to eventchannel port: %d irq: %d\n", __func__,
> + port,
> + ring_info->irq);
> +
> + ret = hyper_dmabuf_register_importer_ring(ring_info);
> +
> + return ret;
> +}
> +
> +int hyper_dmabuf_send_request(int domain, struct hyper_dmabuf_ring_rq *req)
> +{
> + struct hyper_dmabuf_front_ring *ring;
> + struct hyper_dmabuf_ring_rq *new_req;
> + struct hyper_dmabuf_ring_info_export *ring_info;
> + int notify;
> +
> + /* find a ring info for the channel */
> + ring_info = hyper_dmabuf_find_exporter_ring(domain);
> + if (!ring_info) {
> + printk("Can't find ring info for the channel\n");
> + return -EINVAL;
> + }
> +
> + ring = &ring_info->ring_front;
> +
> + if (RING_FULL(ring))
> + return -EBUSY;
> +
> + new_req = RING_GET_REQUEST(ring, ring->req_prod_pvt);
> + if (!new_req) {
> + printk("NULL REQUEST\n");
> + return -EIO;
> + }
> +
> + memcpy(new_req, req, sizeof(*new_req));
> +
> + ring->req_prod_pvt++;
> +
> + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
> + if (notify) {
> + notify_remote_via_irq(ring_info->irq);
> + }
> +
> + return 0;
> +}
> +
> +/* called by interrupt (WORKQUEUE) */
> +int hyper_dmabuf_send_response(struct hyper_dmabuf_ring_rp* response, int domain)
> +{
> + /* as a importer and as a exporter */
> + return 0;
> +}
> +
> +/* ISR for request from exporter (as an importer) */
> +static irqreturn_t hyper_dmabuf_back_ring_isr(int irq, void *dev_id)
> +{
> + RING_IDX rc, rp;
> + struct hyper_dmabuf_ring_rq request;
> + struct hyper_dmabuf_ring_rp response;
> + int notify, more_to_do;
> + int ret;
> +// struct hyper_dmabuf_work *work;
> +
> + struct hyper_dmabuf_ring_info_import *ring_info = (struct hyper_dmabuf_ring_info_import *)dev_id;
> + struct hyper_dmabuf_back_ring *ring;
> +
> + ring = &ring_info->ring_back;
> +
> + do {
> + rc = ring->req_cons;
> + rp = ring->sring->req_prod;
> +
> + while (rc != rp) {
> + if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
> + break;
> +
> + memcpy(&request, RING_GET_REQUEST(ring, rc), sizeof(request));
> + printk("Got request\n");
> + ring->req_cons = ++rc;
> +
> + /* TODO: probably using linked list for multiple requests then let
> + * a task in a workqueue to process those is better idea becuase
> + * we do not want to stay in ISR for long.
> + */
> + ret = hyper_dmabuf_msg_parse(ring_info->sdomain, &request);
> +
> + if (ret > 0) {
> + /* build response */
> + memcpy(&response, &request, sizeof(response));
> +
> + /* we sent back modified request as a response.. we might just need to have request only..*/
> + memcpy(RING_GET_RESPONSE(ring, ring->rsp_prod_pvt), &response, sizeof(response));
> + ring->rsp_prod_pvt++;
> +
> + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
> +
> + if (notify) {
> + printk("Notyfing\n");
> + notify_remote_via_irq(ring_info->irq);
> + }
> + }
> +
> + RING_FINAL_CHECK_FOR_REQUESTS(ring, more_to_do);
> + printk("Final check for requests %d\n", more_to_do);
> + }
> + } while (more_to_do);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/* ISR for responses from importer */
> +static irqreturn_t hyper_dmabuf_front_ring_isr(int irq, void *dev_id)
> +{
> + /* front ring only care about response from back */
> + struct hyper_dmabuf_ring_rp *response;
> + RING_IDX i, rp;
> + int more_to_do, ret;
> +
> + struct hyper_dmabuf_ring_info_export *ring_info = (struct hyper_dmabuf_ring_info_export *)dev_id;
> + struct hyper_dmabuf_front_ring *ring;
> + ring = &ring_info->ring_front;
> +
> + do {
> + more_to_do = 0;
> + rp = ring->sring->rsp_prod;
> + for (i = ring->rsp_cons; i != rp; i++) {
> + unsigned long id;
> +
> + response = RING_GET_RESPONSE(ring, i);
> + id = response->response_id;
> +
> + if (response->status == HYPER_DMABUF_REQ_NEEDS_FOLLOW_UP) {
> + /* parsing response */
> + ret = hyper_dmabuf_msg_parse(ring_info->rdomain, (struct hyper_dmabuf_ring_rq*)response);
> +
> + if (ret < 0) {
> + printk("getting error while parsing response\n");
> + }
> + } else if (response->status == HYPER_DMABUF_REQ_ERROR) {
> + printk("remote domain %d couldn't process request %d\n", ring_info->rdomain, response->command);
> + }
> +
> + }
> +
> + ring->rsp_cons = i;
> +
> + if (i != ring->req_prod_pvt) {
> + RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
> + printk("more to do %d\n", more_to_do);
> + } else {
> + ring->sring->rsp_event = i+1;
> + }
> + } while (more_to_do);
> +
> + return IRQ_HANDLED;
> +}
> diff --git a/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.h b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.h
> new file mode 100644
> index 0000000..2754917
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm.h
> @@ -0,0 +1,62 @@
> +#ifndef __HYPER_DMABUF_XEN_COMM_H__
> +#define __HYPER_DMABUF_XEN_COMM_H__
> +
> +#include "xen/interface/io/ring.h"
> +
> +#define MAX_NUMBER_OF_OPERANDS 9
> +
> +struct hyper_dmabuf_ring_rq {
> + unsigned int request_id;
> + unsigned int status;
> + unsigned int command;
> + unsigned int operands[MAX_NUMBER_OF_OPERANDS];
> +};
> +
> +struct hyper_dmabuf_ring_rp {
> + unsigned int response_id;
> + unsigned int status;
> + unsigned int command;
> + unsigned int operands[MAX_NUMBER_OF_OPERANDS];
> +};
> +
> +DEFINE_RING_TYPES(hyper_dmabuf, struct hyper_dmabuf_ring_rq, struct hyper_dmabuf_ring_rp);
> +
> +struct hyper_dmabuf_ring_info_export {
> + struct hyper_dmabuf_front_ring ring_front;
> + int rdomain;
> + int gref_ring;
> + int irq;
> + int port;
> +};
> +
> +struct hyper_dmabuf_ring_info_import {
> + int sdomain;
> + int irq;
> + int evtchn;
> + struct hyper_dmabuf_back_ring ring_back;
> +};
> +
> +//struct hyper_dmabuf_work {
> +// hyper_dmabuf_ring_rq requrest;
> +// struct work_struct msg_parse;
> +//};
> +
> +int32_t hyper_dmabuf_get_domid(void);
> +
> +int hyper_dmabuf_next_req_id_export(void);
> +
> +int hyper_dmabuf_next_req_id_import(void);
> +
> +/* exporter needs to generated info for page sharing */
> +int hyper_dmabuf_exporter_ringbuf_init(int rdomain, grant_ref_t *gref, int *port);
> +
> +/* importer needs to know about shared page and port numbers for ring buffer and event channel */
> +int hyper_dmabuf_importer_ringbuf_init(int sdomain, grant_ref_t gref, int port);
> +
> +/* send request to the remote domain */
> +int hyper_dmabuf_send_request(int domain, struct hyper_dmabuf_ring_rq *req);
> +
> +/* called by interrupt (WORKQUEUE) */
> +int hyper_dmabuf_send_response(struct hyper_dmabuf_ring_rp* response, int domain);
> +
> +#endif // __HYPER_DMABUF_XEN_COMM_H__
> diff --git a/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c
> new file mode 100644
> index 0000000..15c9d29
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.c
> @@ -0,0 +1,106 @@
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <asm/uaccess.h>
> +#include <linux/hashtable.h>
> +#include <xen/grant_table.h>
> +#include "hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_xen_comm_list.h"
> +
> +DECLARE_HASHTABLE(hyper_dmabuf_hash_importer_ring, MAX_ENTRY_IMPORT_RING);
> +DECLARE_HASHTABLE(hyper_dmabuf_hash_exporter_ring, MAX_ENTRY_EXPORT_RING);
> +
> +int hyper_dmabuf_ring_table_init()
> +{
> + hash_init(hyper_dmabuf_hash_importer_ring);
> + hash_init(hyper_dmabuf_hash_exporter_ring);
> + return 0;
> +}
> +
> +int hyper_dmabuf_ring_table_destroy()
> +{
> + /* TODO: cleanup tables*/
> + return 0;
> +}
> +
> +int hyper_dmabuf_register_exporter_ring(struct hyper_dmabuf_ring_info_export *ring_info)
> +{
> + struct hyper_dmabuf_exporter_ring_info *info_entry;
> +
> + info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> + info_entry->info = ring_info;
> +
> + hash_add(hyper_dmabuf_hash_exporter_ring, &info_entry->node,
> + info_entry->info->rdomain);
> +
> + return 0;
> +}
> +
> +int hyper_dmabuf_register_importer_ring(struct hyper_dmabuf_ring_info_import *ring_info)
> +{
> + struct hyper_dmabuf_importer_ring_info *info_entry;
> +
> + info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> + info_entry->info = ring_info;
> +
> + hash_add(hyper_dmabuf_hash_importer_ring, &info_entry->node,
> + info_entry->info->sdomain);
> +
> + return 0;
> +}
> +
> +struct hyper_dmabuf_ring_info_export *hyper_dmabuf_find_exporter_ring(int domid)
> +{
> + struct hyper_dmabuf_exporter_ring_info *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_exporter_ring, bkt, info_entry, node)
> + if(info_entry->info->rdomain == domid)
> + return info_entry->info;
> +
> + return NULL;
> +}
> +
> +struct hyper_dmabuf_ring_info_import *hyper_dmabuf_find_importer_ring(int domid)
> +{
> + struct hyper_dmabuf_importer_ring_info *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_importer_ring, bkt, info_entry, node)
> + if(info_entry->info->sdomain == domid)
> + return info_entry->info;
> +
> + return NULL;
> +}
> +
> +int hyper_dmabuf_remove_exporter_ring(int domid)
> +{
> + struct hyper_dmabuf_exporter_ring_info *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_exporter_ring, bkt, info_entry, node)
> + if(info_entry->info->rdomain == domid) {
> + hash_del(&info_entry->node);
> + return 0;
> + }
> +
> + return -1;
> +}
> +
> +int hyper_dmabuf_remove_importer_ring(int domid)
> +{
> + struct hyper_dmabuf_importer_ring_info *info_entry;
> + int bkt;
> +
> + hash_for_each(hyper_dmabuf_hash_importer_ring, bkt, info_entry, node)
> + if(info_entry->info->sdomain == domid) {
> + hash_del(&info_entry->node);
> + return 0;
> + }
> +
> + return -1;
> +}
> diff --git a/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.h b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.h
> new file mode 100644
> index 0000000..5929f99
> --- /dev/null
> +++ b/drivers/xen/hyper_dmabuf/xen/hyper_dmabuf_xen_comm_list.h
> @@ -0,0 +1,35 @@
> +#ifndef __HYPER_DMABUF_XEN_COMM_LIST_H__
> +#define __HYPER_DMABUF_XEN_COMM_LIST_H__
> +
> +/* number of bits to be used for exported dmabufs hash table */
> +#define MAX_ENTRY_EXPORT_RING 7
> +/* number of bits to be used for imported dmabufs hash table */
> +#define MAX_ENTRY_IMPORT_RING 7
> +
> +struct hyper_dmabuf_exporter_ring_info {
> + struct hyper_dmabuf_ring_info_export *info;
> + struct hlist_node node;
> +};
> +
> +struct hyper_dmabuf_importer_ring_info {
> + struct hyper_dmabuf_ring_info_import *info;
> + struct hlist_node node;
> +};
> +
> +int hyper_dmabuf_ring_table_init(void);
> +
> +int hyper_dmabuf_ring_table_destroy(void);
> +
> +int hyper_dmabuf_register_exporter_ring(struct hyper_dmabuf_ring_info_export *ring_info);
> +
> +int hyper_dmabuf_register_importer_ring(struct hyper_dmabuf_ring_info_import *ring_info);
> +
> +struct hyper_dmabuf_ring_info_export *hyper_dmabuf_find_exporter_ring(int domid);
> +
> +struct hyper_dmabuf_ring_info_import *hyper_dmabuf_find_importer_ring(int domid);
> +
> +int hyper_dmabuf_remove_exporter_ring(int domid);
> +
> +int hyper_dmabuf_remove_importer_ring(int domid);
> +
> +#endif // __HYPER_DMABUF_XEN_COMM_LIST_H__
> --
> 2.7.4
>
>