From 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:13:47 +0200 Subject: Adding upstream version 2.8.0+dfsg. Signed-off-by: Daniel Baumann --- plat/brcm/board/common/board_arm_trusted_boot.c | 625 ++++++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 plat/brcm/board/common/board_arm_trusted_boot.c (limited to 'plat/brcm/board/common/board_arm_trusted_boot.c') diff --git a/plat/brcm/board/common/board_arm_trusted_boot.c b/plat/brcm/board/common/board_arm_trusted_boot.c new file mode 100644 index 0000000..da18c31 --- /dev/null +++ b/plat/brcm/board/common/board_arm_trusted_boot.c @@ -0,0 +1,625 @@ +/* + * Copyright 2015 - 2020 Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* Weak definition may be overridden in specific platform */ +#pragma weak plat_match_rotpk +#pragma weak plat_get_nv_ctr +#pragma weak plat_set_nv_ctr + +/* SHA256 algorithm */ +#define SHA256_BYTES 32 + +/* ROTPK locations */ +#define ARM_ROTPK_REGS_ID 1 +#define ARM_ROTPK_DEVEL_RSA_ID 2 +#define BRCM_ROTPK_SOTP_RSA_ID 3 + +#if !ARM_ROTPK_LOCATION_ID + #error "ARM_ROTPK_LOCATION_ID not defined" +#endif + +static const unsigned char rotpk_hash_hdr[] = + "\x30\x31\x30\x0D\x06\x09\x60\x86\x48" + "\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; +static const unsigned int rotpk_hash_hdr_len = sizeof(rotpk_hash_hdr) - 1; +static unsigned char rotpk_hash_der[sizeof(rotpk_hash_hdr) - 1 + SHA256_BYTES]; + +#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) +static const unsigned char arm_devel_rotpk_hash[] = + "\xB0\xF3\x82\x09\x12\x97\xD8\x3A" + "\x37\x7A\x72\x47\x1B\xEC\x32\x73" + "\xE9\x92\x32\xE2\x49\x59\xF6\x5E" + "\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA"; +#endif + +#pragma weak plat_rotpk_hash +const unsigned char plat_rotpk_hash[] = + "\xdb\x06\x67\x95\x4f\x88\x2b\x88" + "\x49\xbf\x70\x3f\xde\x50\x4a\x96" + "\xd8\x17\x69\xd4\xa0\x6c\xba\xee" + "\x66\x3e\x71\x82\x2d\x95\x69\xe4"; + +#pragma weak rom_slice +const unsigned char rom_slice[] = + "\x77\x06\xbc\x98\x40\xbe\xfd\xab" + "\x60\x4b\x74\x3c\x9a\xb3\x80\x75" + "\x39\xb6\xda\x27\x07\x2e\x5b\xbf" + "\x5c\x47\x91\xc9\x95\x26\x26\x0c"; + +#if (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID) +static int plat_is_trusted_boot(void) +{ + uint64_t section3_row0_data; + + section3_row0_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); + + if ((section3_row0_data & SOTP_DEVICE_SECURE_CFG0_AB_MASK) == 0) { + INFO("NOT AB\n"); + return 0; + } + + INFO("AB\n"); + return TRUSTED_BOARD_BOOT; +} + +/* + * FAST AUTH is enabled if all following conditions are met: + * - AB part + * - SOTP.DEV != 0 + * - SOTP.CID != 0 + * - SOTP.ENC_DEV_TYPE = ENC_AB_DEV + * - Manuf_debug strap set high + */ +static int plat_fast_auth_enabled(void) +{ + uint32_t chip_state; + uint64_t section3_row0_data; + uint64_t section3_row1_data; + + section3_row0_data = + sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); + section3_row1_data = + sotp_mem_read(SOTP_DEVICE_SECURE_CFG1_ROW, 0); + + chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES); + + if (plat_is_trusted_boot() && + (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_DEV_MASK) && + (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_CID_MASK) && + ((section3_row1_data & SOTP_ENC_DEV_TYPE_MASK) == + SOTP_ENC_DEV_TYPE_AB_DEV) && + (chip_state & SOTP_CHIP_STATES_MANU_DEBUG_MASK)) + return 1; + + return 0; +} +#endif + +/* + * Return the ROTPK hash in the following ASN.1 structure in DER format: + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING + * } + */ +int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, + unsigned int *flags) +{ + uint8_t *dst; + + assert(key_ptr != NULL); + assert(key_len != NULL); + assert(flags != NULL); + + *flags = 0; + + /* Copy the DER header */ + memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len); + dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len]; + +#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) + memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES); +#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID) + uint32_t *src, tmp; + unsigned int words, i; + + /* + * Append the hash from Trusted Root-Key Storage registers. The hash has + * not been written linearly into the registers, so we have to do a bit + * of byte swapping: + * + * 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C + * +---------------------------------------------------------------+ + * | Reg0 | Reg1 | Reg2 | Reg3 | Reg4 | Reg5 | Reg6 | Reg7 | + * +---------------------------------------------------------------+ + * | ... ... | | ... ... | + * | +--------------------+ | +-------+ + * | | | | + * +----------------------------+ +----------------------------+ + * | | | | + * +-------+ | +--------------------+ | + * | | | | + * v v v v + * +---------------------------------------------------------------+ + * | | | + * +---------------------------------------------------------------+ + * 0 15 16 31 + * + * Additionally, we have to access the registers in 32-bit words + */ + words = SHA256_BYTES >> 3; + + /* Swap bytes 0-15 (first four registers) */ + src = (uint32_t *)TZ_PUB_KEY_HASH_BASE; + for (i = 0 ; i < words ; i++) { + tmp = src[words - 1 - i]; + /* Words are read in little endian */ + *dst++ = (uint8_t)((tmp >> 24) & 0xFF); + *dst++ = (uint8_t)((tmp >> 16) & 0xFF); + *dst++ = (uint8_t)((tmp >> 8) & 0xFF); + *dst++ = (uint8_t)(tmp & 0xFF); + } + + /* Swap bytes 16-31 (last four registers) */ + src = (uint32_t *)(TZ_PUB_KEY_HASH_BASE + SHA256_BYTES / 2); + for (i = 0 ; i < words ; i++) { + tmp = src[words - 1 - i]; + *dst++ = (uint8_t)((tmp >> 24) & 0xFF); + *dst++ = (uint8_t)((tmp >> 16) & 0xFF); + *dst++ = (uint8_t)((tmp >> 8) & 0xFF); + *dst++ = (uint8_t)(tmp & 0xFF); + } +#elif (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID) +{ + int i; + int ret = -1; + + /* + * In non-AB mode, we do not read the key. + * In AB mode: + * - The Dauth is in BL11 if SBL is enabled + * - The Dauth is in SOTP if SBL is disabled. + */ + if (plat_is_trusted_boot() == 0) { + + INFO("NON-AB: Do not read DAUTH!\n"); + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + + } else if ((sbl_status() == SBL_ENABLED) && + (mmio_read_32(BL11_DAUTH_BASE) == BL11_DAUTH_ID)) { + + /* Read hash from BL11 */ + INFO("readKeys (DAUTH) from BL11\n"); + + memcpy(dst, + (void *)(BL11_DAUTH_BASE + sizeof(uint32_t)), + SHA256_BYTES); + + for (i = 0; i < SHA256_BYTES; i++) + if (dst[i] != 0) + break; + + if (i >= SHA256_BYTES) + ERROR("Hash not valid from BL11\n"); + else + ret = 0; + + } else if (sotp_key_erased()) { + + memcpy(dst, plat_rotpk_hash, SHA256_BYTES); + + INFO("SOTP erased, Use internal key hash.\n"); + ret = 0; + + } else if (plat_fast_auth_enabled()) { + + INFO("AB DEV: FAST AUTH!\n"); + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + + } else if (!(mmio_read_32(SOTP_STATUS_1) & SOTP_DAUTH_ECC_ERROR_MASK)) { + + /* Read hash from SOTP */ + ret = sotp_read_key(dst, + SHA256_BYTES, + SOTP_DAUTH_ROW, + SOTP_K_HMAC_ROW-1); + + INFO("sotp_read_key (DAUTH): %i\n", ret); + + } else { + + uint64_t row_data; + uint32_t k; + + for (k = 0; k < (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW); k++) { + row_data = sotp_mem_read(SOTP_DAUTH_ROW + k, + SOTP_ROW_NO_ECC); + + if (row_data != 0) + break; + } + + if (k == (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW)) { + INFO("SOTP NOT PROGRAMMED: Do not use DAUTH!\n"); + + if (sotp_mem_read(SOTP_ATF2_CFG_ROW_ID, + SOTP_ROW_NO_ECC) & SOTP_ROMKEY_MASK) { + memcpy(dst, plat_rotpk_hash, SHA256_BYTES); + + INFO("Use internal key hash.\n"); + ret = 0; + } else { + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + } + } else { + INFO("No hash found in SOTP\n"); + } + } + if (ret) + return ret; +} +#endif + + *key_ptr = (void *)rotpk_hash_der; + *key_len = (unsigned int)sizeof(rotpk_hash_der); + *flags |= ROTPK_IS_HASH; + + return 0; +} + +#define SOTP_NUM_BITS_PER_ROW 41 +#define SOTP_NVCTR_ROW_ALL_ONES 0x1ffffffffff +#define SOTP_NVCTR_TRUSTED_IN_USE \ + ((uint64_t)0x3 << (SOTP_NUM_BITS_PER_ROW-2)) +#define SOTP_NVCTR_NON_TRUSTED_IN_USE ((uint64_t)0x3) +#define SOTP_NVCTR_TRUSTED_NEAR_END SOTP_NVCTR_NON_TRUSTED_IN_USE +#define SOTP_NVCTR_NON_TRUSTED_NEAR_END SOTP_NVCTR_TRUSTED_IN_USE + +#define SOTP_NVCTR_ROW_START 64 +#define SOTP_NVCTR_ROW_END 75 + +/* + * SOTP NVCTR are stored in section 10 of SOTP (rows 64-75). + * Each row of SOTP is 41 bits. + * NVCTR's are stored in a bitstream format. + * We are tolerant to consecutive bit errors. + * Trusted NVCTR starts at the top of row 64 in bitstream format. + * Non Trusted NVCTR starts at the bottom of row 75 in reverse bitstream. + * Each row can only be used by 1 of the 2 counters. This is determined + * by 2 zeros remaining at the beginning or end of the last available row. + * If one counter has already starting using a row, the other will be + * prevent from writing to that row. + * + * Example counter values for SOTP programmed below: + * Trusted Counter (rows64-69) = 5 * 41 + 40 = 245 + * NonTrusted Counter (row75-71) = 3 * 41 + 4 = 127 + * 40 39 38 37 36 ..... 5 4 3 2 1 0 + * row 64 1 1 1 1 1 1 1 1 1 1 1 + * row 65 1 1 1 1 1 1 1 1 1 1 1 + * row 66 1 1 1 1 1 1 1 1 1 1 1 + * row 67 1 1 1 1 1 1 1 1 1 1 1 + * row 68 1 1 1 1 1 1 1 1 1 1 1 + * row 69 1 1 1 1 1 1 1 1 1 1 0 + * row 71 0 0 0 0 0 0 0 0 0 0 0 + * row 71 0 0 0 0 0 0 0 0 0 0 0 + * row 71 0 0 0 0 0 0 0 1 1 1 1 + * row 73 1 1 1 1 1 1 1 1 1 1 1 + * row 74 1 1 1 1 1 1 1 1 1 1 1 + * row 75 1 1 1 1 1 1 1 1 1 1 1 + * + */ + +#if (DEBUG == 1) +/* + * Dump sotp rows + */ +void sotp_dump_rows(uint32_t start_row, uint32_t end_row) +{ + int32_t rownum; + uint64_t rowdata; + + for (rownum = start_row; rownum <= end_row; rownum++) { + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + INFO("%d 0x%" PRIx64 "\n", rownum, rowdata); + } +} +#endif + +/* + * Get SOTP Trusted nvctr + */ +unsigned int sotp_get_trusted_nvctr(void) +{ + uint64_t rowdata; + uint64_t nextrowdata; + uint32_t rownum; + unsigned int nvctr; + + rownum = SOTP_NVCTR_ROW_START; + nvctr = SOTP_NUM_BITS_PER_ROW; + + /* + * Determine what row has last valid data for trusted ctr + */ + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + while ((rowdata & SOTP_NVCTR_TRUSTED_IN_USE) && + (rowdata & SOTP_NVCTR_TRUSTED_NEAR_END) && + (rownum < SOTP_NVCTR_ROW_END)) { + /* + * Current row in use and has data in last 2 bits as well. + * Check if next row also has data for this counter + */ + nextrowdata = sotp_mem_read(rownum+1, SOTP_ROW_NO_ECC); + if (nextrowdata & SOTP_NVCTR_TRUSTED_IN_USE) { + /* Next row also has data so increment rownum */ + rownum++; + nvctr += SOTP_NUM_BITS_PER_ROW; + rowdata = nextrowdata; + } else { + /* Next row does not have data */ + break; + } + } + + if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) { + while ((rowdata & 0x1) == 0) { + nvctr--; + rowdata >>= 1; + } + } else + nvctr -= SOTP_NUM_BITS_PER_ROW; + + INFO("CTR %i\n", nvctr); + return nvctr; +} + +/* + * Get SOTP NonTrusted nvctr + */ +unsigned int sotp_get_nontrusted_nvctr(void) +{ + uint64_t rowdata; + uint64_t nextrowdata; + uint32_t rownum; + unsigned int nvctr; + + nvctr = SOTP_NUM_BITS_PER_ROW; + rownum = SOTP_NVCTR_ROW_END; + + /* + * Determine what row has last valid data for nontrusted ctr + */ + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + while ((rowdata & SOTP_NVCTR_NON_TRUSTED_NEAR_END) && + (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) && + (rownum > SOTP_NVCTR_ROW_START)) { + /* + * Current row in use and has data in last 2 bits as well. + * Check if next row also has data for this counter + */ + nextrowdata = sotp_mem_read(rownum-1, SOTP_ROW_NO_ECC); + if (nextrowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) { + /* Next row also has data so decrement rownum */ + rownum--; + nvctr += SOTP_NUM_BITS_PER_ROW; + rowdata = nextrowdata; + } else { + /* Next row does not have data */ + break; + } + } + + if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) { + while ((rowdata & ((uint64_t)0x1 << (SOTP_NUM_BITS_PER_ROW-1))) + == + 0) { + nvctr--; + rowdata <<= 1; + } + } else + nvctr -= SOTP_NUM_BITS_PER_ROW; + + INFO("NCTR %i\n", nvctr); + return nvctr; +} + +/* + * Set SOTP Trusted nvctr + */ +int sotp_set_trusted_nvctr(unsigned int nvctr) +{ + int numrows_available; + uint32_t nontrusted_rownum; + uint32_t trusted_rownum; + uint64_t rowdata; + unsigned int maxnvctr; + + /* + * Read SOTP to find out how many rows are used by the + * NON Trusted nvctr + */ + nontrusted_rownum = SOTP_NVCTR_ROW_END; + do { + rowdata = sotp_mem_read(nontrusted_rownum, SOTP_ROW_NO_ECC); + if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) + nontrusted_rownum--; + else + break; + } while (nontrusted_rownum >= SOTP_NVCTR_ROW_START); + + /* + * Calculate maximum value we can have for nvctr based on + * number of available rows. + */ + numrows_available = nontrusted_rownum - SOTP_NVCTR_ROW_START + 1; + maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW; + if (maxnvctr) { + /* + * Last 2 bits of counter can't be written or it will + * overflow with nontrusted counter + */ + maxnvctr -= 2; + } + + if (nvctr > maxnvctr) { + /* Error - not enough room */ + WARN("tctr not set\n"); + return 1; + } + + /* + * It is safe to write the nvctr, fill all 1's up to the + * last row and then fill the last row with partial bitstream + */ + trusted_rownum = SOTP_NVCTR_ROW_START; + rowdata = SOTP_NVCTR_ROW_ALL_ONES; + + while (nvctr >= SOTP_NUM_BITS_PER_ROW) { + sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata); + nvctr -= SOTP_NUM_BITS_PER_ROW; + trusted_rownum++; + } + rowdata <<= (SOTP_NUM_BITS_PER_ROW - nvctr); + sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata); + return 0; +} + +/* + * Set SOTP NonTrusted nvctr + */ +int sotp_set_nontrusted_nvctr(unsigned int nvctr) +{ + int numrows_available; + uint32_t nontrusted_rownum; + uint32_t trusted_rownum; + uint64_t rowdata; + unsigned int maxnvctr; + + /* + * Read SOTP to find out how many rows are used by the + * Trusted nvctr + */ + trusted_rownum = SOTP_NVCTR_ROW_START; + do { + rowdata = sotp_mem_read(trusted_rownum, SOTP_ROW_NO_ECC); + if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) + trusted_rownum++; + else + break; + } while (trusted_rownum <= SOTP_NVCTR_ROW_END); + + /* + * Calculate maximum value we can have for nvctr based on + * number of available rows. + */ + numrows_available = SOTP_NVCTR_ROW_END - trusted_rownum + 1; + maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW; + if (maxnvctr) { + /* + * Last 2 bits of counter can't be written or it will + * overflow with nontrusted counter + */ + maxnvctr -= 2; + } + + if (nvctr > maxnvctr) { + /* Error - not enough room */ + WARN("nctr not set\n"); + return 1; + } + + /* + * It is safe to write the nvctr, fill all 1's up to the + * last row and then fill the last row with partial bitstream + */ + nontrusted_rownum = SOTP_NVCTR_ROW_END; + rowdata = SOTP_NVCTR_ROW_ALL_ONES; + + while (nvctr >= SOTP_NUM_BITS_PER_ROW) { + sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata); + nvctr -= SOTP_NUM_BITS_PER_ROW; + nontrusted_rownum--; + } + rowdata >>= (SOTP_NUM_BITS_PER_ROW - nvctr); + sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata); + return 0; +} + +/* + * Return the non-volatile counter value stored in the platform. The cookie + * will contain the OID of the counter in the certificate. + * + * Return: 0 = success, Otherwise = error + */ +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) +{ + const char *oid; + + assert(cookie != NULL); + assert(nv_ctr != NULL); + + *nv_ctr = 0; + if ((sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) & + SOTP_ATF_NVCOUNTER_ENABLE_MASK)) { + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) + *nv_ctr = sotp_get_trusted_nvctr(); + else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) + *nv_ctr = sotp_get_nontrusted_nvctr(); + else + return 1; + } + return 0; +} + +/* + * Store a new non-volatile counter value. + * + * Return: 0 = success, Otherwise = error + */ +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) +{ + const char *oid; + + if (sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) & + SOTP_ATF_NVCOUNTER_ENABLE_MASK) { + INFO("set CTR %i\n", nv_ctr); + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) + return sotp_set_trusted_nvctr(nv_ctr); + else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) + return sotp_set_nontrusted_nvctr(nv_ctr); + return 1; + } + return 0; +} + +int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) +{ + return get_mbedtls_heap_helper(heap_addr, heap_size); +} -- cgit v1.2.3