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