300 lines
7.5 KiB
C
300 lines
7.5 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <amlogic/aml_mkl.h>
|
|
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <dma.h>
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/amlogic/arch/regs.h>
|
|
#include <asm/amlogic/arch/secure_apb.h>
|
|
|
|
// #define MKL_DMA_TEST
|
|
//#define DEBUG (0)
|
|
|
|
/* kl offset */
|
|
#define KL_PENDING_OFFSET (31)
|
|
#define KL_PENDING_MASK (1)
|
|
#define KL_STATUS_OFFSET (29)
|
|
#define KL_STATUS_MASK (3)
|
|
#define KL_ALGO_OFFSET (28)
|
|
#define KL_ALGO_MASK (1)
|
|
#define KL_MODE_OFFSET (26)
|
|
#define KL_MODE_MASK (3)
|
|
#define KL_FLAG_OFFSET (24)
|
|
#define KL_FLAG_MASK (3)
|
|
#define KL_KEYALGO_OFFSET (20)
|
|
#define KL_KEYALGO_MASK (0xf)
|
|
#define KL_USERID_OFFSET (16)
|
|
#define KL_USERID_MASK (0xf)
|
|
#define KL_KTE_OFFSET (8)
|
|
#define KL_KTE_MASK (0xff)
|
|
#define KL_MRK_OFFSET (4)
|
|
#define KL_MRK_MASK (0xf)
|
|
#define KL_FUNC_ID_OFFSET (0)
|
|
#define KL_FUNC_ID_MASK (0xf)
|
|
#define KL_MID_OFFSET (24)
|
|
#define KL_MID_MASK (0xff)
|
|
#define KL_MID_EXTRA_OFFSET (8)
|
|
#define KL_TEE_PRIV_OFFSET (7)
|
|
#define KL_TEE_PRIV_MASK (1)
|
|
#define KL_TEE_SEP_OFFSET (2)
|
|
#define KL_TEE_SEP_MASK (3)
|
|
#define KL_LEVEL_OFFSET (4)
|
|
#define KL_LEVEL_MASK (7)
|
|
#define KL_STAGE_OFFSET (0)
|
|
#define KL_STAGE_MASK (3)
|
|
|
|
/* kl etc */
|
|
#define KT_KTE_MAX (256)
|
|
#define HANDLE_TO_KTE(h) ((h) & (KT_KTE_MAX - 1))
|
|
#define KL_PENDING_WAIT_TIMEOUT (20000)
|
|
|
|
/* kl status */
|
|
#define KL_STATUS_OK (0)
|
|
#define KL_STATUS_ERROR_PERMISSION_DINED (1)
|
|
#define KL_STATUS_ERROR_OTP (2)
|
|
#define KL_STATUS_ERROR_DEPOSIT (3)
|
|
#define KL_STATUS_ERROR_TIMEOUT (4)
|
|
#define KL_STATUS_ERROR_BAD_PARAM (5)
|
|
#define KL_STATUS_ERROR_BAD_STATE (6)
|
|
|
|
static int aml_mkl_program_key(uint32_t addr, const uint8_t *data, uint32_t len)
|
|
{
|
|
int i = 0;
|
|
const u32 *data32 = (const u32 *)data;
|
|
|
|
if (!data32 || len != 16)
|
|
return -1;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
writel(data32[i], (uint32_t *)MKL_REE_EK + addr + i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aml_mkl_lock(void)
|
|
{
|
|
int cnt = 0;
|
|
|
|
while (readl((uint32_t *)MKL_REE_RDY) != 1) {
|
|
if (cnt++ > KL_PENDING_WAIT_TIMEOUT) {
|
|
printf("Error: wait KT ready timeout\n");
|
|
return KL_STATUS_ERROR_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
return KL_STATUS_OK;
|
|
}
|
|
|
|
static void aml_mkl_unlock(void)
|
|
{
|
|
writel(1, (uint32_t *)MKL_REE_RDY);
|
|
}
|
|
|
|
int aml_mkl_run(struct amlkl_params *param)
|
|
{
|
|
int ret;
|
|
int i;
|
|
u32 reg_val = 0;
|
|
struct amlkl_usage *pu;
|
|
|
|
if (!param)
|
|
return KL_STATUS_ERROR_BAD_PARAM;
|
|
|
|
pu = ¶m->usage;
|
|
#if DEBUG
|
|
printf("kth:%d, levels:%d, kl_algo:%d, func_id:%d, mrk:%d\n",
|
|
param->kt_handle, param->levels, param->kl_algo, param->func_id,
|
|
param->mrk_cfg_index);
|
|
printf("kt usage, crypto:%d, algo:%d, uid:%d\n",
|
|
pu->crypto, pu->algo, pu->uid);
|
|
#endif
|
|
if (pu->uid & ~KL_USERID_MASK ||
|
|
(pu->uid > AML_KT_USER_M2M_5 && pu->uid < AML_KT_USER_TSD) ||
|
|
(pu->uid > AML_KT_USER_TSE && pu->uid < KL_USERID_MASK) ||
|
|
pu->algo & ~KL_KEYALGO_MASK ||
|
|
(pu->algo > AML_KT_ALGO_DES && pu->algo < AML_KT_ALGO_NDL) ||
|
|
(pu->algo > AML_KT_ALGO_CSA2 && pu->algo < AML_KT_ALGO_HMAC) ||
|
|
(pu->algo > AML_KT_ALGO_HMAC && pu->algo < KL_KEYALGO_MASK) ||
|
|
pu->crypto & ~KL_FLAG_MASK || param->levels != AML_KL_LEVEL_3 ||
|
|
param->kl_algo > AML_KL_ALGO_AES) {
|
|
return KL_STATUS_ERROR_BAD_PARAM;
|
|
}
|
|
|
|
/* 1. Read KL_REE_RDY to lock KL */
|
|
if (aml_mkl_lock() != KL_STATUS_OK) {
|
|
printf("key ladder not ready\n");
|
|
return KL_STATUS_ERROR_BAD_STATE;
|
|
}
|
|
|
|
/* 2. Program Eks */
|
|
for (i = 0; i < param->levels; i++) {
|
|
ret = aml_mkl_program_key(i * 4, param->eks[param->levels - 1 - i],
|
|
sizeof(param->eks[param->levels - 1 - i]));
|
|
if (ret != 0) {
|
|
printf("Error: Ek data has bad parameter\n");
|
|
return KL_STATUS_ERROR_BAD_PARAM;
|
|
}
|
|
}
|
|
|
|
/* 3. Program KL_REE_CMD */
|
|
reg_val = 0;
|
|
reg_val =
|
|
(0 << KL_TEE_PRIV_OFFSET | 0 << KL_LEVEL_OFFSET
|
|
| 0 << KL_STAGE_OFFSET | 0 << KL_TEE_SEP_OFFSET);
|
|
writel(reg_val, (uint32_t *)MKL_REE_CMD);
|
|
|
|
/* 4. Program KL_REE_CFG with KL_pending to 1 */
|
|
reg_val = 0;
|
|
reg_val =
|
|
(1 << KL_PENDING_OFFSET
|
|
| param->kl_algo << KL_ALGO_OFFSET
|
|
| param->kl_mode << KL_MODE_OFFSET
|
|
| param->usage.crypto << KL_FLAG_OFFSET
|
|
| param->usage.algo << KL_KEYALGO_OFFSET
|
|
| param->usage.uid << KL_USERID_OFFSET
|
|
| (HANDLE_TO_KTE(param->kt_handle)) << KL_KTE_OFFSET
|
|
| param->mrk_cfg_index << KL_MRK_OFFSET
|
|
| (param->func_id << KL_FUNC_ID_OFFSET));
|
|
writel(reg_val, (uint32_t *)MKL_REE_CFG);
|
|
|
|
/* 5. Poll KL_REE_CFG till KL_pending is 0 */
|
|
while ((ret = readl((uint32_t *)MKL_REE_CFG) &
|
|
(1 << KL_PENDING_OFFSET)))
|
|
;
|
|
|
|
/* 6. Write KL_REE_RDY to release KL */
|
|
aml_mkl_unlock();
|
|
|
|
/* 7. Get final status */
|
|
ret = (ret >> KL_STATUS_OFFSET) & KL_STATUS_MASK;
|
|
/* coverity[dead_error_condition:SUPPRESS] */
|
|
switch (ret) {
|
|
case 0:
|
|
break;
|
|
/* coverity[dead_error_condition:SUPPRESS] */
|
|
case 1:
|
|
printf("Permission Denied Error code: %d\n", ret);
|
|
return KL_STATUS_ERROR_BAD_STATE;
|
|
/* coverity[dead_error_condition:SUPPRESS] */
|
|
case 2:
|
|
/* coverity[dead_error_condition:SUPPRESS] */
|
|
case 3:
|
|
/* coverity[dead_error_begin:SUPPRESS] */
|
|
default:
|
|
printf("OTP or KL Error code: %d\n", ret);
|
|
return KL_STATUS_ERROR_BAD_STATE;
|
|
}
|
|
#if DEBUG
|
|
printf("aml key ladder run success\n");
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
#ifdef MKL_DMA_TEST
|
|
#include <command.h>
|
|
#include <amlogic/aml_crypto.h>
|
|
|
|
static int mkl_test_dvgk(void)
|
|
{
|
|
int ret = 0;
|
|
struct amlkl_params kl_param;
|
|
uint32_t dvgk_test_key_slot = 31; //only test slot
|
|
uint8_t dst[16] = {0};
|
|
|
|
/* dvgk_func_0_bs_0_tsep_0.test.vector.txt */
|
|
uint8_t dvgk_ek3[16] = {
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
|
|
};
|
|
|
|
uint8_t dvgk_ek2[16] = {
|
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
|
|
};
|
|
|
|
uint8_t dvgk_ek1[16] = {
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
|
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f
|
|
};
|
|
|
|
uint8_t dvgk_plain[16] = {
|
|
0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
|
|
0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xb0
|
|
};
|
|
|
|
uint8_t dvgk_cipher[16] = {
|
|
0x74, 0x1e, 0x39, 0x05, 0xc2, 0x53, 0x05, 0x15,
|
|
0xfd, 0x5c, 0xb0, 0x07, 0xcc, 0x81, 0x3b, 0xaf
|
|
};
|
|
|
|
memset(&kl_param, 0, sizeof(kl_param));
|
|
kl_param.kt_handle = dvgk_test_key_slot;
|
|
kl_param.levels = AML_KL_LEVEL_3;
|
|
kl_param.usage.crypto = AML_KT_FLAG_ENC_DEC;
|
|
kl_param.usage.algo = AML_KT_ALGO_AES;
|
|
kl_param.usage.uid = AML_KT_USER_M2M_0;
|
|
kl_param.kl_algo = AML_KL_ALGO_AES;
|
|
kl_param.kl_mode = AML_KL_MODE_AML;
|
|
kl_param.mrk_cfg_index = AML_KL_MRK_DVGK;
|
|
kl_param.func_id = AML_KL_FUNC_AES_0;
|
|
memcpy(kl_param.eks[0], dvgk_ek1, 16);
|
|
memcpy(kl_param.eks[1], dvgk_ek2, 16);
|
|
memcpy(kl_param.eks[2], dvgk_ek3, 16);
|
|
ret = aml_mkl_run(&kl_param);
|
|
if (ret != 0) {
|
|
printf("aml_mkl_run error[ret:%d]\n", ret);
|
|
return -1;
|
|
}
|
|
|
|
ret = aes_ecb_enc_keytbl(AES_KEY_SIZE_128, dvgk_plain, dst,
|
|
NULL, sizeof(dvgk_plain), dvgk_test_key_slot);
|
|
if (!memcmp(dst, dvgk_cipher, sizeof(dvgk_cipher)))
|
|
printf("MKL DMA TEST PASS\n");
|
|
else
|
|
printf("MKL DMA TEST FAIL\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int do_mkl_dma_test(uint32_t test_case)
|
|
{
|
|
switch (test_case) {
|
|
case 0:
|
|
mkl_test_dvgk();
|
|
return 0;
|
|
default:
|
|
printf("Unknown test case\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int do_mkl_test(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char *const argv[])
|
|
{
|
|
uint32_t test_case = 0;
|
|
char *endp = 0;
|
|
|
|
if (argc != 2) {
|
|
cmd_usage(cmdtp);
|
|
return 1;
|
|
}
|
|
|
|
test_case = ustrtoul(argv[1], &endp, 0);
|
|
|
|
do_mkl_dma_test(test_case);
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(mkl, 2, 0, do_mkl_test,
|
|
"mkl <test case>",
|
|
"if case=0, run mkl dma test for dvgk\n"
|
|
);
|
|
#endif
|