ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/drivers/crypto/asr/te200_optee/asr-rsa-optee.c b/marvell/linux/drivers/crypto/asr/te200_optee/asr-rsa-optee.c
new file mode 100644
index 0000000..d16aea0
--- /dev/null
+++ b/marvell/linux/drivers/crypto/asr/te200_optee/asr-rsa-optee.c
@@ -0,0 +1,383 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/hw_random.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <uapi/linux/hwrsa_ioctl.h>
+#ifdef CONFIG_TEE
+#include <linux/tee_drv.h>
+#endif
+
+#include "asr-te200-optee.h"
+#include "asr-rsa-optee.h"
+
+static struct teec_uuid pta_rsa_uuid = ASR_RSA_ACCESS_UUID;
+
+static int asr_optee_rsa_sign(struct hwrsa_arg *rsa_arg, u_int cmd)
+{
+	struct tee_ioctl_invoke_arg invoke_arg;
+	struct tee_param params[4];
+	struct asrte200_tee_context asrte200_tee_ctx;
+	struct tee_shm *shm;
+	int ret = 0;
+	char *ma = NULL;
+	struct rsa_ioctl_key *key = rsa_arg->rsa_key;
+	uint8_t *n = key->n, *e = key->e, *d = key->d, *p = key->p, *q= key->q;
+	size_t n_size = key->n_size, e_size = key->e_size, d_size = key->d_size;
+	size_t p_size = key->p_size, q_size = key->q_size;
+	uint8_t *msg = rsa_arg->msg, *sign = rsa_arg->sign;
+	size_t msg_size = rsa_arg->msg_size, sign_size = key->n_size;
+	int is_blinding;
+	u_int optee_cmd;
+
+	switch (cmd) {
+	case HWRSA_SIGN_PKCS_V15_SHA1:
+		optee_cmd = CMD_RSA_SIGN_PKCS_V15_SHA1;
+		break;
+	case HWRSA_SIGN_PKCS_V15_SHA256:
+		optee_cmd = CMD_RSA_SIGN_PKCS_V15_SHA256;
+		break;
+	case HWRSA_SIGN_PKCS_V21_SHA1:
+		optee_cmd = CMD_RSA_SIGN_PKCS_V21_SHA1;
+		break;
+	case HWRSA_SIGN_PKCS_V21_SHA256:
+		optee_cmd = CMD_RSA_SIGN_PKCS_V21_SHA256;
+		break;
+	default:
+		ret = -EINVAL;
+		goto exit;		
+	}
+
+	if (!p || !q || !p_size || !q_size) {
+		is_blinding = 0;
+	} else {
+		is_blinding = 1;
+	}
+
+	ret = asrte200_optee_open_ta(&asrte200_tee_ctx, &pta_rsa_uuid);
+	if (ret != 0) {
+		return ret;
+	}
+
+	memset(&invoke_arg, 0x0, sizeof(struct tee_ioctl_invoke_arg));
+	invoke_arg.func = optee_cmd;
+	invoke_arg.session  = asrte200_tee_ctx.session;
+
+	if (is_blinding) {
+		shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, 
+							n_size + e_size + d_size + p_size + q_size + msg_size + sign_size, 
+							TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+	} else {
+		shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, 
+							n_size + e_size + d_size + msg_size + sign_size, 
+							TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+	}
+	if (!shm) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ma = tee_shm_get_va(shm, 0);
+	memcpy(ma, n, n_size);
+	memcpy(ma + n_size, e, e_size);
+	memcpy(ma + n_size + e_size, d, d_size);
+	if (is_blinding) {
+		memcpy(ma + n_size + e_size + d_size, p, p_size);
+		memcpy(ma + n_size + e_size + d_size + q_size, q, q_size);
+	}
+
+	/* import rsa key */
+	params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	params[0].u.memref.shm_offs = 0;
+	if (is_blinding) {
+		params[0].u.memref.size = n_size + e_size + d_size + p_size + q_size;
+	} else {
+		params[0].u.memref.size = n_size + e_size + d_size;
+	}
+	params[0].u.memref.shm = shm;
+
+	params[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+	params[1].u.value.a = 0;
+	params[1].u.value.a |= n_size;
+	params[1].u.value.a |= e_size << 10;
+	params[1].u.value.a |= d_size << 20;
+	params[1].u.value.a |= is_blinding << 30;
+	if (is_blinding) {
+		params[1].u.value.b = 0;
+		params[1].u.value.b |= p_size;
+		params[1].u.value.b |= q_size << 10;
+	}
+
+	/* import message */
+	params[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	if (is_blinding) {
+		memcpy(ma + n_size + e_size + d_size + p_size + q_size, msg, msg_size);
+		params[2].u.memref.shm_offs = n_size + e_size + d_size + p_size + q_size;
+	} else {
+		memcpy(ma + n_size + e_size + d_size, msg, msg_size);
+		params[2].u.memref.shm_offs = n_size + e_size + d_size;
+	}
+	params[2].u.memref.size = msg_size;
+	params[2].u.memref.shm = shm;
+
+	/* import signature */
+	params[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+	if (is_blinding) {
+		params[3].u.memref.shm_offs = n_size + e_size + d_size + p_size + q_size + msg_size;
+	} else {
+		params[3].u.memref.shm_offs = n_size + e_size + d_size + msg_size;
+	}
+	params[3].u.memref.size = sign_size;
+	params[3].u.memref.shm = shm;
+	
+	invoke_arg.num_params = 4;
+
+	ret = tee_client_invoke_func(asrte200_tee_ctx.tee_ctx, &invoke_arg, params);
+	if (ret != 0) {
+		rsa_arg->result = 0;
+	} else if (invoke_arg.ret != 0) {
+		rsa_arg->result = 0;
+		goto free_shm;
+	}
+
+	rsa_arg->result = 1;
+
+	if (is_blinding) {
+		memcpy(sign, ma + n_size + e_size + d_size + p_size + q_size + msg_size, sign_size);
+	} else {
+		memcpy(sign, ma + n_size + e_size + d_size + msg_size, sign_size);
+	}
+
+free_shm:
+	tee_shm_free(shm);
+exit:
+	asrte200_optee_close_ta(&asrte200_tee_ctx);
+	return ret;
+}
+
+static int asr_optee_rsa_verify(struct hwrsa_arg *rsa_arg, u_int cmd)
+{
+	struct tee_ioctl_invoke_arg invoke_arg;
+	struct tee_param params[4];
+	struct asrte200_tee_context asrte200_tee_ctx;
+	struct tee_shm *shm;
+	int ret = 0;
+	char *ma = NULL;
+	struct rsa_ioctl_key *key = rsa_arg->rsa_key;
+	uint8_t *n = key->n, *e = key->e;
+	size_t n_size = key->n_size, e_size = key->e_size;
+	uint8_t *msg = rsa_arg->msg, *sign = rsa_arg->sign;
+	size_t msg_size = rsa_arg->msg_size, sign_size = rsa_arg->sign_size;
+	u_int optee_cmd;
+
+	switch (cmd) {
+	case HWRSA_VERIFY_PKCS_V15_SHA1:
+		optee_cmd = CMD_RSA_VERIFY_PKCS_V15_SHA1;
+		break;
+	case HWRSA_VERIFY_PKCS_V15_SHA256:
+		optee_cmd = CMD_RSA_VERIFY_PKCS_V15_SHA256;
+		break;
+	case HWRSA_VERIFY_PKCS_V21_SHA1:
+		optee_cmd = CMD_RSA_VERIFY_PKCS_V21_SHA1;
+		break;
+	case HWRSA_VERIFY_PKCS_V21_SHA256:
+		optee_cmd = CMD_RSA_VERIFY_PKCS_V21_SHA256;
+		break;
+	default:
+		ret = -EINVAL;
+		goto exit;		
+	}
+
+	ret = asrte200_optee_open_ta(&asrte200_tee_ctx, &pta_rsa_uuid);
+	if (ret != 0) {
+		return ret;
+	}
+
+	memset(&invoke_arg, 0x0, sizeof(struct tee_ioctl_invoke_arg));
+	invoke_arg.func = optee_cmd;
+	invoke_arg.session  = asrte200_tee_ctx.session;
+
+	shm = tee_shm_alloc(asrte200_tee_ctx.tee_ctx, 
+						n_size + e_size + msg_size + sign_size, 
+						TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+
+	if (!shm) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ma = tee_shm_get_va(shm, 0);
+	memcpy(ma, n, n_size);
+	memcpy(ma + n_size, e, e_size);
+
+	/* import rsa key */
+	params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	params[0].u.memref.shm_offs = 0;
+	params[0].u.memref.size = n_size + e_size;
+	params[0].u.memref.shm = shm;
+
+	/* import msg */
+	memcpy(ma + n_size + e_size, msg, msg_size);
+	params[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	params[1].u.memref.shm_offs = n_size + e_size;
+	params[1].u.memref.size = msg_size;
+	params[1].u.memref.shm = shm;
+
+	/* import sign */
+	memcpy(ma + n_size + e_size + msg_size, sign, sign_size);
+	params[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+	params[2].u.memref.shm_offs = n_size + e_size + msg_size;
+	params[2].u.memref.size = sign_size;
+	params[2].u.memref.shm = shm;
+
+	params[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+	params[3].u.value.a = n_size;
+
+	invoke_arg.num_params = 4;
+
+	ret = tee_client_invoke_func(asrte200_tee_ctx.tee_ctx, &invoke_arg, params);
+	if (ret != 0) {
+		rsa_arg->result = 0;
+		goto free_shm;
+	} else if (invoke_arg.ret != 0) {
+		rsa_arg->result = 0;
+		goto free_shm;
+	}
+
+	rsa_arg->result = 1;
+
+free_shm:
+	tee_shm_free(shm);
+exit:
+	asrte200_optee_close_ta(&asrte200_tee_ctx);
+	return ret;
+}
+
+static int asr_rsa_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int asr_rsa_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static long asr_rsa_ioctl(struct file *file, u_int cmd, u_long arg)
+{
+	int ret = 0;
+	struct miscdevice *miscdev;
+	struct asr_te200_rsa *rsa;
+	struct hwrsa_arg rsa_arg;
+	struct rsa_ioctl_key *key;
+	struct hwrsa_arg *u_arg = (void __user *)arg;
+	
+	miscdev = file->private_data;
+	rsa = container_of(miscdev, struct asr_te200_rsa, rsa_misc);
+
+	if (copy_from_user(&rsa_arg, (void __user *)arg, sizeof(rsa_arg))) {
+		return -EFAULT;
+	}
+
+	key = rsa_arg.rsa_key;
+
+	if (!rsa_arg.rsa_key) {
+		return -EFAULT;
+	}
+
+	if (!rsa_arg.msg || !rsa_arg.msg_size) {
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case HWRSA_SIGN_PKCS_V15_SHA1:
+	case HWRSA_SIGN_PKCS_V15_SHA256:
+	case HWRSA_SIGN_PKCS_V21_SHA1:
+	case HWRSA_SIGN_PKCS_V21_SHA256:
+		if (!rsa_arg.sign || !key->is_private) {
+			ret = -EINVAL;
+			goto exit;
+		}
+		ret = asr_optee_rsa_sign(&rsa_arg, cmd);
+		put_user(rsa_arg.result, &u_arg->result);
+		break;
+	case HWRSA_VERIFY_PKCS_V15_SHA1:
+	case HWRSA_VERIFY_PKCS_V15_SHA256:
+	case HWRSA_VERIFY_PKCS_V21_SHA1:
+	case HWRSA_VERIFY_PKCS_V21_SHA256:
+		if (!rsa_arg.sign || !rsa_arg.sign_size || key->is_private) {
+			ret = -EINVAL;
+			goto exit;
+		}
+		ret = asr_optee_rsa_verify(&rsa_arg, cmd);
+		put_user(rsa_arg.result, &u_arg->result);
+		break;
+	default:
+		dev_err(rsa->dev, "asr te200: rsa iotcl invald command %x\n", cmd);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static const struct file_operations asr_rsa_fops = {
+	.owner = THIS_MODULE,
+	.open = asr_rsa_open,
+	.release = asr_rsa_close,
+	.unlocked_ioctl = asr_rsa_ioctl,
+};
+
+int asr_te200_rsa_register(struct asr_te200_dev *te200_dd)
+{
+	int ret = 0;
+	struct asr_te200_rsa *prsa;
+	struct miscdevice *misc;
+	struct device *dev = te200_dd->dev;
+
+	prsa = &te200_dd->asr_rsa;
+	misc = &prsa->rsa_misc;
+
+	misc->name = "hwrsa";
+	misc->minor = MISC_DYNAMIC_MINOR;
+	misc->fops = &asr_rsa_fops;
+	misc->this_device = NULL;
+	prsa->dev = te200_dd->dev;
+
+	/* register the device */
+	ret = misc_register(misc);
+	if (ret < 0) {
+		dev_err(dev,
+			"asr rsa: unable to register device node /dev/hwrsa\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asr_te200_rsa_register);
+
+int asr_te200_rsa_unregister(struct asr_te200_dev *te200_dd)
+{
+	struct miscdevice *miscdev;
+
+	miscdev = &te200_dd->asr_rsa.rsa_misc;
+
+	misc_deregister(miscdev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asr_te200_rsa_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yonggan Wang <yongganwang@asrmicro.com>");
+MODULE_DESCRIPTION("ASR hwrsa driver");
\ No newline at end of file