193e678edSClement Faure // SPDX-License-Identifier: BSD-2-Clause
293e678edSClement Faure /*
393e678edSClement Faure * Copyright 2020 NXP
493e678edSClement Faure */
593e678edSClement Faure
693e678edSClement Faure #include <config.h>
793e678edSClement Faure #include <dcp_utils.h>
893e678edSClement Faure #include <drivers/imx/dcp.h>
993e678edSClement Faure #include <imx-regs.h>
1093e678edSClement Faure #include <io.h>
1193e678edSClement Faure #include <kernel/boot.h>
1293e678edSClement Faure #include <kernel/dt.h>
1393e678edSClement Faure #include <kernel/mutex.h>
1493e678edSClement Faure #include <kernel/spinlock.h>
1593e678edSClement Faure #include <libfdt.h>
1693e678edSClement Faure #include <local.h>
1793e678edSClement Faure #include <mm/core_memprot.h>
1893e678edSClement Faure #include <tee/cache.h>
1993e678edSClement Faure #include <utee_defines.h>
2093e678edSClement Faure
2193e678edSClement Faure static const uint8_t sha1_null_msg[] = {
2293e678edSClement Faure 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
2393e678edSClement Faure 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
2493e678edSClement Faure };
2593e678edSClement Faure
2693e678edSClement Faure static const uint8_t sha256_null_msg[] = {
2793e678edSClement Faure 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
2893e678edSClement Faure 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
2993e678edSClement Faure 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
3093e678edSClement Faure };
3193e678edSClement Faure
3293e678edSClement Faure static vaddr_t dcp_base;
3393e678edSClement Faure static bool driver_initialized;
3493e678edSClement Faure static unsigned int clk_refcount;
3593e678edSClement Faure static unsigned int key_store_spinlock = SPINLOCK_UNLOCK;
3693e678edSClement Faure static unsigned int clock_spinlock = SPINLOCK_UNLOCK;
3793e678edSClement Faure static struct dcp_align_buf hw_context_buffer;
3893e678edSClement Faure
3993e678edSClement Faure static struct mutex lock_channel[DCP_NB_CHANNELS] = {
4093e678edSClement Faure [DCP_CHANN0] = MUTEX_INITIALIZER,
4193e678edSClement Faure [DCP_CHANN1] = MUTEX_INITIALIZER,
4293e678edSClement Faure [DCP_CHANN2] = MUTEX_INITIALIZER,
4393e678edSClement Faure [DCP_CHANN3] = MUTEX_INITIALIZER,
4493e678edSClement Faure };
4593e678edSClement Faure
4693e678edSClement Faure static const struct dcp_hashalg hash_alg[2] = {
4793e678edSClement Faure [DCP_SHA1] = {
4893e678edSClement Faure .type = DCP_CONTROL1_HASH_SELECT_SHA1,
4993e678edSClement Faure .size = TEE_SHA1_HASH_SIZE,
5093e678edSClement Faure },
5193e678edSClement Faure [DCP_SHA256] = {
5293e678edSClement Faure .type = DCP_CONTROL1_HASH_SELECT_SHA256,
5393e678edSClement Faure .size = TEE_SHA256_HASH_SIZE,
5493e678edSClement Faure },
5593e678edSClement Faure };
5693e678edSClement Faure
5793e678edSClement Faure /*
5893e678edSClement Faure * Enable/disable DCP clock.
5993e678edSClement Faure *
6093e678edSClement Faure * @enable Enable the clock if true, disable if false.
6193e678edSClement Faure */
dcp_clk_enable(bool enable)6293e678edSClement Faure static void dcp_clk_enable(bool enable)
6393e678edSClement Faure {
64c2e4eb43SAnton Rybakov vaddr_t ccm_base = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC,
65c2e4eb43SAnton Rybakov CCM_CCGR0 + sizeof(uint32_t));
6693e678edSClement Faure uint32_t clock_except = cpu_spin_lock_xsave(&clock_spinlock);
6793e678edSClement Faure
6893e678edSClement Faure if (enable) {
6993e678edSClement Faure if (clk_refcount > 0) {
7093e678edSClement Faure clk_refcount++;
7193e678edSClement Faure goto out;
7293e678edSClement Faure } else {
7393e678edSClement Faure clk_refcount++;
7493e678edSClement Faure io_setbits32(ccm_base + CCM_CCGR0, DCP_CLK_ENABLE_MASK);
7593e678edSClement Faure }
7693e678edSClement Faure } else {
7793e678edSClement Faure assert(clk_refcount != 0);
7893e678edSClement Faure
7993e678edSClement Faure clk_refcount--;
8093e678edSClement Faure if (clk_refcount > 0)
8193e678edSClement Faure goto out;
8293e678edSClement Faure else
8393e678edSClement Faure io_clrbits32(ccm_base + CCM_CCGR0, DCP_CLK_ENABLE_MASK);
8493e678edSClement Faure }
8593e678edSClement Faure out:
8693e678edSClement Faure cpu_spin_unlock_xrestore(&clock_spinlock, clock_except);
8793e678edSClement Faure }
8893e678edSClement Faure
8993e678edSClement Faure /*
9093e678edSClement Faure * Lock the given channel with a mutex.
9193e678edSClement Faure *
9293e678edSClement Faure * @chan DCP channel to lock
9393e678edSClement Faure */
dcp_lock_known_channel(enum dcp_channel chan)9493e678edSClement Faure static TEE_Result dcp_lock_known_channel(enum dcp_channel chan)
9593e678edSClement Faure {
9693e678edSClement Faure if (mutex_trylock(&lock_channel[chan]))
9793e678edSClement Faure return TEE_SUCCESS;
9893e678edSClement Faure else
9993e678edSClement Faure return TEE_ERROR_BUSY;
10093e678edSClement Faure }
10193e678edSClement Faure
10293e678edSClement Faure /*
10393e678edSClement Faure * Lock a DCP channel
10493e678edSClement Faure *
10593e678edSClement Faure * @channel Pointer on operation channel parameter
10693e678edSClement Faure */
dcp_lock_channel(enum dcp_channel * channel)10793e678edSClement Faure static TEE_Result dcp_lock_channel(enum dcp_channel *channel)
10893e678edSClement Faure {
10993e678edSClement Faure TEE_Result ret = TEE_ERROR_BUSY;
11093e678edSClement Faure enum dcp_channel chan = DCP_CHANN0;
11193e678edSClement Faure
11293e678edSClement Faure for (chan = DCP_CHANN0; chan < DCP_NB_CHANNELS; chan++) {
11393e678edSClement Faure ret = dcp_lock_known_channel(chan);
11493e678edSClement Faure if (ret == TEE_SUCCESS) {
11593e678edSClement Faure *channel = chan;
11693e678edSClement Faure return ret;
11793e678edSClement Faure }
11893e678edSClement Faure }
11993e678edSClement Faure
12093e678edSClement Faure EMSG("All channels are busy");
12193e678edSClement Faure
12293e678edSClement Faure return ret;
12393e678edSClement Faure }
12493e678edSClement Faure
12593e678edSClement Faure /*
12693e678edSClement Faure * Unlock the given channel.
12793e678edSClement Faure *
12893e678edSClement Faure * @chan DCP channel to unlock
12993e678edSClement Faure */
dcp_unlock_channel(enum dcp_channel chan)13093e678edSClement Faure static void dcp_unlock_channel(enum dcp_channel chan)
13193e678edSClement Faure {
13293e678edSClement Faure mutex_unlock(&lock_channel[chan]);
13393e678edSClement Faure }
13493e678edSClement Faure
13593e678edSClement Faure /*
13693e678edSClement Faure * Start the DCP operation.
13793e678edSClement Faure *
13893e678edSClement Faure * @dcp_data Structure containing dcp_descriptor configuration and channel to
13993e678edSClement Faure * use.
14093e678edSClement Faure */
dcp_run(struct dcp_data * dcp_data)14193e678edSClement Faure static TEE_Result dcp_run(struct dcp_data *dcp_data)
14293e678edSClement Faure {
14393e678edSClement Faure TEE_Result ret = TEE_SUCCESS;
14493e678edSClement Faure unsigned int timeout = 0;
14593e678edSClement Faure uint32_t val = 0;
14693e678edSClement Faure
14793e678edSClement Faure dcp_data->desc.next = 0;
14893e678edSClement Faure cache_operation(TEE_CACHEFLUSH, &dcp_data->desc,
14993e678edSClement Faure sizeof(dcp_data->desc));
15093e678edSClement Faure
15193e678edSClement Faure /* Enable clock if it's not done */
15293e678edSClement Faure dcp_clk_enable(true);
15393e678edSClement Faure
15493e678edSClement Faure /* Clear DCP_STAT IRQ field for the channel used by the operation */
15593e678edSClement Faure io_clrbits32(dcp_base + DCP_STAT, BIT32(dcp_data->channel));
15693e678edSClement Faure
15793e678edSClement Faure /* Clear CH_N_STAT to clear IRQ and error codes */
15893e678edSClement Faure io_write32(dcp_base + DCP_CH_N_STAT(dcp_data->channel), 0x0);
15993e678edSClement Faure
16093e678edSClement Faure /* Update descriptor structure to be processed for the channel */
16193e678edSClement Faure io_write32(dcp_base + DCP_CH_N_CMDPTR(dcp_data->channel),
16293e678edSClement Faure virt_to_phys(&dcp_data->desc));
16393e678edSClement Faure
16493e678edSClement Faure /* Increment the semaphore to start the transfer */
16593e678edSClement Faure io_write32(dcp_base + DCP_CH_N_SEMA(dcp_data->channel), 0x1);
16693e678edSClement Faure
16793e678edSClement Faure for (timeout = 0; timeout < DCP_MAX_TIMEOUT; timeout++) {
16893e678edSClement Faure dcp_udelay(10);
16993e678edSClement Faure val = io_read32(dcp_base + DCP_STAT);
17093e678edSClement Faure if (val & BIT(dcp_data->channel))
17193e678edSClement Faure break;
17293e678edSClement Faure }
17393e678edSClement Faure
17493e678edSClement Faure if (timeout == DCP_MAX_TIMEOUT) {
17593e678edSClement Faure EMSG("Timeout elapsed before operation");
17693e678edSClement Faure ret = TEE_ERROR_GENERIC;
17793e678edSClement Faure goto out;
17893e678edSClement Faure }
17993e678edSClement Faure
18093e678edSClement Faure val = io_read32(dcp_base + DCP_CH_N_STAT(dcp_data->channel));
18193e678edSClement Faure if (val & DCP_CH_STAT_ERROR_MASK) {
18293e678edSClement Faure EMSG("Error operation, 0x%" PRIx32, val);
18393e678edSClement Faure ret = TEE_ERROR_GENERIC;
18493e678edSClement Faure }
18593e678edSClement Faure
18693e678edSClement Faure out:
18793e678edSClement Faure dcp_clk_enable(false);
18893e678edSClement Faure
18993e678edSClement Faure return ret;
19093e678edSClement Faure }
19193e678edSClement Faure
dcp_cmac_subkey_generation(struct dcp_cipher_init * init,uint8_t * k1,uint8_t * k2)19293e678edSClement Faure static TEE_Result dcp_cmac_subkey_generation(struct dcp_cipher_init *init,
19393e678edSClement Faure uint8_t *k1, uint8_t *k2)
19493e678edSClement Faure {
19593e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
19693e678edSClement Faure struct dcp_cipher_data data = { };
19793e678edSClement Faure uint8_t l[16] = { };
19893e678edSClement Faure uint8_t tmp[16] = { };
19993e678edSClement Faure uint8_t const_zero[16] = { };
20093e678edSClement Faure uint8_t const_rb[16] = { [15] = 0x87 };
20193e678edSClement Faure
20293e678edSClement Faure ret = dcp_cipher_do_init(&data, init);
20393e678edSClement Faure if (ret != TEE_SUCCESS)
20493e678edSClement Faure return ret;
20593e678edSClement Faure
20693e678edSClement Faure ret = dcp_cipher_do_update(&data, const_zero, l, sizeof(l));
20793e678edSClement Faure if (ret != TEE_SUCCESS)
20893e678edSClement Faure goto out;
20993e678edSClement Faure
21093e678edSClement Faure if ((l[0] & BIT(7)) == 0) {
21193e678edSClement Faure dcp_left_shift_buffer(l, k1, 16);
21293e678edSClement Faure } else {
21393e678edSClement Faure dcp_left_shift_buffer(l, tmp, 16);
21493e678edSClement Faure dcp_xor(tmp, const_rb, k1, 16);
21593e678edSClement Faure }
21693e678edSClement Faure
21793e678edSClement Faure if ((k1[0] & BIT(7)) == 0) {
21893e678edSClement Faure dcp_left_shift_buffer(k1, k2, 16);
21993e678edSClement Faure } else {
22093e678edSClement Faure dcp_left_shift_buffer(k1, tmp, 16);
22193e678edSClement Faure dcp_xor(tmp, const_rb, k2, 16);
22293e678edSClement Faure }
22393e678edSClement Faure
22493e678edSClement Faure ret = TEE_SUCCESS;
22593e678edSClement Faure out:
22693e678edSClement Faure dcp_cipher_do_final(&data);
22793e678edSClement Faure
22893e678edSClement Faure return ret;
22993e678edSClement Faure }
23093e678edSClement Faure
dcp_store_key(uint32_t * key,unsigned int index)23193e678edSClement Faure TEE_Result dcp_store_key(uint32_t *key, unsigned int index)
23293e678edSClement Faure {
23393e678edSClement Faure uint32_t val = 0;
23493e678edSClement Faure unsigned int i = 0;
23593e678edSClement Faure uint32_t key_store_except = 0;
23693e678edSClement Faure
23793e678edSClement Faure if (!key)
23893e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
23993e678edSClement Faure
24093e678edSClement Faure if (index > DCP_SRAM_KEY_NB_SUBWORD - 1) {
24193e678edSClement Faure EMSG("Bad parameters, index must be < %u",
24293e678edSClement Faure DCP_SRAM_KEY_NB_SUBWORD);
24393e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
24493e678edSClement Faure }
24593e678edSClement Faure
24693e678edSClement Faure key_store_except = cpu_spin_lock_xsave(&key_store_spinlock);
24793e678edSClement Faure
24893e678edSClement Faure dcp_clk_enable(true);
24993e678edSClement Faure
25093e678edSClement Faure val = DCP_SRAM_KEY_INDEX(index);
25193e678edSClement Faure io_write32(dcp_base + DCP_KEY, val);
25293e678edSClement Faure
25393e678edSClement Faure /*
25493e678edSClement Faure * Key is stored as four uint32 values, starting with subword0
25593e678edSClement Faure * (least-significant word)
25693e678edSClement Faure */
25793e678edSClement Faure for (i = 0; i < DCP_SRAM_KEY_NB_SUBWORD; i++) {
25893e678edSClement Faure val = TEE_U32_TO_BIG_ENDIAN(key[i]);
25993e678edSClement Faure io_write32(dcp_base + DCP_KEYDATA, val);
26093e678edSClement Faure }
26193e678edSClement Faure
26293e678edSClement Faure dcp_clk_enable(false);
26393e678edSClement Faure
26493e678edSClement Faure cpu_spin_unlock_xrestore(&key_store_spinlock, key_store_except);
26593e678edSClement Faure
26693e678edSClement Faure return TEE_SUCCESS;
26793e678edSClement Faure }
26893e678edSClement Faure
dcp_cmac(struct dcp_cipher_init * init,uint8_t * input,size_t input_size,uint8_t * output)26993e678edSClement Faure TEE_Result dcp_cmac(struct dcp_cipher_init *init, uint8_t *input,
27093e678edSClement Faure size_t input_size, uint8_t *output)
27193e678edSClement Faure {
27293e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
27393e678edSClement Faure uint8_t key1[DCP_AES128_KEY_SIZE] = { };
27493e678edSClement Faure uint8_t key2[DCP_AES128_KEY_SIZE] = { };
27593e678edSClement Faure unsigned int nb_blocks = 0;
27693e678edSClement Faure bool block_complete = false;
27793e678edSClement Faure struct dcp_cipher_data data = { };
27893e678edSClement Faure uint8_t y[DCP_AES128_BLOCK_SIZE] = { };
27993e678edSClement Faure uint8_t x[DCP_AES128_BLOCK_SIZE] = { };
28093e678edSClement Faure uint8_t last[DCP_AES128_BLOCK_SIZE] = { };
28193e678edSClement Faure unsigned int i = 0;
28293e678edSClement Faure uint8_t offset = 0;
28393e678edSClement Faure
28493e678edSClement Faure if (!output || !init)
28593e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
28693e678edSClement Faure
28793e678edSClement Faure if (!input && input_size)
28893e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
28993e678edSClement Faure
29093e678edSClement Faure ret = dcp_cipher_do_init(&data, init);
29193e678edSClement Faure if (ret != TEE_SUCCESS) {
29293e678edSClement Faure ret = TEE_ERROR_OUT_OF_MEMORY;
29393e678edSClement Faure goto out;
29493e678edSClement Faure }
29593e678edSClement Faure
29693e678edSClement Faure /* Generate CMAC subkeys */
29793e678edSClement Faure ret = dcp_cmac_subkey_generation(init, key1, key2);
29893e678edSClement Faure if (ret != TEE_SUCCESS)
29993e678edSClement Faure goto out;
30093e678edSClement Faure
30193e678edSClement Faure /* Get number of block */
302*04e46975SEtienne Carriere nb_blocks = ROUNDUP_DIV(input_size, DCP_AES128_BLOCK_SIZE);
30393e678edSClement Faure
30493e678edSClement Faure block_complete = nb_blocks && !(input_size % DCP_AES128_BLOCK_SIZE);
30593e678edSClement Faure if (nb_blocks == 0)
30693e678edSClement Faure nb_blocks = 1;
30793e678edSClement Faure
30893e678edSClement Faure for (i = 0; i < nb_blocks - 1; i++) {
30993e678edSClement Faure dcp_xor(x, input + offset, y, DCP_AES128_BLOCK_SIZE);
31093e678edSClement Faure ret = dcp_cipher_do_update(&data, y, x,
31193e678edSClement Faure DCP_AES128_BLOCK_SIZE);
31293e678edSClement Faure if (ret)
31393e678edSClement Faure goto out;
31493e678edSClement Faure offset += DCP_AES128_BLOCK_SIZE;
31593e678edSClement Faure }
31693e678edSClement Faure
31793e678edSClement Faure /* Process the last block */
31893e678edSClement Faure memcpy(last, input + offset, input_size - offset);
31993e678edSClement Faure
32093e678edSClement Faure if (block_complete) {
32193e678edSClement Faure dcp_xor(last, key1, last, DCP_AES128_BLOCK_SIZE);
32293e678edSClement Faure } else {
32393e678edSClement Faure dcp_cmac_padding(last, input_size % DCP_AES128_BLOCK_SIZE);
32493e678edSClement Faure dcp_xor(last, key2, last, DCP_AES128_BLOCK_SIZE);
32593e678edSClement Faure }
32693e678edSClement Faure
32793e678edSClement Faure dcp_xor(x, last, y, DCP_AES128_BLOCK_SIZE);
32893e678edSClement Faure ret = dcp_cipher_do_update(&data, y, x,
32993e678edSClement Faure DCP_AES128_BLOCK_SIZE);
33093e678edSClement Faure if (ret)
33193e678edSClement Faure goto out;
33293e678edSClement Faure
33393e678edSClement Faure memcpy(output, x, DCP_AES128_BLOCK_SIZE);
33493e678edSClement Faure
33593e678edSClement Faure out:
33693e678edSClement Faure dcp_cipher_do_final(&data);
33793e678edSClement Faure
33893e678edSClement Faure return ret;
33993e678edSClement Faure }
34093e678edSClement Faure
dcp_cipher_do_init(struct dcp_cipher_data * data,struct dcp_cipher_init * init)34193e678edSClement Faure TEE_Result dcp_cipher_do_init(struct dcp_cipher_data *data,
34293e678edSClement Faure struct dcp_cipher_init *init)
34393e678edSClement Faure {
34493e678edSClement Faure struct dcp_descriptor *desc = NULL;
34593e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
34693e678edSClement Faure
34793e678edSClement Faure if (!init || !data)
34893e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
34993e678edSClement Faure
35093e678edSClement Faure ret = dcp_lock_channel(&data->dcp_data.channel);
35193e678edSClement Faure if (ret != TEE_SUCCESS)
35293e678edSClement Faure return ret;
35393e678edSClement Faure
35493e678edSClement Faure desc = &data->dcp_data.desc;
35593e678edSClement Faure
35693e678edSClement Faure desc->ctrl0 = DCP_CONTROL0_DECR_SEMAPHORE | DCP_CONTROL0_ENABLE_CIPHER |
35793e678edSClement Faure DCP_CONTROL0_INTERRUPT_ENABLE;
35893e678edSClement Faure desc->ctrl1 = DCP_CONTROL1_CIPHER_SELECT_AES128;
35993e678edSClement Faure
36093e678edSClement Faure if (init->op == DCP_ENCRYPT)
36193e678edSClement Faure desc->ctrl0 |= DCP_CONTROL0_CIPHER_ENCRYPT;
36293e678edSClement Faure
36393e678edSClement Faure if (init->key_mode == DCP_OTP) {
364ebc90499SClement Faure desc->ctrl0 &= ~DCP_CONTROL0_OTP_KEY;
36593e678edSClement Faure desc->ctrl1 |= DCP_CONTROL1_KEY_SELECT_OTP_CRYPTO;
36693e678edSClement Faure } else if (init->key_mode == DCP_PAYLOAD) {
36793e678edSClement Faure desc->ctrl0 |= DCP_CONTROL0_PAYLOAD_KEY;
36893e678edSClement Faure if (!init->key)
36993e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
37093e678edSClement Faure memcpy(data->key, init->key, DCP_AES128_KEY_SIZE);
37193e678edSClement Faure } else {
37293e678edSClement Faure desc->ctrl1 |= SHIFT_U32(init->key_mode, 8);
37393e678edSClement Faure }
37493e678edSClement Faure
37593e678edSClement Faure if (init->mode == DCP_CBC) {
37693e678edSClement Faure desc->ctrl0 |= DCP_CONTROL0_CIPHER_INIT;
37793e678edSClement Faure desc->ctrl1 |= DCP_CONTROL1_CIPHER_MODE_CBC;
37893e678edSClement Faure if (!init->iv)
37993e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
38093e678edSClement Faure memcpy(data->iv, init->iv, DCP_AES128_IV_SIZE);
38193e678edSClement Faure }
38293e678edSClement Faure
38393e678edSClement Faure /* Allocate aligned buffer for dcp iv and key */
38493e678edSClement Faure ret = dcp_calloc_align_buf(&data->payload,
38593e678edSClement Faure DCP_AES128_IV_SIZE + DCP_AES128_KEY_SIZE);
38693e678edSClement Faure if (ret != TEE_SUCCESS)
38793e678edSClement Faure return ret;
38893e678edSClement Faure
38993e678edSClement Faure desc->src_buffer = 0;
39093e678edSClement Faure desc->dest_buffer = 0;
39193e678edSClement Faure desc->status = 0;
39293e678edSClement Faure desc->buff_size = 0;
39393e678edSClement Faure desc->next = virt_to_phys(desc);
39493e678edSClement Faure
39593e678edSClement Faure data->initialized = true;
39693e678edSClement Faure
39793e678edSClement Faure return ret;
39893e678edSClement Faure }
39993e678edSClement Faure
dcp_cipher_do_update(struct dcp_cipher_data * data,const uint8_t * src,uint8_t * dst,size_t size)40093e678edSClement Faure TEE_Result dcp_cipher_do_update(struct dcp_cipher_data *data,
40193e678edSClement Faure const uint8_t *src, uint8_t *dst, size_t size)
40293e678edSClement Faure {
40393e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
40493e678edSClement Faure struct dcp_align_buf output = { };
40593e678edSClement Faure struct dcp_align_buf input = { };
40693e678edSClement Faure struct dcp_descriptor *desc = NULL;
40793e678edSClement Faure
40893e678edSClement Faure if (!data || !src || !dst)
40993e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
41093e678edSClement Faure
41193e678edSClement Faure if (!data->initialized) {
41293e678edSClement Faure EMSG("Error, please call dcp_aes_do_init() before");
41393e678edSClement Faure return TEE_ERROR_BAD_STATE;
41493e678edSClement Faure }
41593e678edSClement Faure
41693e678edSClement Faure if (size % DCP_AES128_BLOCK_SIZE) {
41793e678edSClement Faure EMSG("Input size has to be a multiple of %zu bytes",
41893e678edSClement Faure DCP_AES128_BLOCK_SIZE);
41993e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
42093e678edSClement Faure }
42193e678edSClement Faure
42293e678edSClement Faure ret = dcp_calloc_align_buf(&output, size);
42393e678edSClement Faure if (ret != TEE_SUCCESS)
42493e678edSClement Faure goto out;
42593e678edSClement Faure
42693e678edSClement Faure ret = dcp_calloc_align_buf(&input, size);
42793e678edSClement Faure if (ret != TEE_SUCCESS)
42893e678edSClement Faure goto out;
42993e678edSClement Faure
43093e678edSClement Faure desc = &data->dcp_data.desc;
43193e678edSClement Faure
43293e678edSClement Faure /* Copy input data */
43393e678edSClement Faure memcpy(input.data, src, size);
43493e678edSClement Faure
43593e678edSClement Faure /* Copy key and IV */
43693e678edSClement Faure memcpy(data->payload.data, data->key, DCP_AES128_KEY_SIZE);
43793e678edSClement Faure data->payload_size = DCP_AES128_KEY_SIZE;
43893e678edSClement Faure if (desc->ctrl0 & DCP_CONTROL0_CIPHER_INIT) {
43993e678edSClement Faure memcpy(data->payload.data + DCP_AES128_KEY_SIZE, data->iv,
44093e678edSClement Faure DCP_AES128_IV_SIZE);
44193e678edSClement Faure data->payload_size += DCP_AES128_IV_SIZE;
44293e678edSClement Faure }
44393e678edSClement Faure
44493e678edSClement Faure desc->src_buffer = input.paddr;
44593e678edSClement Faure desc->dest_buffer = output.paddr;
44693e678edSClement Faure desc->payload = data->payload.paddr;
44793e678edSClement Faure desc->buff_size = size;
44893e678edSClement Faure
44993e678edSClement Faure cache_operation(TEE_CACHECLEAN, data->payload.data,
45093e678edSClement Faure data->payload_size);
45193e678edSClement Faure cache_operation(TEE_CACHECLEAN, input.data, size);
45293e678edSClement Faure cache_operation(TEE_CACHEINVALIDATE, output.data, size);
45393e678edSClement Faure
45493e678edSClement Faure ret = dcp_run(&data->dcp_data);
45593e678edSClement Faure if (ret)
45693e678edSClement Faure goto out;
45793e678edSClement Faure
45893e678edSClement Faure cache_operation(TEE_CACHEINVALIDATE, output.data, size);
45993e678edSClement Faure
46093e678edSClement Faure desc->ctrl0 &= ~DCP_CONTROL0_CIPHER_INIT;
46193e678edSClement Faure
46293e678edSClement Faure memcpy(dst, output.data, size);
46393e678edSClement Faure out:
46493e678edSClement Faure dcp_free(&output);
46593e678edSClement Faure dcp_free(&input);
46693e678edSClement Faure
46793e678edSClement Faure return ret;
46893e678edSClement Faure }
46993e678edSClement Faure
dcp_cipher_do_final(struct dcp_cipher_data * data)47093e678edSClement Faure void dcp_cipher_do_final(struct dcp_cipher_data *data)
47193e678edSClement Faure {
47293e678edSClement Faure if (data)
47393e678edSClement Faure data->initialized = false;
47493e678edSClement Faure
47593e678edSClement Faure dcp_free(&data->payload);
47693e678edSClement Faure dcp_unlock_channel(data->dcp_data.channel);
47793e678edSClement Faure }
47893e678edSClement Faure
dcp_sha_do_init(struct dcp_hash_data * hashdata)47993e678edSClement Faure TEE_Result dcp_sha_do_init(struct dcp_hash_data *hashdata)
48093e678edSClement Faure {
48193e678edSClement Faure struct dcp_descriptor *desc = NULL;
48293e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
48393e678edSClement Faure
48493e678edSClement Faure if (!hashdata) {
48593e678edSClement Faure EMSG("Bad parameters, hashdata is NULL");
48693e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
48793e678edSClement Faure }
48893e678edSClement Faure
48993e678edSClement Faure desc = &hashdata->dcp_data.desc;
49093e678edSClement Faure
49193e678edSClement Faure /* DCP descriptor init */
49293e678edSClement Faure desc->status = 0;
49393e678edSClement Faure desc->payload = 0;
49493e678edSClement Faure desc->dest_buffer = 0;
49593e678edSClement Faure desc->ctrl0 = DCP_CONTROL0_ENABLE_HASH | DCP_CONTROL0_INTERRUPT_ENABLE |
49693e678edSClement Faure DCP_CONTROL0_DECR_SEMAPHORE | DCP_CONTROL0_HASH_INIT;
49793e678edSClement Faure desc->ctrl1 = hash_alg[hashdata->alg].type;
49893e678edSClement Faure desc->buff_size = 0;
49993e678edSClement Faure desc->next = 0;
50093e678edSClement Faure desc->src_buffer = 0;
50193e678edSClement Faure
50293e678edSClement Faure ret = dcp_lock_channel(&hashdata->dcp_data.channel);
50393e678edSClement Faure if (ret != TEE_SUCCESS) {
50493e678edSClement Faure EMSG("Channel is busy, can't start operation now");
50593e678edSClement Faure return ret;
50693e678edSClement Faure }
50793e678edSClement Faure
50893e678edSClement Faure /* Allocate context data */
50993e678edSClement Faure ret = dcp_calloc_align_buf(&hashdata->ctx, DCP_SHA_BLOCK_SIZE);
51093e678edSClement Faure if (ret != TEE_SUCCESS)
51193e678edSClement Faure return ret;
51293e678edSClement Faure
51393e678edSClement Faure hashdata->initialized = true;
51493e678edSClement Faure hashdata->ctx_size = 0;
51593e678edSClement Faure
51693e678edSClement Faure return ret;
51793e678edSClement Faure }
51893e678edSClement Faure
dcp_sha_do_update(struct dcp_hash_data * hashdata,const uint8_t * data,size_t len)51993e678edSClement Faure TEE_Result dcp_sha_do_update(struct dcp_hash_data *hashdata,
52093e678edSClement Faure const uint8_t *data, size_t len)
52193e678edSClement Faure {
52293e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
52393e678edSClement Faure struct dcp_descriptor *desc = NULL;
52493e678edSClement Faure struct dcp_align_buf input = { };
52593e678edSClement Faure uint32_t offset = 0;
52693e678edSClement Faure uint32_t nb_blocks = 0;
52793e678edSClement Faure size_t size_todo = 0;
52893e678edSClement Faure size_t size_left = 0;
52993e678edSClement Faure size_t size_total = 0;
53093e678edSClement Faure
53193e678edSClement Faure if (!hashdata || !data || !len)
53293e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
53393e678edSClement Faure
53493e678edSClement Faure if (!hashdata->initialized) {
53593e678edSClement Faure EMSG("hashdata is uninitialized");
53693e678edSClement Faure return TEE_ERROR_BAD_STATE;
53793e678edSClement Faure }
53893e678edSClement Faure
53993e678edSClement Faure /* Get number of blocks */
54093e678edSClement Faure if (ADD_OVERFLOW(hashdata->ctx_size, len, &size_total))
54193e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
54293e678edSClement Faure
54393e678edSClement Faure nb_blocks = size_total / DCP_SHA_BLOCK_SIZE;
54493e678edSClement Faure size_todo = nb_blocks * DCP_SHA_BLOCK_SIZE;
54593e678edSClement Faure size_left = len - size_todo + hashdata->ctx_size;
54693e678edSClement Faure desc = &hashdata->dcp_data.desc;
54793e678edSClement Faure
54893e678edSClement Faure if (size_todo) {
54993e678edSClement Faure /* Allocate buffer as input */
55093e678edSClement Faure ret = dcp_calloc_align_buf(&input, size_todo);
55193e678edSClement Faure if (ret != TEE_SUCCESS)
55293e678edSClement Faure return ret;
55393e678edSClement Faure
55493e678edSClement Faure /* Copy previous data if any */
55593e678edSClement Faure offset = size_todo - hashdata->ctx_size;
55693e678edSClement Faure memcpy(input.data, hashdata->ctx.data, hashdata->ctx_size);
55793e678edSClement Faure memcpy(input.data + hashdata->ctx_size, data, offset);
55893e678edSClement Faure hashdata->ctx_size = 0;
55993e678edSClement Faure
56093e678edSClement Faure desc->src_buffer = input.paddr;
56193e678edSClement Faure desc->buff_size = size_todo;
56293e678edSClement Faure
56393e678edSClement Faure cache_operation(TEE_CACHECLEAN, input.data, size_todo);
56493e678edSClement Faure
56593e678edSClement Faure ret = dcp_run(&hashdata->dcp_data);
56693e678edSClement Faure desc->ctrl0 &= ~DCP_CONTROL0_HASH_INIT;
56793e678edSClement Faure
56893e678edSClement Faure dcp_free(&input);
56993e678edSClement Faure } else {
57093e678edSClement Faure size_left = len;
57193e678edSClement Faure offset = 0;
57293e678edSClement Faure ret = TEE_SUCCESS;
57393e678edSClement Faure }
57493e678edSClement Faure
57593e678edSClement Faure /* Save any data left */
57693e678edSClement Faure memcpy(hashdata->ctx.data + hashdata->ctx_size, data + offset,
57793e678edSClement Faure size_left);
57893e678edSClement Faure hashdata->ctx_size += size_left;
57993e678edSClement Faure
58093e678edSClement Faure return ret;
58193e678edSClement Faure }
58293e678edSClement Faure
dcp_sha_do_final(struct dcp_hash_data * hashdata,uint8_t * digest,size_t digest_size)58393e678edSClement Faure TEE_Result dcp_sha_do_final(struct dcp_hash_data *hashdata, uint8_t *digest,
58493e678edSClement Faure size_t digest_size)
58593e678edSClement Faure {
58693e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
58793e678edSClement Faure size_t payload_size = 0;
58893e678edSClement Faure struct dcp_descriptor *desc = NULL;
58993e678edSClement Faure struct dcp_align_buf payload = { };
59093e678edSClement Faure
59193e678edSClement Faure if (!hashdata || !digest)
59293e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
59393e678edSClement Faure
59493e678edSClement Faure if (!hashdata->initialized) {
59593e678edSClement Faure EMSG("hashdata is uninitialized");
59693e678edSClement Faure return TEE_ERROR_BAD_STATE;
59793e678edSClement Faure }
59893e678edSClement Faure
59993e678edSClement Faure if (digest_size < hash_alg[hashdata->alg].size) {
60093e678edSClement Faure EMSG("Digest buffer size is to small, should be %" PRId32,
60193e678edSClement Faure hash_alg[hashdata->alg].size);
60293e678edSClement Faure return TEE_ERROR_BAD_PARAMETERS;
60393e678edSClement Faure }
60493e678edSClement Faure
60593e678edSClement Faure desc = &hashdata->dcp_data.desc;
60693e678edSClement Faure payload_size = hash_alg[hashdata->alg].size;
60793e678edSClement Faure
60893e678edSClement Faure /* Handle the case where the input message is NULL */
60993e678edSClement Faure if ((desc->ctrl0 & DCP_CONTROL0_HASH_INIT) && hashdata->ctx_size == 0) {
61093e678edSClement Faure if (hashdata->alg == DCP_SHA1)
61193e678edSClement Faure memcpy(digest, sha1_null_msg, payload_size);
61293e678edSClement Faure if (hashdata->alg == DCP_SHA256)
61393e678edSClement Faure memcpy(digest, sha256_null_msg, payload_size);
61493e678edSClement Faure ret = TEE_SUCCESS;
61593e678edSClement Faure } else {
61693e678edSClement Faure /* Allocate buffer for the digest */
61793e678edSClement Faure ret = dcp_calloc_align_buf(&payload, payload_size);
61893e678edSClement Faure if (ret != TEE_SUCCESS)
61993e678edSClement Faure return ret;
62093e678edSClement Faure
62193e678edSClement Faure /* Set work packet for last iteration */
62293e678edSClement Faure desc->ctrl0 |= DCP_CONTROL0_HASH_TERM;
62393e678edSClement Faure desc->src_buffer = hashdata->ctx.paddr;
62493e678edSClement Faure desc->buff_size = hashdata->ctx_size;
62593e678edSClement Faure desc->payload = payload.paddr;
62693e678edSClement Faure
62793e678edSClement Faure cache_operation(TEE_CACHECLEAN, hashdata->ctx.data,
62893e678edSClement Faure hashdata->ctx_size);
62993e678edSClement Faure cache_operation(TEE_CACHEINVALIDATE, payload.data,
63093e678edSClement Faure payload_size);
63193e678edSClement Faure
63293e678edSClement Faure ret = dcp_run(&hashdata->dcp_data);
63393e678edSClement Faure
63493e678edSClement Faure /* Copy the result */
63593e678edSClement Faure cache_operation(TEE_CACHEINVALIDATE, payload.data,
63693e678edSClement Faure payload_size);
63793e678edSClement Faure /* DCP payload result is flipped */
63893e678edSClement Faure dcp_reverse(payload.data, digest, payload_size);
63993e678edSClement Faure
64093e678edSClement Faure dcp_free(&payload);
64193e678edSClement Faure }
64293e678edSClement Faure
64393e678edSClement Faure dcp_free(&hashdata->ctx);
64493e678edSClement Faure
64593e678edSClement Faure /* Reset hashdata strcuture */
64693e678edSClement Faure hashdata->initialized = false;
64793e678edSClement Faure
64893e678edSClement Faure dcp_unlock_channel(hashdata->dcp_data.channel);
64993e678edSClement Faure
65093e678edSClement Faure return ret;
65193e678edSClement Faure }
65293e678edSClement Faure
dcp_disable_unique_key(void)6533fc5c287SClement Faure void dcp_disable_unique_key(void)
6543fc5c287SClement Faure {
6553fc5c287SClement Faure dcp_clk_enable(true);
6563fc5c287SClement Faure io_setbits32(dcp_base + DCP_CAPABILITY0,
6573fc5c287SClement Faure DCP_CAPABILITY0_DISABLE_UNIQUE_KEY);
6583fc5c287SClement Faure dcp_clk_enable(false);
6593fc5c287SClement Faure }
6603fc5c287SClement Faure
66193e678edSClement Faure #ifdef CFG_DT
66293e678edSClement Faure static const char *const dt_ctrl_match_table[] = {
66393e678edSClement Faure "fsl,imx28-dcp",
66493e678edSClement Faure "fsl,imx6sl-dcp",
66593e678edSClement Faure };
66693e678edSClement Faure
66793e678edSClement Faure /*
66893e678edSClement Faure * Fetch DCP base address from DT
66993e678edSClement Faure *
67093e678edSClement Faure * @base [out] DCP base address
67193e678edSClement Faure */
dcp_pbase(paddr_t * base)67293e678edSClement Faure static TEE_Result dcp_pbase(paddr_t *base)
67393e678edSClement Faure {
67493e678edSClement Faure void *fdt = NULL;
67593e678edSClement Faure int node = -1;
67693e678edSClement Faure unsigned int i = 0;
67793e678edSClement Faure
67893e678edSClement Faure fdt = get_dt();
67993e678edSClement Faure if (!fdt) {
68093e678edSClement Faure EMSG("DTB no present");
68193e678edSClement Faure return TEE_ERROR_ITEM_NOT_FOUND;
68293e678edSClement Faure }
68393e678edSClement Faure
68493e678edSClement Faure for (i = 0; i < ARRAY_SIZE(dt_ctrl_match_table); i++) {
68593e678edSClement Faure node = fdt_node_offset_by_compatible(fdt, 0,
68693e678edSClement Faure dt_ctrl_match_table[i]);
68793e678edSClement Faure if (node >= 0)
68893e678edSClement Faure break;
68993e678edSClement Faure }
69093e678edSClement Faure
69193e678edSClement Faure if (node < 0) {
69293e678edSClement Faure EMSG("DCP node not found err = %d", node);
69393e678edSClement Faure return TEE_ERROR_ITEM_NOT_FOUND;
69493e678edSClement Faure }
69593e678edSClement Faure
696f354a5d8SGatien Chevallier if (fdt_get_status(fdt, node) == DT_STATUS_DISABLED)
69793e678edSClement Faure return TEE_ERROR_ITEM_NOT_FOUND;
69893e678edSClement Faure
69993e678edSClement Faure /* Force secure-status = "okay" and status="disabled" */
70093e678edSClement Faure if (dt_enable_secure_status(fdt, node)) {
70193e678edSClement Faure EMSG("Not able to set DCP Control DTB entry secure");
70293e678edSClement Faure return TEE_ERROR_NOT_SUPPORTED;
70393e678edSClement Faure }
70493e678edSClement Faure
705f354a5d8SGatien Chevallier *base = fdt_reg_base_address(fdt, node);
70693e678edSClement Faure if (*base == DT_INFO_INVALID_REG) {
70793e678edSClement Faure EMSG("Unable to get the DCP Base address");
70893e678edSClement Faure return TEE_ERROR_ITEM_NOT_FOUND;
70993e678edSClement Faure }
71093e678edSClement Faure
71193e678edSClement Faure return TEE_SUCCESS;
71293e678edSClement Faure }
71393e678edSClement Faure #endif /* CFG_DT */
71493e678edSClement Faure
dcp_init(void)71593e678edSClement Faure TEE_Result dcp_init(void)
71693e678edSClement Faure {
71793e678edSClement Faure TEE_Result ret = TEE_ERROR_GENERIC;
71893e678edSClement Faure paddr_t pbase = 0;
71993e678edSClement Faure
72093e678edSClement Faure if (driver_initialized)
72193e678edSClement Faure return TEE_SUCCESS;
72293e678edSClement Faure
72393e678edSClement Faure dcp_clk_enable(true);
72493e678edSClement Faure
72593e678edSClement Faure ret = dcp_pbase(&pbase);
72693e678edSClement Faure if (ret != TEE_SUCCESS)
72793e678edSClement Faure pbase = DCP_BASE;
72893e678edSClement Faure
729c2e4eb43SAnton Rybakov dcp_base = core_mmu_get_va(pbase, MEM_AREA_IO_SEC, DCP_CONTEXT +
730c2e4eb43SAnton Rybakov sizeof(uint32_t));
73193e678edSClement Faure if (!dcp_base) {
73293e678edSClement Faure EMSG("Unable to get DCP physical address");
73393e678edSClement Faure return TEE_ERROR_ITEM_NOT_FOUND;
73493e678edSClement Faure }
73593e678edSClement Faure
73693e678edSClement Faure /* Context switching buffer memory allocation */
73793e678edSClement Faure ret = dcp_calloc_align_buf(&hw_context_buffer, DCP_CONTEXT_BUFFER_SIZE);
73893e678edSClement Faure if (ret != TEE_SUCCESS) {
73993e678edSClement Faure EMSG("hw_context_buffer allocation failed");
74093e678edSClement Faure return ret;
74193e678edSClement Faure }
74293e678edSClement Faure
74393e678edSClement Faure /*
744b6760712SClement Faure * Reset the DCP before initialization. Depending on the SoC lifecycle
745b6760712SClement Faure * state, the DCP needs to be reset to reload the OTP master key from
746b6760712SClement Faure * the SNVS.
747b6760712SClement Faure */
748b6760712SClement Faure io_write32(dcp_base + DCP_CTRL_SET, DCP_CTRL_SFTRST | DCP_CTRL_CLKGATE);
749b6760712SClement Faure
750b6760712SClement Faure /*
75193e678edSClement Faure * Initialize control register.
75293e678edSClement Faure * Enable normal DCP operation (SFTRST & CLKGATE bits set to 0)
75393e678edSClement Faure */
75493e678edSClement Faure io_write32(dcp_base + DCP_CTRL_CLR, DCP_CTRL_SFTRST | DCP_CTRL_CLKGATE);
75593e678edSClement Faure
75693e678edSClement Faure io_write32(dcp_base + DCP_CTRL_SET,
75793e678edSClement Faure DCP_CTRL_GATHER_RESIDUAL_WRITES |
75893e678edSClement Faure DCP_CTRL_ENABLE_CONTEXT_SWITCHING);
75993e678edSClement Faure
76093e678edSClement Faure /* Enable all DCP channels */
76193e678edSClement Faure io_write32(dcp_base + DCP_CHANNELCTRL,
76293e678edSClement Faure DCP_CHANNELCTRL_ENABLE_CHANNEL_MASK);
76393e678edSClement Faure
76493e678edSClement Faure /* Clear DCP_STAT register */
76593e678edSClement Faure io_write32(dcp_base + DCP_STAT_CLR, DCP_STAT_CLEAR);
76693e678edSClement Faure
76793e678edSClement Faure /* Copy context switching buffer address in DCP_CONTEXT register */
76893e678edSClement Faure io_write32(dcp_base + DCP_CONTEXT, (uint32_t)hw_context_buffer.paddr);
76993e678edSClement Faure
77093e678edSClement Faure driver_initialized = true;
77193e678edSClement Faure
77293e678edSClement Faure dcp_clk_enable(false);
77393e678edSClement Faure
77493e678edSClement Faure return ret;
77593e678edSClement Faure }
776