lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20201130230707.46351-23-mgross@linux.intel.com>
Date:   Mon, 30 Nov 2020 15:07:07 -0800
From:   mgross@...ux.intel.com
To:     linux-kernel@...r.kernel.org
Cc:     markgross@...nel.org, mgross@...ux.intel.com,
        adam.r.gretzinger@...el.com, Seamus Kelly <seamus.kelly@...el.com>,
        Arnd Bergmann <arnd@...db.de>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Subject: [PATCH 22/22] xlink-core: factorize xlink_ioctl function by creating sub-functions for each ioctl command

From: Seamus Kelly <seamus.kelly@...el.com>

Refactor the too large IOCTL function to call helper functions.

Cc: Arnd Bergmann <arnd@...db.de>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Reviewed-by: Mark Gross <mgross@...ux.intel.com>
Signed-off-by: Seamus Kelly <seamus.kelly@...el.com>
---
 drivers/misc/xlink-core/Makefile      |   2 +-
 drivers/misc/xlink-core/xlink-core.c  | 625 ++++++--------------------
 drivers/misc/xlink-core/xlink-core.h  |  24 +
 drivers/misc/xlink-core/xlink-defs.h  |   2 +-
 drivers/misc/xlink-core/xlink-ioctl.c | 584 ++++++++++++++++++++++++
 drivers/misc/xlink-core/xlink-ioctl.h |  36 ++
 6 files changed, 773 insertions(+), 500 deletions(-)
 create mode 100644 drivers/misc/xlink-core/xlink-core.h
 create mode 100644 drivers/misc/xlink-core/xlink-ioctl.c
 create mode 100644 drivers/misc/xlink-core/xlink-ioctl.h

diff --git a/drivers/misc/xlink-core/Makefile b/drivers/misc/xlink-core/Makefile
index 6e604c0b8962..2f64703301d6 100644
--- a/drivers/misc/xlink-core/Makefile
+++ b/drivers/misc/xlink-core/Makefile
@@ -2,4 +2,4 @@
 # Makefile for KeemBay xlink Linux driver
 #
 obj-$(CONFIG_XLINK_CORE) += xlink.o
-xlink-objs += xlink-core.o xlink-multiplexer.o xlink-dispatcher.o xlink-platform.o
+xlink-objs += xlink-core.o xlink-multiplexer.o xlink-dispatcher.o xlink-platform.o xlink-ioctl.o
diff --git a/drivers/misc/xlink-core/xlink-core.c b/drivers/misc/xlink-core/xlink-core.c
index 63f65def8aa9..ed2b37085851 100644
--- a/drivers/misc/xlink-core/xlink-core.c
+++ b/drivers/misc/xlink-core/xlink-core.c
@@ -20,9 +20,11 @@
 #endif
 
 #include "xlink-defs.h"
+#include "xlink-core.h"
 #include "xlink-dispatcher.h"
 #include "xlink-multiplexer.h"
 #include "xlink-platform.h"
+#include "xlink-ioctl.h"
 
 // xlink version number
 #define XLINK_VERSION_MAJOR		0
@@ -52,25 +54,7 @@ static struct class *dev_class;
 static struct cdev xlink_cdev;
 
 static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-static enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
-					      u16 chan, u8 const *pmessage,
-					      u32 size);
 
