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__
