mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
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:
15
MAINTAINERS
15
MAINTAINERS
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -61,5 +61,7 @@ source "drivers/amlogic/cec/Kconfig"
|
||||
|
||||
source "drivers/amlogic/securitykey/Kconfig"
|
||||
|
||||
source "drivers/amlogic/key_manage/Kconfig"
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -57,3 +57,5 @@ obj-$(CONFIG_AMLOGIC_AO_CEC) += cec/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_SECURITY_KEY) += securitykey/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_KEY_MANAGE) += key_manage/
|
||||
|
||||
|
||||
15
drivers/amlogic/key_manage/Kconfig
Normal file
15
drivers/amlogic/key_manage/Kconfig
Normal 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
|
||||
4
drivers/amlogic/key_manage/Makefile
Normal file
4
drivers/amlogic/key_manage/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# Makefile for unifykey
|
||||
#
|
||||
obj-$(CONFIG_AMLOGIC_KEY_MANAGE) += unifykey.o unifykey_dts.o storagekey.o
|
||||
79
drivers/amlogic/key_manage/amlkey_if.h
Normal file
79
drivers/amlogic/key_manage/amlkey_if.h
Normal 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
|
||||
|
||||
368
drivers/amlogic/key_manage/storagekey.c
Normal file
368
drivers/amlogic/key_manage/storagekey.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
1419
drivers/amlogic/key_manage/unifykey.c
Normal file
1419
drivers/amlogic/key_manage/unifykey.c
Normal file
File diff suppressed because it is too large
Load Diff
97
drivers/amlogic/key_manage/unifykey.h
Normal file
97
drivers/amlogic/key_manage/unifykey.h
Normal 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
|
||||
|
||||
271
drivers/amlogic/key_manage/unifykey_dts.c
Normal file
271
drivers/amlogic/key_manage/unifykey_dts.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
212
drivers/amlogic/mmc/emmc_key.c
Normal file
212
drivers/amlogic/mmc/emmc_key.c
Normal 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;
|
||||
}
|
||||
|
||||
74
drivers/amlogic/mmc/emmc_key.h
Normal file
74
drivers/amlogic/mmc/emmc_key.h
Normal 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
|
||||
|
||||
@@ -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");
|
||||
|
||||
37
include/linux/amlogic/key_manage.h
Normal file
37
include/linux/amlogic/key_manage.h
Normal 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__*/
|
||||
Reference in New Issue
Block a user