unifykey: add key manage driver support

PD#138714: initial add unifykey driver

Change-Id: Iab32caa7b2b8921f8c9dfb66de339cf4cc04477c
Signed-off-by: Nan Li <nan.li@amlogic.com>
This commit is contained in:
Nan Li
2017-02-22 20:04:55 +08:00
committed by Jianxin Pan
parent c32c62408c
commit 42dcc2cf34
19 changed files with 2886 additions and 1 deletions

View File

@@ -13639,3 +13639,18 @@ F: drivers\amlogic\securitykey\Kconfig
F: drivers\amlogic\securitykey\Makefile
F: drivers\amlogic\securitykey\securitykey.c
F: include\linux\amlogic\security_key.h
AMLOGIC key_manage
M: Nan Li <nan.li@amlogic.com>
F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts
F: arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts
F: arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts
F: arch/arm64/configs/meson64_defconfig
F: drivers/amlogic/Kconfig
F: drivers/amlogic/Makefile
F: drivers/amlogic/mmc/Makefile
F: drivers/amlogic/mmc/emmc_partitions.c
F: drivers/amlogic/key_manage/*
F: drivers/amlogic/mmc/emmc_key.c
F: drivers/amlogic/mmc/emmc_key.h
F: include/linux/amlogic/key_manage.h

View File

@@ -714,6 +714,102 @@
*/
tv_bit_mode = <1>;
};
unifykey{
compatible = "amlogic, unifykey";
status = "ok";
unifykey-num = <14>;
unifykey-index-0 = <&keysn_0>;
unifykey-index-1 = <&keysn_1>;
unifykey-index-2 = <&keysn_2>;
unifykey-index-3 = <&keysn_3>;
unifykey-index-4 = <&keysn_4>;
unifykey-index-5 = <&keysn_5>;
unifykey-index-6 = <&keysn_6>;
unifykey-index-7 = <&keysn_7>;
unifykey-index-8 = <&keysn_8>;
unifykey-index-9 = <&keysn_9>;
unifykey-index-10= <&keysn_10>;
unifykey-index-11= <&keysn_11>;
unifykey-index-12= <&keysn_12>;
unifykey-index-13= <&keysn_13>;
keysn_0: key_0{
key-name = "usid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_1:key_1{
key-name = "mac";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_2:key_2{
key-name = "hdcp";
key-device = "secure";
key-type = "sha1";
key-permit = "read","write","del";
};
keysn_3:key_3{
key-name = "secure_boot_set";
key-device = "efuse";
key-permit = "write";
};
keysn_4:key_4{
key-name = "mac_bt";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_5:key_5{
key-name = "mac_wifi";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_6:key_6{
key-name = "hdcp2_tx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_7:key_7{
key-name = "hdcp2_rx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_8:key_8{
key-name = "widevinekeybox";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_9:key_9{
key-name = "deviceid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_10:key_10{
key-name = "hdcp22_fw_private";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_11:key_11{
key-name = "PlayReadykeybox25";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_12:key_12{
key-name = "prpubkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
keysn_13:key_13{
key-name = "prprivkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
};//End unifykey
};
&efuse {
status = "ok";

View File

@@ -712,6 +712,101 @@
*/
tv_bit_mode = <1>;
};
unifykey{
compatible = "amlogic, unifykey";
status = "ok";
unifykey-num = <14>;
unifykey-index-0 = <&keysn_0>;
unifykey-index-1 = <&keysn_1>;
unifykey-index-2 = <&keysn_2>;
unifykey-index-3 = <&keysn_3>;
unifykey-index-4 = <&keysn_4>;
unifykey-index-5 = <&keysn_5>;
unifykey-index-6 = <&keysn_6>;
unifykey-index-7 = <&keysn_7>;
unifykey-index-8 = <&keysn_8>;
unifykey-index-9 = <&keysn_9>;
unifykey-index-10= <&keysn_10>;
unifykey-index-11= <&keysn_11>;
unifykey-index-12= <&keysn_12>;
unifykey-index-13= <&keysn_13>;
keysn_0: key_0{
key-name = "usid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_1:key_1{
key-name = "mac";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_2:key_2{
key-name = "hdcp";
key-device = "secure";
key-type = "sha1";
key-permit = "read","write","del";
};
keysn_3:key_3{
key-name = "secure_boot_set";
key-device = "efuse";
key-permit = "write";
};
keysn_4:key_4{
key-name = "mac_bt";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_5:key_5{
key-name = "mac_wifi";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_6:key_6{
key-name = "hdcp2_tx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_7:key_7{
key-name = "hdcp2_rx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_8:key_8{
key-name = "widevinekeybox";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_9:key_9{
key-name = "deviceid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_10:key_10{
key-name = "hdcp22_fw_private";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_11:key_11{
key-name = "PlayReadykeybox25";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_12:key_12{
key-name = "prpubkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
keysn_13:key_13{
key-name = "prprivkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
};//End unifykey
};
&efuse {
status = "ok";

View File

@@ -713,6 +713,100 @@
*/
tv_bit_mode = <1>;
};
unifykey{
compatible = "amlogic, unifykey";
status = "ok";
unifykey-num = <14>;
unifykey-index-0 = <&keysn_0>;
unifykey-index-1 = <&keysn_1>;
unifykey-index-2 = <&keysn_2>;
unifykey-index-3 = <&keysn_3>;
unifykey-index-4 = <&keysn_4>;
unifykey-index-5 = <&keysn_5>;
unifykey-index-6 = <&keysn_6>;
unifykey-index-7 = <&keysn_7>;
unifykey-index-8 = <&keysn_8>;
unifykey-index-9 = <&keysn_9>;
unifykey-index-10= <&keysn_10>;
unifykey-index-11= <&keysn_11>;
unifykey-index-12= <&keysn_12>;
unifykey-index-13= <&keysn_13>;
keysn_0: key_0{
key-name = "usid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_1:key_1{
key-name = "mac";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_2:key_2{
key-name = "hdcp";
key-device = "secure";
key-type = "sha1";
key-permit = "read","write","del";
};
keysn_3:key_3{
key-name = "secure_boot_set";
key-device = "efuse";
key-permit = "write";
};
keysn_4:key_4{
key-name = "mac_bt";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_5:key_5{
key-name = "mac_wifi";
key-device = "normal";
key-permit = "read","write","del";
key-type = "mac";
};
keysn_6:key_6{
key-name = "hdcp2_tx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_7:key_7{
key-name = "hdcp2_rx";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_8:key_8{
key-name = "widevinekeybox";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_9:key_9{
key-name = "deviceid";
key-device = "normal";
key-permit = "read","write","del";
};
keysn_10:key_10{
key-name = "hdcp22_fw_private";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_11:key_11{
key-name = "PlayReadykeybox25";
key-device = "secure";
key-permit = "read","write","del";
};
keysn_12:key_12{
key-name = "prpubkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
keysn_13:key_13{
key-name = "prprivkeybox";// PlayReady
key-device = "secure";
key-permit = "read","write","del";
};
};//End unifykey
};
&efuse {
status = "ok";

View File

@@ -219,6 +219,7 @@ CONFIG_AMLOGIC_MMC=y
CONFIG_AMLOGIC_VRTC=y
CONFIG_AMLOGIC_SMARTCARD=y
CONFIG_AMLOGIC_SECURITY_KEY=y
CONFIG_AMLOGIC_KEY_MANAGE=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y

View File

@@ -61,5 +61,7 @@ source "drivers/amlogic/cec/Kconfig"
source "drivers/amlogic/securitykey/Kconfig"
source "drivers/amlogic/key_manage/Kconfig"
endmenu
endif

View File

@@ -57,3 +57,5 @@ obj-$(CONFIG_AMLOGIC_AO_CEC) += cec/
obj-$(CONFIG_AMLOGIC_SECURITY_KEY) += securitykey/
obj-$(CONFIG_AMLOGIC_KEY_MANAGE) += key_manage/

View File

@@ -0,0 +1,15 @@
#
# Amlogic key device configuration
#
menu "key management Support"
config AMLOGIC_KEY_MANAGE
bool "key management Driver"
default n
help
key management device driver.
y here, means select key manage
n here, means don't use key manage
endmenu

View File

@@ -0,0 +1,4 @@
#
# Makefile for unifykey
#
obj-$(CONFIG_AMLOGIC_KEY_MANAGE) += unifykey.o unifykey_dts.o storagekey.o

View File

@@ -0,0 +1,79 @@
/*
* drivers/amlogic/key_manage/amlkey_if.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __AMLKEY_IF_H__
#define __AMLKEY_IF_H__
#define AMLKEY_NAME_LEN_MAX (80)
/*
* init
*/
int32_t amlkey_init(uint8_t *seed, uint32_t len);
/*
* query if the key already programmed
* exsit 1, non 0
*/
int32_t amlkey_isexsit(const uint8_t *name);
/*
* query if the prgrammed key is secure
* secure 1, non 0
*/
int32_t amlkey_issecure(const uint8_t *name);
/*
* query if the prgrammed key is encrypt
* return encrypt 1, non 0;
*/
int32_t amlkey_isencrypt(const uint8_t *name);
/*
* actual bytes of key value
*/
ssize_t amlkey_size(const uint8_t *name);
/*
* read non-secure key in bytes, return byets readback actully.
*/
ssize_t amlkey_read(const uint8_t *name, uint8_t *buffer, uint32_t len);
/*
* write key with attr in bytes , return bytes readback actully
* attr: bit0, secure/non-secure
* bit8, encrypt/non-encrypt
*/
ssize_t amlkey_write(const uint8_t *name,
uint8_t *buffer,
uint32_t len,
uint32_t attr);
/*
* get the hash value of programmed secure key | 32bytes length, sha256
*/
int32_t amlkey_hash_4_secure(const uint8_t *name, uint8_t *hash);
extern int32_t nand_key_read(uint8_t *buf,
uint32_t len, uint32_t *actual_length);
extern int32_t nand_key_write(uint8_t *buf,
uint32_t len, uint32_t *actual_length);
extern int32_t emmc_key_read(uint8_t *buf,
uint32_t len, uint32_t *actual_length);
extern int32_t emmc_key_write(uint8_t *buf,
uint32_t len, uint32_t *actual_length);
#endif

View File

@@ -0,0 +1,368 @@
/*
* drivers/amlogic/key_manage/storagekey.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
/* extern from bl31 */
/*
* when RET_OK
* query: retval=1: key exsit,=0: key not exsit
* tell: retvak = key size
* status: retval=1: secure, retval=0: non-secure
*/
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/kallsyms.h>
#include <linux/amlogic/efuse.h>
#include <linux/amlogic/security_key.h>
#include <linux/amlogic/key_manage.h>
#include <linux/of.h>
#include "unifykey.h"
#include "amlkey_if.h"
/* #include <amlogic/storage_if.h> */
/* key buffer status */
/* bit0, dirty flag*/
#define KEYBUFFER_CLEAN (0 << 0)
#define KEYBUFFER_DIRTY (1 << 0)
#define SECUESTORAGE_HEAD_SIZE (256)
#define SECUESTORAGE_WHOLE_SIZE (0x40000)
#define OTHER_METHOD_CALL
struct storagekey_info_t {
uint8_t *buffer;
uint32_t size;
uint32_t status;
};
static struct storagekey_info_t storagekey_info = {
.buffer = NULL,
/* default size */
.size = SECUESTORAGE_WHOLE_SIZE,
.status = KEYBUFFER_CLEAN,
};
store_key_ops store_key_read;
store_key_ops store_key_write;
#ifndef OTHER_METHOD_CALL
int store_operation_init(void)
{
int ret = 0;
if (kallsyms_lookup_name("nand_key_read")) {
pr_info(" %s() nand storeage ops!\n", __func__);
store_key_read = nand_key_read;
store_key_write = nand_key_write;
} else if (kallsyms_lookup_name("emmc_key_read")) {
pr_info(" %s() emmc storeage ops!\n", __func__);
store_key_read = emmc_key_read;
store_key_write = emmc_key_write;
} else {
ret = -1;
pr_err(" %s() fail!\n", __func__);
}
return ret;
}
#endif
void storage_ops_read(store_key_ops read)
{
#ifdef OTHER_METHOD_CALL
store_key_read = read;
#endif
}
EXPORT_SYMBOL(storage_ops_read);
void storage_ops_write(store_key_ops write)
{
#ifdef OTHER_METHOD_CALL
store_key_write = write;
#endif
}
EXPORT_SYMBOL(storage_ops_write);
/**
*1.init
* return ok 0, fail 1
*/
int32_t amlkey_init(uint8_t *seed, uint32_t len)
{
int32_t ret = 0;
uint32_t buffer_size, actual_size;
#ifndef OTHER_METHOD_CALL
ret = store_operation_init();
if (ret < 0) {
ret = -1;
pr_err(" %s store_operation_init fail!\n", __func__);
goto _out;
}
#endif
/* do nothing for now*/
pr_info("%s() enter!\n", __func__);
if (storagekey_info.buffer != NULL) {
pr_err("%s() %d: already init!\n", __func__, __LINE__);
goto _out;
}
/* get buffer from bl31 */
storagekey_info.buffer = secure_storage_getbuffer(&buffer_size);
if (storagekey_info.buffer == NULL) {
pr_err("%s() %d: can't get buffer from bl31!\n",
__func__, __LINE__);
ret = -1;
goto _out;
}
/* full fill key infos from storage. */
if (store_key_read)
ret = store_key_read(storagekey_info.buffer,
storagekey_info.size, &actual_size);
storagekey_info.size = actual_size;
pr_info("%s() storagekey_info.buffer=%p, storagekey_info.size = %0x!\n",
__func__,
storagekey_info.buffer,
storagekey_info.size);
if (ret) {
/* memset head info for bl31 */
memset(storagekey_info.buffer, 0, SECUESTORAGE_HEAD_SIZE);
ret = 0;
goto _out;
}
_out:
return ret;
}
/**
*2. query if the key already programmed
* return: exsit 1, non 0
*/
int32_t amlkey_isexsit(const uint8_t *name)
{
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_query((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
return (int32_t)retval;
}
/**
* 3. query if the prgrammed key is secure
* return secure 1, non 0;
*/
int32_t amlkey_get_attr(const uint8_t *name)
{
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_status((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
return (int32_t)retval;
}
/**
* 3.1 query if the prgrammed key is secure
* return secure 1, non 0;
*/
int32_t amlkey_issecure(const uint8_t *name)
{
return amlkey_get_attr(name) & KEY_UNIFY_ATTR_SECURE_MASK;
}
/**
* 3.2 query if the prgrammed key is encrypt
* return encrypt 1, non 0;
*/
int32_t amlkey_isencrypt(const uint8_t *name)
{
return amlkey_get_attr(name) & KEY_UNIFY_ATTR_ENCRYPT_MASK;
}
/**
* 4. actual bytes of key value
* return actual size.
*/
ssize_t amlkey_size(const uint8_t *name)
{
ssize_t size = 0;
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_tell((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
size = (ssize_t)retval;
return size;
}
/**
*5. read non-secure key in bytes, return bytes readback actully.
* return actual size read back.
*/
ssize_t amlkey_read(const uint8_t *name, uint8_t *buffer, uint32_t len)
{
int32_t ret = 0;
ssize_t retval = 0;
uint32_t actul_len;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_read((uint8_t *)name, buffer, len, &actul_len);
if (ret) {
pr_err("%s() %d: return %d\n", __func__, __LINE__, ret);
retval = 0;
goto _out;
}
retval = actul_len;
_out:
return retval;
}
/**
* 6.write key with attr in bytes , return bytes readback actully
* attr: bit0, secure/non-secure
* bit8, encrypt/non-encrypt
* return actual size write down.
*/
ssize_t amlkey_write(const uint8_t *name,
uint8_t *buffer,
uint32_t len,
uint32_t attr)
{
int32_t ret = 0;
ssize_t retval = 0;
uint32_t actual_length;
uint8_t *buf = NULL;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return retval;
}
pr_info("%s %d\n", __func__, __LINE__);
ret = secure_storage_write((uint8_t *)name,
buffer, len,
attr);
if (ret) {
pr_err("%s() %d: return %d\n", __func__, __LINE__, ret);
retval = 0;
goto _out;
} else {
retval = (ssize_t)len;
/* write down! */
if (storagekey_info.buffer != NULL) {
buf = kzalloc(storagekey_info.size, GFP_KERNEL);
memcpy(buf, storagekey_info.buffer,
storagekey_info.size);
if (store_key_write)
ret = store_key_write(buf,
storagekey_info.size,
&actual_length);
if (ret) {
pr_err("%s() %d, store_key_write fail\n",
__func__, __LINE__);
retval = 0;
}
kfree(buf);
}
}
_out:
return retval;
}
/**
* 7. get the hash value of programmed secure key | 32bytes length, sha256
* return success 0, fail -1
*/
int32_t amlkey_hash_4_secure(const uint8_t *name, uint8_t *hash)
{
int32_t ret = 0;
ret = secure_storage_verify((uint8_t *)name, hash);
return ret;
}
/**
* 7. del key by name
* return success 0, fail -1
*/
int32_t amlkey_del(const uint8_t *name)
{
int32_t ret = 0;
uint32_t actual_length;
if ((ret == 0) && (storagekey_info.buffer != NULL)) {
/* flush back */
if (store_key_write)
ret = store_key_write(storagekey_info.buffer,
storagekey_info.size, &actual_length);
if (ret) {
pr_err("%s() %d, store_key_write fail\n",
__func__,
__LINE__);
}
} else {
pr_err("%s() %d, remove key fail\n",
__func__,
__LINE__);
}
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
/*
* drivers/amlogic/key_manage/unifykey.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __UNIFYKEY_MANAGE_H__
#define __UNIFYKEY_MANAGE_H__
#include <linux/cdev.h>
#include <linux/ioctl.h>
#define KEYUNIFY_ATTACH _IO('f', 0x60)
#define KEYUNIFY_GET_INFO _IO('f', 0x62)
/* need query! */
enum key_manager_dev_e {
KEY_M_UNKNOWN_DEV = 0,
KEY_M_EFUSE,
KEY_M_NORMAL,/*include general key(nand key,emmc key)*/
KEY_M_SECURE,
KEY_M_MAX_DEV,
};
enum key_manager_permit_e {
KEY_M_PERMIT_READ = (1<<0),
KEY_M_PERMIT_WRITE = (1<<1),
KEY_M_PERMIT_DEL = (1<<2),
KEY_M_PERMIT_MASK = 0Xf,
};
enum key_manager_flag_e {
KEY_M_FLAG_EMPTY = (0<<0),
KEY_M_FLAG_EXSIT = (1<<0),
};
#define KEY_UNIFY_NAME_LEN 48
/* for ioctrl transfer parameters. */
struct key_item_info_t {
unsigned int id;
char name[KEY_UNIFY_NAME_LEN];
unsigned int size;
unsigned int permit;
unsigned int flag; /*bit 0: 1 exsit, 0-none;*/
unsigned int reserve;
};
#define KEY_UNIFY_ATTR_ENCRYPT (1 << 8)
#define KEY_UNIFY_ATTR_ENCRYPT_MASK (KEY_UNIFY_ATTR_ENCRYPT)
#define KEY_UNIFY_ATTR_SECURE (1 << 0)
#define KEY_UNIFY_ATTR_SECURE_MASK (KEY_UNIFY_ATTR_SECURE)
struct key_item_t {
char name[KEY_UNIFY_NAME_LEN];
int id;
unsigned int dev; /* key save in device //efuse, */
/* unsigned int df; */
unsigned int permit;
int attr;
int reserve;
struct key_item_t *next;
};
struct key_info_t {
int key_num;
int efuse_version;
int key_flag;
};
struct unifykey_dev_t {
struct cdev cdev;
unsigned int flags;
};
extern int unifykey_dt_create(struct platform_device *pdev);
extern int unifykey_dt_release(struct platform_device *pdev);
extern struct key_item_t *unifykey_find_item_by_name(char *name);
extern struct key_item_t *unifykey_find_item_by_id(int id);
extern int unifykey_item_verify_check(struct key_item_t *key_item);
extern int unifykey_count_key(void);
extern char unifykey_get_efuse_version(void);
#endif

View File

@@ -0,0 +1,271 @@
/*
* drivers/amlogic/key_manage/unifykey_dts.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/of.h>
#include "unifykey.h"
/* storages where key stored */
#define KEY_DEV_EFUSE "efuse"
#define KEY_DEV_NORMAL "normal"
#define KEY_DEV_SECURE "secure"
/* permision */
#define KEY_PERMIT_READ "read"
#define KEY_PERMIT_WRITE "write"
#define KEY_PERMIT_DEL "del"
/* attribute */
#define KEY_ATTR_TRUE "true"
#define KEY_ATTR_FALSE "false"
static struct key_info_t unify_key_info = {.key_num = 0, .key_flag = 0};
static struct key_item_t *unifykey_item;
int unifykey_item_verify_check(struct key_item_t *key_item)
{
if (!key_item) {
pr_err("%s:%d unify key item is invalid\n", __func__, __LINE__);
return -1;
}
if (key_item->dev == KEY_M_UNKNOWN_DEV) {
pr_err("%s:%d unify key item is invalid\n", __func__, __LINE__);
return -1;
}
return 0;
}
struct key_item_t *unifykey_find_item_by_name(char *name)
{
struct key_item_t *pre_item;
pre_item = unifykey_item;
while (pre_item) {
if (!strncmp(pre_item->name, name,
((strlen(pre_item->name) > strlen(name))
? strlen(pre_item->name) : strlen(name))))
return pre_item;
pre_item = pre_item->next;
}
return NULL;
}
struct key_item_t *unifykey_find_item_by_id(int id)
{
struct key_item_t *pre_item;
pre_item = unifykey_item;
while (pre_item) {
if (pre_item->id == id)
return pre_item;
pre_item = pre_item->next;
}
return NULL;
}
int unifykey_count_key(void)
{
int count = 0;
struct key_item_t *pre_item;
pre_item = unifykey_item;
while (pre_item) {
count++;
pre_item = pre_item->next;
}
return count;
}
char unifykey_get_efuse_version(void)
{
char ver = 0;
if (unify_key_info.efuse_version != -1)
ver = (char)unify_key_info.efuse_version;
return ver;
}
static int unifykey_add_to_list(struct key_item_t *item)
{
struct key_item_t *pre_item;
if (unifykey_item == NULL) {
unifykey_item = item;
} else {
pre_item = unifykey_item;
while (pre_item->next != NULL)
pre_item = pre_item->next;
pre_item->next = item;
}
return 0;
}
static int unifykey_free_list(void)
{
struct key_item_t *pre_item;
pre_item = unifykey_item;
while (pre_item) {
unifykey_item = unifykey_item->next;
kfree(pre_item);
pre_item = unifykey_item;
}
return 0;
}
static int unifykey_item_parse_dt(struct device_node *node, int id)
{
int count;
int ret = -1;
const char *propname;
struct key_item_t *temp_item = NULL;
temp_item = kzalloc(sizeof(struct key_item_t), GFP_KERNEL);
if (!temp_item) {
ret = -ENOMEM;
return ret;
}
propname = NULL;
ret = of_property_read_string(node, "key-name", &propname);
if (ret < 0) {
pr_err("%s:%d,get key-name fail\n", __func__, __LINE__);
ret = -EINVAL;
goto exit;
}
if (propname) {
count = strlen(propname);
memset(temp_item->name, 0, KEY_UNIFY_NAME_LEN);
if (count >= KEY_UNIFY_NAME_LEN)
count = KEY_UNIFY_NAME_LEN-1;
strncpy(temp_item->name, propname, count);
}
propname = NULL;
ret = of_property_read_string(node, "key-device", &propname);
if (ret < 0) {
pr_err("%s:%d,get key-device fail\n", __func__, __LINE__);
ret = -EINVAL;
goto exit;
}
if (propname) {
if (strcmp(propname, KEY_DEV_EFUSE) == 0)
temp_item->dev = KEY_M_EFUSE;
else if (strcmp(propname, KEY_DEV_NORMAL) == 0)
temp_item->dev = KEY_M_NORMAL;
else if (strcmp(propname, KEY_DEV_SECURE) == 0)
temp_item->dev = KEY_M_SECURE;
else
temp_item->dev = KEY_M_UNKNOWN_DEV;
}
temp_item->permit = 0;
if (of_property_match_string(node, "key-permit", KEY_PERMIT_READ) >= 0)
temp_item->permit |= KEY_M_PERMIT_READ;
if (of_property_match_string(node, "key-permit", KEY_PERMIT_WRITE) >= 0)
temp_item->permit |= KEY_M_PERMIT_WRITE;
if (of_property_match_string(node, "key-permit", KEY_PERMIT_DEL) >= 0)
temp_item->permit |= KEY_M_PERMIT_DEL;
temp_item->id = id;
temp_item->attr = 0;
ret = of_property_read_string(node, "key-encrypt", &propname);
if (ret < 0)
goto _next_attr;
if (propname) {
if (strcmp(propname, KEY_ATTR_TRUE) == 0)
temp_item->attr = KEY_UNIFY_ATTR_ENCRYPT;
}
_next_attr:
/*todo, add new attribute here*/
unifykey_add_to_list(temp_item);
return 0;
exit:
kfree(temp_item);
return ret;
}
static int unifykey_item_create(struct platform_device *pdev, int num)
{
int ret = -1;
int index;
struct device_node *child;
struct device_node *np = pdev->dev.of_node;
of_node_get(np);
index = 0;
for_each_child_of_node(np, child) {
ret = unifykey_item_parse_dt(child, index);
if (!ret)
index++;
}
pr_info("key unify fact unifykey-num is %d\n", index);
return 0;
}
int unifykey_dt_create(struct platform_device *pdev)
{
int ret = -1;
int key_num;
ret = of_property_read_u32(pdev->dev.of_node,
"unifykey-num", &key_num);
if (ret) {
pr_err("%s:%d,don't find to match unifykey-num\n",
__func__,
__LINE__);
return ret;
}
/* set default efuse version info */
unify_key_info.efuse_version = -1;
of_property_read_u32(pdev->dev.of_node, "efuse-version",
&unify_key_info.efuse_version);
pr_info("key unify config unifykey-num is %d\n", key_num);
unify_key_info.key_num = key_num;
if (!unify_key_info.key_flag) {
unifykey_item_create(pdev, key_num);
unify_key_info.key_flag = 1;
}
return ret;
}
int unifykey_dt_release(struct platform_device *pdev)
{
if (pdev->dev.of_node)
of_node_put(pdev->dev.of_node);
unifykey_free_list();
unify_key_info.key_flag = 0;
return 0;
}

View File

@@ -2,4 +2,4 @@
# Amlogic MMC specific Makefile
#
obj-$(CONFIG_AMLOGIC_MMC) += amlsd.o amlsd_of.o emmc_partitions.o aml_sd_emmc.o
obj-$(CONFIG_AMLOGIC_MMC) += amlsd.o amlsd_of.o emmc_partitions.o aml_sd_emmc.o emmc_key.o

View File

@@ -0,0 +1,212 @@
/*
* drivers/amlogic/mmc/emmc_key.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/types.h>
#include <linux/err.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
#include <linux/mmc/card.h>
#include <linux/mmc/emmc_partitions.h>
#include <linux/amlogic/key_manage.h>
#include "emmc_key.h"
#define EMMC_BLOCK_SIZE (0x100)
#define MAX_EMMC_BLOCK_SIZE (128*1024)
/*
* kernel head file
*
*/
static struct mmc_card *mmc_card_key;
static struct aml_emmckey_info_t *emmckey_info;
static int aml_emmc_key_check(void)
{
u8 keypart_cnt;
u64 part_size;
struct emmckey_valid_node_t *emmckey_valid_node, *temp_valid_node;
emmckey_info->key_part_count =
emmckey_info->keyarea_phy_size / EMMC_KEYAREA_SIZE;
if (emmckey_info->key_part_count
> EMMC_KEYAREA_COUNT) {
emmckey_info->key_part_count = EMMC_KEYAREA_COUNT;
}
keypart_cnt = 0;
part_size = EMMC_KEYAREA_SIZE;
do {
emmckey_valid_node = kmalloc(
sizeof(*emmckey_valid_node), GFP_KERNEL);
if (emmckey_valid_node == NULL) {
pr_info("%s:%d,kmalloc memory fail\n",
__func__, __LINE__);
return -ENOMEM;
}
emmckey_valid_node->phy_addr = emmckey_info->keyarea_phy_addr
+ part_size * keypart_cnt;
emmckey_valid_node->phy_size = EMMC_KEYAREA_SIZE;
emmckey_valid_node->next = NULL;
emmckey_info->key_valid = 0;
if (emmckey_info->key_valid_node == NULL) {
emmckey_info->key_valid_node = emmckey_valid_node;
} else{
temp_valid_node = emmckey_info->key_valid_node;
while (temp_valid_node->next != NULL)
temp_valid_node = temp_valid_node->next;
temp_valid_node->next = emmckey_valid_node;
}
} while (++keypart_cnt < emmckey_info->key_part_count);
emmckey_info->key_valid = 1;
return 0;
}
int32_t emmc_key_read(uint8_t *buffer,
uint32_t length, uint32_t *actual_length)
{
int ret;
u64 addr = 0;
u32 size = 0;
int blk, cnt;
unsigned char *dst = NULL;
struct mmc_card *card = mmc_card_key;
int bit = card->csd.read_blkbits;
size = length;
*actual_length = length;
addr = get_reserve_partition_off_from_tbl() + EMMCKEY_RESERVE_OFFSET;
blk = addr >> bit;
cnt = size >> bit;
dst = (unsigned char *)buffer;
mmc_claim_host(card->host);
do {
ret = mmc_read_internal(card, blk, EMMC_BLOCK_SIZE, dst);
if (ret) {
pr_err("%s [%d] mmc_write_internal error\n",
__func__, __LINE__);
return ret;
}
blk += EMMC_BLOCK_SIZE;
cnt -= EMMC_BLOCK_SIZE;
dst = (unsigned char *)buffer + MAX_EMMC_BLOCK_SIZE;
} while (cnt != 0);
pr_info("%s:%d, read %s\n", __func__, __LINE__, (ret) ? "error":"ok");
mmc_release_host(card->host);
return ret;
}
EXPORT_SYMBOL(emmc_key_read);
int32_t emmc_key_write(uint8_t *buffer,
uint32_t length, uint32_t *actual_length)
{
int ret;
u64 addr = 0;
u32 size = 0;
int blk, cnt;
unsigned char *src = NULL;
struct mmc_card *card = mmc_card_key;
int bit = card->csd.read_blkbits;
size = length;
addr = get_reserve_partition_off_from_tbl() + EMMCKEY_RESERVE_OFFSET;
blk = addr >> bit;
cnt = size >> bit;
src = (unsigned char *)buffer;
mmc_claim_host(card->host);
do {
ret = mmc_write_internal(card, blk, EMMC_BLOCK_SIZE, src);
if (ret) {
pr_err("%s [%d] mmc_write_internal error\n",
__func__, __LINE__);
return ret;
}
blk += EMMC_BLOCK_SIZE;
cnt -= EMMC_BLOCK_SIZE;
src = (unsigned char *)buffer + MAX_EMMC_BLOCK_SIZE;
} while (cnt != 0);
pr_info("%s:%d, write %s\n", __func__, __LINE__, (ret) ? "error":"ok");
mmc_release_host(card->host);
return ret;
}
EXPORT_SYMBOL(emmc_key_write);
int emmc_key_init(struct mmc_card *card)
{
u64 addr = 0;
u32 size = 0;
u64 lba_start = 0, lba_end = 0;
int err = 0;
int bit = card->csd.read_blkbits;
pr_info("card key: card_blk_probe.\n");
emmckey_info = kmalloc(sizeof(*emmckey_info), GFP_KERNEL);
if (emmckey_info == NULL) {
pr_info("%s:%d,kmalloc memory fail\n", __func__, __LINE__);
return -ENOMEM;
}
memset(emmckey_info, 0, sizeof(*emmckey_info));
emmckey_info->key_init = 0;
size = EMMCKEY_AREA_PHY_SIZE;
addr = get_reserve_partition_off_from_tbl() + EMMCKEY_RESERVE_OFFSET;
if (addr < 0) {
err = -EINVAL;
goto exit_err;
}
lba_start = addr >> bit;
lba_end = (addr + size) >> bit;
emmckey_info->key_init = 1;
pr_info("%s:%d emmc key lba_start:0x%llx,lba_end:0x%llx\n",
__func__, __LINE__, lba_start, lba_end);
if (!emmckey_info->key_init) {
err = -EINVAL;
pr_info("%s:%d,emmc key init fail\n", __func__, __LINE__);
goto exit_err;
}
emmckey_info->keyarea_phy_addr = addr;
emmckey_info->keyarea_phy_size = size;
emmckey_info->lba_start = lba_start;
emmckey_info->lba_end = lba_end;
mmc_card_key = card;
err = aml_emmc_key_check();
if (err) {
pr_info("%s:%d,emmc key check fail\n", __func__, __LINE__);
goto exit_err;
}
storage_ops_read(emmc_key_read);
storage_ops_write(emmc_key_write);
pr_info("emmc key: %s:%d ok.\n", __func__, __LINE__);
return err;
exit_err:
kfree(emmckey_info);
return err;
}

View File

@@ -0,0 +1,74 @@
/*
* drivers/amlogic/mmc/emmc_key.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __EMMC_KEY_H__
#define __EMMC_KEY_H__
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
#define EMMC_KEY_AREA_SIGNAL "emmckeys"
#define EMMC_KEY_AREA_SIGNAL_LEN 16
#define EMMC_KEYAREA_SIZE (128*1024)
#define EMMC_KEYAREA_COUNT 2
/* we store partition table in the previous 16KB space */
#define EMMCKEY_RESERVE_OFFSET 0x4000
#define EMMCKEY_AREA_PHY_SIZE (EMMC_KEYAREA_COUNT * EMMC_KEYAREA_SIZE)
struct emmckey_valid_node_t {
u64 phy_addr;
u64 phy_size;
struct emmckey_valid_node_t *next;
};
struct aml_emmckey_info_t {
/* struct memory_card *card; */
struct emmckey_valid_node_t *key_valid_node;
u64 keyarea_phy_addr;
u64 keyarea_phy_size;
u64 lba_start;
u64 lba_end;
u32 blk_size;
u32 blk_shift;
u8 key_init;
u8 key_valid;
u8 key_part_count;
};
#define EMMCKEY_DATA_VALID_LEN \
(EMMC_KEYAREA_SIZE - EMMC_KEY_AREA_SIGNAL_LEN - 4 - 4 - 4)
struct emmckey_data_t {
u8 keyarea_mark[EMMC_KEY_AREA_SIGNAL_LEN];
u32 keyarea_mark_checksum;
u32 checksum;
u32 reserve;
u8 data[EMMCKEY_DATA_VALID_LEN];
};
int emmc_key_init(struct mmc_card *card);
int32_t emmc_key_read(uint8_t *buffer,
uint32_t length, uint32_t *actual_length);
int32_t emmc_key_write(uint8_t *buffer,
uint32_t length, uint32_t *actual_length);
#endif

View File

@@ -33,6 +33,7 @@
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/sd.h>
#include "emmc_key.h"
#define DTB_NAME "dtb"
#define SZ_1M 0x00100000
@@ -957,6 +958,9 @@ int aml_emmc_partition_ops(struct mmc_card *card, struct gendisk *disk)
}
mmc_release_host(card->host);
if (ret == 0) /* ok */
ret = emmc_key_init(card);
amlmmc_dtb_init(card);
aml_store_class = class_create(THIS_MODULE, "aml_store");

View File

@@ -0,0 +1,37 @@
/*
* include/linux/amlogic/key_manage.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __KEYMANAGE1__
#define __KEYMANAGE1__
typedef int32_t (*store_key_ops)(uint8_t *buf,
uint32_t len, uint32_t *actual_length);
#ifdef CONFIG_AMLOGIC_KEY_MANAGE
void storage_ops_read(store_key_ops read);
void storage_ops_write(store_key_ops write);
#else
void storage_ops_read(store_key_ops read)
{
}
void storage_ops_write(store_key_ops read)
{
}
#endif /*CONFIG_KEY_MANAGE*/
#endif /*__KEYMANAGE1__*/