-static enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
-						  u16 chan, u8 const *message,
-						  u32 size);
-static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
-						u16 chan, u8 const *message,
-						u32 size, u32 user_flag);
-static enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
-							 u32 *event_list,
-							 u32 num_events,
-							 xlink_device_event_cb event_notif_fn);
-static enum xlink_error do_xlink_register_device_event(struct xlink_handle *handle,
-						       u32 *event_list,
-						       u32 num_events,
-						       xlink_device_event_cb event_notif_fn,
-						       u32 user_flag);
 static struct mutex dev_event_lock;
 
 static const struct file_operations fops = {
@@ -105,9 +89,6 @@ struct event_info {
 	xlink_device_event_cb event_notif_fn;
 };
 
-static u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
-#define NUM_REG_EVENTS 4
-
 // sysfs attribute functions
 
 static ssize_t event0_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -342,427 +323,84 @@ static int kmb_xlink_remove(struct platform_device *pdev)
  * IOCTL function for User Space access to xlink kernel functions
  *
  */
+int ioctl_connect(unsigned long arg);
 
 static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct xlink_handle		devh	= {0};
-	struct xlinkopenchannel		op	= {0};
-	struct xlinkwritedata		wr	= {0};
-	struct xlinkreaddata		rd	= {0};
-	struct xlinkreadtobuffer	rdtobuf = {0};
-	struct xlinkconnect		con	= {0};
-	struct xlinkrelease		rel	= {0};
-	struct xlinkstartvpu		startvpu = {0};
-	struct xlinkcallback		cb	= {0};
-	struct xlinkgetdevicename	devn	= {0};
-	struct xlinkgetdevicelist	devl	= {0};
-	struct xlinkgetdevicestatus	devs	= {0};
-	struct xlinkbootdevice		boot	= {0};
-	struct xlinkresetdevice		res	= {0};
-	struct xlinkdevmode		devm	= {0};
-	struct xlinkregdevevent		regdevevent = {0};
-	u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
-	char name[XLINK_MAX_DEVICE_NAME_SIZE];
-	int interface = NULL_INTERFACE;
-	u32 device_status = 0;
-	u32 num_devices = 0;
-	u32 device_mode = 0;
-	u32 num_events = 0;
-	char filename[64];
-	u32 *ev_list;
-	u8 reladdr;
-	u8 *rdaddr;
-	u32 size;
 	int rc;
 
 	switch (cmd) {
 	case XL_CONNECT:
-		if (copy_from_user(&con, (void __user *)arg,
-				   sizeof(struct xlinkconnect)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)con.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_connect(&devh);
-		if (rc == X_LINK_SUCCESS) {
-			if (copy_to_user((void __user *)con.handle,
-					 &devh, sizeof(struct xlink_handle)))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)con.return_code, (void *)&rc,
-				 sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_connect(arg);
 		break;
 	case XL_OPEN_CHANNEL:
-		if (copy_from_user(&op, (void __user *)arg,
-				   sizeof(struct xlinkopenchannel)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)op.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_open_channel(&devh, op.chan, op.mode, op.data_size,
-					op.timeout);
-		if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_open_channel(arg);
 		break;
 	case XL_DATA_READY_CALLBACK:
-		if (copy_from_user(&cb, (void __user *)arg,
-				   sizeof(struct xlinkcallback)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)cb.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
-		rc = xlink_data_available_event(&devh, cb.chan, cb.callback);
-		if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_data_ready_callback(arg);
 		break;
 	case XL_DATA_CONSUMED_CALLBACK:
-		if (copy_from_user(&cb, (void __user *)arg,
-				   sizeof(struct xlinkcallback)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)cb.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
-		rc = xlink_data_consumed_event(&devh, cb.chan, cb.callback);
-		if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_data_consumed_callback(arg);
 		break;
 	case XL_READ_DATA:
-		if (copy_from_user(&rd, (void __user *)arg,
-				   sizeof(struct xlinkreaddata)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)rd.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_read_data(&devh, rd.chan, &rdaddr, &size);
-		if (!rc) {
-			interface = get_interface_from_sw_device_id(devh.sw_device_id);
-			if (interface == IPC_INTERFACE) {
-				if (copy_to_user((void __user *)rd.pmessage, (void *)&rdaddr,
-						 sizeof(u32)))
-					return -EFAULT;
-			} else {
-				if (copy_to_user((void __user *)rd.pmessage, (void *)rdaddr,
-						 size))
-					return -EFAULT;
-			}
-			if (copy_to_user((void __user *)rd.size, (void *)&size, sizeof(size)))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)rd.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_read_data(arg);
 		break;
 	case XL_READ_TO_BUFFER:
-		if (copy_from_user(&rdtobuf, (void __user *)arg,
-				   sizeof(struct xlinkreadtobuffer)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
-					       (u8 *)volbuf, &size);
-		if (!rc) {
-			if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
-					 size))
-				return -EFAULT;
-			if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
-					 sizeof(size)))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)rdtobuf.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_read_to_buffer(arg);
 		break;
 	case XL_WRITE_DATA:
-		if (copy_from_user(&wr, (void __user *)arg,
-				   sizeof(struct xlinkwritedata)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)wr.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (wr.size <= XLINK_MAX_DATA_SIZE) {
-			rc = xlink_write_data_user(&devh, wr.chan, wr.pmessage,
-						   wr.size);
-			if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
-					 sizeof(rc)))
-				return -EFAULT;
-		} else {
-			return -EFAULT;
-		}
+		rc = ioctl_write_data(arg);
 		break;
 	case XL_WRITE_VOLATILE:
-		if (copy_from_user(&wr, (void __user *)arg,
-				   sizeof(struct xlinkwritedata)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)wr.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (wr.size <= XLINK_MAX_BUF_SIZE) {
-			if (copy_from_user(volbuf, (void __user *)wr.pmessage,
-					   wr.size))
-				return -EFAULT;
-			rc = xlink_write_volatile_user(&devh, wr.chan, volbuf,
-						       wr.size);
-			if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
-					 sizeof(rc)))
-				return -EFAULT;
-		} else {
-			return -EFAULT;
-		}
+		rc = ioctl_write_volatile_data(arg);
 		break;
 	case XL_WRITE_CONTROL_DATA:
-		if (copy_from_user(&wr, (void __user *)arg,
-				   sizeof(struct xlinkwritedata)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)wr.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (wr.size <= XLINK_MAX_CONTROL_DATA_SIZE) {
-			if (copy_from_user(volbuf, (void __user *)wr.pmessage,
-					   wr.size))
-				return -EFAULT;
-			rc = xlink_write_control_data(&devh, wr.chan, volbuf,
-						      wr.size);
-			if (copy_to_user((void __user *)wr.return_code,
-					 (void *)&rc, sizeof(rc)))
-				return -EFAULT;
-		} else {
-			return -EFAULT;
-		}
+		rc = ioctl_write_control_data(arg);
 		break;
 	case XL_RELEASE_DATA:
-		if (copy_from_user(&rel, (void __user *)arg,
-				   sizeof(struct xlinkrelease)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)rel.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (rel.addr) {
-			if (get_user(reladdr, (u32 __user *const)rel.addr))
-				return -EFAULT;
-			rc = xlink_release_data(&devh, rel.chan,
-						(u8 *)&reladdr);
-		} else {
-			rc = xlink_release_data(&devh, rel.chan, NULL);
-		}
-		if (copy_to_user((void __user *)rel.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_release_data(arg);
 		break;
 	case XL_CLOSE_CHANNEL:
-		if (copy_from_user(&op, (void __user *)arg,
-				   sizeof(struct xlinkopenchannel)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)op.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_close_channel(&devh, op.chan);
-		if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_close_channel(arg);
 		break;
 	case XL_START_VPU:
-		if (copy_from_user(&startvpu, (void __user *)arg,
-				   sizeof(struct xlinkstartvpu)))
-			return -EFAULT;
-		if (startvpu.namesize > sizeof(filename))
-			return -EINVAL;
-		memset(filename, 0, sizeof(filename));
-		if (copy_from_user(filename, (void __user *)startvpu.filename,
-				   startvpu.namesize))
-			return -EFAULT;
-		rc = xlink_start_vpu(filename);
-		if (copy_to_user((void __user *)startvpu.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_start_vpu(arg);
 		break;
 	case XL_STOP_VPU:
-		rc = xlink_stop_vpu();
+		rc = ioctl_stop_vpu();
 		break;
 	case XL_RESET_VPU:
-		rc = xlink_stop_vpu();
+		rc = ioctl_stop_vpu();
 		break;
 	case XL_DISCONNECT:
-		if (copy_from_user(&con, (void __user *)arg,
-				   sizeof(struct xlinkconnect)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)con.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_disconnect(&devh);
-		if (copy_to_user((void __user *)con.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_disconnect(arg);
 		break;
 	case XL_GET_DEVICE_NAME:
-		if (copy_from_user(&devn, (void __user *)arg,
-				   sizeof(struct xlinkgetdevicename)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)devn.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
-			rc = xlink_get_device_name(&devh, name, devn.name_size);
-			if (!rc) {
-				if (copy_to_user((void __user *)devn.name, (void *)name,
-						 devn.name_size))
-					return -EFAULT;
-			}
-		} else {
-			rc = X_LINK_ERROR;
-		}
-		if (copy_to_user((void __user *)devn.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_get_device_name(arg);
 		break;
 	case XL_GET_DEVICE_LIST:
-		if (copy_from_user(&devl, (void __user *)arg,
-				   sizeof(struct xlinkgetdevicelist)))
-			return -EFAULT;
-		rc = xlink_get_device_list(sw_device_id_list, &num_devices);
-		if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
-			/* TODO: this next copy is dangerous! we have no idea
-			 * how large the devl.sw_device_id_list buffer is
-			 * provided by the user. if num_devices is too large,
-			 * the copy will overflow the buffer.
-			 */
-			if (copy_to_user((void __user *)devl.sw_device_id_list,
-					 (void *)sw_device_id_list,
-					 (sizeof(*sw_device_id_list)
-					 * num_devices)))
-				return -EFAULT;
-			if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
-					 (sizeof(num_devices))))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)devl.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_get_device_list(arg);
 		break;
 	case XL_GET_DEVICE_STATUS:
-		if (copy_from_user(&devs, (void __user *)arg,
-				   sizeof(struct xlinkgetdevicestatus)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)devs.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_get_device_status(&devh, &device_status);
-		if (!rc) {
-			if (copy_to_user((void __user *)devs.device_status,
-					 (void *)&device_status,
-					 sizeof(device_status)))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)devs.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_get_device_status(arg);
 		break;
 	case XL_BOOT_DEVICE:
-		if (copy_from_user(&boot, (void __user *)arg,
-				   sizeof(struct xlinkbootdevice)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)boot.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (boot.binary_name_size > sizeof(filename))
-			return -EINVAL;
-		memset(filename, 0, sizeof(filename));
-		if (copy_from_user(filename, (void __user *)boot.binary_name,
-				   boot.binary_name_size))
-			return -EFAULT;
-		rc = xlink_boot_device(&devh, filename);
-		if (copy_to_user((void __user *)boot.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_boot_device(arg);
 		break;
 	case XL_RESET_DEVICE:
-		if (copy_from_user(&res, (void __user *)arg,
-				   sizeof(struct xlinkresetdevice)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)res.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_reset_device(&devh);
-		if (copy_to_user((void __user *)res.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_reset_device(arg);
 		break;
 	case XL_GET_DEVICE_MODE:
-		if (copy_from_user(&devm, (void __user *)arg,
-				   sizeof(struct xlinkdevmode)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)devm.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		rc = xlink_get_device_mode(&devh, &device_mode);
-		if (!rc) {
-			if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
-					 sizeof(device_mode)))
-				return -EFAULT;
-		}
-		if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_get_device_mode(arg);
 		break;
 	case XL_SET_DEVICE_MODE:
-		if (copy_from_user(&devm, (void __user *)arg,
-				   sizeof(struct xlinkdevmode)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)devm.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
-				   sizeof(device_mode)))
-			return -EFAULT;
-		rc = xlink_set_device_mode(&devh, device_mode);
-		if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_set_device_mode(arg);
 		break;
 	case XL_REGISTER_DEV_EVENT:
-		if (copy_from_user(&regdevevent, (void __user *)arg,
-				   sizeof(struct xlinkregdevevent)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)regdevevent.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		num_events = regdevevent.num_events;
-		if (num_events > 0 && num_events <= NUM_REG_EVENTS) {
-			ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
-			if (ev_list) {
-				if (copy_from_user(ev_list,
-						   (void __user *)regdevevent.event_list,
-						   (num_events * sizeof(u32)))) {
-					kfree(ev_list);
-					return -EFAULT;
-				}
-				rc = xlink_register_device_event_user(&devh,
-								      ev_list,
-								      num_events,
-								      NULL);
-				kfree(ev_list);
-			} else {
-				rc = X_LINK_ERROR;
-			}
-		} else {
-			rc = X_LINK_ERROR;
-		}
-		if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_register_device_event(arg);
 		break;
 	case XL_UNREGISTER_DEV_EVENT:
-		if (copy_from_user(&regdevevent, (void __user *)arg,
-				   sizeof(struct xlinkregdevevent)))
-			return -EFAULT;
-		if (copy_from_user(&devh, (void __user *)regdevevent.handle,
-				   sizeof(struct xlink_handle)))
-			return -EFAULT;
-		num_events = regdevevent.num_events;
-		if (num_events <= NUM_REG_EVENTS) {
-			ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
-			if (copy_from_user(ev_list,
-					   (void __user *)regdevevent.event_list,
-					   (num_events * sizeof(u32)))) {
-				kfree(ev_list);
-				return -EFAULT;
-			}
-			rc = xlink_unregister_device_event(&devh, ev_list, num_events);
-			kfree(ev_list);
-		} else {
-			rc = X_LINK_ERROR;
-		}
-		if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
-			return -EFAULT;
+		rc = ioctl_unregister_device_event(arg);
 		break;
 	}
 	if (rc)
@@ -997,13 +635,16 @@ enum xlink_error xlink_close_channel(struct xlink_handle *handle,
 }
 EXPORT_SYMBOL(xlink_close_channel);
 
-enum xlink_error xlink_write_data(struct xlink_handle *handle,
-				  u16 chan, u8 const *pmessage, u32 size)
+static enum xlink_error do_xlink_write_data(struct xlink_handle *handle,
+					    u16 chan, u8 const *pmessage,
+					    u32 size, u32 user_flag)
 {
 	struct xlink_event *event;
 	struct xlink_link *link;
 	enum xlink_error rc;
 	int event_queued = 0;
+	dma_addr_t paddr = 0;
+	u32 addr;
 
 	if (!xlink || !handle)
 		return X_LINK_ERROR;
@@ -1019,88 +660,75 @@ enum xlink_error xlink_write_data(struct xlink_handle *handle,
 				   chan, size, 0);
 	if (!event)
 		return X_LINK_ERROR;
+	event->user_data = user_flag;
 
 	if (chan < XLINK_IPC_MAX_CHANNELS &&
 	    event->interface == IPC_INTERFACE) {
 		/* only passing message address across IPC interface */
-		event->data = &pmessage;
+		if (user_flag) {
+			if (get_user(addr, (u32 __user *)pmessage)) {
+				xlink_destroy_event(event);
+				return X_LINK_ERROR;
+			}
+			event->data = &addr;
+		} else {
+			event->data = &pmessage;
+		}
 		rc = xlink_multiplexer_tx(event, &event_queued);
 		xlink_destroy_event(event);
 	} else {
-		event->data = (u8 *)pmessage;
-		event->paddr = 0;
+		if (user_flag) {
+			event->data = xlink_platform_allocate(&xlink->pdev->dev, &paddr,
+							      size,
+							      XLINK_PACKET_ALIGNMENT,
+							      XLINK_NORMAL_MEMORY);
+			if (!event->data) {
+				xlink_destroy_event(event);
+				return X_LINK_ERROR;
+			}
+			if (copy_from_user(event->data, (void __user *)pmessage, size)) {
+				xlink_platform_deallocate(&xlink->pdev->dev,
+							  event->data, paddr, size,
+							  XLINK_PACKET_ALIGNMENT,
+							  XLINK_NORMAL_MEMORY);
+				xlink_destroy_event(event);
+				return X_LINK_ERROR;
+			}
+			event->paddr = paddr;
+		} else {
+			event->data = (u8 *)pmessage;
+			event->paddr = 0;
+		}
 		rc = xlink_multiplexer_tx(event, &event_queued);
-		if (!event_queued)
+		if (!event_queued) {
+			if (user_flag) {
+				xlink_platform_deallocate(&xlink->pdev->dev,
+							  event->data, paddr, size,
+							  XLINK_PACKET_ALIGNMENT,
+							  XLINK_NORMAL_MEMORY);
+			}
 			xlink_destroy_event(event);
+		}
 	}
 	return rc;
 }
-EXPORT_SYMBOL(xlink_write_data);
 
-static enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
-					      u16 chan, u8 const *pmessage,
-					      u32 size)
+enum xlink_error xlink_write_data(struct xlink_handle *handle,
+				  u16 chan, u8 const *pmessage, u32 size)
 {
-	struct xlink_event *event;
-	struct xlink_link *link;
-	enum xlink_error rc;
-	int event_queued = 0;
-	dma_addr_t paddr = 0;
-	u32 addr;
-
-	if (!xlink || !handle)
-		return X_LINK_ERROR;
-
-	if (size > XLINK_MAX_DATA_SIZE)
-		return X_LINK_ERROR;
+	enum xlink_error rc = 0;
 
-	link = get_link_by_sw_device_id(handle->sw_device_id);
-	if (!link)
-		return X_LINK_ERROR;
+	rc = do_xlink_write_data(handle, chan, pmessage, size, 0);
+	return rc;
+}
+EXPORT_SYMBOL(xlink_write_data);
 
-	event = xlink_create_event(link->id, XLINK_WRITE_REQ, &link->handle,
-				   chan, size, 0);
-	if (!event)
-		return X_LINK_ERROR;
-	event->user_data = 1;
+enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
+				       u16 chan, u8 const *pmessage, u32 size)
+{
+	enum xlink_error rc = 0;
 
-	if (chan < XLINK_IPC_MAX_CHANNELS &&
-	    event->interface == IPC_INTERFACE) {
-		/* only passing message address across IPC interface */
-		if (get_user(addr, (u32 __user *)pmessage)) {
-			xlink_destroy_event(event);
-			return X_LINK_ERROR;
-		}
-		event->data = &addr;
-		rc = xlink_multiplexer_tx(event, &event_queued);
-		xlink_destroy_event(event);
-	} else {
-		event->data = xlink_platform_allocate(&xlink->pdev->dev, &paddr,
-						      size,
-						      XLINK_PACKET_ALIGNMENT,
-						      XLINK_NORMAL_MEMORY);
-		if (!event->data) {
-			xlink_destroy_event(event);
-			return X_LINK_ERROR;
-		}
-		if (copy_from_user(event->data, (void __user *)pmessage, size)) {
-			xlink_platform_deallocate(&xlink->pdev->dev,
-						  event->data, paddr, size,
-						  XLINK_PACKET_ALIGNMENT,
-						  XLINK_NORMAL_MEMORY);
-			xlink_destroy_event(event);
-			return X_LINK_ERROR;
-		}
-		event->paddr = paddr;
-		rc = xlink_multiplexer_tx(event, &event_queued);
-		if (!event_queued) {
-			xlink_platform_deallocate(&xlink->pdev->dev,
-						  event->data, paddr, size,
-						  XLINK_PACKET_ALIGNMENT,
-						  XLINK_NORMAL_MEMORY);
-			xlink_destroy_event(event);
-		}
-	}
+	rc = do_xlink_write_data(handle, chan, pmessage, size, 1);
 	return rc;
 }
 
@@ -1131,25 +759,6 @@ enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
 	return rc;
 }
 EXPORT_SYMBOL(xlink_write_control_data);
-static enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
-						  u16 chan, u8 const *message,
-						  u32 size)
-{
-	enum xlink_error rc = 0;
-
-	rc = do_xlink_write_volatile(handle, chan, message, size, 1);
-	return rc;
-}
-
-enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
-				      u16 chan, u8 const *message, u32 size)
-{
-	enum xlink_error rc = 0;
-
-	rc = do_xlink_write_volatile(handle, chan, message, size, 0);
-	return rc;
-}
-EXPORT_SYMBOL(xlink_write_volatile);
 
 static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
 						u16 chan, u8 const *message,
@@ -1196,6 +805,26 @@ static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
 	return rc;
 }
 
+enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
+					   u16 chan, u8 const *message,
+					   u32 size)
+{
+	enum xlink_error rc = 0;
+
+	rc = do_xlink_write_volatile(handle, chan, message, size, 1);
+	return rc;
+}
+
+enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
+				      u16 chan, u8 const *message, u32 size)
+{
+	enum xlink_error rc = 0;
+
+	rc = do_xlink_write_volatile(handle, chan, message, size, 0);
+	return rc;
+}
+EXPORT_SYMBOL(xlink_write_volatile);
+
 enum xlink_error xlink_read_data(struct xlink_handle *handle,
 				 u16 chan, u8 **pmessage, u32 *size)
 {
@@ -1531,29 +1160,6 @@ static bool event_registered(u32 sw_dev_id, u32 event)
 return false;
 }
 
-static enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
-							 u32 *event_list, u32 num_events,
-							 xlink_device_event_cb event_notif_fn)
-{
-	enum xlink_error rc;
-
-	rc = do_xlink_register_device_event(handle, event_list, num_events,
-					    event_notif_fn, 1);
-	return rc;
-}
-
-enum xlink_error xlink_register_device_event(struct xlink_handle *handle,
-					     u32 *event_list, u32 num_events,
-					     xlink_device_event_cb event_notif_fn)
-{
-	enum xlink_error rc;
-
-	rc = do_xlink_register_device_event(handle, event_list, num_events,
-					    event_notif_fn, 0);
-	return rc;
-}
-EXPORT_SYMBOL(xlink_register_device_event);
-
 static enum xlink_error do_xlink_register_device_event(struct xlink_handle *handle,
 						       u32 *event_list,
 						       u32 num_events,
@@ -1599,6 +1205,29 @@ static enum xlink_error do_xlink_register_device_event(struct xlink_handle *hand
 	return X_LINK_SUCCESS;
 }
 
+enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
+						  u32 *event_list, u32 num_events,
+						  xlink_device_event_cb event_notif_fn)
+{
+	enum xlink_error rc;
+
+	rc = do_xlink_register_device_event(handle, event_list, num_events,
+					    event_notif_fn, 1);
+	return rc;
+}
+
+enum xlink_error xlink_register_device_event(struct xlink_handle *handle,
+					     u32 *event_list, u32 num_events,
+					     xlink_device_event_cb event_notif_fn)
+{
+	enum xlink_error rc;
+
+	rc = do_xlink_register_device_event(handle, event_list, num_events,
+					    event_notif_fn, 0);
+	return rc;
+}
+EXPORT_SYMBOL(xlink_register_device_event);
+
 enum xlink_error xlink_unregister_device_event(struct xlink_handle *handle,
 					       u32 *event_list,
 					       u32 num_events)
diff --git a/drivers/misc/xlink-core/xlink-core.h b/drivers/misc/xlink-core/xlink-core.h
new file mode 100644
index 000000000000..c3d100a75c44
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-core.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * xlink core header file.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+
+#ifndef XLINK_CORE_H_
+#define XLINK_CORE_H_
+#include "xlink-defs.h"
+
+#define NUM_REG_EVENTS 4
+
+enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
+				       u16 chan, u8 const *pmessage,
+				       u32 size);
+enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
+						  u32 *event_list, u32 num_events,
+						  xlink_device_event_cb event_notif_fn);
+enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
+					   u16 chan, u8 const *message,
+					   u32 size);
+#endif /* XLINK_CORE_H_ */
diff --git a/drivers/misc/xlink-core/xlink-defs.h b/drivers/misc/xlink-core/xlink-defs.h
index df686e5185c5..81aa3bfffcd3 100644
--- a/drivers/misc/xlink-core/xlink-defs.h
+++ b/drivers/misc/xlink-core/xlink-defs.h
@@ -35,7 +35,7 @@
 #define CONTROL_CHANNEL_TIMEOUT_MS	0U	// wait indefinitely
 #define SIGXLNK				44	// signal XLink uses for callback signalling
 
-#define UNUSED(x) (void)(x)
+#define UNUSED(x) ((void)(x))
 
 // the end of the IPC channel range (starting at zero)
 #define XLINK_IPC_MAX_CHANNELS	1024
diff --git a/drivers/misc/xlink-core/xlink-ioctl.c b/drivers/misc/xlink-core/xlink-ioctl.c
new file mode 100644
index 000000000000..9c1a8c896945
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-ioctl.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * xlink Core Driver.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+
+#include "xlink-defs.h"
+#include "xlink-core.h"
+#include "xlink-ioctl.h"
+
+#define CHANNEL_SET_USER_BIT(chan) ((chan) |= (1 << 15))
+
+int ioctl_connect(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkconnect		con	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&con, (void __user *)arg,
+			   sizeof(struct xlinkconnect)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)con.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_connect(&devh);
+	if (rc == X_LINK_SUCCESS) {
+		if (copy_to_user((void __user *)con.handle,
+				 &devh, sizeof(struct xlink_handle)))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)con.return_code, (void *)&rc,
+			 sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_open_channel(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkopenchannel	op	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&op, (void __user *)arg,
+			   sizeof(struct xlinkopenchannel)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)op.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_open_channel(&devh, op.chan, op.mode, op.data_size,
+				op.timeout);
+	if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_read_data(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkreaddata	rd	= {0};
+	int rc = 0;
+	u8 *rdaddr;
+	u32 size;
+	int interface;
+
+	if (copy_from_user(&rd, (void __user *)arg,
+			   sizeof(struct xlinkreaddata)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)rd.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_read_data(&devh, rd.chan, &rdaddr, &size);
+	if (!rc) {
+		interface = get_interface_from_sw_device_id(devh.sw_device_id);
+		if (interface == IPC_INTERFACE) {
+			if (copy_to_user((void __user *)rd.pmessage, (void *)&rdaddr,
+					 sizeof(u32)))
+				return -EFAULT;
+		} else {
+			if (copy_to_user((void __user *)rd.pmessage, (void *)rdaddr,
+					 size))
+				return -EFAULT;
+		}
+		if (copy_to_user((void __user *)rd.size, (void *)&size, sizeof(size)))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)rd.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_read_to_buffer(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkreadtobuffer	rdtobuf = {0};
+	int rc = 0;
+	u32 size;
+	u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
+	if (copy_from_user(&rdtobuf, (void __user *)arg,
+			   sizeof(struct xlinkreadtobuffer)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
+				       (u8 *)volbuf, &size);
+	if (!rc) {
+		if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
+				 size))
+			return -EFAULT;
+		if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
+				 sizeof(size)))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)rdtobuf.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_write_data(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkwritedata		wr	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&wr, (void __user *)arg,
+			   sizeof(struct xlinkwritedata)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)wr.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (wr.size <= XLINK_MAX_DATA_SIZE) {
+		rc = xlink_write_data_user(&devh, wr.chan, wr.pmessage,
+					   wr.size);
+		if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
+				 sizeof(rc)))
+			return -EFAULT;
+	} else {
+		return -EFAULT;
+	}
+	return rc;
+}
+
+int ioctl_write_control_data(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkwritedata		wr	= {0};
+	u8 volbuf[XLINK_MAX_BUF_SIZE];
+	int rc = 0;
+
+	if (copy_from_user(&wr, (void __user *)arg,
+			   sizeof(struct xlinkwritedata)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)wr.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (wr.size <= XLINK_MAX_CONTROL_DATA_SIZE) {
+		if (copy_from_user(volbuf, (void __user *)wr.pmessage,
+				   wr.size))
+			return -EFAULT;
+		rc = xlink_write_control_data(&devh, wr.chan, volbuf,
+					      wr.size);
+		if (copy_to_user((void __user *)wr.return_code,
+				 (void *)&rc, sizeof(rc)))
+			return -EFAULT;
+	} else {
+		return -EFAULT;
+	}
+	return rc;
+}
+
+int ioctl_write_volatile_data(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkwritedata	wr	= {0};
+	int rc = 0;
+	u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
+	if (copy_from_user(&wr, (void __user *)arg,
+			   sizeof(struct xlinkwritedata)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)wr.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (wr.size <= XLINK_MAX_BUF_SIZE) {
+		if (copy_from_user(volbuf, (void __user *)wr.pmessage,
+				   wr.size))
+			return -EFAULT;
+		rc = xlink_write_volatile_user(&devh, wr.chan, volbuf,
+					       wr.size);
+		if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
+				 sizeof(rc)))
+			return -EFAULT;
+	} else {
+		return -EFAULT;
+	}
+	return rc;
+}
+
+int ioctl_release_data(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkrelease	rel	= {0};
+	int rc = 0;
+	u8 reladdr;
+
+	if (copy_from_user(&rel, (void __user *)arg,
+			   sizeof(struct xlinkrelease)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)rel.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (rel.addr) {
+		if (get_user(reladdr, (u32 __user *const)rel.addr))
+			return -EFAULT;
+		rc = xlink_release_data(&devh, rel.chan,
+					(u8 *)&reladdr);
+	} else {
+		rc = xlink_release_data(&devh, rel.chan, NULL);
+	}
+	if (copy_to_user((void __user *)rel.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_close_channel(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkopenchannel		op	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&op, (void __user *)arg,
+			   sizeof(struct xlinkopenchannel)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)op.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_close_channel(&devh, op.chan);
+	if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_start_vpu(unsigned long arg)
+{
+	struct xlinkstartvpu		startvpu = {0};
+	char filename[64];
+	int rc = 0;
+
+	if (copy_from_user(&startvpu, (void __user *)arg,
+			   sizeof(struct xlinkstartvpu)))
+		return -EFAULT;
+	if (startvpu.namesize > sizeof(filename))
+		return -EINVAL;
+	memset(filename, 0, sizeof(filename));
+	if (copy_from_user(filename, (void __user *)startvpu.filename,
+			   startvpu.namesize))
+		return -EFAULT;
+	rc = xlink_start_vpu(filename);
+	if (copy_to_user((void __user *)startvpu.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_stop_vpu(void)
+{
+	int rc = 0;
+
+	rc = xlink_stop_vpu();
+	return rc;
+}
+
+int ioctl_disconnect(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkconnect		con	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&con, (void __user *)arg,
+			   sizeof(struct xlinkconnect)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)con.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_disconnect(&devh);
+	if (copy_to_user((void __user *)con.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_get_device_name(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkgetdevicename	devn	= {0};
+	char name[XLINK_MAX_DEVICE_NAME_SIZE];
+	int rc = 0;
+
+	if (copy_from_user(&devn, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicename)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devn.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
+		rc = xlink_get_device_name(&devh, name, devn.name_size);
+		if (!rc) {
+			if (copy_to_user((void __user *)devn.name, (void *)name,
+					 devn.name_size))
+				return -EFAULT;
+		}
+	} else {
+		rc = X_LINK_ERROR;
+	}
+	if (copy_to_user((void __user *)devn.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_get_device_list(unsigned long arg)
+{
+	struct xlinkgetdevicelist	devl	= {0};
+	u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
+	u32 num_devices = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devl, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicelist)))
+		return -EFAULT;
+	rc = xlink_get_device_list(sw_device_id_list, &num_devices);
+	if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
+		/* TODO: this next copy is dangerous! we have no idea
+		 * how large the devl.sw_device_id_list buffer is
+		 * provided by the user. if num_devices is too large,
+		 * the copy will overflow the buffer.
+		 */
+		if (copy_to_user((void __user *)devl.sw_device_id_list,
+				 (void *)sw_device_id_list,
+				 (sizeof(*sw_device_id_list)
+				 * num_devices)))
+			return -EFAULT;
+		if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
+				 (sizeof(num_devices))))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)devl.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_get_device_status(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkgetdevicestatus	devs	= {0};
+	u32 device_status = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devs, (void __user *)arg,
+			   sizeof(struct xlinkgetdevicestatus)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devs.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_get_device_status(&devh, &device_status);
+	if (!rc) {
+		if (copy_to_user((void __user *)devs.device_status,
+				 (void *)&device_status,
+				 sizeof(device_status)))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)devs.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_boot_device(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkbootdevice		boot	= {0};
+	char filename[64];
+	int rc = 0;
+
+	if (copy_from_user(&boot, (void __user *)arg,
+			   sizeof(struct xlinkbootdevice)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)boot.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (boot.binary_name_size > sizeof(filename))
+		return -EINVAL;
+	memset(filename, 0, sizeof(filename));
+	if (copy_from_user(filename, (void __user *)boot.binary_name,
+			   boot.binary_name_size))
+		return -EFAULT;
+	rc = xlink_boot_device(&devh, filename);
+	if (copy_to_user((void __user *)boot.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_reset_device(unsigned long arg)
+{
+	struct xlink_handle		devh	= {0};
+	struct xlinkresetdevice		res	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&res, (void __user *)arg,
+			   sizeof(struct xlinkresetdevice)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)res.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_reset_device(&devh);
+	if (copy_to_user((void __user *)res.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_get_device_mode(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkdevmode	devm	= {0};
+	u32 device_mode = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devm, (void __user *)arg,
+			   sizeof(struct xlinkdevmode)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devm.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	rc = xlink_get_device_mode(&devh, &device_mode);
+	if (!rc) {
+		if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
+				 sizeof(device_mode)))
+			return -EFAULT;
+	}
+	if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_set_device_mode(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkdevmode	devm	= {0};
+	u32 device_mode = 0;
+	int rc = 0;
+
+	if (copy_from_user(&devm, (void __user *)arg,
+			   sizeof(struct xlinkdevmode)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)devm.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
+			   sizeof(device_mode)))
+		return -EFAULT;
+	rc = xlink_set_device_mode(&devh, device_mode);
+	if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_register_device_event(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkregdevevent	regdevevent = {0};
+	u32 num_events = 0;
+	u32 *ev_list;
+	int rc = 0;
+
+	if (copy_from_user(&regdevevent, (void __user *)arg,
+			   sizeof(struct xlinkregdevevent)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)regdevevent.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	num_events = regdevevent.num_events;
+	if (num_events > 0 && num_events <= NUM_REG_EVENTS) {
+		ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
+		if (ev_list) {
+			if (copy_from_user(ev_list,
+					   (void __user *)regdevevent.event_list,
+					   (num_events * sizeof(u32)))) {
+				kfree(ev_list);
+				return -EFAULT;
+			}
+			rc = xlink_register_device_event_user(&devh,
+							      ev_list,
+							      num_events,
+							      NULL);
+			kfree(ev_list);
+		} else {
+			rc = X_LINK_ERROR;
+		}
+	} else {
+		rc = X_LINK_ERROR;
+	}
+	if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_unregister_device_event(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkregdevevent	regdevevent = {0};
+	u32 num_events = 0;
+	u32 *ev_list;
+	int rc = 0;
+
+	if (copy_from_user(&regdevevent, (void __user *)arg,
+			   sizeof(struct xlinkregdevevent)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)regdevevent.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	num_events = regdevevent.num_events;
+	if (num_events <= NUM_REG_EVENTS) {
+		ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
+		if (copy_from_user(ev_list,
+				   (void __user *)regdevevent.event_list,
+				   (num_events * sizeof(u32)))) {
+			kfree(ev_list);
+			return -EFAULT;
+		}
+		rc = xlink_unregister_device_event(&devh, ev_list, num_events);
+		kfree(ev_list);
+	} else {
+		rc = X_LINK_ERROR;
+	}
+	if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_data_ready_callback(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkcallback	cb	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&cb, (void __user *)arg,
+			   sizeof(struct xlinkcallback)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)cb.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
+	rc = xlink_data_available_event(&devh, cb.chan, cb.callback);
+	if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
+
+int ioctl_data_consumed_callback(unsigned long arg)
+{
+	struct xlink_handle	devh	= {0};
+	struct xlinkcallback	cb	= {0};
+	int rc = 0;
+
+	if (copy_from_user(&cb, (void __user *)arg,
+			   sizeof(struct xlinkcallback)))
+		return -EFAULT;
+	if (copy_from_user(&devh, (void __user *)cb.handle,
+			   sizeof(struct xlink_handle)))
+		return -EFAULT;
+	CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
+	rc = xlink_data_consumed_event(&devh, cb.chan, cb.callback);
+	if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
+		return -EFAULT;
+	return rc;
+}
diff --git a/drivers/misc/xlink-core/xlink-ioctl.h b/drivers/misc/xlink-core/xlink-ioctl.h
new file mode 100644
index 000000000000..7818b676d488
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-ioctl.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * xlink ioctl header files.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+
+#ifndef XLINK_IOCTL_H_
+#define XLINK_IOCTL_H_
+
+int ioctl_connect(unsigned long arg);
+int ioctl_open_channel(unsigned long arg);
+int ioctl_read_data(unsigned long arg);
+int ioctl_read_to_buffer(unsigned long arg);
+int ioctl_write_data(unsigned long arg);
+int ioctl_write_control_data(unsigned long arg);
+int ioctl_write_volatile_data(unsigned long arg);
+int ioctl_release_data(unsigned long arg);
+int ioctl_close_channel(unsigned long arg);
+int ioctl_start_vpu(unsigned long arg);
+int ioctl_stop_vpu(void);
+int ioctl_disconnect(unsigned long arg);
+int ioctl_get_device_name(unsigned long arg);
+int ioctl_get_device_list(unsigned long arg);
+int ioctl_get_device_status(unsigned long arg);
+int ioctl_boot_device(unsigned long arg);
+int ioctl_reset_device(unsigned long arg);
+int ioctl_get_device_mode(unsigned long arg);
+int ioctl_set_device_mode(unsigned long arg);
+int ioctl_register_device_event(unsigned long arg);
+int ioctl_unregister_device_event(unsigned long arg);
+int ioctl_data_ready_callback(unsigned long arg);
+int ioctl_data_consumed_callback(unsigned long arg);
+
+#endif /* XLINK_IOCTL_H_ */
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