From f0266e9f6d115c40f8cdd14c1d1207b572f3e7de Mon Sep 17 00:00:00 2001 From: Royyan Zahir Date: Sat, 19 Sep 2026 06:36:54 +0400 Subject: [PATCH 1/2] arch/arm64: implement up_addrenv_va_to_pa(). up_addrenv_va_to_pa() is declared in include/nuttx/arch.h but implemented only by armv7-a, so no arm64 port can map a virtual address to a physical one. A driver whose device addresses memory physically has nothing to call. The translation is asked of the MMU with AT S1E1R rather than walked in software, so it answers for whatever is actually mapped: any granule size, block or page, at any level, and it cannot drift from the tables in use. PAR_EL1 is one register per CPU, so nothing may run between the translation and reading the result. Interrupts are banked with it, so masking them locally is sufficient and SMP needs nothing further. Returns zero for an address that is not mapped for a privileged read, which is what the declaration in arch.h specifies. Note this differs from the armv7-a implementation, which returns the virtual address unchanged. Signed-off-by: Royyan Zahir --- arch/arm64/src/common/CMakeLists.txt | 6 ++ arch/arm64/src/common/Make.defs | 6 ++ arch/arm64/src/common/arm64_physpgaddr.c | 101 +++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 arch/arm64/src/common/arm64_physpgaddr.c diff --git a/arch/arm64/src/common/CMakeLists.txt b/arch/arm64/src/common/CMakeLists.txt index 02c301031d26e..670c9f37a0aa8 100644 --- a/arch/arm64/src/common/CMakeLists.txt +++ b/arch/arm64/src/common/CMakeLists.txt @@ -73,6 +73,12 @@ endif() if(CONFIG_ARCH_HAVE_MMU) list(APPEND SRCS arm64_mmu.c) + + # drivers/misc/addrenv.c defines the same entry points from a table. + + if(NOT CONFIG_DEV_SIMPLE_ADDRENV) + list(APPEND SRCS arm64_physpgaddr.c) + endif() endif() if(CONFIG_ARM64_MTE) diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs index f41ed4f096aff..90d2f89e36e53 100644 --- a/arch/arm64/src/common/Make.defs +++ b/arch/arm64/src/common/Make.defs @@ -80,6 +80,12 @@ endif ifeq ($(CONFIG_ARCH_HAVE_MMU),y) CMN_CSRCS += arm64_mmu.c + +# drivers/misc/addrenv.c defines the same entry points from a table. + +ifneq ($(CONFIG_DEV_SIMPLE_ADDRENV),y) +CMN_CSRCS += arm64_physpgaddr.c +endif endif ifeq ($(CONFIG_ARM64_MTE),y) diff --git a/arch/arm64/src/common/arm64_physpgaddr.c b/arch/arm64/src/common/arm64_physpgaddr.c new file mode 100644 index 0000000000000..9180387fdcc4f --- /dev/null +++ b/arch/arm64/src/common/arm64_physpgaddr.c @@ -0,0 +1,101 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_physpgaddr.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +#include "arm64_arch.h" +#include "arm64_internal.h" + +#ifndef CONFIG_DEV_SIMPLE_ADDRENV + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* PAR_EL1, Physical Address Register. Bit 0 reports a failed translation; + * on success bits [51:12] carry the physical frame. + */ + +#define PAR_F (1ull << 0) +#define PAR_PA_MASK (0x000ffffffffff000ull) +#define VA_PAGE_OFFSET_MASK (0xfffull) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_addrenv_va_to_pa + * + * Description: + * Map a virtual address to its physical address. + * + * The translation is asked of the MMU rather than walked in software, so + * it answers for whatever is actually mapped: any granule size, block or + * page, at any level, and it cannot drift from the tables in use. + * + * Input Parameters: + * va - The virtual address to be mapped. + * + * Returned Value: + * Physical address on success; zero if the address is not mapped for a + * privileged read. + * + ****************************************************************************/ + +uintptr_t up_addrenv_va_to_pa(void *va) +{ + irqstate_t flags; + uint64_t par; + + /* PAR_EL1 is a single register per CPU, so nothing may run between the + * translation and reading the result or it reads someone else's answer. + * Interrupts are banked with it, so masking them locally is enough. + */ + + flags = up_irq_save(); + + __asm__ volatile ("at s1e1r, %0" : : "r" (va) : "memory"); + UP_ISB(); + par = read_sysreg(par_el1); + + up_irq_restore(flags); + + if ((par & PAR_F) != 0) + { + return 0; + } + + return (uintptr_t)((par & PAR_PA_MASK) | + ((uintptr_t)va & VA_PAGE_OFFSET_MASK)); +} + +#endif /* CONFIG_DEV_SIMPLE_ADDRENV */ From 0aacd809df799338c7ea91f636fdb753d4b2aca9 Mon Sep 17 00:00:00 2001 From: Royyan Zahir Date: Sat, 19 Sep 2026 15:16:06 +0400 Subject: [PATCH 2/2] arch/arm64: AES using the Armv8 Cryptography Extension. NuttX emits no AES instruction on any arm64 core. There is no runtime feature dispatch in arch/arm64, so every AES goes through crypto/rijndael.c or crypto/aes.c, and the table-driven one indexes memory with key-dependent values, so its timing follows the cache. Provide aes_cypher() for ECB, CBC and CTR built on AESE, AESD and the MixColumns pair, and register it with /dev/crypto as a hardware driver alongside the existing stm32h7, sam34 and esp32 modules. ID_AA64ISAR0_EL1.AES is read on every call, which returns -ENOTSUP rather than trapping on a core without the extension. Verified against the NIST SP 800-38A appendix F vectors for ECB-128, ECB-256, CBC-128, CBC-192 and CTR-128, encrypt and decrypt, in place and out of place. Signed-off-by: Royyan Zahir --- arch/arm64/Kconfig | 13 + arch/arm64/src/common/CMakeLists.txt | 8 + arch/arm64/src/common/Make.defs | 10 + arch/arm64/src/common/arm64_aes.c | 387 +++++++++++++++++++++++++++ arch/arm64/src/common/arm64_crypto.c | 138 ++++++++++ 5 files changed, 556 insertions(+) create mode 100644 arch/arm64/src/common/arm64_aes.c create mode 100644 arch/arm64/src/common/arm64_crypto.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 84b3c1dfe0361..c3d713af0d0fa 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -229,6 +229,19 @@ config ARCH_AS_HAS_ARMV8_5 menu "ARMv8.5 architectural features" depends on ARCH_AS_HAS_ARMV8_5 +config ARM64_CRYPTO_AES + bool "AES using the Armv8 Cryptography Extension" + select CRYPTO + select CRYPTO_AES + ---help--- + Provide aes_cypher() with AESE, AESD and the MixColumns pair. The + table-driven cipher indexes memory with key-dependent values, so + its timing follows the cache; these instructions do not. + + The core must implement the extension. ID_AA64ISAR0_EL1 is read on + every call, which returns -ENOTSUP rather than trapping if it does + not. + config ARM64_MTE bool "Memory Tagging Extension support" select ARCH_HAVE_MEMTAG diff --git a/arch/arm64/src/common/CMakeLists.txt b/arch/arm64/src/common/CMakeLists.txt index 670c9f37a0aa8..bd53b5aba86f8 100644 --- a/arch/arm64/src/common/CMakeLists.txt +++ b/arch/arm64/src/common/CMakeLists.txt @@ -81,6 +81,14 @@ if(CONFIG_ARCH_HAVE_MMU) endif() endif() +if(CONFIG_ARM64_CRYPTO_AES) + list(APPEND SRCS arm64_aes.c) +endif() + +if(CONFIG_ARM64_CRYPTO_AES AND CONFIG_CRYPTO_CRYPTODEV_HARDWARE) + list(APPEND SRCS arm64_crypto.c) +endif() + if(CONFIG_ARM64_MTE) list(APPEND SRCS arm64_mte.c) endif() diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs index 90d2f89e36e53..4bef36a3b1c9b 100644 --- a/arch/arm64/src/common/Make.defs +++ b/arch/arm64/src/common/Make.defs @@ -88,6 +88,16 @@ CMN_CSRCS += arm64_physpgaddr.c endif endif +ifeq ($(CONFIG_ARM64_CRYPTO_AES),y) +CMN_CSRCS += arm64_aes.c +endif + +ifeq ($(CONFIG_CRYPTO_CRYPTODEV_HARDWARE),y) +ifeq ($(CONFIG_ARM64_CRYPTO_AES),y) +CMN_CSRCS += arm64_crypto.c +endif +endif + ifeq ($(CONFIG_ARM64_MTE),y) CMN_CSRCS += arm64_mte.c endif diff --git a/arch/arm64/src/common/arm64_aes.c b/arch/arm64/src/common/arm64_aes.c new file mode 100644 index 0000000000000..7d44397b1e178 --- /dev/null +++ b/arch/arm64/src/common/arm64_aes.c @@ -0,0 +1,387 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_aes.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* ID_AA64ISAR0_EL1.AES, bits [7:4]. Non-zero means AESE/AESD and the + * MixColumns pair are implemented. + */ + +#define ID_AA64ISAR0_AES_SHIFT 4 +#define ID_AA64ISAR0_AES_MASK 0xful + +#define AES_BLOCK_SIZE 16 +#define AES_MAX_ROUNDS 14 +#define AES_MAX_WORDS (4 * (AES_MAX_ROUNDS + 1)) + +/* The counter occupies the last four bytes of the block, as in + * crypto/xform.c, so both agree on what a CTR stream looks like. + */ + +#define AES_CTR_OFFSET 12 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct arm64_aes_s +{ + uint32_t ek[AES_MAX_WORDS]; + uint32_t dk[AES_MAX_WORDS]; + unsigned rounds; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static bool arm64_aes_present(void) +{ + uint64_t isar0; + + __asm__ volatile ("mrs %0, id_aa64isar0_el1" : "=r" (isar0)); + + return ((isar0 >> ID_AA64ISAR0_AES_SHIFT) & ID_AA64ISAR0_AES_MASK) != 0; +} + +/* Only SubWord is accelerated; the rest of the schedule is ordinary + * arithmetic, so it stays in C. + */ + +static uint32_t arm64_aes_subword(uint32_t in) +{ + uint8_t block[AES_BLOCK_SIZE]; + uint32_t out; + + /* A zero round key leaves AESE doing SubBytes and ShiftRows only, and + * ShiftRows cannot disturb a state whose four columns are identical. + */ + + memcpy(block + 0, &in, 4); + memcpy(block + 4, &in, 4); + memcpy(block + 8, &in, 4); + memcpy(block + 12, &in, 4); + + __asm__ volatile ( + "ld1 {v0.16b}, [%0] \n" + "movi v1.16b, #0 \n" + "aese v0.16b, v1.16b \n" + "st1 {v0.16b}, [%0] \n" + :: "r" (block) : "v0", "v1", "memory"); + + memcpy(&out, block, sizeof(out)); + return out; +} + +static void arm64_aes_encrypt(FAR const struct arm64_aes_s *ctx, + FAR const uint8_t *in, FAR uint8_t *out) +{ + FAR const uint8_t *rk = (FAR const uint8_t *)ctx->ek; + unsigned n = ctx->rounds - 1; + + __asm__ volatile ( + "ld1 {v0.16b}, [%[in]] \n" + "1: \n" + "ld1 {v1.16b}, [%[rk]], #16 \n" + "aese v0.16b, v1.16b \n" + "aesmc v0.16b, v0.16b \n" + "subs %w[n], %w[n], #1 \n" + "b.ne 1b \n" + "ld1 {v1.16b}, [%[rk]], #16 \n" + "aese v0.16b, v1.16b \n" + "ld1 {v1.16b}, [%[rk]] \n" + "eor v0.16b, v0.16b, v1.16b \n" + "st1 {v0.16b}, [%[out]] \n" + : [rk] "+r" (rk), [n] "+r" (n) + : [in] "r" (in), [out] "r" (out) + : "v0", "v1", "cc", "memory"); +} + +static void arm64_aes_decrypt(FAR const struct arm64_aes_s *ctx, + FAR const uint8_t *in, FAR uint8_t *out) +{ + FAR const uint8_t *rk = (FAR const uint8_t *)&ctx->dk[4 * ctx->rounds]; + unsigned n = ctx->rounds - 1; + + __asm__ volatile ( + "ld1 {v0.16b}, [%[in]] \n" + "1: \n" + "ld1 {v1.16b}, [%[rk]] \n" + "sub %[rk], %[rk], #16 \n" + "aesd v0.16b, v1.16b \n" + "aesimc v0.16b, v0.16b \n" + "subs %w[n], %w[n], #1 \n" + "b.ne 1b \n" + "ld1 {v1.16b}, [%[rk]] \n" + "sub %[rk], %[rk], #16 \n" + "aesd v0.16b, v1.16b \n" + "ld1 {v1.16b}, [%[rk]] \n" + "eor v0.16b, v0.16b, v1.16b \n" + "st1 {v0.16b}, [%[out]] \n" + : [rk] "+r" (rk), [n] "+r" (n) + : [in] "r" (in), [out] "r" (out) + : "v0", "v1", "cc", "memory"); +} + +static int arm64_aes_setkey(FAR struct arm64_aes_s *ctx, + FAR const uint8_t *key, size_t len, + bool decrypt) +{ + static const uint8_t rcon[] = + { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 + }; + + unsigned nk; + unsigned words; + unsigned i; + + switch (len) + { + case 16: + ctx->rounds = 10; + break; + + case 24: + ctx->rounds = 12; + break; + + case 32: + ctx->rounds = 14; + break; + + default: + return -EINVAL; + } + + nk = (unsigned)len / 4; + words = 4 * (ctx->rounds + 1); + + memcpy(ctx->ek, key, len); + + for (i = nk; i < words; i++) + { + uint32_t t = ctx->ek[i - 1]; + + if (i % nk == 0) + { + t = (t >> 8) | (t << 24); + t = arm64_aes_subword(t) ^ (uint32_t)rcon[i / nk - 1]; + } + else if (nk > 6 && i % nk == 4) + { + t = arm64_aes_subword(t); + } + + ctx->ek[i] = ctx->ek[i - nk] ^ t; + } + + if (!decrypt) + { + return OK; + } + + /* The equivalent inverse cipher wants InvMixColumns applied to every round + * key except the first and the last, so decryption is the same shape as + * encryption rather than a separate schedule. + */ + + memcpy(ctx->dk, ctx->ek, (size_t)words * 4); + + for (i = 1; i < ctx->rounds; i++) + { + FAR uint8_t *rk = (FAR uint8_t *)&ctx->dk[4 * i]; + + __asm__ volatile ( + "ld1 {v0.16b}, [%0] \n" + "aesimc v0.16b, v0.16b \n" + "st1 {v0.16b}, [%0] \n" + :: "r" (rk) : "v0", "memory"); + } + + return OK; +} + +static void arm64_aes_xor_block(FAR uint8_t *dst, FAR const uint8_t *src) +{ + int i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) + { + dst[i] ^= src[i]; + } +} + +static void arm64_aes_ctr_inc(FAR uint8_t *block) +{ + int i; + + for (i = AES_BLOCK_SIZE - 1; i >= AES_CTR_OFFSET; i--) + { + if (++block[i] != 0) + { + break; + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: aes_cypher + * + * Description: + * Encrypt or decrypt a whole number of AES blocks in ECB, CBC or CTR mode + * using the Armv8 Cryptography Extension. + * + * Returned Value: + * OK, -ENOTSUP on a core without the extension, or -EINVAL for a bad mode, + * key length or size. + * + ****************************************************************************/ + +int aes_cypher(FAR void *out, FAR const void *in, size_t size, + FAR const void *iv, FAR const void *key, size_t keysize, + int mode, int encrypt) +{ + struct arm64_aes_s ctx; + uint8_t chain[AES_BLOCK_SIZE]; + FAR const uint8_t *src = in; + FAR uint8_t *dst = out; + int ret; + + if (!arm64_aes_present()) + { + return -ENOTSUP; + } + + if (size % AES_BLOCK_SIZE != 0) + { + return -EINVAL; + } + + switch (mode & AES_MODE_MASK) + { + case AES_MODE_ECB: + case AES_MODE_CBC: + case AES_MODE_CTR: + break; + + default: + return -EINVAL; + } + + /* CTR runs the cipher forwards in both directions, so it never needs the + * inverse schedule. + */ + + ret = arm64_aes_setkey(&ctx, key, keysize, + !encrypt && (mode & AES_MODE_MASK) != AES_MODE_CTR); + if (ret < 0) + { + return ret; + } + + if (iv != NULL) + { + memcpy(chain, iv, AES_BLOCK_SIZE); + } + else + { + memset(chain, 0, AES_BLOCK_SIZE); + } + + while (size != 0) + { + switch (mode & AES_MODE_MASK) + { + case AES_MODE_ECB: + if (encrypt) + { + arm64_aes_encrypt(&ctx, src, dst); + } + else + { + arm64_aes_decrypt(&ctx, src, dst); + } + break; + + case AES_MODE_CBC: + if (encrypt) + { + memcpy(dst, src, AES_BLOCK_SIZE); + arm64_aes_xor_block(dst, chain); + arm64_aes_encrypt(&ctx, dst, dst); + memcpy(chain, dst, AES_BLOCK_SIZE); + } + else + { + uint8_t prev[AES_BLOCK_SIZE]; + + memcpy(prev, src, AES_BLOCK_SIZE); + arm64_aes_decrypt(&ctx, src, dst); + arm64_aes_xor_block(dst, chain); + memcpy(chain, prev, AES_BLOCK_SIZE); + } + break; + + case AES_MODE_CTR: + { + uint8_t stream[AES_BLOCK_SIZE]; + + arm64_aes_encrypt(&ctx, chain, stream); + memcpy(dst, src, AES_BLOCK_SIZE); + arm64_aes_xor_block(dst, stream); + arm64_aes_ctr_inc(chain); + explicit_bzero(stream, sizeof(stream)); + } + break; + } + + src += AES_BLOCK_SIZE; + dst += AES_BLOCK_SIZE; + size -= AES_BLOCK_SIZE; + } + + explicit_bzero(&ctx, sizeof(ctx)); + explicit_bzero(chain, sizeof(chain)); + return OK; +} diff --git a/arch/arm64/src/common/arm64_crypto.c b/arch/arm64/src/common/arm64_crypto.c new file mode 100644 index 0000000000000..760bb00384567 --- /dev/null +++ b/arch/arm64/src/common/arm64_crypto.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_crypto.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int arm64_crypto_newsession(FAR uint32_t *sid, + FAR struct cryptoini *cri) +{ + if (sid == NULL || cri == NULL) + { + return -EINVAL; + } + + switch (cri->cri_alg) + { + case CRYPTO_AES_CBC: + break; + + case CRYPTO_AES_CTR: + + /* cri_klen counts the trailing nonce, which is not key material. */ + + if ((cri->cri_klen / 8 - AESCTR_NONCESIZE) > 32) + { + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return OK; +} + +static int arm64_crypto_freesession(uint64_t tid) +{ + return OK; +} + +static int arm64_crypto_process(FAR struct cryptop *crp) +{ + FAR struct cryptodesc *crd; + uint8_t iv[AESCTR_BLOCKSIZE]; + + for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) + { + switch (crd->crd_alg) + { + case CRYPTO_AES_CBC: + return aes_cypher(crp->crp_dst, crp->crp_buf, crd->crd_len, + crd->crd_iv, crd->crd_key, crd->crd_klen / 8, + AES_MODE_CBC, + crd->crd_flags & CRD_F_ENCRYPT); + + case CRYPTO_AES_CTR: + memcpy(iv, crd->crd_key + crd->crd_klen / 8 - AESCTR_NONCESIZE, + AESCTR_NONCESIZE); + memcpy(iv + AESCTR_NONCESIZE, crd->crd_iv, AESCTR_IVSIZE); + memset(iv + AESCTR_NONCESIZE + AESCTR_IVSIZE, 0, + AESCTR_BLOCKSIZE - AESCTR_NONCESIZE - AESCTR_IVSIZE); + return aes_cypher(crp->crp_dst, crp->crp_buf, crd->crd_len, + iv, crd->crd_key, + crd->crd_klen / 8 - AESCTR_NONCESIZE, + AES_MODE_CTR, + crd->crd_flags & CRD_F_ENCRYPT); + + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hwcr_init + * + * Description: + * Register the Armv8 AES instructions with /dev/crypto. + * + ****************************************************************************/ + +void hwcr_init(void) +{ + int algs[CRYPTO_ALGORITHM_MAX + 1]; + int hwcr_id; + + hwcr_id = crypto_get_driverid(0); + DEBUGASSERT(hwcr_id >= 0); + + memset(algs, 0, sizeof(algs)); + algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED; + + crypto_register(hwcr_id, algs, arm64_crypto_newsession, + arm64_crypto_freesession, arm64_crypto_process); +}