clear-pkgs-linux-iot-lts2018/0161-mei-dal-add-test-modul...

1015 lines
26 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yael Samet <yael.samet@intel.com>
Date: Mon, 14 Aug 2017 11:32:37 +0300
Subject: [PATCH] mei: dal: add test module
DAL test module allows the user space to test the DAL kernel space api.
It exposes a character device to the user space, and calls DAL api's
according to the protocol which is defined in kdi_cmd_defs.h header file.
This patch adds the code of DAL test module.
Change-Id: Id7ec2e7d3f22b07c41941dc5bada6edaf16e893b
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Yael Samet <yael.samet@intel.com>
---
drivers/misc/mei/dal/Kconfig | 8 +
drivers/misc/mei/dal/Makefile | 2 +
drivers/misc/mei/dal/dal_test.c | 775 +++++++++++++++++++++++
drivers/misc/mei/dal/uapi/kdi_cmd_defs.h | 176 +++++
4 files changed, 961 insertions(+)
create mode 100644 drivers/misc/mei/dal/dal_test.c
create mode 100644 drivers/misc/mei/dal/uapi/kdi_cmd_defs.h
diff --git a/drivers/misc/mei/dal/Kconfig b/drivers/misc/mei/dal/Kconfig
index 5d8356ae931e..8943d4f7f7e4 100644
--- a/drivers/misc/mei/dal/Kconfig
+++ b/drivers/misc/mei/dal/Kconfig
@@ -5,3 +5,11 @@ config INTEL_MEI_DAL
Dynamic Application Loader enables downloading java applets
to DAL FW and run it in a secure environment.
The DAL module exposes both user space api and kernel space api.
+
+config INTEL_MEI_DAL_TEST
+ tristate "Test Module for Dynamic Application Loader for ME"
+ depends on INTEL_MEI_DAL
+ help
+ Testing Module for Dynamic Application Loader, to test the
+ kernel space api from a user space client. The test module
+ calls the kernel space api functions of DAL module.
diff --git a/drivers/misc/mei/dal/Makefile b/drivers/misc/mei/dal/Makefile
index b8d5456c94a1..fa3f8150131e 100644
--- a/drivers/misc/mei/dal/Makefile
+++ b/drivers/misc/mei/dal/Makefile
@@ -10,3 +10,5 @@ mei_dal-objs += bh_internal.o
mei_dal-objs += dal_cdev.o
mei_dal-objs += dal_kdi.o
mei_dal-objs += dal_ta_access.o
+
+obj-$(CONFIG_INTEL_MEI_DAL_TEST) += dal_test.o
diff --git a/drivers/misc/mei/dal/dal_test.c b/drivers/misc/mei/dal/dal_test.c
new file mode 100644
index 000000000000..56da059e5cc6
--- /dev/null
+++ b/drivers/misc/mei/dal/dal_test.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/uuid.h>
+#include <linux/ctype.h>
+#include <linux/sizes.h>
+#include <linux/atomic.h>
+
+#include <linux/mei_cl_bus.h>
+#include <linux/dal.h>
+
+#include "uapi/kdi_cmd_defs.h"
+#define KDI_MODULE "mei_dal"
+
+/**
+ * this is the max data size possible:
+ * there is no actually max size for acp file,
+ * but for testing 512k is good enough
+ */
+#define MAX_DATA_SIZE SZ_512K
+
+#define KDI_TEST_OPENED 0
+
+/**
+ * struct dal_test_data - dal test cmd and response data
+ *
+ * @cmd_data_size: size of cmd got from user space
+ * @cmd_data: the cmd got from user space
+ * @cmd_lock: protects cmd_data buffer
+ *
+ * @resp_data_size: size of response from kdi
+ * @resp_data: the response from kdi
+ * @resp_lock: protects resp_data buffer
+ */
+struct dal_test_data {
+ u32 cmd_data_size;
+ u8 *cmd_data;
+ struct mutex cmd_lock; /* protects cmd_data buffer */
+
+ u32 resp_data_size;
+ u8 *resp_data;
+ struct mutex resp_lock; /* protects resp_data buffer */
+};
+
+/**
+ * struct dal_test_device - dal test private data
+ *
+ * @dev: the device structure
+ * @cdev: character device
+ *
+ * @kdi_test_status: status of test module
+ * @data: cmd and response data
+ */
+static struct dal_test_device {
+ struct device *dev;
+ struct cdev cdev;
+
+ unsigned long kdi_test_status;
+ struct dal_test_data *data;
+} dal_test_dev;
+
+#if IS_MODULE(CONFIG_INTEL_MEI_DAL)
+/**
+ * dal_test_find_module - find the given module
+ *
+ * @mod_name: the module name to find
+ *
+ * Return: pointer to the module if it is found
+ * NULL otherwise
+ */
+static struct module *dal_test_find_module(const char *mod_name)
+{
+ struct module *mod;
+
+ mutex_lock(&module_mutex);
+ mod = find_module(mod_name);
+ mutex_unlock(&module_mutex);
+
+ return mod;
+}
+
+/**
+ * dal_test_load_kdi - load kdi module
+ *
+ * @dev: dal test device
+ *
+ * Return: 0 on success
+ * <0 on failure
+ */
+static int dal_test_load_kdi(struct dal_test_device *dev)
+{
+ struct module *mod;
+
+ /* load KDI if it wasn't loaded */
+ request_module(KDI_MODULE);
+
+ mod = dal_test_find_module(KDI_MODULE);
+ if (!mod) {
+ dev_err(dev->dev, "failed to find KDI module: %s\n",
+ KDI_MODULE);
+ return -ENODEV;
+ }
+
+ if (!try_module_get(mod)) {
+ dev_err(dev->dev, "failed to get KDI module\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/**
+ * dal_test_unload_kdi - unload kdi module
+ *
+ * @dev: dal test device
+ *
+ * Return: 0 on success
+ * <0 on failure
+ */
+static int dal_test_unload_kdi(struct dal_test_device *dev)
+{
+ struct module *mod;
+
+ mod = dal_test_find_module(KDI_MODULE);
+ if (!mod) {
+ dev_err(dev->dev, "failed to find KDI module: %s\n",
+ KDI_MODULE);
+ return -ENODEV;
+ }
+ module_put(mod);
+
+ return 0;
+}
+#else
+static inline int dal_test_load_kdi(struct dal_test_device *dev) { return 0; }
+static inline int dal_test_unload_kdi(struct dal_test_device *dev) { return 0; }
+#endif
+
+/**
+ * dal_test_result_set - set data to the result buffer
+ *
+ * @test_data: test command and response buffers
+ * @data: new data
+ * @size: size of the data buffer
+ */
+static void dal_test_result_set(struct dal_test_data *test_data,
+ void *data, u32 size)
+{
+ memcpy(test_data->resp_data, data, size);
+ test_data->resp_data_size = size;
+}
+
+/**
+ * dal_test_result_append - append data to the result buffer
+ *
+ * @test_data: test command and response buffers
+ * @data: new data
+ * @size: size of the data buffer
+ */
+static void dal_test_result_append(struct dal_test_data *test_data,
+ void *data, u32 size)
+{
+ size_t offset = test_data->resp_data_size;
+
+ memcpy(test_data->resp_data + offset, data, size);
+ test_data->resp_data_size += size;
+}
+
+/**
+ * dal_test_send_and_recv - call send and receive function of kdi
+ *
+ * @dev: dal test device
+ * @t_cmd: the command to send kdi
+ * @t_data: test command and response buffers
+ */
+static void dal_test_send_and_recv(struct dal_test_device *dev,
+ struct kdi_test_command *t_cmd,
+ struct dal_test_data *t_data)
+{
+ struct send_and_rcv_cmd *cmd;
+ struct send_and_rcv_resp resp;
+ ssize_t data_size;
+ size_t output_len;
+ s32 response_code;
+ u8 *input;
+ u8 *output;
+ s32 status;
+
+ memset(&resp, 0, sizeof(resp));
+
+ cmd = (struct send_and_rcv_cmd *)t_cmd->data;
+ data_size = t_data->cmd_data_size - sizeof(t_cmd->cmd_id) -
+ sizeof(*cmd);
+ if (data_size < 0) {
+ dev_dbg(dev->dev, "malformed command struct: data_size = %zu\n",
+ data_size);
+ resp.test_mod_status = -EINVAL;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+ return;
+ }
+
+ response_code = 0;
+ output = NULL;
+ input = (data_size) ? cmd->input : NULL;
+ output_len = (cmd->is_output_len_ptr) ? cmd->output_buf_len : 0;
+
+ dev_dbg(dev->dev, "call dal_send_and_receive: handle=%llu command_id=%d input_len=%zd\n",
+ cmd->session_handle, cmd->command_id, data_size);
+
+ status = dal_send_and_receive(cmd->session_handle, cmd->command_id,
+ input, data_size,
+ cmd->is_output_buf ? &output : NULL,
+ cmd->is_output_len_ptr ?
+ &output_len : NULL,
+ cmd->is_response_code_ptr ?
+ &response_code : NULL);
+
+ dev_dbg(dev->dev, "dal_send_and_receive return: status=%d output_len=%zu response_code=%d\n",
+ status, output_len, response_code);
+
+ resp.output_len = (u32)output_len;
+ resp.response_code = response_code;
+ resp.status = status;
+ resp.test_mod_status = 0;
+
+ /* in case the call failed we don't copy the data */
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ if (output && resp.output_len)
+ dal_test_result_append(t_data, output, resp.output_len);
+ mutex_unlock(&t_data->resp_lock);
+
+ kfree(output);
+}
+
+/**
+ * dal_test_create_session - call create session function of kdi
+ *
+ * @dev: dal test device
+ * @t_cmd: the command to send kdi
+ * @t_data: test command and response buffers
+ */
+static void dal_test_create_session(struct dal_test_device *dev,
+ struct kdi_test_command *t_cmd,
+ struct dal_test_data *t_data)
+{
+ struct session_create_cmd *cmd;
+ struct session_create_resp resp;
+ u32 data_size;
+ u64 handle;
+ char *app_id;
+ u8 *acp_pkg;
+ u8 *init_params;
+ u32 offset;
+ s32 status;
+
+ memset(&resp, 0, sizeof(resp));
+
+ cmd = (struct session_create_cmd *)t_cmd->data;
+ data_size = t_data->cmd_data_size - sizeof(t_cmd->cmd_id) -
+ sizeof(*cmd);
+
+ if (cmd->app_id_len + cmd->acp_pkg_len + cmd->init_param_len !=
+ data_size) {
+ dev_dbg(dev->dev, "malformed command struct: data_size = %d\n",
+ data_size);
+ resp.test_mod_status = -EINVAL;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+ return;
+ }
+
+ handle = 0;
+
+ offset = 0;
+ app_id = (cmd->app_id_len) ? cmd->data + offset : NULL;
+ offset += cmd->app_id_len;
+
+ acp_pkg = (cmd->acp_pkg_len) ? cmd->data + offset : NULL;
+ offset += cmd->acp_pkg_len;
+
+ init_params = (cmd->init_param_len) ? cmd->data + offset : NULL;
+ offset += cmd->init_param_len;
+
+ dev_dbg(dev->dev, "call dal_create_session params: app_id = %s, app_id len = %d, acp pkg len = %d, init params len = %d\n",
+ app_id, cmd->app_id_len, cmd->acp_pkg_len, cmd->init_param_len);
+
+ status = dal_create_session(cmd->is_session_handle_ptr ?
+ &handle : NULL,
+ app_id, acp_pkg,
+ cmd->acp_pkg_len,
+ init_params,
+ cmd->init_param_len);
+ dev_dbg(dev->dev, "dal_create_session return: status = %d, handle = %llu\n",
+ status, handle);
+
+ resp.session_handle = handle;
+ resp.status = status;
+ resp.test_mod_status = 0;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+}
+
+/**
+ * dal_test_close_session - call close session function of kdi
+ *
+ * @dev: dal test device
+ * @t_cmd: the command to send kdi
+ * @t_data: test command and response buffers
+ */
+static void dal_test_close_session(struct dal_test_device *dev,
+ struct kdi_test_command *t_cmd,
+ struct dal_test_data *t_data)
+{
+ struct session_close_cmd *cmd;
+ struct session_close_resp resp;
+
+ memset(&resp, 0, sizeof(resp));
+
+ cmd = (struct session_close_cmd *)t_cmd->data;
+ if (t_data->cmd_data_size != sizeof(t_cmd->cmd_id) + sizeof(*cmd)) {
+ dev_dbg(dev->dev, "malformed command struct\n");
+ resp.test_mod_status = -EINVAL;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+ return;
+ }
+
+ resp.status = dal_close_session(cmd->session_handle);
+ resp.test_mod_status = 0;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+}
+
+/**
+ * dal_test_version_info - call get version function of kdi
+ *
+ * @dev: dal test device
+ * @t_cmd: the command to send kdi
+ * @t_data: test command and response buffers
+ */
+static void dal_test_version_info(struct dal_test_device *dev,
+ struct kdi_test_command *t_cmd,
+ struct dal_test_data *t_data)
+{
+ struct version_get_info_cmd *cmd;
+ struct version_get_info_resp resp;
+ struct dal_version_info *version;
+
+ memset(&resp, 0, sizeof(resp));
+
+ cmd = (struct version_get_info_cmd *)t_cmd->data;
+ if (t_data->cmd_data_size != sizeof(t_cmd->cmd_id) + sizeof(*cmd)) {
+ dev_dbg(dev->dev, "malformed command struct\n");
+ resp.test_mod_status = -EINVAL;
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+ return;
+ }
+
+ version = (cmd->is_version_ptr) ?
+ (struct dal_version_info *)resp.kdi_version : NULL;
+
+ resp.status = dal_get_version_info(version);
+ resp.test_mod_status = 0;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+}
+
+/**
+ * dal_test_set_ex_access - call set/remove access function of kdi
+ *
+ * @dev: dal test device
+ * @t_cmd: the command to send kdi
+ * @t_data: test command and response buffers
+ * @set_access: true when calling set access function
+ * false when calling remove access function
+ */
+static void dal_test_set_ex_access(struct dal_test_device *dev,
+ struct kdi_test_command *t_cmd,
+ struct dal_test_data *t_data,
+ bool set_access)
+{
+ struct ta_access_set_remove_cmd *cmd;
+ struct ta_access_set_remove_resp resp;
+ u32 data_size;
+ uuid_t app_uuid;
+ char *app_id;
+ s32 status;
+
+ memset(&resp, 0, sizeof(resp));
+
+ cmd = (struct ta_access_set_remove_cmd *)t_cmd->data;
+ data_size = t_data->cmd_data_size - sizeof(t_cmd->cmd_id) -
+ sizeof(*cmd);
+
+ if (cmd->app_id_len != data_size) {
+ dev_dbg(dev->dev, "malformed command struct\n");
+ resp.test_mod_status = -EINVAL;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+ return;
+ }
+
+ app_id = (cmd->app_id_len) ? cmd->data : NULL;
+
+ status = dal_uuid_parse(app_id, &app_uuid);
+ if (status < 0)
+ goto out;
+
+ if (set_access)
+ status = dal_set_ta_exclusive_access(&app_uuid);
+ else
+ status = dal_unset_ta_exclusive_access(&app_uuid);
+
+out:
+ resp.status = status;
+ resp.test_mod_status = 0;
+
+ mutex_lock(&t_data->resp_lock);
+ dal_test_result_set(t_data, &resp, sizeof(resp));
+ mutex_unlock(&t_data->resp_lock);
+}
+
+/**
+ * dal_test_kdi_command - parse and invoke the requested command
+ *
+ * @dev: dal test device
+ */
+static void dal_test_kdi_command(struct dal_test_device *dev)
+{
+ struct dal_test_data *test_data;
+ struct kdi_test_command *cmd;
+ s32 status;
+
+ test_data = dev->data;
+ cmd = (struct kdi_test_command *)test_data->cmd_data;
+
+ if (test_data->cmd_data_size < sizeof(cmd->cmd_id)) {
+ dev_dbg(dev->dev, "malformed command struct\n");
+ status = -EINVAL;
+ goto prep_err_test_mod;
+ }
+
+ switch (cmd->cmd_id) {
+ case KDI_SESSION_CREATE: {
+ dev_dbg(dev->dev, "KDI_CREATE_SESSION[%d]\n", cmd->cmd_id);
+ dal_test_create_session(dev, cmd, test_data);
+ break;
+ }
+ case KDI_SESSION_CLOSE: {
+ dev_dbg(dev->dev, "KDI_CLOSE_SESSION[%d]\n", cmd->cmd_id);
+ dal_test_close_session(dev, cmd, test_data);
+ break;
+ }
+ case KDI_SEND_AND_RCV: {
+ dev_dbg(dev->dev, "KDI_SEND_AND_RCV[%d]\n", cmd->cmd_id);
+ dal_test_send_and_recv(dev, cmd, test_data);
+ break;
+ }
+ case KDI_VERSION_GET_INFO: {
+ dev_dbg(dev->dev, "KDI_GET_VERSION_INFO[%d]\n", cmd->cmd_id);
+ dal_test_version_info(dev, cmd, test_data);
+ break;
+ }
+ case KDI_EXCLUSIVE_ACCESS_SET:
+ case KDI_EXCLUSIVE_ACCESS_REMOVE: {
+ dev_dbg(dev->dev, "KDI_SET_EXCLUSIVE_ACCESS or KDI_REMOVE_EXCLUSIVE_ACCESS[%d]\n",
+ cmd->cmd_id);
+ dal_test_set_ex_access(dev, cmd, test_data,
+ cmd->cmd_id == KDI_EXCLUSIVE_ACCESS_SET);
+ break;
+ }
+ default:
+ dev_dbg(dev->dev, "unknown command %d\n", cmd->cmd_id);
+ status = -EINVAL;
+ goto prep_err_test_mod;
+ }
+
+ return;
+
+prep_err_test_mod:
+ mutex_lock(&test_data->resp_lock);
+ dal_test_result_set(test_data, &status, sizeof(status));
+ mutex_unlock(&test_data->resp_lock);
+}
+
+/**
+ * dal_test_read - dal test read function
+ *
+ * @filp: pointer to file structure
+ * @buff: pointer to user buffer
+ * @count: buffer length
+ * @offp: data offset in buffer
+ *
+ * Return: >=0 data length on success
+ * <0 on failure
+ */
+static ssize_t dal_test_read(struct file *filp, char __user *buff, size_t count,
+ loff_t *offp)
+{
+ struct dal_test_device *dev;
+ struct dal_test_data *test_data;
+ int ret;
+
+ dev = filp->private_data;
+ test_data = dev->data;
+
+ mutex_lock(&test_data->resp_lock);
+
+ if (test_data->resp_data_size > count) {
+ ret = -EMSGSIZE;
+ goto unlock;
+ }
+
+ dev_dbg(dev->dev, "copying %d bytes to userspace\n",
+ test_data->resp_data_size);
+ if (copy_to_user(buff, test_data->resp_data,
+ test_data->resp_data_size)) {
+ dev_dbg(dev->dev, "copy_to_user failed\n");
+ ret = -EFAULT;
+ goto unlock;
+ }
+ ret = test_data->resp_data_size;
+
+unlock:
+ mutex_unlock(&test_data->resp_lock);
+
+ return ret;
+}
+
+/**
+ * dal_test_write - dal test write function
+ *
+ * @filp: pointer to file structure
+ * @buff: pointer to user buffer
+ * @count: buffer length
+ * @offp: data offset in buffer
+ *
+ * Return: >=0 data length on success
+ * <0 on failure
+ */
+static ssize_t dal_test_write(struct file *filp, const char __user *buff,
+ size_t count, loff_t *offp)
+{
+ struct dal_test_device *dev;
+ struct dal_test_data *test_data;
+
+ dev = filp->private_data;
+ test_data = dev->data;
+
+ if (count > MAX_DATA_SIZE)
+ return -EMSGSIZE;
+
+ mutex_lock(&test_data->cmd_lock);
+
+ if (copy_from_user(test_data->cmd_data, buff, count)) {
+ mutex_unlock(&test_data->cmd_lock);
+ dev_dbg(dev->dev, "copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ test_data->cmd_data_size = count;
+ dev_dbg(dev->dev, "write %zu bytes\n", count);
+
+ dal_test_kdi_command(dev);
+
+ mutex_unlock(&test_data->cmd_lock);
+
+ return count;
+}
+
+/**
+ * dal_test_open - dal test open function
+ *
+ * @inode: pointer to inode structure
+ * @filp: pointer to file structure
+ *
+ * Return: 0 on success
+ * <0 on failure
+ */
+static int dal_test_open(struct inode *inode, struct file *filp)
+{
+ struct dal_test_device *dev;
+ struct dal_test_data *test_data;
+ int ret;
+
+ dev = container_of(inode->i_cdev, struct dal_test_device, cdev);
+ if (!dev)
+ return -ENODEV;
+
+ /* single open */
+ if (test_and_set_bit(KDI_TEST_OPENED, &dev->kdi_test_status))
+ return -EBUSY;
+
+ test_data = kzalloc(sizeof(*test_data), GFP_KERNEL);
+ if (!test_data) {
+ ret = -ENOMEM;
+ goto err_clear_bit;
+ }
+
+ test_data->cmd_data = kzalloc(MAX_DATA_SIZE, GFP_KERNEL);
+ test_data->resp_data = kzalloc(MAX_DATA_SIZE, GFP_KERNEL);
+ if (!test_data->cmd_data || !test_data->resp_data) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ mutex_init(&test_data->cmd_lock);
+ mutex_init(&test_data->resp_lock);
+
+ ret = dal_test_load_kdi(dev);
+ if (ret)
+ goto err_free;
+
+ dev->data = test_data;
+ filp->private_data = dev;
+
+ return nonseekable_open(inode, filp);
+
+err_free:
+ kfree(test_data->cmd_data);
+ kfree(test_data->resp_data);
+ kfree(test_data);
+
+err_clear_bit:
+ clear_bit(KDI_TEST_OPENED, &dev->kdi_test_status);
+
+ return ret;
+}
+
+/**
+ * dal_test_release - dal test release function
+ *
+ * @inode: pointer to inode structure
+ * @filp: pointer to file structure
+ *
+ * Return: 0 on success
+ * <0 on failure
+ */
+static int dal_test_release(struct inode *inode, struct file *filp)
+{
+ struct dal_test_device *dev;
+ struct dal_test_data *test_data;
+
+ dev = filp->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ dal_test_unload_kdi(dev);
+
+ test_data = dev->data;
+ if (test_data) {
+ kfree(test_data->cmd_data);
+ kfree(test_data->resp_data);
+ kfree(test_data);
+ }
+
+ clear_bit(KDI_TEST_OPENED, &dev->kdi_test_status);
+
+ filp->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations dal_test_fops = {
+ .owner = THIS_MODULE,
+ .open = dal_test_open,
+ .release = dal_test_release,
+ .read = dal_test_read,
+ .write = dal_test_write,
+ .llseek = no_llseek,
+};
+
+/**
+ * dal_test_exit - destroy dal test device
+ */
+static void __exit dal_test_exit(void)
+{
+ struct dal_test_device *dev = &dal_test_dev;
+ struct class *dal_test_class;
+ static dev_t devt;
+
+ dal_test_class = dev->dev->class;
+ devt = dev->dev->devt;
+
+ cdev_del(&dev->cdev);
+ unregister_chrdev_region(devt, MINORMASK);
+ device_destroy(dal_test_class, devt);
+ class_destroy(dal_test_class);
+}
+
+/**
+ * dal_test_init - initiallize dal test device
+ *
+ * Return: 0 on success
+ * <0 on failure
+ */
+static int __init dal_test_init(void)
+{
+ struct dal_test_device *dev = &dal_test_dev;
+ struct class *dal_test_class;
+ static dev_t devt;
+ int ret;
+
+ ret = alloc_chrdev_region(&devt, 0, 1, "mei_dal_test");
+ if (ret)
+ return ret;
+
+ dal_test_class = class_create(THIS_MODULE, "mei_dal_test");
+ if (IS_ERR(dal_test_class)) {
+ ret = PTR_ERR(dal_test_class);
+ dal_test_class = NULL;
+ goto err_unregister_cdev;
+ }
+
+ dev->dev = device_create(dal_test_class, NULL, devt, dev, "dal_test0");
+ if (IS_ERR(dev->dev)) {
+ ret = PTR_ERR(dev->dev);
+ goto err_class_destroy;
+ }
+
+ cdev_init(&dev->cdev, &dal_test_fops);
+ dev->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&dev->cdev, devt, 1);
+ if (ret)
+ goto err_device_destroy;
+
+ return 0;
+
+err_device_destroy:
+ device_destroy(dal_test_class, devt);
+err_class_destroy:
+ class_destroy(dal_test_class);
+err_unregister_cdev:
+ unregister_chrdev_region(devt, 1);
+
+ return ret;
+}
+
+module_init(dal_test_init);
+module_exit(dal_test_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) DAL test");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/dal/uapi/kdi_cmd_defs.h b/drivers/misc/mei/dal/uapi/kdi_cmd_defs.h
new file mode 100644
index 000000000000..13717df1ae54
--- /dev/null
+++ b/drivers/misc/mei/dal/uapi/kdi_cmd_defs.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved.
+ */
+
+#ifndef KDI_CMD_DEFS_H
+#define KDI_CMD_DEFS_H
+
+/**
+ * enum kdi_command_id - cmd id to invoke in kdi module
+ *
+ * @KDI_SESSION_CREATE: call kdi "create session" function
+ * @KDI_SESSION_CLOSE: call kdi "close session" function
+ * @KDI_SEND_AND_RCV: call kdi "send and receive" function
+ * @KDI_VERSION_GET_INFO: call kdi "get version" function
+ * @KDI_EXCLUSIVE_ACCESS_SET: call kdi "set exclusive access" function
+ * @KDI_EXCLUSIVE_ACCESS_REMOVE: call kdi "unset exclusive access" function
+ */
+enum kdi_command_id {
+ KDI_SESSION_CREATE,
+ KDI_SESSION_CLOSE,
+ KDI_SEND_AND_RCV,
+ KDI_VERSION_GET_INFO,
+ KDI_EXCLUSIVE_ACCESS_SET,
+ KDI_EXCLUSIVE_ACCESS_REMOVE
+};
+
+/**
+ * struct kdi_test_command - contains the command received from user space
+ *
+ * @cmd_id: the command id
+ * @data: the command data
+ */
+struct kdi_test_command {
+ __u8 cmd_id;
+ unsigned char data[0];
+} __packed;
+
+/**
+ * struct session_create_cmd - create session cmd data
+ *
+ * @app_id_len: length of app_id arg
+ * @acp_pkg_len: length of the acp_pkg arg
+ * @init_param_len: length of init param arg
+ * @is_session_handle_ptr: either send kdi a valid ptr to hold the
+ * session handle or NULL
+ * @data: buffer to hold the cmd arguments
+ */
+struct session_create_cmd {
+ __u32 app_id_len;
+ __u32 acp_pkg_len;
+ __u32 init_param_len;
+ __u8 is_session_handle_ptr;
+ unsigned char data[0];
+} __packed;
+
+/**
+ * struct session_create_resp - create session response
+ *
+ * @session_handle: the session handle
+ * @test_mod_status: status returned from the test module
+ * @status: status returned from kdi
+ */
+struct session_create_resp {
+ __u64 session_handle;
+ __s32 test_mod_status;
+ __s32 status;
+} __packed;
+
+/**
+ * struct session_close_cmd - close session cmd
+ *
+ * @session_handle: the session handle to close
+ */
+struct session_close_cmd {
+ __u64 session_handle;
+} __packed;
+
+/**
+ * struct session_close_resp - close session response
+ *
+ * @test_mod_status: status returned from the test module
+ * @status: status returned from kdi
+ */
+struct session_close_resp {
+ __s32 test_mod_status;
+ __s32 status;
+} __packed;
+
+/**
+ * struct send_and_rcv_cmd - send and receive cmd
+ *
+ * @session_handle: the session handle
+ * @command_id: the cmd id to send the applet
+ * @output_buf_len: the size of the output buffer
+ * @is_output_buf: either send kdi a valid ptr to hold the output buffer or NULL
+ * @is_output_len_ptr: either send kdi a valid ptr to hold
+ * the output len or NULL
+ * @is_response_code_ptr: either send kdi a valid ptr to hold
+ * the applet response code or NULL
+ * @input: the input data to send the applet
+ */
+struct send_and_rcv_cmd {
+ __u64 session_handle;
+ __u32 command_id;
+ __u32 output_buf_len;
+ __u8 is_output_buf;
+ __u8 is_output_len_ptr;
+ __u8 is_response_code_ptr;
+ unsigned char input[0];
+} __packed;
+
+/**
+ * struct send_and_rcv_resp - send and receive response
+ *
+ * @test_mod_status: status returned from the test module
+ * @status: status returned from kdi
+ * @response_code: response code returned from the applet
+ * @output_len: length of output from the applet
+ * @output: the output got from the applet
+ */
+struct send_and_rcv_resp {
+ __s32 test_mod_status;
+ __s32 status;
+ __s32 response_code;
+ __u32 output_len;
+ unsigned char output[0];
+} __packed;
+
+/**
+ * struct version_get_info_cmd - get version cmd
+ *
+ * @is_version_ptr: either send kdi a valid ptr to hold the version info or NULL
+ */
+struct version_get_info_cmd {
+ __u8 is_version_ptr;
+} __packed;
+
+/**
+ * struct version_get_info_resp - get version response
+ *
+ * @kdi_version: kdi version
+ * @reserved: reserved bytes
+ * @test_mod_status: status returned from the test module
+ * @status: status returned from kdi
+ */
+struct version_get_info_resp {
+ char kdi_version[32];
+ __u32 reserved[4];
+ __s32 test_mod_status;
+ __s32 status;
+} __packed;
+
+/**
+ * struct ta_access_set_remove_cmd - set/remove access cmd
+ *
+ * @app_id_len: length of app_id arg
+ * @data: the cmd data. contains the app_id
+ */
+struct ta_access_set_remove_cmd {
+ __u32 app_id_len;
+ unsigned char data[0];
+} __packed;
+
+/**
+ * struct ta_access_set_remove_resp - set/remove access response
+ *
+ * @test_mod_status: status returned from the test module
+ * @status: status returned from kdi
+ */
+struct ta_access_set_remove_resp {
+ __s32 test_mod_status;
+ __s32 status;
+} __packed;
+
+#endif /* KDI_CMD_DEFS_H */
--
https://clearlinux.org