455
bdk/sec/se.c
455
bdk/sec/se.c
@@ -1,8 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2021 CTCaer
|
||||
* Copyright (c) 2018 Atmosphère-NX
|
||||
* Copyright (c) 2019-2021 shchmue
|
||||
* Copyright (c) 2018-2022 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -20,13 +18,13 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "se.h"
|
||||
#include "se_t210.h"
|
||||
#include <memory_map.h>
|
||||
#include <mem/heap.h>
|
||||
#include <soc/bpmp.h>
|
||||
#include <soc/hw_init.h>
|
||||
#include <soc/pmc.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
typedef struct _se_ll_t
|
||||
{
|
||||
@@ -35,8 +33,8 @@ typedef struct _se_ll_t
|
||||
vu32 size;
|
||||
} se_ll_t;
|
||||
|
||||
static u32 _se_rsa_mod_sizes[SE_RSA_KEYSLOT_COUNT];
|
||||
static u32 _se_rsa_exp_sizes[SE_RSA_KEYSLOT_COUNT];
|
||||
se_ll_t ll_src, ll_dst;
|
||||
se_ll_t *ll_src_ptr, *ll_dst_ptr; // Must be u32 aligned.
|
||||
|
||||
static void _gf256_mul_x(void *block)
|
||||
{
|
||||
@@ -72,67 +70,57 @@ static void _gf256_mul_x_le(void *block)
|
||||
|
||||
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
|
||||
{
|
||||
ll->num = 0;
|
||||
ll->num = 0;
|
||||
ll->addr = addr;
|
||||
ll->size = size;
|
||||
}
|
||||
|
||||
static void _se_ll_set(se_ll_t *dst, se_ll_t *src)
|
||||
static void _se_ll_set(se_ll_t *src, se_ll_t *dst)
|
||||
{
|
||||
SE(SE_IN_LL_ADDR_REG) = (u32)src;
|
||||
SE(SE_IN_LL_ADDR_REG) = (u32)src;
|
||||
SE(SE_OUT_LL_ADDR_REG) = (u32)dst;
|
||||
}
|
||||
|
||||
static int _se_wait()
|
||||
{
|
||||
bool tegra_t210 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210;
|
||||
|
||||
// Wait for operation to be done.
|
||||
while (!(SE(SE_INT_STATUS_REG) & SE_INT_OP_DONE))
|
||||
;
|
||||
if (SE(SE_INT_STATUS_REG) & SE_INT_ERR_STAT ||
|
||||
(SE(SE_STATUS_REG) & SE_STATUS_STATE_MASK) != SE_STATUS_STATE_IDLE ||
|
||||
SE(SE_ERR_STATUS_REG) != 0)
|
||||
|
||||
// Check for errors.
|
||||
if ((SE(SE_INT_STATUS_REG) & SE_INT_ERR_STAT) ||
|
||||
(SE(SE_STATUS_REG) & SE_STATUS_STATE_MASK) != SE_STATUS_STATE_IDLE ||
|
||||
(SE(SE_ERR_STATUS_REG) != 0)
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
se_ll_t *ll_dst, *ll_src;
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot)
|
||||
{
|
||||
ll_dst = NULL;
|
||||
ll_src = NULL;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
|
||||
_se_ll_init(ll_dst, (u32)dst, dst_size);
|
||||
}
|
||||
|
||||
if (src)
|
||||
// T210B01: IRAM/TZRAM/DRAM AHB coherency WAR.
|
||||
if (!tegra_t210 && ll_dst_ptr)
|
||||
{
|
||||
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
|
||||
_se_ll_init(ll_src, (u32)src, src_size);
|
||||
}
|
||||
u32 timeout = get_tmr_us() + 1000000;
|
||||
// Ensure data is out from SE.
|
||||
while (SE(SE_STATUS_REG) & SE_STATUS_MEM_IF_BUSY)
|
||||
{
|
||||
if (get_tmr_us() > timeout)
|
||||
return 0;
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
_se_ll_set(ll_dst, ll_src);
|
||||
|
||||
SE(SE_ERR_STATUS_REG) = SE(SE_ERR_STATUS_REG);
|
||||
SE(SE_INT_STATUS_REG) = SE(SE_INT_STATUS_REG);
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
SE(SE_OPERATION_REG) = op;
|
||||
|
||||
if (is_oneshot)
|
||||
{
|
||||
int res = _se_wait();
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
|
||||
if (src)
|
||||
free(ll_src);
|
||||
if (dst)
|
||||
free(ll_dst);
|
||||
|
||||
return res;
|
||||
// Ensure data is out from AHB.
|
||||
if (ll_dst_ptr->addr >= DRAM_START)
|
||||
{
|
||||
timeout = get_tmr_us() + 200000;
|
||||
while (AHB_GIZMO(AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID) & MEM_WRQUE_SE_MST_ID)
|
||||
{
|
||||
if (get_tmr_us() > timeout)
|
||||
return 0;
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -142,22 +130,48 @@ static int _se_execute_finalize()
|
||||
{
|
||||
int res = _se_wait();
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||
// Invalidate data after OP is done.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
|
||||
|
||||
if (ll_src)
|
||||
{
|
||||
free(ll_src);
|
||||
ll_src = NULL;
|
||||
}
|
||||
if (ll_dst)
|
||||
{
|
||||
free(ll_dst);
|
||||
ll_dst = NULL;
|
||||
}
|
||||
ll_src_ptr = NULL;
|
||||
ll_dst_ptr = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot)
|
||||
{
|
||||
ll_src_ptr = NULL;
|
||||
ll_dst_ptr = NULL;
|
||||
|
||||
if (src)
|
||||
{
|
||||
ll_src_ptr = &ll_src;
|
||||
_se_ll_init(ll_src_ptr, (u32)src, src_size);
|
||||
}
|
||||
|
||||
if (dst)
|
||||
{
|
||||
ll_dst_ptr = &ll_dst;
|
||||
_se_ll_init(ll_dst_ptr, (u32)dst, dst_size);
|
||||
}
|
||||
|
||||
_se_ll_set(ll_src_ptr, ll_dst_ptr);
|
||||
|
||||
SE(SE_ERR_STATUS_REG) = SE(SE_ERR_STATUS_REG);
|
||||
SE(SE_INT_STATUS_REG) = SE(SE_INT_STATUS_REG);
|
||||
|
||||
// Flush data before starting OP.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLEAN_WAY, false);
|
||||
|
||||
SE(SE_OPERATION_REG) = op;
|
||||
|
||||
if (is_oneshot)
|
||||
return _se_execute_finalize();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
return _se_execute(op, dst, dst_size, src, src_size, true);
|
||||
@@ -168,8 +182,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
|
||||
if (!src || !dst)
|
||||
return 0;
|
||||
|
||||
u8 *block = (u8 *)malloc(SE_AES_BLOCK_SIZE);
|
||||
memset(block, 0, SE_AES_BLOCK_SIZE);
|
||||
u8 *block = (u8 *)calloc(1, SE_AES_BLOCK_SIZE);
|
||||
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1;
|
||||
|
||||
@@ -194,72 +207,12 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
||||
{
|
||||
if (flags & SE_RSA_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
||||
SE(SE_RSA_KEYTABLE_ACCESS_REG + 4 * rs) =
|
||||
(((flags >> 4) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |(flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG)) ^
|
||||
(((flags >> 4) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | (flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG)) ^
|
||||
SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_USE_FLAG;
|
||||
if (flags & SE_RSA_KEY_LOCK_FLAG)
|
||||
SE(SE_RSA_SECURITY_PERKEY_REG) &= ~BIT(rs);
|
||||
}
|
||||
|
||||
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
|
||||
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
|
||||
{
|
||||
u32 *data = (u32 *)mod;
|
||||
for (u32 i = 0; i < mod_size / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[mod_size / 4 - i - 1]);
|
||||
}
|
||||
|
||||
data = (u32 *)exp;
|
||||
for (u32 i = 0; i < exp_size / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA_REG) = byte_swap_32(data[exp_size / 4 - i - 1]);
|
||||
}
|
||||
|
||||
_se_rsa_mod_sizes[ks] = mod_size;
|
||||
_se_rsa_exp_sizes[ks] = exp_size;
|
||||
}
|
||||
|
||||
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
|
||||
void se_rsa_key_clear(u32 ks)
|
||||
{
|
||||
for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA_REG) = 0;
|
||||
}
|
||||
for (u32 i = 0; i < SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR_REG) = RSA_KEY_NUM(ks) | SE_RSA_KEYTABLE_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA_REG) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
|
||||
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
int res;
|
||||
u8 stack_buf[SE_RSA2048_DIGEST_SIZE];
|
||||
|
||||
for (u32 i = 0; i < src_size; i++)
|
||||
stack_buf[i] = *((u8 *)src + src_size - i - 1);
|
||||
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
|
||||
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
|
||||
SE(SE_RSA_KEY_SIZE_REG) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
|
||||
SE(SE_RSA_EXP_SIZE_REG) = _se_rsa_exp_sizes[ks] >> 2;
|
||||
|
||||
res = _se_execute_oneshot(SE_OP_START, NULL, 0, stack_buf, src_size);
|
||||
|
||||
// Copy output hash.
|
||||
u32 *dst32 = (u32 *)dst;
|
||||
for (u32 i = 0; i < dst_size / 4; i++)
|
||||
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT_REG + (i << 2)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags)
|
||||
{
|
||||
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
||||
@@ -273,7 +226,7 @@ u32 se_key_acc_ctrl_get(u32 ks)
|
||||
return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks);
|
||||
}
|
||||
|
||||
void se_aes_key_set(u32 ks, const void *key, u32 size)
|
||||
void se_aes_key_set(u32 ks, void *key, u32 size)
|
||||
{
|
||||
u32 data[SE_AES_MAX_KEY_SIZE / 4];
|
||||
memcpy(data, key, size);
|
||||
@@ -285,13 +238,7 @@ void se_aes_key_set(u32 ks, const void *key, u32 size)
|
||||
}
|
||||
}
|
||||
|
||||
void se_aes_key_partial_set(u32 ks, u32 index, u32 data)
|
||||
{
|
||||
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | index;
|
||||
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data;
|
||||
}
|
||||
|
||||
void se_aes_iv_set(u32 ks, const void *iv)
|
||||
void se_aes_iv_set(u32 ks, void *iv)
|
||||
{
|
||||
u32 data[SE_AES_IV_SIZE / 4];
|
||||
memcpy(data, iv, SE_AES_IV_SIZE);
|
||||
@@ -334,10 +281,11 @@ void se_aes_iv_clear(u32 ks)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1;
|
||||
SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | SE_KEYTABLE_DST_WORD_QUAD(KEYS_0_3);
|
||||
|
||||
@@ -365,14 +313,14 @@ int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src,
|
||||
if (enc)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
}
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = (src_size >> 4) - 1;
|
||||
return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size);
|
||||
@@ -387,8 +335,9 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
|
||||
{
|
||||
SE(SE_SPARE_REG) = SE_ECO(SE_ERRATA_FIX_ENABLE);
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
|
||||
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_CNTN(1);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
|
||||
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) |
|
||||
SE_CRYPTO_CTR_CNTN(1);
|
||||
_se_aes_ctr_set(ctr);
|
||||
|
||||
u32 src_size_aligned = src_size & 0xFFFFFFF0;
|
||||
@@ -409,89 +358,69 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
|
||||
return 1;
|
||||
}
|
||||
|
||||
// random calls were derived from Atmosphère's
|
||||
int se_initialize_rng()
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
|
||||
{
|
||||
static bool initialized = false;
|
||||
int res = 0;
|
||||
u8 *tweak = (u8 *)malloc(SE_AES_BLOCK_SIZE);
|
||||
u8 *pdst = (u8 *)dst;
|
||||
u8 *psrc = (u8 *)src;
|
||||
|
||||
if (initialized)
|
||||
return 1;
|
||||
|
||||
u8 *output_buf = (u8 *)malloc(0x10);
|
||||
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(SRC_ENTROPY);
|
||||
SE(SE_RNG_RESEED_INTERVAL_REG) = 70001;
|
||||
SE(SE_RNG_SRC_CONFIG_REG) = SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE) |
|
||||
SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(RO_ENTR_LOCK_ENABLE);
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 0;
|
||||
|
||||
int res =_se_execute_oneshot(SE_OP_START, output_buf, 0x10, NULL, 0);
|
||||
|
||||
free(output_buf);
|
||||
if (res)
|
||||
initialized = true;
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_generate_random(void *dst, u32 size)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_NORMAL) | SE_RNG_CONFIG_SRC(SRC_ENTROPY);
|
||||
|
||||
u32 num_blocks = size >> 4;
|
||||
u32 aligned_size = num_blocks << 4;
|
||||
if (num_blocks)
|
||||
{
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = num_blocks - 1;
|
||||
if (!_se_execute_oneshot(SE_OP_START, dst, aligned_size, NULL, 0))
|
||||
return 0;
|
||||
}
|
||||
if (size > aligned_size)
|
||||
return _se_execute_one_block(SE_OP_START, dst + aligned_size, size - aligned_size, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int se_generate_random_key(u32 ks_dst, u32 ks_src)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
|
||||
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_MODE(MODE_NORMAL) | SE_RNG_CONFIG_SRC(SRC_ENTROPY);
|
||||
|
||||
SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst);
|
||||
if (!_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0))
|
||||
return 0;
|
||||
SE(SE_CRYPTO_KEYTABLE_DST_REG) = SE_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1;
|
||||
if (!_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size)
|
||||
{
|
||||
u8 tweak[0x10];
|
||||
u8 orig_tweak[0x10];
|
||||
u32 *pdst = (u32 *)dst;
|
||||
u32 *psrc = (u32 *)src;
|
||||
u32 *ptweak = (u32 *)tweak;
|
||||
|
||||
//Generate tweak.
|
||||
// Generate tweak.
|
||||
for (int i = 0xF; i >= 0; i--)
|
||||
{
|
||||
tweak[i] = sec & 0xFF;
|
||||
sec >>= 8;
|
||||
}
|
||||
if (!se_aes_crypt_block_ecb(tweak_ks, 1, tweak, tweak))
|
||||
return 0;
|
||||
|
||||
memcpy(orig_tweak, tweak, 0x10);
|
||||
if (!se_aes_crypt_block_ecb(tweak_ks, CORE_ENCRYPT, tweak, tweak))
|
||||
goto out;
|
||||
|
||||
// We are assuming a 0x10-aligned sector size in this implementation.
|
||||
for (u32 i = 0; i < sec_size / 0x10; i++)
|
||||
for (u32 i = 0; i < secsize / SE_AES_BLOCK_SIZE; i++)
|
||||
{
|
||||
for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)
|
||||
pdst[j] = psrc[j] ^ tweak[j];
|
||||
if (!se_aes_crypt_block_ecb(crypt_ks, enc, pdst, pdst))
|
||||
goto out;
|
||||
for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)
|
||||
pdst[j] = pdst[j] ^ tweak[j];
|
||||
_gf256_mul_x(tweak);
|
||||
psrc += SE_AES_BLOCK_SIZE;
|
||||
pdst += SE_AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
res = 1;
|
||||
|
||||
out:;
|
||||
free(tweak);
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size)
|
||||
{
|
||||
u32 *pdst = (u32 *)dst;
|
||||
u32 *psrc = (u32 *)src;
|
||||
u32 *ptweak = (u32 *)tweak;
|
||||
|
||||
if (regen_tweak)
|
||||
{
|
||||
for (int i = 0xF; i >= 0; i--)
|
||||
{
|
||||
tweak[i] = sec & 0xFF;
|
||||
sec >>= 8;
|
||||
}
|
||||
if (!se_aes_crypt_block_ecb(tweak_ks, CORE_ENCRYPT, tweak, tweak))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// tweak_exp allows using a saved tweak to reduce _gf256_mul_x_le calls.
|
||||
for (u32 i = 0; i < (tweak_exp << 5); i++)
|
||||
_gf256_mul_x_le(tweak);
|
||||
|
||||
u8 orig_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));
|
||||
memcpy(orig_tweak, tweak, SE_KEY_128_SIZE);
|
||||
|
||||
// We are assuming a 16 sector aligned size in this implementation.
|
||||
for (u32 i = 0; i < (sec_size >> 4); i++)
|
||||
{
|
||||
for (u32 j = 0; j < 4; j++)
|
||||
pdst[j] = psrc[j] ^ ptweak[j];
|
||||
@@ -506,7 +435,7 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst
|
||||
|
||||
pdst = (u32 *)dst;
|
||||
ptweak = (u32 *)orig_tweak;
|
||||
for (u32 i = 0; i < sec_size / 0x10; i++)
|
||||
for (u32 i = 0; i < (sec_size >> 4); i++)
|
||||
{
|
||||
for (u32 j = 0; j < 4; j++)
|
||||
pdst[j] = pdst[j] ^ ptweak[j];
|
||||
@@ -518,13 +447,13 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst
|
||||
return 1;
|
||||
}
|
||||
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs)
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)
|
||||
{
|
||||
u8 *pdst = (u8 *)dst;
|
||||
u8 *psrc = (u8 *)src;
|
||||
|
||||
for (u32 i = 0; i < num_secs; i++)
|
||||
if (!se_aes_xts_crypt_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + sec_size * i, psrc + sec_size * i, sec_size))
|
||||
if (!se_aes_xts_crypt_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -668,7 +597,7 @@ int se_calc_sha256_finalize(void *hash, u32 *msg_left)
|
||||
|
||||
// Copy output hash.
|
||||
for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++)
|
||||
hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i << 2)));
|
||||
hash32[i] = byte_swap_32(SE(SE_HASH_RESULT_REG + (i * 4)));
|
||||
memcpy(hash, hash32, SE_SHA_256_SIZE);
|
||||
|
||||
return res;
|
||||
@@ -718,74 +647,20 @@ out:;
|
||||
return res;
|
||||
}
|
||||
|
||||
// _mgf1_xor() and rsa_oaep_decode were derived from Atmosphère
|
||||
static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size)
|
||||
int se_gen_prng128(void *dst)
|
||||
{
|
||||
u8 cur_hash[0x20] __attribute__((aligned(4)));
|
||||
u8 hash_buf[0xe4] __attribute__((aligned(4)));
|
||||
// Setup config for X931 PRNG.
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_NORMAL);
|
||||
//SE(SE_RNG_SRC_CONFIG_REG) =
|
||||
// SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE) | SE_RNG_SRC_CONFIG_ENTR_SRC_LOCK(RO_ENTR_LOCK_ENABLE);
|
||||
SE(SE_RNG_RESEED_INTERVAL_REG) = 1;
|
||||
|
||||
u32 hash_buf_size = seed_size + 4;
|
||||
memcpy(hash_buf, seed, seed_size);
|
||||
u32 round_num = 0;
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = (16 >> 4) - 1;
|
||||
|
||||
u8 *p_out = (u8 *)masked;
|
||||
|
||||
while (masked_size) {
|
||||
u32 cur_size = MIN(masked_size, 0x20);
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff;
|
||||
round_num++;
|
||||
|
||||
se_calc_sha256_oneshot(cur_hash, hash_buf, hash_buf_size);
|
||||
|
||||
for (unsigned int i = 0; i < cur_size; i++) {
|
||||
*p_out ^= cur_hash[i];
|
||||
p_out++;
|
||||
}
|
||||
|
||||
masked_size -= cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size)
|
||||
{
|
||||
if (dst_size <= 0 || buf_size < 0x43 || label_digest_size != 0x20)
|
||||
return 0;
|
||||
|
||||
bool is_valid = buf[0] == 0;
|
||||
|
||||
u32 db_len = buf_size - 0x21;
|
||||
u8 *seed = buf + 1;
|
||||
u8 *db = seed + 0x20;
|
||||
_mgf1_xor(seed, 0x20, db, db_len);
|
||||
_mgf1_xor(db, db_len, seed, 0x20);
|
||||
|
||||
is_valid &= memcmp(label_digest, db, 0x20) ? 0 : 1;
|
||||
|
||||
db += 0x20;
|
||||
db_len -= 0x20;
|
||||
|
||||
int msg_ofs = 0;
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (int i = 0; i < db_len; )
|
||||
{
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
msg_ofs += (looking_for_one & is_one) * (++i);
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
|
||||
const u32 msg_size = MIN(dst_size, is_valid * (db_len - msg_ofs));
|
||||
memcpy(dst, db + msg_ofs, msg_size);
|
||||
|
||||
return msg_size;
|
||||
// Trigger the operation.
|
||||
return _se_execute_oneshot(SE_OP_START, dst, 16, NULL, 0);
|
||||
}
|
||||
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
@@ -793,9 +668,9 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
|
||||
|
||||
// Set Secure Random Key.
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_FORCE_RESEED);
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_FORCE_RESEED);
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute_oneshot(SE_OP_START, NULL, 0, NULL, 0);
|
||||
|
||||
@@ -805,7 +680,7 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
for (u32 i = 0; i < SE_AES_KEYSLOT_COUNT; i++)
|
||||
{
|
||||
SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) |
|
||||
SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_0_3);
|
||||
SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_0_3);
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0);
|
||||
@@ -814,7 +689,7 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
if (keysize > SE_KEY_128_SIZE)
|
||||
{
|
||||
SE(SE_CONTEXT_SAVE_CONFIG_REG) = SE_CONTEXT_SRC(AES_KEYTABLE) | SE_KEYTABLE_DST_KEY_INDEX(i) |
|
||||
SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_4_7);
|
||||
SE_CONTEXT_AES_KEY_INDEX(0) | SE_CONTEXT_AES_WORD_QUAD(KEYS_4_7);
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||
_se_execute_oneshot(SE_OP_CTX_SAVE, aligned_buf, SE_AES_BLOCK_SIZE, NULL, 0);
|
||||
@@ -841,6 +716,6 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
// Decrypt context.
|
||||
se_aes_key_clear(3);
|
||||
se_aes_key_set(3, srk, SE_KEY_128_SIZE);
|
||||
se_aes_crypt_cbc(3, 0, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize);
|
||||
se_aes_crypt_cbc(3, CORE_DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize);
|
||||
se_aes_key_clear(3);
|
||||
}
|
||||
|
||||
70
bdk/sec/se.h
70
bdk/sec/se.h
@@ -1,54 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019-2021 CTCaer
|
||||
* Copyright (c) 2019-2021 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2019-2022 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SE_H_
|
||||
#define _SE_H_
|
||||
|
||||
#include "se_t210.h"
|
||||
#include <utils/types.h>
|
||||
|
||||
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
||||
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size);
|
||||
void se_rsa_key_clear(u32 ks);
|
||||
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags);
|
||||
u32 se_key_acc_ctrl_get(u32 ks);
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
|
||||
void se_aes_key_set(u32 ks, const void *key, u32 size);
|
||||
void se_aes_iv_set(u32 ks, const void *iv);
|
||||
void se_aes_key_partial_set(u32 ks, u32 index, u32 data);
|
||||
void se_aes_key_set(u32 ks, void *key, u32 size);
|
||||
void se_aes_iv_set(u32 ks, void *iv);
|
||||
void se_aes_key_get(u32 ks, void *key, u32 size);
|
||||
void se_aes_key_clear(u32 ks);
|
||||
void se_aes_iv_clear(u32 ks);
|
||||
int se_initialize_rng();
|
||||
int se_generate_random(void *dst, u32 size);
|
||||
int se_generate_random_key(u32 ks_dst, u32 ks_src);
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size);
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, const void *src, u32 sec_size, u32 num_secs);
|
||||
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot);
|
||||
int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size);
|
||||
int se_calc_sha256_finalize(void *hash, u32 *msg_left);
|
||||
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
|
||||
u32 se_rsa_oaep_decode(void *dst, u32 dst_size, const void *label_digest, u32 label_digest_size, u8 *buf, u32 buf_size);
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize);
|
||||
int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size);
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot);
|
||||
int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size);
|
||||
int se_calc_sha256_finalize(void *hash, u32 *msg_left);
|
||||
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
|
||||
int se_gen_prng128(void *dst);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -301,6 +301,8 @@
|
||||
#define SE_STATUS_STATE_WAIT_OUT 2
|
||||
#define SE_STATUS_STATE_WAIT_IN 3
|
||||
#define SE_STATUS_STATE_MASK 3
|
||||
#define SE_STATUS_MEM_IF_IDLE (0 << 2)
|
||||
#define SE_STATUS_MEM_IF_BUSY BIT(2)
|
||||
|
||||
#define SE_ERR_STATUS_REG 0x804
|
||||
#define SE_ERR_STATUS_SE_NS_ACCESS BIT(0)
|
||||
|
||||
115
bdk/sec/tsec.c
115
bdk/sec/tsec.c
@@ -20,20 +20,23 @@
|
||||
|
||||
#include "tsec.h"
|
||||
#include "tsec_t210.h"
|
||||
#include <memory_map.h>
|
||||
#include <mem/heap.h>
|
||||
#include <mem/mc.h>
|
||||
#include <mem/smmu.h>
|
||||
#include <sec/se_t210.h>
|
||||
#include <soc/bpmp.h>
|
||||
#include <soc/clock.h>
|
||||
#include <soc/kfuse.h>
|
||||
#include <soc/pmc.h>
|
||||
#include <soc/t210.h>
|
||||
#include <mem/heap.h>
|
||||
#include <mem/mc.h>
|
||||
#include <mem/smmu.h>
|
||||
#include <utils/util.h>
|
||||
#include <soc/timer.h>
|
||||
|
||||
// #include <gfx_utils.h>
|
||||
|
||||
#define PKG11_MAGIC 0x31314B50
|
||||
#define KB_TSEC_FW_EMU_COMPAT 6 // KB ID for HOS 6.2.0.
|
||||
|
||||
#define TSEC_HOS_KB_620 6
|
||||
|
||||
static int _tsec_dma_wait_idle()
|
||||
{
|
||||
@@ -55,17 +58,18 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse
|
||||
else
|
||||
cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory)
|
||||
|
||||
TSEC(TSEC_DMATRFMOFFS) = i_offset;
|
||||
TSEC(TSEC_DMATRFMOFFS) = i_offset;
|
||||
TSEC(TSEC_DMATRFFBOFFS) = pa_offset;
|
||||
TSEC(TSEC_DMATRFCMD) = cmd;
|
||||
TSEC(TSEC_DMATRFCMD) = cmd;
|
||||
|
||||
return _tsec_dma_wait_idle();
|
||||
}
|
||||
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
int res = 0;
|
||||
u8 *fwbuf = NULL;
|
||||
u32 type = tsec_ctxt->type;
|
||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
@@ -73,30 +77,42 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// Enable clocks.
|
||||
clock_enable_host1x();
|
||||
usleep(2);
|
||||
clock_enable_tsec();
|
||||
clock_enable_sor_safe();
|
||||
clock_enable_sor0();
|
||||
clock_enable_sor1();
|
||||
clock_enable_kfuse();
|
||||
|
||||
kfuse_wait_ready();
|
||||
|
||||
//Configure Falcon.
|
||||
// Disable AHB aperture.
|
||||
mc_disable_ahb_redirect();
|
||||
|
||||
if (type == TSEC_FW_TYPE_NEW)
|
||||
{
|
||||
// Disable all CCPLEX core rails.
|
||||
pmc_enable_partition(POWER_RAIL_CE0, DISABLE);
|
||||
pmc_enable_partition(POWER_RAIL_CE1, DISABLE);
|
||||
pmc_enable_partition(POWER_RAIL_CE2, DISABLE);
|
||||
pmc_enable_partition(POWER_RAIL_CE3, DISABLE);
|
||||
|
||||
// Enable AHB aperture and set it to full mmio.
|
||||
mc_enable_ahb_redirect();
|
||||
}
|
||||
|
||||
// Configure Falcon.
|
||||
TSEC(TSEC_DMACTL) = 0;
|
||||
TSEC(TSEC_IRQMSET) =
|
||||
TSEC_IRQMSET_EXT(0xFF) |
|
||||
TSEC_IRQMSET_WDTMR |
|
||||
TSEC_IRQMSET_HALT |
|
||||
TSEC_IRQMSET_EXTERR |
|
||||
TSEC_IRQMSET_SWGEN0 |
|
||||
TSEC_IRQMSET_WDTMR |
|
||||
TSEC_IRQMSET_HALT |
|
||||
TSEC_IRQMSET_EXTERR |
|
||||
TSEC_IRQMSET_SWGEN0 |
|
||||
TSEC_IRQMSET_SWGEN1;
|
||||
TSEC(TSEC_IRQDEST) =
|
||||
TSEC_IRQDEST_EXT(0xFF) |
|
||||
TSEC_IRQDEST_HALT |
|
||||
TSEC_IRQDEST_EXTERR |
|
||||
TSEC_IRQDEST_SWGEN0 |
|
||||
TSEC_IRQDEST_HALT |
|
||||
TSEC_IRQDEST_EXTERR |
|
||||
TSEC_IRQDEST_SWGEN0 |
|
||||
TSEC_IRQDEST_SWGEN1;
|
||||
TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;
|
||||
if (!_tsec_dma_wait_idle())
|
||||
@@ -105,14 +121,15 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
goto out;
|
||||
}
|
||||
|
||||
//Load firmware or emulate memio environment for newer TSEC fw.
|
||||
if (kb == KB_TSEC_FW_EMU_COMPAT)
|
||||
// Load firmware or emulate memio environment for newer TSEC fw.
|
||||
if (type == TSEC_FW_TYPE_EMU)
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||
else
|
||||
{
|
||||
fwbuf = (u8 *)malloc(0x4000);
|
||||
fwbuf = (u8 *)malloc(SZ_16K);
|
||||
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);
|
||||
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
|
||||
|
||||
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
|
||||
}
|
||||
|
||||
@@ -125,27 +142,27 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
}
|
||||
}
|
||||
|
||||
if (kb == KB_TSEC_FW_EMU_COMPAT)
|
||||
if (type == TSEC_FW_TYPE_EMU)
|
||||
{
|
||||
// Init SMMU translation for TSEC.
|
||||
pdir = smmu_init_for_tsec();
|
||||
smmu_init(0x4002B000);
|
||||
smmu_init(tsec_ctxt->secmon_base);
|
||||
// Enable SMMU
|
||||
if (!smmu_is_used())
|
||||
smmu_enable();
|
||||
|
||||
// Clock reset controller.
|
||||
car = page_alloc(1);
|
||||
memcpy(car, (void *)CLOCK_BASE, 0x1000);
|
||||
memcpy(car, (void *)CLOCK_BASE, SZ_PAGE);
|
||||
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2;
|
||||
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE);
|
||||
|
||||
// Fuse driver.
|
||||
fuse = page_alloc(1);
|
||||
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400);
|
||||
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, SZ_1K);
|
||||
fuse[0x82C / 4] = 0;
|
||||
fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1;
|
||||
fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1;
|
||||
fuse[0x9E0 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;
|
||||
fuse[0x9E4 / 4] = (1 << (TSEC_HOS_KB_620 + 2)) - 1;
|
||||
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// Power management controller.
|
||||
@@ -158,21 +175,21 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
|
||||
// Security engine.
|
||||
se = page_alloc(1);
|
||||
memcpy(se, (void *)SE_BASE, 0x1000);
|
||||
memcpy(se, (void *)SE_BASE, SZ_PAGE);
|
||||
smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Memory controller.
|
||||
mc = page_alloc(1);
|
||||
memcpy(mc, (void *)MC_BASE, 0x1000);
|
||||
memcpy(mc, (void *)MC_BASE, SZ_PAGE);
|
||||
mc[MC_IRAM_BOM / 4] = 0;
|
||||
mc[MC_IRAM_TOM / 4] = 0x80000000;
|
||||
mc[MC_IRAM_TOM / 4] = DRAM_START;
|
||||
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE);
|
||||
|
||||
// IRAM
|
||||
iram = page_alloc(0x30);
|
||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||
// PKG1.1 magic offset.
|
||||
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
|
||||
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
|
||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||
|
||||
// Exception vectors
|
||||
@@ -180,17 +197,17 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
}
|
||||
|
||||
//Execute firmware.
|
||||
// Execute firmware.
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
|
||||
|
||||
if (kb == KB_TSEC_FW_EMU_COMPAT)
|
||||
if (type == TSEC_FW_TYPE_EMU)
|
||||
{
|
||||
u32 start = get_tmr_us();
|
||||
u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4];
|
||||
u32 timeout = get_tmr_us() + 125000;
|
||||
u32 key[16] = {0};
|
||||
u32 kidx = 0;
|
||||
|
||||
@@ -205,7 +222,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
}
|
||||
|
||||
// Failsafe.
|
||||
if ((u32)get_tmr_us() - start > 125000)
|
||||
if ((u32)get_tmr_us() > timeout)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -257,27 +274,26 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
//Fetch result.
|
||||
// Fetch result.
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||
u32 buf[4];
|
||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
|
||||
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
|
||||
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
|
||||
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
|
||||
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
|
||||
|
||||
memcpy(tsec_keys, &buf, SE_KEY_128_SIZE);
|
||||
}
|
||||
|
||||
out_free:;
|
||||
out_free:
|
||||
free(fwbuf);
|
||||
|
||||
out:;
|
||||
|
||||
//Disable clocks.
|
||||
out:
|
||||
// Disable clocks.
|
||||
clock_disable_kfuse();
|
||||
clock_disable_sor1();
|
||||
clock_disable_sor0();
|
||||
@@ -286,5 +302,10 @@ out:;
|
||||
bpmp_mmu_enable();
|
||||
bpmp_clk_rate_set(prev_fid);
|
||||
|
||||
#ifdef BDK_MC_ENABLE_AHB_REDIRECT
|
||||
// Re-enable AHB aperture.
|
||||
mc_enable_ahb_redirect();
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
* Copyright (c) 2018-2021 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -22,30 +22,41 @@
|
||||
|
||||
#define TSEC_KEY_DATA_OFFSET 0x300
|
||||
|
||||
enum tsec_fw_type
|
||||
{
|
||||
// Retail Hovi Keygen.
|
||||
TSEC_FW_TYPE_OLD = 0, // 1.0.0 - 6.1.0.
|
||||
TSEC_FW_TYPE_EMU = 1, // 6.2.0 emulated enviroment.
|
||||
TSEC_FW_TYPE_NEW = 2, // 7.0.0+.
|
||||
};
|
||||
|
||||
typedef struct _tsec_ctxt_t
|
||||
{
|
||||
void *fw;
|
||||
u32 size;
|
||||
u32 type;
|
||||
void *pkg1;
|
||||
u32 pkg11_off;
|
||||
u32 secmon_base;
|
||||
} tsec_ctxt_t;
|
||||
|
||||
typedef struct _tsec_key_data_t
|
||||
{
|
||||
u8 debug_key[0x10];
|
||||
u8 blob0_auth_hash[0x10];
|
||||
u8 blob1_auth_hash[0x10];
|
||||
u8 blob2_auth_hash[0x10];
|
||||
u8 blob2_aes_iv[0x10];
|
||||
u8 hovi_eks_seed[0x10];
|
||||
u8 hovi_common_seed[0x10];
|
||||
u32 blob0_size;
|
||||
u32 blob1_size;
|
||||
u32 blob2_size;
|
||||
u32 blob3_size;
|
||||
u32 blob4_size;
|
||||
u8 reserved[0x7C];
|
||||
u8 debug_key[0x10];
|
||||
u8 blob0_auth_hash[0x10];
|
||||
u8 blob1_auth_hash[0x10];
|
||||
u8 blob2_auth_hash[0x10];
|
||||
u8 blob2_aes_iv[0x10];
|
||||
u8 hovi_eks_seed[0x10];
|
||||
u8 hovi_common_seed[0x10];
|
||||
u32 blob0_size;
|
||||
u32 blob1_size;
|
||||
u32 blob2_size;
|
||||
u32 blob3_size;
|
||||
u32 blob4_size;
|
||||
u8 reserved[0x7C];
|
||||
} tsec_key_data_t;
|
||||
|
||||
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
|
||||
int tsec_query(void *tsec_keys, tsec_ctxt_t *tsec_ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user