mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
e140541e72
PD#SWPL-135332 Problem: Ensure old keyable driver compatibility. Maintain the old keytable driver for one year. Solution: Move old keytable driver to new keytable driver Verify: T3 metacas Change-Id: I40fb4935f6f0f08ca9be4044cfe760f03b6c85c2 Signed-off-by: Doosan Baek <doosan.baek@amlogic.com>
431 lines
9.9 KiB
C
431 lines
9.9 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2021 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/amlogic/aml_key.h>
|
|
#include <linux/amlogic/aml_kt.h>
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/string.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/amlogic/iomap.h>
|
|
#include "aml_seckey_log.h"
|
|
#include "aml_kt_dev.h"
|
|
|
|
#define AML_KEY_DEVICE_NAME "key"
|
|
#define DEVICE_INSTANCES 1
|
|
|
|
#define KT_SUCCESS (0)
|
|
#define KT_ERROR (-1)
|
|
|
|
struct aml_key_dev {
|
|
struct cdev cdev;
|
|
};
|
|
|
|
static struct aml_key_dev aml_key_dev;
|
|
static dev_t aml_key_devt;
|
|
static struct class *aml_key_class;
|
|
static struct dentry *aml_key_debug_dent;
|
|
u32 old_kt_log_level = 3;
|
|
|
|
static int aml_key_init_dbgfs(void)
|
|
{
|
|
if (!aml_key_debug_dent) {
|
|
aml_key_debug_dent = debugfs_create_dir("aml_key", NULL);
|
|
if (!aml_key_debug_dent) {
|
|
LOGE("can not create debugfs directory\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
debugfs_create_u32("log_level", 0644, aml_key_debug_dent, &old_kt_log_level);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int aml_key_config(struct aml_kt_dev *dev, struct key_config key_cfg)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
struct amlkt_cfg_param kt_cfg;
|
|
|
|
switch (key_cfg.key_userid) {
|
|
case DSC_LOC_DEC:
|
|
key_cfg.key_userid = AML_KT_USER_TSD;
|
|
break;
|
|
case DSC_NETWORK:
|
|
key_cfg.key_userid = AML_KT_USER_TSN;
|
|
break;
|
|
case DSC_LOC_ENC:
|
|
key_cfg.key_userid = AML_KT_USER_TSE;
|
|
break;
|
|
case CRYPTO_T0:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_0;
|
|
break;
|
|
case CRYPTO_T1:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_1;
|
|
break;
|
|
case CRYPTO_T2:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_2;
|
|
break;
|
|
case CRYPTO_T3:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_3;
|
|
break;
|
|
case CRYPTO_T4:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_4;
|
|
break;
|
|
case CRYPTO_T5:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_5;
|
|
break;
|
|
case CRYPTO_ANY:
|
|
key_cfg.key_userid = AML_KT_USER_M2M_ANY;
|
|
break;
|
|
default:
|
|
LOGE("%s, %d invalid user id\n", __func__, __LINE__);
|
|
ret = KT_ERROR;
|
|
return ret;
|
|
}
|
|
|
|
switch (key_cfg.key_algo) {
|
|
case KEY_ALGO_AES:
|
|
key_cfg.key_algo = AML_KT_ALGO_AES;
|
|
break;
|
|
case KEY_ALGO_TDES:
|
|
key_cfg.key_algo = AML_KT_ALGO_TDES;
|
|
break;
|
|
case KEY_ALGO_DES:
|
|
key_cfg.key_algo = AML_KT_ALGO_DES;
|
|
break;
|
|
case KEY_ALGO_CSA2:
|
|
key_cfg.key_algo = AML_KT_ALGO_CSA2;
|
|
break;
|
|
case KEY_ALGO_CSA3:
|
|
key_cfg.key_algo = AML_KT_ALGO_CSA3;
|
|
break;
|
|
case KEY_ALGO_NDL:
|
|
key_cfg.key_algo = AML_KT_ALGO_NDL;
|
|
break;
|
|
case KEY_ALGO_ND:
|
|
key_cfg.key_algo = AML_KT_ALGO_ND;
|
|
break;
|
|
case KEY_ALGO_S17:
|
|
key_cfg.key_algo = AML_KT_ALGO_S17;
|
|
break;
|
|
case KEY_ALGO_SM4:
|
|
key_cfg.key_algo = AML_KT_ALGO_SM4;
|
|
break;
|
|
default:
|
|
LOGE("%s, %d invalid algo\n", __func__, __LINE__);
|
|
ret = KT_ERROR;
|
|
return ret;
|
|
}
|
|
|
|
memset(&kt_cfg, 0, sizeof(kt_cfg));
|
|
kt_cfg.handle = key_cfg.key_index;
|
|
kt_cfg.key_userid = key_cfg.key_userid;
|
|
kt_cfg.key_algo = key_cfg.key_algo;
|
|
kt_cfg.key_flag = AML_KT_FLAG_NONE;
|
|
kt_cfg.key_source = AML_KT_SRC_REE_HOST; //fixed
|
|
kt_cfg.ext_value = key_cfg.ext_value;
|
|
|
|
ret = aml_kt_config(dev, kt_cfg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aml_key_set_host_key(struct aml_kt_dev *dev, struct key_descr *key_param)
|
|
{
|
|
int ret = KT_SUCCESS;
|
|
u32 index = 0;
|
|
u32 key_userid = 0;
|
|
u32 key_source = 0;
|
|
u32 key_flag = 0;
|
|
u8 is_iv = 0;
|
|
struct amlkt_set_key_param kt_param;
|
|
|
|
ret = aml_kt_handle_to_kte(dev, key_param->key_index, &index);
|
|
if (ret != KT_SUCCESS) {
|
|
KT_LOGE("index get error\n");
|
|
return ret;
|
|
}
|
|
|
|
is_iv = key_param->key_index >> KT_IV_FLAG_OFFSET;
|
|
if (is_iv) {
|
|
if (!dev->kt_iv_slot[index])
|
|
return KT_ERROR;
|
|
key_userid = dev->kt_iv_slot[index]->key_userid;
|
|
} else {
|
|
if (!dev->kt_slot[index])
|
|
return KT_ERROR;
|
|
key_userid = dev->kt_slot[index]->key_userid;
|
|
}
|
|
|
|
if (key_param->key_len == 1 || key_param->key_len == 2) {
|
|
/* key_len 1:CAS_A decrypt, 2:CAS_A encrypt */
|
|
KT_LOGI("key_len=%d, mode=1 CAS_A\n", key_param->key_len);
|
|
key_source = AML_KT_SRC_REE_CERT;
|
|
}
|
|
|
|
if (key_userid <= AML_KT_USER_M2M_ANY) {
|
|
if (key_param->key_len == 1)
|
|
key_flag = AML_KT_FLAG_ENC_ONLY;
|
|
else if (key_param->key_len == 2)
|
|
key_flag = AML_KT_FLAG_DEC_ONLY;
|
|
else
|
|
key_flag = AML_KT_FLAG_ENC_DEC;
|
|
} else if (key_userid == AML_KT_USER_TSD ||
|
|
key_userid == AML_KT_USER_TSN) {
|
|
key_flag = AML_KT_FLAG_DEC_ONLY;
|
|
} else {
|
|
key_flag = AML_KT_FLAG_ENC_ONLY;
|
|
}
|
|
|
|
if (is_iv) {
|
|
dev->kt_iv_slot[index]->key_flag = key_flag;
|
|
dev->kt_iv_slot[index]->key_source = key_source;
|
|
} else {
|
|
dev->kt_slot[index]->key_flag = key_flag;
|
|
dev->kt_slot[index]->key_source = key_source;
|
|
}
|
|
|
|
if (key_source == AML_KT_SRC_REE_CERT) {
|
|
ret = aml_kt_set_hw_key(dev, key_param->key_index);
|
|
} else {
|
|
memset(&kt_param, 0, sizeof(kt_param));
|
|
kt_param.handle = key_param->key_index;
|
|
kt_param.key_len = key_param->key_len;
|
|
memcpy(kt_param.key, key_param->key, key_param->key_len);
|
|
ret = aml_kt_set_host_key(dev, &kt_param);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int aml_key_open(struct inode *inode, struct file *filp)
|
|
{
|
|
struct aml_key_dev *dev;
|
|
|
|
dev = container_of(inode->i_cdev, struct aml_key_dev, cdev);
|
|
filp->private_data = dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int aml_key_release(struct inode *inode, struct file *filp)
|
|
{
|
|
if (!filp->private_data)
|
|
return 0;
|
|
|
|
filp->private_data = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static long aml_key_ioctl(struct file *filp, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
struct key_alloc alloc_param;
|
|
struct key_config cfg_param;
|
|
struct key_descr key_param;
|
|
u32 handle = 0;
|
|
u32 flag = 0;
|
|
u32 key_sts = 0;
|
|
int ret = 0;
|
|
|
|
switch (cmd) {
|
|
case KEY_ALLOC:
|
|
memset(&alloc_param, 0, sizeof(alloc_param));
|
|
if (copy_from_user(&alloc_param, (void __user *)arg,
|
|
sizeof(alloc_param))) {
|
|
LOGE("aml_key_alloc copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (alloc_param.is_iv)
|
|
flag = AML_KT_ALLOC_FLAG_IV;
|
|
ret = aml_kt_alloc(&aml_kt_dev, flag, &alloc_param.key_index);
|
|
if (ret != 0) {
|
|
LOGE("aml_key_alloc failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = copy_to_user((void __user *)arg, &alloc_param,
|
|
sizeof(alloc_param));
|
|
if (unlikely(ret)) {
|
|
LOGE("aml_key_alloc copy_to_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case KEY_CONFIG:
|
|
memset(&cfg_param, 0, sizeof(cfg_param));
|
|
if (copy_from_user(&cfg_param, (void __user *)arg,
|
|
sizeof(cfg_param))) {
|
|
LOGE("aml_key_config copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_key_config(&aml_kt_dev, cfg_param);
|
|
if (ret != 0) {
|
|
LOGE("aml_key_config failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case KEY_SET:
|
|
memset(&key_param, 0, sizeof(key_param));
|
|
if (copy_from_user(&key_param, (void __user *)arg,
|
|
sizeof(key_param))) {
|
|
LOGE("aml_key_set_host_key copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (key_param.key_len > 32) {
|
|
LOGE("key len[%d] error\n", key_param.key_len);
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_key_set_host_key(&aml_kt_dev, &key_param);
|
|
if (ret != 0) {
|
|
LOGE("aml_key_set_host_key failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case KEY_FREE:
|
|
handle = (u32)arg;
|
|
ret = aml_kt_free(&aml_kt_dev, handle);
|
|
if (ret != 0) {
|
|
LOGE("aml_key_free failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
case KEY_GET_FLAG:
|
|
memset(&key_param, 0, sizeof(key_param));
|
|
if (copy_from_user(&key_param, (void __user *)arg,
|
|
sizeof(key_param))) {
|
|
LOGE("aml_kt_get_status copy_from_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
ret = aml_kt_get_status(&aml_kt_dev, key_param.key_index,
|
|
&key_sts);
|
|
if (ret != 0) {
|
|
LOGE("aml_kt_get_status failed retval=0x%08x\n", ret);
|
|
return -EFAULT;
|
|
}
|
|
memcpy(key_param.key, &key_sts, sizeof(key_sts));
|
|
|
|
ret = copy_to_user((void __user *)arg, &key_param,
|
|
sizeof(key_param));
|
|
if (unlikely(ret)) {
|
|
LOGE("aml_kt_get_status copy_to_user error\n");
|
|
return -EFAULT;
|
|
}
|
|
break;
|
|
default:
|
|
LOGE("Unknown cmd: %d\n", cmd);
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations aml_key_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = aml_key_open,
|
|
.release = aml_key_release,
|
|
.unlocked_ioctl = aml_key_ioctl,
|
|
.compat_ioctl = aml_key_ioctl,
|
|
};
|
|
|
|
int aml_key_init(struct class *aml_key_class)
|
|
{
|
|
int ret = -1;
|
|
struct device *device;
|
|
|
|
if (alloc_chrdev_region(&aml_key_devt, 0, DEVICE_INSTANCES,
|
|
AML_KEY_DEVICE_NAME) < 0) {
|
|
LOGE("%s device can't be allocated.\n", AML_KEY_DEVICE_NAME);
|
|
return -ENXIO;
|
|
}
|
|
|
|
cdev_init(&aml_key_dev.cdev, &aml_key_fops);
|
|
aml_key_dev.cdev.owner = THIS_MODULE;
|
|
ret = cdev_add(&aml_key_dev.cdev,
|
|
MKDEV(MAJOR(aml_key_devt), MINOR(aml_key_devt)), 1);
|
|
if (unlikely(ret < 0))
|
|
goto unregister_chrdev;
|
|
|
|
device = device_create(aml_key_class, NULL, aml_key_devt, NULL,
|
|
AML_KEY_DEVICE_NAME);
|
|
if (IS_ERR(device)) {
|
|
LOGE("device_create failed\n");
|
|
ret = PTR_ERR(device);
|
|
goto delete_cdev;
|
|
}
|
|
|
|
return ret;
|
|
|
|
delete_cdev:
|
|
cdev_del(&aml_key_dev.cdev);
|
|
unregister_chrdev:
|
|
unregister_chrdev_region(aml_key_devt, DEVICE_INSTANCES);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void aml_key_exit(struct class *aml_key_class)
|
|
{
|
|
device_destroy(aml_key_class, aml_key_devt);
|
|
cdev_del(&aml_key_dev.cdev);
|
|
unregister_chrdev_region(MKDEV(MAJOR(aml_key_devt),
|
|
MINOR(aml_key_devt)),
|
|
DEVICE_INSTANCES);
|
|
}
|
|
|
|
int __init aml_key_driver_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
aml_key_class = class_create(THIS_MODULE, AML_KEY_DEVICE_NAME);
|
|
if (IS_ERR(aml_key_class)) {
|
|
LOGE("class_create failed\n");
|
|
ret = PTR_ERR(aml_key_class);
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_key_init(aml_key_class);
|
|
if (unlikely(ret < 0)) {
|
|
LOGE("aml_key_init failed\n");
|
|
class_destroy(aml_key_class);
|
|
return ret;
|
|
}
|
|
|
|
ret = aml_key_init_dbgfs();
|
|
if (ret) {
|
|
LOGE("aml_key_init_dbgfs failed\n");
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void __exit aml_key_driver_exit(void)
|
|
{
|
|
aml_key_exit(aml_key_class);
|
|
class_destroy(aml_key_class);
|
|
debugfs_remove_recursive(aml_key_debug_dent);
|
|
}
|