blob: 76c64fdca9a4fd896d131fbd27b08e07fd0a2f57 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <fs.h>
#include <fat.h>
#include <u-boot/sha256.h>
#include <emmc_partitions.h>
#include <stdlib.h>
#include <mapmem.h>
#include <amlogic/storage.h>
#define CMD_DEBUG (0)
#define CMD_LOG_TAG "[FACTORY-PROVISION] "
#if CMD_DEBUG
#define LOGD(fmt, ...) printf("%s"fmt, CMD_LOG_TAG, ##__VA_ARGS__)
#else
#define LOGD(fmt, ...)
#endif
#define LOGE(fmt, ...) printf("%sERROR: "fmt, CMD_LOG_TAG, ##__VA_ARGS__)
#define LOGI(fmt, ...) printf("%s"fmt, CMD_LOG_TAG, ##__VA_ARGS__)
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
#ifndef getenv
#define getenv env_get
#endif
#define FUNCID_PROVISION_SET_IV 0xB200E030
#define FUNCID_PROVISION_ENCRYPT 0xB200E031
#define FUNCID_PROVISION_GET_TRANSFER_ADDR 0xB2000007
#define SIZE_1K (1024)
#define SIZE_1M (SIZE_1K * SIZE_1K)
#define SIZE_TAG (16)
#define SIZE_IV (16)
#define SIZE_AES_KEY (16)
#define SIZE_HMAC_KEY (32)
#define SIZE_HMAC_DIGEST (32)
#define SIZE_BLOCK (512)
#define MAX_SIZE_CMD (256)
#define MAX_SIZE_KEYBOX_NAME (256)
#define MAX_SIZE_PART_NAME (32)
#define MAX_SIZE_KEYBOX (SIZE_1K * 16)
#define MAX_CNT_FS_VALUE (256)
#define KEYBOX_HDR_MAGIC (0x6B626F78) //"kbox"
#define KEYBOX_HDR_MIN_VERSION (5)
#define PROVISION_TYPE_FACTORY (0)
#define ACTION_UNKNOWN (0x00)
#define ACTION_INIT (0x01)
#define ACTION_WRITE (0x02)
#define ACTION_QUERY (0x03)
#define ACTION_REMOVE (0x04)
#define ACTION_CLEAR (0x05)
#define ACTION_LIST (0x06)
#define DEV_NAME "mmc"
#define DEV_NO (1)
#define PART_TYPE "user"
#define PART_NAME_RSV "rsv"
#define PART_NAME_FTY "factory"
#define CMD_RET_SUCCESS 0x00000000
#define CMD_RET_KEYBOX_NOT_EXIST 0x00000001
#define CMD_RET_KEYBOX_TOO_LARGE 0x00000002
#define CMD_RET_KEYBOX_NAME_TOO_LONG 0x00000003
#define CMD_RET_KEYBOX_BAD_FORMAT 0x00000004
#define CMD_RET_DEVICE_NO_SPACE 0x00000011
#define CMD_RET_DEVICE_NOT_AVAILABLE 0x00000012
#define CMD_RET_BAD_PARAMETER 0x00000021
#define CMD_RET_SMC_CALL_FAILED 0x00000031
#define CMD_RET_UNKNOWN_ERROR 0x0000FFFF
struct keybox_header {
uint32_t magic;
uint32_t version;
uint32_t key_type;
uint32_t key_size;
uint32_t provision_type;
uint32_t ta_uuid[4];
uint32_t reserved[4];
};
struct encryption_context {
char iv[SIZE_IV];
char tag[SIZE_TAG];
char epek[SIZE_AES_KEY];
char rsv[64];
};
struct input_param {
uint32_t action;
const char *keybox_name;
uint32_t keybox_phy_addr;
uint32_t keybox_size;
uint32_t ret_data_addr;
};
struct fs_value {
int idx;
uint32_t value;
};
static char g_keybox[MAX_SIZE_KEYBOX] = { 0 };
static char g_fs_data[SIZE_1K] = { 0 };
static char g_part_name[MAX_SIZE_PART_NAME] = { 0 };
static struct fs_value g_fs_vals_rsv[MAX_CNT_FS_VALUE] = {
{ 0, 0xEB }, { 1, 0x3C }, { 2, 0x90 }, { 3, 0x6D },
{ 4, 0x6B }, { 5, 0x66 }, { 6, 0x73 }, { 7, 0x2E },
{ 8, 0x66 }, { 9, 0x61 }, { 10, 0x74 }, { 12, 0x02 },
{ 13, 0x10 }, { 14, 0x01 }, { 16, 0x02 }, { 18, 0x02 },
{ 20, 0x80 }, { 21, 0xF8 }, { 22, 0x10 }, { 24, 0x20 },
{ 26, 0x40 }, { 36, 0x80 }, { 38, 0x29 }, { 39, 0x13 },
{ 40, 0x4C }, { 41, 0x98 }, { 42, 0x6A }, { 43, 0x4B },
{ 44, 0x45 }, { 45, 0x59 }, { 46, 0x42 }, { 47, 0x4F },
{ 48, 0x58 }, { 49, 0x20 }, { 50, 0x50 }, { 51, 0x41 },
{ 52, 0x52 }, { 53, 0x54 }, { 54, 0x46 }, { 55, 0x41 },
{ 56, 0x54 }, { 57, 0x31 }, { 58, 0x32 }, { 59, 0x20 },
{ 60, 0x20 }, { 61, 0x20 }, { 62, 0x0E }, { 63, 0x1F },
{ 64, 0xBE }, { 65, 0x5B }, { 66, 0x7C }, { 67, 0xAC },
{ 68, 0x22 }, { 69, 0xC0 }, { 70, 0x74 }, { 71, 0x0B },
{ 72, 0x56 }, { 73, 0xB4 }, { 74, 0x0E }, { 75, 0xBB },
{ 76, 0x07 }, { 78, 0xCD }, { 79, 0x10 }, { 80, 0x5E },
{ 81, 0xEB }, { 82, 0xF0 }, { 83, 0x32 }, { 84, 0xE4 },
{ 85, 0xCD }, { 86, 0x16 }, { 87, 0xCD }, { 88, 0x19 },
{ 89, 0xEB }, { 90, 0xFE }, { 91, 0x54 }, { 92, 0x68 },
{ 93, 0x69 }, { 94, 0x73 }, { 95, 0x20 }, { 96, 0x69 },
{ 97, 0x73 }, { 98, 0x20 }, { 99, 0x6E }, { 100, 0x6F },
{ 101, 0x74 }, { 102, 0x20 }, { 103, 0x61 }, { 104, 0x20 },
{ 105, 0x62 }, { 106, 0x6F }, { 107, 0x6F }, { 108, 0x74 },
{ 109, 0x61 }, { 110, 0x62 }, { 111, 0x6C }, { 112, 0x65 },
{ 113, 0x20 }, { 114, 0x64 }, { 115, 0x69 }, { 116, 0x73 },
{ 117, 0x6B }, { 118, 0x2E }, { 119, 0x20 }, { 120, 0x20 },
{ 121, 0x50 }, { 122, 0x6C }, { 123, 0x65 }, { 124, 0x61 },
{ 125, 0x73 }, { 126, 0x65 }, { 127, 0x20 }, { 128, 0x69 },
{ 129, 0x6E }, { 130, 0x73 }, { 131, 0x65 }, { 132, 0x72 },
{ 133, 0x74 }, { 134, 0x20 }, { 135, 0x61 }, { 136, 0x20 },
{ 137, 0x62 }, { 138, 0x6F }, { 139, 0x6F }, { 140, 0x74 },
{ 141, 0x61 }, { 142, 0x62 }, { 143, 0x6C }, { 144, 0x65 },
{ 145, 0x20 }, { 146, 0x66 }, { 147, 0x6C }, { 148, 0x6F },
{ 149, 0x70 }, { 150, 0x70 }, { 151, 0x79 }, { 152, 0x20 },
{ 153, 0x61 }, { 154, 0x6E }, { 155, 0x64 }, { 156, 0x0D },
{ 157, 0x0A }, { 158, 0x70 }, { 159, 0x72 }, { 160, 0x65 },
{ 161, 0x73 }, { 162, 0x73 }, { 163, 0x20 }, { 164, 0x61 },
{ 165, 0x6E }, { 166, 0x79 }, { 167, 0x20 }, { 168, 0x6B },
{ 169, 0x65 }, { 170, 0x79 }, { 171, 0x20 }, { 172, 0x74 },
{ 173, 0x6F }, { 174, 0x20 }, { 175, 0x74 }, { 176, 0x72 },
{ 177, 0x79 }, { 178, 0x20 }, { 179, 0x61 }, { 180, 0x67 },
{ 181, 0x61 }, { 182, 0x69 }, { 183, 0x6E }, { 184, 0x20 },
{ 185, 0x2E }, { 186, 0x2E }, { 187, 0x2E }, { 188, 0x20 },
{ 189, 0x0D }, { 190, 0x0A }, { 510, 0x55 }, { 511, 0xAA },
{ 512, 0xF8 }, { 513, 0xFF }, { 514, 0xFF }, { 8704, 0xF8 },
{ 8705, 0xFF }, { 8706, 0xFF }, { 16896, 0x4B }, { 16897, 0x45 },
{ 16898, 0x59 }, { 16899, 0x42 }, { 16900, 0x4F }, { 16901, 0x58 },
{ 16902, 0x20 }, { 16903, 0x50 }, { 16904, 0x41 }, { 16905, 0x52 },
{ 16906, 0x54 }, { 16907, 0x08 }, { 16910, 0x1C }, { 16911, 0x78 },
{ 16912, 0x44 }, { 16913, 0x50 }, { 16914, 0x44 }, { 16915, 0x50 },
{ 16918, 0x1C }, { 16919, 0x78 }, { 16920, 0x44 }, { 16921, 0x50 },
{ 0, 0 },
};
static struct fs_value g_fs_vals_fty[MAX_CNT_FS_VALUE] = {
{ 0, 0xEB }, { 1, 0x3C }, { 2, 0x90 }, { 3, 0x6D },
{ 4, 0x6B }, { 5, 0x66 }, { 6, 0x73 }, { 7, 0x2E },
{ 8, 0x66 }, { 9, 0x61 }, { 10, 0x74 }, { 12, 0x02 },
{ 13, 0x08 }, { 14, 0x01 }, { 16, 0x02 }, { 18, 0x02 },
{ 20, 0x40 }, { 21, 0xF8 }, { 22, 0x08 }, { 24, 0x20 },
{ 26, 0x40 }, { 36, 0x80 }, { 38, 0x29 }, { 39, 0xDE },
{ 40, 0x62 }, { 41, 0xA6 }, { 42, 0xD0 }, { 43, 0x4B },
{ 44, 0x45 }, { 45, 0x59 }, { 46, 0x42 }, { 47, 0x4F },
{ 48, 0x58 }, { 49, 0x20 }, { 50, 0x50 }, { 51, 0x41 },
{ 52, 0x52 }, { 53, 0x54 }, { 54, 0x46 }, { 55, 0x41 },
{ 56, 0x54 }, { 57, 0x31 }, { 58, 0x32 }, { 59, 0x20 },
{ 60, 0x20 }, { 61, 0x20 }, { 62, 0x0E }, { 63, 0x1F },
{ 64, 0xBE }, { 65, 0x5B }, { 66, 0x7C }, { 67, 0xAC },
{ 68, 0x22 }, { 69, 0xC0 }, { 70, 0x74 }, { 71, 0x0B },
{ 72, 0x56 }, { 73, 0xB4 }, { 74, 0x0E }, { 75, 0xBB },
{ 76, 0x07 }, { 78, 0xCD }, { 79, 0x10 }, { 80, 0x5E },
{ 81, 0xEB }, { 82, 0xF0 }, { 83, 0x32 }, { 84, 0xE4 },
{ 85, 0xCD }, { 86, 0x16 }, { 87, 0xCD }, { 88, 0x19 },
{ 89, 0xEB }, { 90, 0xFE }, { 91, 0x54 }, { 92, 0x68 },
{ 93, 0x69 }, { 94, 0x73 }, { 95, 0x20 }, { 96, 0x69 },
{ 97, 0x73 }, { 98, 0x20 }, { 99, 0x6E }, { 100, 0x6F },
{ 101, 0x74 }, { 102, 0x20 }, { 103, 0x61 }, { 104, 0x20 },
{ 105, 0x62 }, { 106, 0x6F }, { 107, 0x6F }, { 108, 0x74 },
{ 109, 0x61 }, { 110, 0x62 }, { 111, 0x6C }, { 112, 0x65 },
{ 113, 0x20 }, { 114, 0x64 }, { 115, 0x69 }, { 116, 0x73 },
{ 117, 0x6B }, { 118, 0x2E }, { 119, 0x20 }, { 120, 0x20 },
{ 121, 0x50 }, { 122, 0x6C }, { 123, 0x65 }, { 124, 0x61 },
{ 125, 0x73 }, { 126, 0x65 }, { 127, 0x20 }, { 128, 0x69 },
{ 129, 0x6E }, { 130, 0x73 }, { 131, 0x65 }, { 132, 0x72 },
{ 133, 0x74 }, { 134, 0x20 }, { 135, 0x61 }, { 136, 0x20 },
{ 137, 0x62 }, { 138, 0x6F }, { 139, 0x6F }, { 140, 0x74 },
{ 141, 0x61 }, { 142, 0x62 }, { 143, 0x6C }, { 144, 0x65 },
{ 145, 0x20 }, { 146, 0x66 }, { 147, 0x6C }, { 148, 0x6F },
{ 149, 0x70 }, { 150, 0x70 }, { 151, 0x79 }, { 152, 0x20 },
{ 153, 0x61 }, { 154, 0x6E }, { 155, 0x64 }, { 156, 0x0D },
{ 157, 0x0A }, { 158, 0x70 }, { 159, 0x72 }, { 160, 0x65 },
{ 161, 0x73 }, { 162, 0x73 }, { 163, 0x20 }, { 164, 0x61 },
{ 165, 0x6E }, { 166, 0x79 }, { 167, 0x20 }, { 168, 0x6B },
{ 169, 0x65 }, { 170, 0x79 }, { 171, 0x20 }, { 172, 0x74 },
{ 173, 0x6F }, { 174, 0x20 }, { 175, 0x74 }, { 176, 0x72 },
{ 177, 0x79 }, { 178, 0x20 }, { 179, 0x61 }, { 180, 0x67 },
{ 181, 0x61 }, { 182, 0x69 }, { 183, 0x6E }, { 184, 0x20 },
{ 185, 0x2E }, { 186, 0x2E }, { 187, 0x2E }, { 188, 0x20 },
{ 189, 0x0D }, { 190, 0x0A }, { 510, 0x55 }, { 511, 0xAA },
{ 512, 0xF8 }, { 513, 0xFF }, { 514, 0xFF }, { 4608, 0xF8 },
{ 4609, 0xFF }, { 4610, 0xFF }, { 8704, 0x4B }, { 8705, 0x45 },
{ 8706, 0x59 }, { 8707, 0x42 }, { 8708, 0x4F }, { 8709, 0x58 },
{ 8710, 0x20 }, { 8711, 0x50 }, { 8712, 0x41 }, { 8713, 0x52 },
{ 8714, 0x54 }, { 8715, 0x08 }, { 8718, 0x49 }, { 8719, 0xA2 },
{ 8720, 0x4C }, { 8721, 0x50 }, { 8722, 0x4C }, { 8723, 0x50 },
{ 8726, 0x49 }, { 8727, 0xA2 }, { 8728, 0x4C }, { 8729, 0x50 },
{ 0, 0 },
};
static uint32_t get_transfer_phy_addr(uint32_t *transfer_phy_addr)
{
register uint32_t x0 asm("x0") = FUNCID_PROVISION_GET_TRANSFER_ADDR;
register uint32_t x1 asm("x1") = 0;
do {
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x0")
"smc #0\n"
: "=r"(x0), "=r"(x1)
: "r"(x0));
} while (0);
if (x0 == 0)
*transfer_phy_addr = x1;
return x0;
}
static uint32_t set_iv(uint32_t transfer_addr, uint32_t iv_size)
{
register uint32_t x0 asm("x0") = FUNCID_PROVISION_SET_IV;
register uint32_t x1 asm("x1") = iv_size;
register uint32_t x2 asm("x2") = transfer_addr;
do {
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x0")
__asmeq("%2", "x1")
__asmeq("%3", "x2")
"smc #0\n"
: "=r"(x0)
: "r"(x0), "r"(x1), "r"(x2));
} while (0);
return x0;
}
static uint32_t encrypt(uint32_t transfer_addr, uint32_t *data_size)
{
register uint32_t x0 asm("x0") = FUNCID_PROVISION_ENCRYPT;
register uint32_t x1 asm("x1") = *data_size;
register uint32_t x2 asm("x2") = transfer_addr;
do {
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x0")
__asmeq("%4", "x1")
__asmeq("%5", "x2")
"smc #0\n"
: "=r"(x0), "=r"(x1), "=r"(x2)
: "r"(x0), "r"(x1), "r"(x2));
} while (0);
if (x0 == 0)
*data_size = x1;
return x0;
}
static void usage(void)
{
printf("factory_provision -- provision keybox\n\n"
"Usage:\n"
"factory_provision write <keybox_name> <keybox_addr> <keybox_size>\n"
" - write keybox to key partition\n\n"
"factory_provision query <keybox_name> [ret_data_addr]\n"
" - query whether the keybox exists by keybox name\n"
" - when keybox exists, return data: keybox_size(4bytes)\n\n"
"factory_provision remove <keybox_name>\n"
" - remove the keybox by keybox name\n\n");
}
static void parse_params(int argc, char * const argv[],
struct input_param *params)
{
memset(params, 0, sizeof(struct input_param));
switch (argc) {
case 5:
if (!memcmp(argv[1], "write", strlen("write"))) {
params->action = ACTION_WRITE;
params->keybox_name = argv[2];
params->keybox_phy_addr =
(uint32_t)simple_strtoul(argv[3], NULL, 0);
params->keybox_size =
(uint32_t)simple_strtoul(argv[4], NULL, 0);
}
break;
case 4:
if (!memcmp(argv[1], "query", strlen("query"))) {
params->action = ACTION_QUERY;
params->keybox_name = argv[2];
params->ret_data_addr =
(uint32_t)simple_strtoul(argv[3], NULL, 0);
}
break;
case 3:
if (!memcmp(argv[1], "query", strlen("query"))) {
params->action = ACTION_QUERY;
params->keybox_name = argv[2];
if (env_get("loadaddr"))
params->ret_data_addr =
(uint32_t)simple_strtoul(
(char * const)env_get("loadaddr"), NULL, 0);
else
params->ret_data_addr = CONFIG_SYS_LOAD_ADDR;
} else if (!memcmp(argv[1], "remove", strlen("remove"))) {
params->action = ACTION_REMOVE;
params->keybox_name = argv[2];
}
break;
case 2:
if (!memcmp(argv[1], "init", strlen("init")))
params->action = ACTION_INIT;
else if (!memcmp(argv[1], "clear", strlen("clear")))
params->action = ACTION_CLEAR;
else if (!memcmp(argv[1], "list", strlen("list")))
params->action = ACTION_LIST;
break;
default:
break;
}
}
static int check_params(const struct input_param *params)
{
int ret = CMD_RET_SUCCESS;
switch (params->action) {
case ACTION_INIT:
case ACTION_CLEAR:
case ACTION_LIST:
break;
case ACTION_WRITE:
if (strlen(params->keybox_name) > MAX_SIZE_KEYBOX_NAME) {
LOGE("keybox name is too long, and max length is "
"%d\n", MAX_SIZE_KEYBOX_NAME);
ret = CMD_RET_KEYBOX_NAME_TOO_LONG;
goto exit;
}
if (params->keybox_size > MAX_SIZE_KEYBOX) {
LOGE("keybox size is too large, and max size is %d\n",
MAX_SIZE_KEYBOX);
ret = CMD_RET_KEYBOX_TOO_LARGE;
goto exit;
}
if (!params->keybox_phy_addr) {
LOGE("keybox addr error\n");
ret = CMD_RET_BAD_PARAMETER;
goto exit;
}
break;
case ACTION_QUERY:
case ACTION_REMOVE:
if (strlen(params->keybox_name) > MAX_SIZE_KEYBOX_NAME) {
LOGE("keybox name is too long, and max length is "
"%d\n", MAX_SIZE_KEYBOX_NAME);
ret = CMD_RET_KEYBOX_NAME_TOO_LONG;
goto exit;
}
break;
default:
ret = CMD_RET_BAD_PARAMETER;
break;
}
exit:
return ret;
}
static int preprocess_keybox(char *keybox, uint32_t size)
{
uint32_t res = 0;
struct encryption_context *enc_cxt = (struct encryption_context *)
(keybox + sizeof(struct keybox_header));
uint32_t epek_size = sizeof(enc_cxt->epek);
uint32_t transfer_phy_addr = 0;
char *transfer_buf = NULL;
res = get_transfer_phy_addr(&transfer_phy_addr);
if (res) {
LOGE("get transfer address failed, "
"smc fast call ret = 0x%08X\n", res);
return CMD_RET_SMC_CALL_FAILED;
}
transfer_buf = map_sysmem(transfer_phy_addr, 0);
memcpy(transfer_buf, enc_cxt->iv, sizeof(enc_cxt->iv));
res = set_iv(transfer_phy_addr, sizeof(enc_cxt->iv));
if (res) {
LOGE("set iv failed, smc fast call ret = 0x%08X\n", res);
return CMD_RET_SMC_CALL_FAILED;
}
memcpy(transfer_buf, enc_cxt->epek, sizeof(enc_cxt->epek));
res = encrypt(transfer_phy_addr, &epek_size);
if (res) {
LOGE("encrypt epek failed, smc fast call ret = 0x%08X\n", res);
return CMD_RET_SMC_CALL_FAILED;
}
memcpy(enc_cxt->epek, transfer_buf, epek_size);
unmap_sysmem(transfer_buf);
return CMD_RET_SUCCESS;
}
static const char* get_valid_part_name(void)
{
int part_num = get_partition_num_by_name(PART_NAME_FTY);
memset(g_part_name, 0, sizeof(g_part_name));
if (part_num >= 0)
strcpy(g_part_name, PART_NAME_FTY);
else
strcpy(g_part_name, PART_NAME_RSV);
return g_part_name;
}
static const struct fs_value* get_fs_values(void)
{
int part_num = get_partition_num_by_name(PART_NAME_FTY);
if (part_num >= 0)
return g_fs_vals_fty;
else
return g_fs_vals_rsv;
}
static int make_fat_fs(void)
{
char cmd[MAX_SIZE_CMD] = { 0 };
int i = 0;
const char *part_name = get_valid_part_name();
const struct fs_value *fs_vals = get_fs_values();
uint32_t data_phy_addr = (uint32_t)virt_to_phys(g_fs_data);
uint32_t offset = 0;
/* erase partition */
sprintf(cmd, "mmc dev %d;amlmmc switch %d %s;amlmmc erase %s;",
DEV_NO, DEV_NO, PART_TYPE, part_name);
if (run_command(cmd, 0)) {
LOGE("command[%s] failed\n", cmd);
return CMD_RET_UNKNOWN_ERROR;
}
/* write fat file system */
memset(g_fs_data, 0, SIZE_1K);
for (i = 0; i < MAX_CNT_FS_VALUE && fs_vals[i].value; i++) {
if ((i > 0) && (fs_vals[i].idx / SIZE_1K !=
fs_vals[i - 1].idx / SIZE_1K)) {
memset(cmd, 0, sizeof(cmd));
offset = fs_vals[i - 1].idx / SIZE_1K * SIZE_1K;
sprintf(cmd, "amlmmc write %s 0x%08X 0x%X 0x%X;",
part_name, data_phy_addr, offset, SIZE_1K);
if (run_command(cmd, 0)) {
LOGE("command[%s] failed\n", cmd);
return CMD_RET_UNKNOWN_ERROR;
}
}
g_fs_data[fs_vals[i].idx % SIZE_1K] = fs_vals[i].value;
}
memset(cmd, 0, sizeof(cmd));
offset = fs_vals[i - 1].idx / SIZE_1K * SIZE_1K;
sprintf(cmd, "amlmmc write %s 0x%08X 0x%X 0x%X;",
part_name, data_phy_addr, offset, SIZE_1K);
if (run_command(cmd, 0)) {
LOGE("command[%s] failed\n", cmd);
return CMD_RET_UNKNOWN_ERROR;
}
return CMD_RET_SUCCESS;
}
static int dev_writable(void)
{
char cmd[MAX_SIZE_CMD] = { 0 };
sprintf(cmd, "fatinfo %s 0x%X:0x%X", DEV_NAME, DEV_NO,
get_partition_num_by_name((char *)get_valid_part_name()));
if (run_command(cmd, 0)) {
LOGD("command[%s] failed\n", cmd);
return CMD_RET_DEVICE_NOT_AVAILABLE;
}
return CMD_RET_SUCCESS;
}
static int dev_write(const char *name, const char *data, uint32_t size)
{
char cmd[MAX_SIZE_CMD] = { 0 };
sprintf(cmd, "fatwrite %s 0x%X:0x%X 0x%08X %s 0x%X", DEV_NAME, DEV_NO,
get_partition_num_by_name((char *)get_valid_part_name()),
(uint32_t)virt_to_phys((void *)data), name, size);
if (run_command(cmd, 0)) {
LOGD("command[%s] failed\n", cmd);
return CMD_RET_DEVICE_NOT_AVAILABLE;
}
return CMD_RET_SUCCESS;
}
static int init_partition(void)
{
int ret = CMD_RET_SUCCESS;
char dev_part_str[16] = { 0 };
ret = dev_writable();
if (ret) {
ret = make_fat_fs();
if (ret) {
LOGE("make fat file system failed\n");
return ret;
}
ret = dev_writable();
if (ret) {
LOGE("device not available\n");
return ret;
}
}
sprintf(dev_part_str, "0x%X:0x%X", DEV_NO,
get_partition_num_by_name((char *)get_valid_part_name()));
if (fs_set_blk_dev(DEV_NAME, dev_part_str, FS_TYPE_FAT)) {
LOGE("set block device failed\n");
ret = CMD_RET_UNKNOWN_ERROR;
}
return ret;
}
void convert_to_uuid_str(const char uuid[16], char uuid_str[40])
{
int i = 0;
const char *uuid_ptr = uuid;
char *str_ptr = uuid_str;
for (i = 0; i < 4; i++) {
sprintf(str_ptr, "%02x", *uuid_ptr);
str_ptr += 2;
uuid_ptr++;
}
*str_ptr++ = '-';
for (i = 0; i < 2; i++) {
sprintf(str_ptr, "%02x", *uuid_ptr);
str_ptr += 2;
uuid_ptr++;
}
*str_ptr++ = '-';
for (i = 0; i < 2; i++) {
sprintf(str_ptr, "%02x", *uuid_ptr);
str_ptr += 2;
uuid_ptr++;
}
*str_ptr++ = '-';
for (i = 0; i < 8; i++) {
sprintf(str_ptr, "%02x", *uuid_ptr);
str_ptr += 2;
uuid_ptr++;
}
}
static int check_keybox(const char *keybox, uint32_t size)
{
const struct keybox_header *hdr = (const struct keybox_header *)keybox;
uint32_t hdr_cxt_size = sizeof(struct keybox_header)
+ sizeof(struct encryption_context);
if (hdr->magic != KEYBOX_HDR_MAGIC) {
LOGE("keybox header magic error"
"(expected magic: 0x%08X; wrong magic: 0x%08X)\n",
KEYBOX_HDR_MAGIC, hdr->magic);
return CMD_RET_KEYBOX_BAD_FORMAT;
}
if (hdr->version < KEYBOX_HDR_MIN_VERSION) {
LOGE("keybox header version error"
"(min version: %d; wrong version: %d)\n",
KEYBOX_HDR_MIN_VERSION, hdr->version);
return CMD_RET_KEYBOX_BAD_FORMAT;
}
if (size > MAX_SIZE_KEYBOX || size <= hdr_cxt_size
|| hdr->key_size != size - hdr_cxt_size) {
LOGE("keybox length error\n");
return CMD_RET_KEYBOX_BAD_FORMAT;
}
if (hdr->provision_type != PROVISION_TYPE_FACTORY) {
LOGE("keybox provision type error"
"(expected type: %d; wrong type: %d)\n",
PROVISION_TYPE_FACTORY, hdr->provision_type);
return CMD_RET_KEYBOX_BAD_FORMAT;
}
return CMD_RET_SUCCESS;
}
static void calc_sha256(const char *data, uint32_t data_size, char *sha256)
{
sha256_context sha256_cxt;
sha256_starts(&sha256_cxt);
sha256_update(&sha256_cxt, (const uint8_t *)data, (uint32_t)data_size);
sha256_finish(&sha256_cxt, (uint8_t *)sha256);
}
static int verify_written_keybox(const char *keybox_name, const char *keybox,
uint32_t keybox_size)
{
char sha256[SHA256_SUM_LEN] = { 0 };
char written_sha256[SHA256_SUM_LEN] = { 0 };
loff_t act_read = 0;
calc_sha256(keybox, keybox_size, sha256);
memset(g_keybox, 0, sizeof(g_keybox));
if (fat_read_file(keybox_name, g_keybox, 0, MAX_SIZE_KEYBOX, &act_read))
return CMD_RET_UNKNOWN_ERROR;
if (keybox_size != act_read)
return CMD_RET_UNKNOWN_ERROR;
calc_sha256(g_keybox, act_read, written_sha256);
if (memcmp(sha256, written_sha256, SHA256_SUM_LEN))
return CMD_RET_UNKNOWN_ERROR;
return CMD_RET_SUCCESS;
}
static int append_keybox(const char *keybox_name, const char *keybox,
uint32_t keybox_size)
{
int ret = CMD_RET_SUCCESS;
ret = init_partition();
if (ret)
return ret;
ret = dev_write(keybox_name, keybox, keybox_size);
if (ret)
return ret;
ret = verify_written_keybox(keybox_name, keybox, keybox_size);
if (ret) {
LOGE("verify written keybox '%s' failed\n", keybox_name);
return ret;
}
LOGI("write keybox '%s' success\n", keybox_name);
return ret;
}
static int get_keybox_size(const char *keybox_name, uint32_t *size)
{
loff_t keybox_size = 0;
if (fat_size(keybox_name, &keybox_size)) {
LOGE("get keybox '%s' size failed\n", keybox_name);
return CMD_RET_UNKNOWN_ERROR;
} else {
*size = (uint32_t)keybox_size;
LOGI("keybox '%s' size is %d\n", keybox_name, *size);
return CMD_RET_SUCCESS;
}
}
static int query_keybox(const char *keybox_name, char *ret_data)
{
int ret = CMD_RET_SUCCESS;
ret = init_partition();
if (ret)
return ret;
if (!fat_exists(keybox_name)) {
LOGI("keybox '%s' not exists\n", keybox_name);
return CMD_RET_KEYBOX_NOT_EXIST;
}
else {
return get_keybox_size(keybox_name, (uint32_t *)ret_data);
}
}
static int remove_keybox(const char *keybox_name)
{
int ret = init_partition();
if (ret)
return ret;
if (fs_unlink(keybox_name)) {
LOGE("remove '%s' failed\n", keybox_name);
return CMD_RET_UNKNOWN_ERROR;
}
LOGI("remove '%s' success\n", keybox_name);
return CMD_RET_SUCCESS;
}
static int remove_all_keyboxes(void)
{
int ret = CMD_RET_SUCCESS;
struct fs_dir_stream *dirs = NULL;
struct fs_dirent *dent = NULL;
char cmd[MAX_SIZE_CMD] = { 0 };
ret = init_partition();
if (ret)
return ret;
if (fat_opendir("/", &dirs)) {
LOGE("open '/' failed\n");
return CMD_RET_UNKNOWN_ERROR;
}
while (!fat_readdir(dirs, &dent)) {
if (dent->type != FS_DT_REG) // not regular file
continue;
sprintf(cmd, "fatrm %s 0x%X:0x%X %s", DEV_NAME, DEV_NO,
get_partition_num_by_name(
(char *)get_valid_part_name()),
dent->name);
if (run_command(cmd, 0)) {
ret = CMD_RET_UNKNOWN_ERROR;
LOGE("remove '%s' failed\n", dent->name);
} else {
LOGI("remove '%s' success\n", dent->name);
}
}
fat_closedir(dirs);
return ret;
}
static int list_all_keyboxes(void)
{
int ret = CMD_RET_SUCCESS;
char cmd[MAX_SIZE_CMD] = { 0 };
ret = init_partition();
if (ret)
return ret;
sprintf(cmd, "fatls %s 0x%X:0x%X", DEV_NAME, DEV_NO,
get_partition_num_by_name((char *)get_valid_part_name()));
if (run_command(cmd, 0)) {
LOGE("command[%s] failed\n", cmd);
ret = CMD_RET_UNKNOWN_ERROR;
}
return ret;
}
static int remove_same_type_keybox(uint32_t key_type, const char *uuid)
{
int ret = CMD_RET_SUCCESS;
struct fs_dir_stream *dirs = NULL;
struct fs_dirent *dent = NULL;
struct keybox_header hdr;
loff_t act_read = 0;
char uuid_str[40] = { 0 };
ret = init_partition();
if (ret)
return ret;
if (fat_opendir("/", &dirs)) {
LOGE("open '/' failed\n");
return CMD_RET_UNKNOWN_ERROR;
}
convert_to_uuid_str(uuid, uuid_str);
while (!fat_readdir(dirs, &dent)) {
if (dent->type != FS_DT_REG) // not regular file
continue;
memset(&hdr, 0, sizeof(hdr));
if (fat_read_file(dent->name, &hdr, 0, sizeof(hdr), &act_read)
|| act_read != sizeof(hdr)) {
LOGE("read keybox '%s' failed\n", dent->name);
ret = CMD_RET_UNKNOWN_ERROR;
goto exit;
}
if (!memcmp(uuid, hdr.ta_uuid, sizeof(hdr.ta_uuid)) &&
key_type == hdr.key_type) {
ret = remove_keybox(dent->name);
if (ret != CMD_RET_SUCCESS) {
LOGE("remove the same type"
"(uuid = %s, key_type = 0x%02X) "
"keybox '%s' failed\n",
uuid_str, key_type, dent->name);
goto exit;
}
}
}
exit:
fat_closedir(dirs);
return ret;
}
int is_storage_medium_supported(void)
{
int ret = CMD_RET_SUCCESS;
int medium_type = store_get_type();
char type_str[64] = { 0 };
if (medium_type != BOOT_EMMC) {
switch (medium_type) {
case BOOT_SD:
strcpy(type_str, "SD");
break;
case BOOT_NAND_NFTL:
strcpy(type_str, "NAND_NFTL");
break;
case BOOT_NAND_MTD:
strcpy(type_str, "NAND_MTD");
break;
case BOOT_SNAND:
strcpy(type_str, "SNAND");
break;
case BOOT_SNOR:
strcpy(type_str, "SNOR");
break;
default:
strcpy(type_str, "Unknown Storage Medium");
break;
}
LOGE("Provision function is not supported on '%s' storage medium", type_str);
ret = CMD_RET_DEVICE_NOT_AVAILABLE;
}
return ret;
}
int cmd_func(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int ret = CMD_RET_SUCCESS;
struct input_param params;
char *in_kb = NULL;
char *ret_data = NULL;
const struct keybox_header *hdr = NULL;
ret = is_storage_medium_supported();
if (ret != CMD_RET_SUCCESS)
goto exit;
parse_params(argc, argv, &params);
ret = check_params(&params);
if (ret != CMD_RET_SUCCESS)
goto exit;
switch (params.action) {
case ACTION_INIT:
ret = init_partition();
break;
case ACTION_WRITE:
in_kb = map_sysmem(params.keybox_phy_addr, 0);
ret = check_keybox(in_kb, params.keybox_size);
if (ret != CMD_RET_SUCCESS)
goto exit;
hdr = (const struct keybox_header *)in_kb;
ret = remove_same_type_keybox(hdr->key_type,
(const char *)hdr->ta_uuid);
if (ret != CMD_RET_SUCCESS)
goto exit;
memcpy(g_keybox, in_kb, params.keybox_size);
ret = preprocess_keybox(g_keybox, params.keybox_size);
if (ret != CMD_RET_SUCCESS)
goto exit;
ret = append_keybox(params.keybox_name, g_keybox,
params.keybox_size);
if (ret != CMD_RET_SUCCESS)
goto exit;
break;
case ACTION_QUERY:
ret_data = map_sysmem(params.ret_data_addr, 0);
ret = query_keybox(params.keybox_name, ret_data);
if (ret != CMD_RET_SUCCESS)
goto exit;
break;
case ACTION_REMOVE:
ret = remove_keybox(params.keybox_name);
if (ret != CMD_RET_SUCCESS)
goto exit;
break;
case ACTION_CLEAR:
ret = remove_all_keyboxes();
if (ret != CMD_RET_SUCCESS)
goto exit;
break;
case ACTION_LIST:
ret = list_all_keyboxes();
if (ret != CMD_RET_SUCCESS)
goto exit;
break;
default:
break;
}
exit:
if (in_kb)
unmap_sysmem(in_kb);
if (ret_data)
unmap_sysmem(ret_data);
if (ret == CMD_RET_BAD_PARAMETER)
usage();
return ret;
}
/* -------------------------------------------------------------------- */
U_BOOT_CMD(
factory_provision, CONFIG_SYS_MAXARGS, 0, cmd_func,
"provision keybox\n",
"write <keybox_name> <keybox_addr> <keybox_size>\n"
" - write keybox to key partition\n\n"
"query <keybox_name> [ret_data_addr]\n"
" - query whether the keybox exists by keybox name\n"
" - when keybox exists, return data: keybox_size(4bytes)\n\n"
"remove <keybox_name>\n"
" - remove the keybox by keybox name\n"
);