/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) * * Copyright 2008-2016 Freescale Semiconductor Inc. * Copyright 2016 NXP * */ #ifndef __RTA_KEY_CMD_H__ #define __RTA_KEY_CMD_H__ extern enum rta_sec_era rta_sec_era; /* Allowed encryption flags for each SEC Era */ static const uint32_t key_enc_flags[] = { ENC, ENC | NWB | EKT | TK, ENC | NWB | EKT | TK, ENC | NWB | EKT | TK, ENC | NWB | EKT | TK, ENC | NWB | EKT | TK, ENC | NWB | EKT | TK | PTS, ENC | NWB | EKT | TK | PTS }; static inline int rta_key(struct program *program, uint32_t key_dst, uint32_t encrypt_flags, uint64_t src, uint32_t length, uint32_t flags) { uint32_t opcode = 0; bool is_seq_cmd = false; unsigned int start_pc = program->current_pc; if (encrypt_flags & ~key_enc_flags[rta_sec_era]) { pr_err("KEY: Flag(s) not supported by SEC Era %d\n", USER_SEC_ERA(rta_sec_era)); goto err; } /* write cmd type */ if (flags & SEQ) { opcode = CMD_SEQ_KEY; is_seq_cmd = true; } else { opcode = CMD_KEY; } /* check parameters */ if (is_seq_cmd) { if ((flags & IMMED) || (flags & SGF)) { pr_err("SEQKEY: Invalid flag. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } if ((rta_sec_era <= RTA_SEC_ERA_5) && ((flags & VLF) || (flags & AIDF))) { pr_err("SEQKEY: Flag(s) not supported by SEC Era %d\n", USER_SEC_ERA(rta_sec_era)); goto err; } } else { if ((flags & AIDF) || (flags & VLF)) { pr_err("KEY: Invalid flag. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } if ((flags & SGF) && (flags & IMMED)) { pr_err("KEY: Invalid flag. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } } if ((encrypt_flags & PTS) && ((encrypt_flags & ENC) || (encrypt_flags & NWB) || (key_dst == PKE))) { pr_err("KEY: Invalid flag / destination. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } if (key_dst == AFHA_SBOX) { if (rta_sec_era == RTA_SEC_ERA_7) { pr_err("KEY: AFHA S-box not supported by SEC Era %d\n", USER_SEC_ERA(rta_sec_era)); goto err; } if (flags & IMMED) { pr_err("KEY: Invalid flag. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } /* * Sbox data loaded into the ARC-4 processor must be exactly * 258 bytes long, or else a data sequence error is generated. */ if (length != 258) { pr_err("KEY: Invalid length. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } } /* write key destination and class fields */ switch (key_dst) { case (KEY1): opcode |= KEY_DEST_CLASS1; break; case (KEY2): opcode |= KEY_DEST_CLASS2; break; case (PKE): opcode |= KEY_DEST_CLASS1 | KEY_DEST_PKHA_E; break; case (AFHA_SBOX): opcode |= KEY_DEST_CLASS1 | KEY_DEST_AFHA_SBOX; break; case (MDHA_SPLIT_KEY): opcode |= KEY_DEST_CLASS2 | KEY_DEST_MDHA_SPLIT; break; default: pr_err("KEY: Invalid destination. SEC PC: %d; Instr: %d\n", program->current_pc, program->current_instruction); goto err; } /* write key length */ length &= KEY_LENGTH_MASK; opcode |= length; /* write key command specific flags */ if (encrypt_flags & ENC) { /* Encrypted (black) keys must be padded to 8 bytes (CCM) or * 16 bytes (ECB) depending on EKT bit. AES-CCM encrypted keys * (EKT = 1) have 6-byte nonce and 6-byte MAC after padding. */ opcode |= KEY_ENC; if (encrypt_flags & EKT) { opcode |= KEY_EKT; length = ALIGN(length, 8); length += 12; } else { length = ALIGN(length, 16); } if (encrypt_flags & TK) opcode |= KEY_TK; } if (encrypt_flags & NWB) opcode |= KEY_NWB; if (encrypt_flags & PTS) opcode |= KEY_PTS; /* write general command flags */ if (!is_seq_cmd) { if (flags & IMMED) opcode |= KEY_IMM; if (flags & SGF) opcode |= KEY_SGF; } else { if (flags & AIDF) opcode |= KEY_AIDF; if (flags & VLF) opcode |= KEY_VLF; } __rta_out32(program, opcode); program->current_instruction++; if (flags & IMMED) __rta_inline_data(program, src, flags & __COPY_MASK, length); else __rta_out64(program, program->ps, src); return (int)start_pc; err: program->first_error_pc = start_pc; program->current_instruction++; return -EINVAL; } #endif /* __RTA_KEY_CMD_H__ */