/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) * * Copyright 2008-2016 Freescale Semiconductor Inc. * Copyright 2016 NXP * */ #ifndef __RTA_OPERATION_CMD_H__ #define __RTA_OPERATION_CMD_H__ #if defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 70000) #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif extern enum rta_sec_era rta_sec_era; static inline int __rta_alg_aai_aes(uint16_t aai) { uint16_t aes_mode = aai & OP_ALG_AESA_MODE_MASK; if (aai & OP_ALG_AAI_C2K) { if (rta_sec_era < RTA_SEC_ERA_5) return -1; if ((aes_mode != OP_ALG_AAI_CCM) && (aes_mode != OP_ALG_AAI_GCM)) return -EINVAL; } switch (aes_mode) { case OP_ALG_AAI_CBC_CMAC: case OP_ALG_AAI_CTR_CMAC_LTE: case OP_ALG_AAI_CTR_CMAC: if (rta_sec_era < RTA_SEC_ERA_2) return -EINVAL; /* no break */ case OP_ALG_AAI_CTR: case OP_ALG_AAI_CBC: case OP_ALG_AAI_ECB: case OP_ALG_AAI_OFB: case OP_ALG_AAI_CFB: case OP_ALG_AAI_XTS: case OP_ALG_AAI_CMAC: case OP_ALG_AAI_XCBC_MAC: case OP_ALG_AAI_CCM: case OP_ALG_AAI_GCM: case OP_ALG_AAI_CBC_XCBCMAC: case OP_ALG_AAI_CTR_XCBCMAC: return 0; } return -EINVAL; } static inline int __rta_alg_aai_des(uint16_t aai) { uint16_t aai_code = (uint16_t)(aai & ~OP_ALG_AAI_CHECKODD); switch (aai_code) { case OP_ALG_AAI_CBC: case OP_ALG_AAI_ECB: case OP_ALG_AAI_CFB: case OP_ALG_AAI_OFB: return 0; } return -EINVAL; } static inline int __rta_alg_aai_md5(uint16_t aai) { switch (aai) { case OP_ALG_AAI_HMAC: if (rta_sec_era < RTA_SEC_ERA_2) return -EINVAL; /* no break */ case OP_ALG_AAI_SMAC: case OP_ALG_AAI_HASH: case OP_ALG_AAI_HMAC_PRECOMP: return 0; } return -EINVAL; } static inline int __rta_alg_aai_sha(uint16_t aai) { switch (aai) { case OP_ALG_AAI_HMAC: if (rta_sec_era < RTA_SEC_ERA_2) return -EINVAL; /* no break */ case OP_ALG_AAI_HASH: case OP_ALG_AAI_HMAC_PRECOMP: return 0; } return -EINVAL; } static inline int __rta_alg_aai_rng(uint16_t aai) { uint16_t rng_mode = aai & OP_ALG_RNG_MODE_MASK; uint16_t rng_sh = aai & OP_ALG_AAI_RNG4_SH_MASK; switch (rng_mode) { case OP_ALG_AAI_RNG: case OP_ALG_AAI_RNG_NZB: case OP_ALG_AAI_RNG_OBP: break; default: return -EINVAL; } /* State Handle bits are valid only for SEC Era >= 5 */ if ((rta_sec_era < RTA_SEC_ERA_5) && rng_sh) return -EINVAL; /* PS, AI, SK bits are also valid only for SEC Era >= 5 */ if ((rta_sec_era < RTA_SEC_ERA_5) && (aai & (OP_ALG_AAI_RNG4_PS | OP_ALG_AAI_RNG4_AI | OP_ALG_AAI_RNG4_SK))) return -EINVAL; switch (rng_sh) { case OP_ALG_AAI_RNG4_SH_0: case OP_ALG_AAI_RNG4_SH_1: return 0; } return -EINVAL; } static inline int __rta_alg_aai_crc(uint16_t aai) { uint16_t aai_code = aai & OP_ALG_CRC_POLY_MASK; switch (aai_code) { case OP_ALG_AAI_802: case OP_ALG_AAI_3385: case OP_ALG_AAI_CUST_POLY: return 0; } return -EINVAL; } static inline int __rta_alg_aai_kasumi(uint16_t aai) { switch (aai) { case OP_ALG_AAI_GSM: case OP_ALG_AAI_EDGE: case OP_ALG_AAI_F8: case OP_ALG_AAI_F9: return 0; } return -EINVAL; } static inline int __rta_alg_aai_snow_f9(uint16_t aai) { if (aai == OP_ALG_AAI_F9) return 0; return -EINVAL; } static inline int __rta_alg_aai_snow_f8(uint16_t aai) { if (aai == OP_ALG_AAI_F8) return 0; return -EINVAL; } static inline int __rta_alg_aai_zuce(uint16_t aai) { if (aai == OP_ALG_AAI_F8) return 0; return -EINVAL; } static inline int __rta_alg_aai_zuca(uint16_t aai) { if (aai == OP_ALG_AAI_F9) return 0; return -EINVAL; } struct alg_aai_map { uint32_t chipher_algo; int (*aai_func)(uint16_t); uint32_t class; }; static const struct alg_aai_map alg_table[] = { /*1*/ { OP_ALG_ALGSEL_AES, __rta_alg_aai_aes, OP_TYPE_CLASS1_ALG }, { OP_ALG_ALGSEL_DES, __rta_alg_aai_des, OP_TYPE_CLASS1_ALG }, { OP_ALG_ALGSEL_3DES, __rta_alg_aai_des, OP_TYPE_CLASS1_ALG }, { OP_ALG_ALGSEL_MD5, __rta_alg_aai_md5, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_SHA1, __rta_alg_aai_md5, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_SHA224, __rta_alg_aai_sha, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_SHA256, __rta_alg_aai_sha, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_SHA384, __rta_alg_aai_sha, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_SHA512, __rta_alg_aai_sha, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_RNG, __rta_alg_aai_rng, OP_TYPE_CLASS1_ALG }, /*11*/ { OP_ALG_ALGSEL_CRC, __rta_alg_aai_crc, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_ARC4, NULL, OP_TYPE_CLASS1_ALG }, { OP_ALG_ALGSEL_SNOW_F8, __rta_alg_aai_snow_f8, OP_TYPE_CLASS1_ALG }, /*14*/ { OP_ALG_ALGSEL_KASUMI, __rta_alg_aai_kasumi, OP_TYPE_CLASS1_ALG }, { OP_ALG_ALGSEL_SNOW_F9, __rta_alg_aai_snow_f9, OP_TYPE_CLASS2_ALG }, { OP_ALG_ALGSEL_ZUCE, __rta_alg_aai_zuce, OP_TYPE_CLASS1_ALG }, /*17*/ { OP_ALG_ALGSEL_ZUCA, __rta_alg_aai_zuca, OP_TYPE_CLASS2_ALG } }; /* * Allowed OPERATION algorithms for each SEC Era. * Values represent the number of entries from alg_table[] that are supported. */ static const unsigned int alg_table_sz[] = {14, 15, 15, 15, 17, 17, 11, 17}; static inline int rta_operation(struct program *program, uint32_t cipher_algo, uint16_t aai, uint8_t algo_state, int icv_checking, int enc) { uint32_t opcode = CMD_OPERATION; unsigned int i, found = 0; unsigned int start_pc = program->current_pc; int ret; for (i = 0; i < alg_table_sz[rta_sec_era]; i++) { if (alg_table[i].chipher_algo == cipher_algo) { opcode |= cipher_algo | alg_table[i].class; /* nothing else to verify */ if (alg_table[i].aai_func == NULL) { found = 1; break; } aai &= OP_ALG_AAI_MASK; ret = (*alg_table[i].aai_func)(aai); if (ret < 0) { pr_err("OPERATION: Bad AAI Type. SEC Program Line: %d\n", program->current_pc); goto err; } opcode |= aai; found = 1; break; } } if (!found) { pr_err("OPERATION: Invalid Command. SEC Program Line: %d\n", program->current_pc); ret = -EINVAL; goto err; } switch (algo_state) { case OP_ALG_AS_UPDATE: case OP_ALG_AS_INIT: case OP_ALG_AS_FINALIZE: case OP_ALG_AS_INITFINAL: opcode |= algo_state; break; default: pr_err("Invalid Operation Command\n"); ret = -EINVAL; goto err; } switch (icv_checking) { case ICV_CHECK_DISABLE: /* * opcode |= OP_ALG_ICV_OFF; * OP_ALG_ICV_OFF is 0 */ break; case ICV_CHECK_ENABLE: opcode |= OP_ALG_ICV_ON; break; default: pr_err("Invalid Operation Command\n"); ret = -EINVAL; goto err; } switch (enc) { case DIR_DEC: /* * opcode |= OP_ALG_DECRYPT; * OP_ALG_DECRYPT is 0 */ break; case DIR_ENC: opcode |= OP_ALG_ENCRYPT; break; default: pr_err("Invalid Operation Command\n"); ret = -EINVAL; goto err; } __rta_out32(program, opcode); program->current_instruction++; return (int)start_pc; err: program->first_error_pc = start_pc; return ret; } /* * OPERATION PKHA routines */ static inline int __rta_pkha_clearmem(uint32_t pkha_op) { switch (pkha_op) { case (OP_ALG_PKMODE_CLEARMEM_ALL): case (OP_ALG_PKMODE_CLEARMEM_ABE): case (OP_ALG_PKMODE_CLEARMEM_ABN): case (OP_ALG_PKMODE_CLEARMEM_AB): case (OP_ALG_PKMODE_CLEARMEM_AEN): case (OP_ALG_PKMODE_CLEARMEM_AE): case (OP_ALG_PKMODE_CLEARMEM_AN): case (OP_ALG_PKMODE_CLEARMEM_A): case (OP_ALG_PKMODE_CLEARMEM_BEN): case (OP_ALG_PKMODE_CLEARMEM_BE): case (OP_ALG_PKMODE_CLEARMEM_BN): case (OP_ALG_PKMODE_CLEARMEM_B): case (OP_ALG_PKMODE_CLEARMEM_EN): case (OP_ALG_PKMODE_CLEARMEM_N): case (OP_ALG_PKMODE_CLEARMEM_E): return 0; } return -EINVAL; } static inline int __rta_pkha_mod_arithmetic(uint32_t pkha_op) { pkha_op &= (uint32_t)~OP_ALG_PKMODE_OUT_A; switch (pkha_op) { case (OP_ALG_PKMODE_MOD_ADD): case (OP_ALG_PKMODE_MOD_SUB_AB): case (OP_ALG_PKMODE_MOD_SUB_BA): case (OP_ALG_PKMODE_MOD_MULT): case (OP_ALG_PKMODE_MOD_MULT_IM): case (OP_ALG_PKMODE_MOD_MULT_IM_OM): case (OP_ALG_PKMODE_MOD_EXPO): case (OP_ALG_PKMODE_MOD_EXPO_TEQ): case (OP_ALG_PKMODE_MOD_EXPO_IM): case (OP_ALG_PKMODE_MOD_EXPO_IM_TEQ): case (OP_ALG_PKMODE_MOD_REDUCT): case (OP_ALG_PKMODE_MOD_INV): case (OP_ALG_PKMODE_MOD_MONT_CNST): case (OP_ALG_PKMODE_MOD_CRT_CNST): case (OP_ALG_PKMODE_MOD_GCD): case (OP_ALG_PKMODE_MOD_PRIMALITY): case (OP_ALG_PKMODE_MOD_SML_EXP): case (OP_ALG_PKMODE_F2M_ADD): case (OP_ALG_PKMODE_F2M_MUL): case (OP_ALG_PKMODE_F2M_MUL_IM): case (OP_ALG_PKMODE_F2M_MUL_IM_OM): case (OP_ALG_PKMODE_F2M_EXP): case (OP_ALG_PKMODE_F2M_EXP_TEQ): case (OP_ALG_PKMODE_F2M_AMODN): case (OP_ALG_PKMODE_F2M_INV): case (OP_ALG_PKMODE_F2M_R2): case (OP_ALG_PKMODE_F2M_GCD): case (OP_ALG_PKMODE_F2M_SML_EXP): case (OP_ALG_PKMODE_ECC_F2M_ADD): case (OP_ALG_PKMODE_ECC_F2M_ADD_IM_OM_PROJ): case (OP_ALG_PKMODE_ECC_F2M_DBL): case (OP_ALG_PKMODE_ECC_F2M_DBL_IM_OM_PROJ): case (OP_ALG_PKMODE_ECC_F2M_MUL): case (OP_ALG_PKMODE_ECC_F2M_MUL_TEQ): case (OP_ALG_PKMODE_ECC_F2M_MUL_R2): case (OP_ALG_PKMODE_ECC_F2M_MUL_R2_TEQ): case (OP_ALG_PKMODE_ECC_F2M_MUL_R2_PROJ): case (OP_ALG_PKMODE_ECC_F2M_MUL_R2_PROJ_TEQ): case (OP_ALG_PKMODE_ECC_MOD_ADD): case (OP_ALG_PKMODE_ECC_MOD_ADD_IM_OM_PROJ): case (OP_ALG_PKMODE_ECC_MOD_DBL): case (OP_ALG_PKMODE_ECC_MOD_DBL_IM_OM_PROJ): case (OP_ALG_PKMODE_ECC_MOD_MUL): case (OP_ALG_PKMODE_ECC_MOD_MUL_TEQ): case (OP_ALG_PKMODE_ECC_MOD_MUL_R2): case (OP_ALG_PKMODE_ECC_MOD_MUL_R2_TEQ): case (OP_ALG_PKMODE_ECC_MOD_MUL_R2_PROJ): case (OP_ALG_PKMODE_ECC_MOD_MUL_R2_PROJ_TEQ): return 0; } return -EINVAL; } static inline int __rta_pkha_copymem(uint32_t pkha_op) { switch (pkha_op) { case (OP_ALG_PKMODE_COPY_NSZ_A0_B0): case (OP_ALG_PKMODE_COPY_NSZ_A0_B1): case (OP_ALG_PKMODE_COPY_NSZ_A0_B2): case (OP_ALG_PKMODE_COPY_NSZ_A0_B3): case (OP_ALG_PKMODE_COPY_NSZ_A1_B0): case (OP_ALG_PKMODE_COPY_NSZ_A1_B1): case (OP_ALG_PKMODE_COPY_NSZ_A1_B2): case (OP_ALG_PKMODE_COPY_NSZ_A1_B3): case (OP_ALG_PKMODE_COPY_NSZ_A2_B0): case (OP_ALG_PKMODE_COPY_NSZ_A2_B1): case (OP_ALG_PKMODE_COPY_NSZ_A2_B2): case (OP_ALG_PKMODE_COPY_NSZ_A2_B3): case (OP_ALG_PKMODE_COPY_NSZ_A3_B0): case (OP_ALG_PKMODE_COPY_NSZ_A3_B1): case (OP_ALG_PKMODE_COPY_NSZ_A3_B2): case (OP_ALG_PKMODE_COPY_NSZ_A3_B3): case (OP_ALG_PKMODE_COPY_NSZ_B0_A0): case (OP_ALG_PKMODE_COPY_NSZ_B0_A1): case (OP_ALG_PKMODE_COPY_NSZ_B0_A2): case (OP_ALG_PKMODE_COPY_NSZ_B0_A3): case (OP_ALG_PKMODE_COPY_NSZ_B1_A0): case (OP_ALG_PKMODE_COPY_NSZ_B1_A1): case (OP_ALG_PKMODE_COPY_NSZ_B1_A2): case (OP_ALG_PKMODE_COPY_NSZ_B1_A3): case (OP_ALG_PKMODE_COPY_NSZ_B2_A0): case (OP_ALG_PKMODE_COPY_NSZ_B2_A1): case (OP_ALG_PKMODE_COPY_NSZ_B2_A2): case (OP_ALG_PKMODE_COPY_NSZ_B2_A3): case (OP_ALG_PKMODE_COPY_NSZ_B3_A0): case (OP_ALG_PKMODE_COPY_NSZ_B3_A1): case (OP_ALG_PKMODE_COPY_NSZ_B3_A2): case (OP_ALG_PKMODE_COPY_NSZ_B3_A3): case (OP_ALG_PKMODE_COPY_NSZ_A_E): case (OP_ALG_PKMODE_COPY_NSZ_A_N): case (OP_ALG_PKMODE_COPY_NSZ_B_E): case (OP_ALG_PKMODE_COPY_NSZ_B_N): case (OP_ALG_PKMODE_COPY_NSZ_N_A): case (OP_ALG_PKMODE_COPY_NSZ_N_B): case (OP_ALG_PKMODE_COPY_NSZ_N_E): case (OP_ALG_PKMODE_COPY_SSZ_A0_B0): case (OP_ALG_PKMODE_COPY_SSZ_A0_B1): case (OP_ALG_PKMODE_COPY_SSZ_A0_B2): case (OP_ALG_PKMODE_COPY_SSZ_A0_B3): case (OP_ALG_PKMODE_COPY_SSZ_A1_B0): case (OP_ALG_PKMODE_COPY_SSZ_A1_B1): case (OP_ALG_PKMODE_COPY_SSZ_A1_B2): case (OP_ALG_PKMODE_COPY_SSZ_A1_B3): case (OP_ALG_PKMODE_COPY_SSZ_A2_B0): case (OP_ALG_PKMODE_COPY_SSZ_A2_B1): case (OP_ALG_PKMODE_COPY_SSZ_A2_B2): case (OP_ALG_PKMODE_COPY_SSZ_A2_B3): case (OP_ALG_PKMODE_COPY_SSZ_A3_B0): case (OP_ALG_PKMODE_COPY_SSZ_A3_B1): case (OP_ALG_PKMODE_COPY_SSZ_A3_B2): case (OP_ALG_PKMODE_COPY_SSZ_A3_B3): case (OP_ALG_PKMODE_COPY_SSZ_B0_A0): case (OP_ALG_PKMODE_COPY_SSZ_B0_A1): case (OP_ALG_PKMODE_COPY_SSZ_B0_A2): case (OP_ALG_PKMODE_COPY_SSZ_B0_A3): case (OP_ALG_PKMODE_COPY_SSZ_B1_A0): case (OP_ALG_PKMODE_COPY_SSZ_B1_A1): case (OP_ALG_PKMODE_COPY_SSZ_B1_A2): case (OP_ALG_PKMODE_COPY_SSZ_B1_A3): case (OP_ALG_PKMODE_COPY_SSZ_B2_A0): case (OP_ALG_PKMODE_COPY_SSZ_B2_A1): case (OP_ALG_PKMODE_COPY_SSZ_B2_A2): case (OP_ALG_PKMODE_COPY_SSZ_B2_A3): case (OP_ALG_PKMODE_COPY_SSZ_B3_A0): case (OP_ALG_PKMODE_COPY_SSZ_B3_A1): case (OP_ALG_PKMODE_COPY_SSZ_B3_A2): case (OP_ALG_PKMODE_COPY_SSZ_B3_A3): case (OP_ALG_PKMODE_COPY_SSZ_A_E): case (OP_ALG_PKMODE_COPY_SSZ_A_N): case (OP_ALG_PKMODE_COPY_SSZ_B_E): case (OP_ALG_PKMODE_COPY_SSZ_B_N): case (OP_ALG_PKMODE_COPY_SSZ_N_A): case (OP_ALG_PKMODE_COPY_SSZ_N_B): case (OP_ALG_PKMODE_COPY_SSZ_N_E): return 0; } return -EINVAL; } static inline int rta_pkha_operation(struct program *program, uint32_t op_pkha) { uint32_t opcode = CMD_OPERATION | OP_TYPE_PK | OP_ALG_PK; uint32_t pkha_func; unsigned int start_pc = program->current_pc; int ret = -EINVAL; pkha_func = op_pkha & OP_ALG_PK_FUN_MASK; switch (pkha_func) { case (OP_ALG_PKMODE_CLEARMEM): ret = __rta_pkha_clearmem(op_pkha); if (ret < 0) { pr_err("OPERATION PKHA: Type not supported. SEC Program Line: %d\n", program->current_pc); goto err; } break; case (OP_ALG_PKMODE_MOD_ADD): case (OP_ALG_PKMODE_MOD_SUB_AB): case (OP_ALG_PKMODE_MOD_SUB_BA): case (OP_ALG_PKMODE_MOD_MULT): case (OP_ALG_PKMODE_MOD_EXPO): case (OP_ALG_PKMODE_MOD_REDUCT): case (OP_ALG_PKMODE_MOD_INV): case (OP_ALG_PKMODE_MOD_MONT_CNST): case (OP_ALG_PKMODE_MOD_CRT_CNST): case (OP_ALG_PKMODE_MOD_GCD): case (OP_ALG_PKMODE_MOD_PRIMALITY): case (OP_ALG_PKMODE_MOD_SML_EXP): case (OP_ALG_PKMODE_ECC_MOD_ADD): case (OP_ALG_PKMODE_ECC_MOD_DBL): case (OP_ALG_PKMODE_ECC_MOD_MUL): ret = __rta_pkha_mod_arithmetic(op_pkha); if (ret < 0) { pr_err("OPERATION PKHA: Type not supported. SEC Program Line: %d\n", program->current_pc); goto err; } break; case (OP_ALG_PKMODE_COPY_NSZ): case (OP_ALG_PKMODE_COPY_SSZ): ret = __rta_pkha_copymem(op_pkha); if (ret < 0) { pr_err("OPERATION PKHA: Type not supported. SEC Program Line: %d\n", program->current_pc); goto err; } break; default: pr_err("Invalid Operation Command\n"); goto err; } opcode |= op_pkha; __rta_out32(program, opcode); program->current_instruction++; return (int)start_pc; err: program->first_error_pc = start_pc; program->current_instruction++; return ret; } #endif /* __RTA_OPERATION_CMD_H__ */