royzah commented on code in PR #20343:
URL: https://github.com/apache/nuttx/pull/20343#discussion_r4116509094
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -171,10 +380,205 @@ static uintptr_t imx9_ele_buffer_pa(void *va)
#endif
}
+/****************************************************************************
+ * Name: imx9_ele_service_request
+ *
+ * Description:
+ * Answer a request the enclave sent while a command of this side's was in
+ * flight. Having been asked to sync a key store it asks back where to put
+ * the blob, then whether it was kept, and the command that provoked those
+ * does not reply until they are answered. An unrecognised request is
+ * refused, so it fails rather than hangs.
+ *
+ ****************************************************************************/
+
+static int imx9_ele_blob_slot(uint32_t id, uint32_t id_ext, bool allocate)
+{
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < ELE_BLOB_SLOTS; i++)
Review Comment:
that's just cpu bookkeeping, the ELE only DMAs into g_ele_blob_data, so
nothing to invalidate
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -83,29 +221,46 @@ struct ele_trng_state
*
****************************************************************************/
-static void imx9_ele_sendmsg(struct ele_msg *msg_ptr)
+static int imx9_ele_wait_tx(int channel)
{
- /* Check that ele is ready to receive */
+ uint32_t waited;
+
+ for (waited = 0; !(getreg32(ELE_MU_TSR) & (1 << channel));
+ waited += ELE_POLL_SLEEP_US)
+ {
+ if (waited >= ELE_REPLY_TIMEOUT_US)
+ {
+ return -ETIMEDOUT;
+ }
- while (!((1) & getreg32(ELE_MU_TSR)));
+ up_udelay(ELE_POLL_SLEEP_US);
Review Comment:
fair, udelay spins anyway. 1us now
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -171,10 +380,205 @@ static uintptr_t imx9_ele_buffer_pa(void *va)
#endif
}
+/****************************************************************************
+ * Name: imx9_ele_service_request
+ *
+ * Description:
+ * Answer a request the enclave sent while a command of this side's was in
+ * flight. Having been asked to sync a key store it asks back where to put
+ * the blob, then whether it was kept, and the command that provoked those
+ * does not reply until they are answered. An unrecognised request is
+ * refused, so it fails rather than hangs.
+ *
+ ****************************************************************************/
+
+static int imx9_ele_blob_slot(uint32_t id, uint32_t id_ext, bool allocate)
+{
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < ELE_BLOB_SLOTS; i++)
+ {
+ if (g_ele_blob[i].valid &&
+ g_ele_blob[i].id == id && g_ele_blob[i].id_ext == id_ext)
+ {
+ return i;
+ }
+
+ if (!g_ele_blob[i].valid && free_slot < 0)
+ {
+ free_slot = i;
+ }
+ }
+
+ return allocate ? free_slot : -1;
+}
+
+static void imx9_ele_service_request(struct ele_msg *req)
+{
+ /* A kilobyte does not belong on the caller's stack. */
+
+ static struct ele_msg rsp;
+ uint32_t handle = req->data[0];
+ uintptr_t paddr;
+ int slot;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.header.version = req->header.version;
+ rsp.header.tag = ELE_RESP_TAG;
+ rsp.header.command = req->header.command;
+
+ rsp.header.size = 2;
+ rsp.data[0] = ELE_STORAGE_FAILURE;
+
+ switch (req->header.command)
+ {
+ case ELE_STORAGE_EXPORT_START:
+
+ /* data[1] is the size it will write; a smaller buffer overruns. */
+
+ slot = imx9_ele_blob_slot(ELE_BLOB_MASTER_ID, 0, true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = ELE_BLOB_MASTER_ID;
+ g_ele_blob[slot].id_ext = 0;
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ /* The enclave writes behind the cache. */
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] + ELE_BLOB_SIZE);
+
+ rsp.header.size = 4;
+ rsp.data[0] = handle;
+ rsp.data[1] = ELE_OK;
+ rsp.data[2] = (uint32_t)paddr;
+ break;
+
+ case ELE_STORAGE_CHUNK_EXPORT:
+
+ /* One key group. data[1] is its size, data[2] and data[3] name it. */
+
+ slot = imx9_ele_blob_slot(req->data[2], req->data[3], true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = req->data[2];
+ g_ele_blob[slot].id_ext = req->data[3];
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
Review Comment:
same, clean
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -171,10 +380,205 @@ static uintptr_t imx9_ele_buffer_pa(void *va)
#endif
}
+/****************************************************************************
+ * Name: imx9_ele_service_request
+ *
+ * Description:
+ * Answer a request the enclave sent while a command of this side's was in
+ * flight. Having been asked to sync a key store it asks back where to put
+ * the blob, then whether it was kept, and the command that provoked those
+ * does not reply until they are answered. An unrecognised request is
+ * refused, so it fails rather than hangs.
+ *
+ ****************************************************************************/
+
+static int imx9_ele_blob_slot(uint32_t id, uint32_t id_ext, bool allocate)
+{
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < ELE_BLOB_SLOTS; i++)
+ {
+ if (g_ele_blob[i].valid &&
+ g_ele_blob[i].id == id && g_ele_blob[i].id_ext == id_ext)
+ {
+ return i;
+ }
+
+ if (!g_ele_blob[i].valid && free_slot < 0)
+ {
+ free_slot = i;
+ }
+ }
+
+ return allocate ? free_slot : -1;
+}
+
+static void imx9_ele_service_request(struct ele_msg *req)
+{
+ /* A kilobyte does not belong on the caller's stack. */
+
+ static struct ele_msg rsp;
+ uint32_t handle = req->data[0];
+ uintptr_t paddr;
+ int slot;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.header.version = req->header.version;
+ rsp.header.tag = ELE_RESP_TAG;
+ rsp.header.command = req->header.command;
+
+ rsp.header.size = 2;
+ rsp.data[0] = ELE_STORAGE_FAILURE;
+
+ switch (req->header.command)
+ {
+ case ELE_STORAGE_EXPORT_START:
+
+ /* data[1] is the size it will write; a smaller buffer overruns. */
+
+ slot = imx9_ele_blob_slot(ELE_BLOB_MASTER_ID, 0, true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = ELE_BLOB_MASTER_ID;
+ g_ele_blob[slot].id_ext = 0;
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ /* The enclave writes behind the cache. */
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
Review Comment:
clean now. the invalidate's already there in EXPORT_FINISH
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -171,10 +380,205 @@ static uintptr_t imx9_ele_buffer_pa(void *va)
#endif
}
+/****************************************************************************
+ * Name: imx9_ele_service_request
+ *
+ * Description:
+ * Answer a request the enclave sent while a command of this side's was in
+ * flight. Having been asked to sync a key store it asks back where to put
+ * the blob, then whether it was kept, and the command that provoked those
+ * does not reply until they are answered. An unrecognised request is
+ * refused, so it fails rather than hangs.
+ *
+ ****************************************************************************/
+
+static int imx9_ele_blob_slot(uint32_t id, uint32_t id_ext, bool allocate)
+{
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < ELE_BLOB_SLOTS; i++)
+ {
+ if (g_ele_blob[i].valid &&
+ g_ele_blob[i].id == id && g_ele_blob[i].id_ext == id_ext)
+ {
+ return i;
+ }
+
+ if (!g_ele_blob[i].valid && free_slot < 0)
+ {
+ free_slot = i;
+ }
+ }
+
+ return allocate ? free_slot : -1;
+}
+
+static void imx9_ele_service_request(struct ele_msg *req)
+{
+ /* A kilobyte does not belong on the caller's stack. */
+
+ static struct ele_msg rsp;
+ uint32_t handle = req->data[0];
+ uintptr_t paddr;
+ int slot;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.header.version = req->header.version;
+ rsp.header.tag = ELE_RESP_TAG;
+ rsp.header.command = req->header.command;
+
+ rsp.header.size = 2;
+ rsp.data[0] = ELE_STORAGE_FAILURE;
+
+ switch (req->header.command)
+ {
+ case ELE_STORAGE_EXPORT_START:
+
+ /* data[1] is the size it will write; a smaller buffer overruns. */
+
+ slot = imx9_ele_blob_slot(ELE_BLOB_MASTER_ID, 0, true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = ELE_BLOB_MASTER_ID;
+ g_ele_blob[slot].id_ext = 0;
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ /* The enclave writes behind the cache. */
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] + ELE_BLOB_SIZE);
+
+ rsp.header.size = 4;
+ rsp.data[0] = handle;
+ rsp.data[1] = ELE_OK;
+ rsp.data[2] = (uint32_t)paddr;
+ break;
+
+ case ELE_STORAGE_CHUNK_EXPORT:
+
+ /* One key group. data[1] is its size, data[2] and data[3] name it. */
+
+ slot = imx9_ele_blob_slot(req->data[2], req->data[3], true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = req->data[2];
+ g_ele_blob[slot].id_ext = req->data[3];
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] + ELE_BLOB_SIZE);
+
+ rsp.header.size = 3;
+ rsp.data[0] = ELE_OK;
+ rsp.data[1] = (uint32_t)paddr;
+ break;
+
+ case ELE_STORAGE_EXPORT_FINISH:
+
+ /* Only the pieces this export wrote are settled by it. */
+
+ for (slot = 0; slot < ELE_BLOB_SLOTS; slot++)
+ {
+ if (!g_ele_blob[slot].pending)
+ {
+ continue;
+ }
+
+ g_ele_blob[slot].pending = false;
+
+ if (req->data[1] != ELE_EXPORT_STATUS_SUCCESS)
+ {
+ g_ele_blob[slot].len = 0;
+ continue;
+ }
+
+ up_invalidate_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] +
+ ELE_BLOB_SIZE);
+
+ g_ele_blob[slot].valid = true;
+ }
+
+ rsp.header.size = 3;
+ rsp.data[0] = handle;
+ rsp.data[1] = ELE_OK;
+ break;
+
+ case ELE_STORAGE_CHUNK_GET:
+
+ /* Not having it is the ordinary first boot, not a failure. */
+
+ slot = imx9_ele_blob_slot(req->data[1], req->data[2], false);
+
+ if (slot < 0)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
Review Comment:
ELE reads here, and blob_put() fills it from the cpu, so invalidate would
nuke it. clean tho
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -577,3 +989,818 @@ int imx9_ele_commit(uint32_t info, uint32_t *response)
return -EIO;
}
+
+/****************************************************************************
+ * Name: imx9_ele_session_open
+ *
+ * Description:
+ * Open an ELE session. Every key store service hangs off one of these, and
+ * the enclave holds it until it is closed.
+ *
+ * Output Parameters:
+ * session - handle for the opened session
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_sab_init
+ *
+ * Description:
+ * Start the enclave's security services. Every key store command answers
+ * "not ready" until this has been done once.
+ *
+ * Output Parameters:
+ * rsp - the raw ELE response word, or NULL
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_update_crc
+ *
+ * Description:
+ * Fill the trailing crc word of a key store command. The enclave refuses
+ * these commands with rating 0xb9 without it. It is the exclusive or of
+ * every word of the message, the header included, except the crc word
+ * itself, which is the last one.
+ *
+ ****************************************************************************/
+
+static void imx9_ele_update_crc(struct ele_msg *msg_ptr)
+{
+ uint32_t *words = (uint32_t *)msg_ptr;
+ uint32_t crc = 0;
+ unsigned int i;
+
+ for (i = 0; i < msg_ptr->header.size - 1; i++)
+ {
+ crc ^= words[i];
+ }
+
+ msg_ptr->data[msg_ptr->header.size - 2] = crc;
+}
+
+int imx9_ele_sab_init(uint32_t *rsp)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1;
+ msg.header.command = ELE_SAB_INIT_REQ;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+int imx9_ele_session_open_rsp(uint32_t *session, uint32_t *rsp)
+{
+ struct ele_session_open_s cmd;
+
+ if (session == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SESSION_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *session = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_session_open(uint32_t *session)
+{
+ return imx9_ele_session_open_rsp(session, NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_session_close
+ *
+ * Description:
+ * Close a session opened by imx9_ele_session_open().
+ *
+ * Input Parameters:
+ * session - the session handle
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_session_close(uint32_t session)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SESSION_CLOSE_REQ;
+ msg.data[0] = session;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_open
+ *
+ * Description:
+ * Open a key store, creating it if asked. A key store is where a generated
+ * key lives, and the private half has no command that returns it.
+ *
+ * Input Parameters:
+ * session - an open session
+ * id - caller-chosen key store identifier
+ * nonce - authentication nonce for the store
+ * flags - ELE_KEY_STORE_FLAG_*, none of them to load an existing store
+ *
+ * Output Parameters:
+ * store - handle for the opened key store
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_open_rsp(uint32_t session, uint32_t id,
+ uint32_t nonce, uint8_t flags,
+ uint32_t *store, uint32_t *rsp)
+{
+ struct ele_key_store_open_s cmd;
+
+ if (store == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.session_handle = session;
+ cmd.key_store_id = id;
+ cmd.auth_nonce = nonce;
+
+ /* Asking for SYNC is asking the enclave to hand the store back. */
+
+ cmd.flags = flags;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_STORE_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *store = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_store_open(uint32_t session, uint32_t id, uint32_t nonce,
+ uint8_t flags, uint32_t *store)
+{
+ return imx9_ele_key_store_open_rsp(session, id, nonce, flags, store,
+ NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_close
+ *
+ * Description:
+ * Close a key store opened by imx9_ele_key_store_open().
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_close(uint32_t store)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_STORE_CLOSE_REQ;
+ msg.data[0] = store;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_mgmt_open / imx9_ele_key_mgmt_close
+ *
+ * Description:
+ * Open a key management service on a key store. Generating a key needs one
+ * of these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_mgmt_open(uint32_t store, uint32_t *mgmt, uint32_t *rsp)
+{
+ struct ele_key_mgmt_open_s cmd;
+
+ if (mgmt == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_MGMT_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *mgmt = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_mgmt_close(uint32_t mgmt)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_MGMT_CLOSE_REQ;
+ msg.data[0] = mgmt;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_generate_key
+ *
+ * Description:
+ * Generate a key pair inside the enclave. The public half is written to
+ * the caller's buffer; the private half stays in the key store and there
+ * is no command that returns it. Withholding the export usage is what
+ * makes that true rather than merely unimplemented.
+ *
+ * Input Parameters:
+ * mgmt - an open key management handle
+ * key_type - ELE_KEY_TYPE_ECC_PAIR_SECP_R1 and friends
+ * key_bits - key size in bits
+ * algo - the one algorithm this key is permitted to perform
+ * lifecycle - the device lifecycle the key may be used in
+ * pubkey - buffer for the public half, cache line aligned and sized
+ * pubkey_len- its length
+ *
+ * Output Parameters:
+ * key_id - identifier of the generated key
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_generate_key(uint32_t mgmt, uint16_t key_type,
+ uint16_t key_bits, uint32_t algo,
+ uint32_t lifecycle,
+ void *pubkey, size_t pubkey_len,
+ uint32_t *key_id, uint32_t *rsp)
+{
+ struct ele_generate_key_s cmd;
+
+ uintptr_t paddr;
+
+ if (pubkey == NULL || key_id == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* A neighbour sharing an end cache line would lose its contents. */
+
+ if (!IS_ALIGNED((uintptr_t)pubkey, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED(pubkey_len, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ paddr = imx9_ele_buffer_pa(pubkey);
+ if (paddr == 0 || paddr > UINT32_MAX - pubkey_len)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_mgmt_handle = mgmt;
+ cmd.public_key_size = (uint16_t)pubkey_len;
+ cmd.key_group = ELE_KEY_GROUP_PERSISTENT;
+ cmd.key_type = key_type;
+ cmd.key_size = key_bits;
+ cmd.key_lifetime = ELE_KEY_LIFETIME_PERSISTENT;
+
+ /* Sign only, and no export: the private half has no way out. */
+
+ cmd.key_usage = ELE_KEY_USAGE_SIGN_HASH;
+ cmd.permitted_algo = algo;
+ cmd.key_lifecycle = lifecycle;
+
+ /* The lifetime is intent; this is what writes the key to the store. */
+
+ cmd.flags = ELE_KEY_FLAG_STRICT;
+ cmd.public_key_addr = (uint32_t)paddr;
+
+ up_flush_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_GENERATE_KEY_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ up_invalidate_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ *key_id = msg.data[1];
+ return 0;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sig_gen_open / imx9_ele_sig_gen_close
+ *
+ * Description:
+ * Open a signature generation service on a key store. Signing needs one of
+ * these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sig_gen_open(uint32_t store, uint32_t *svc, uint32_t *rsp)
+{
+ struct ele_sig_gen_open_s cmd;
+
+ if (svc == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SIG_GEN_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *svc = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_sig_gen_close(uint32_t svc)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SIG_GEN_CLOSE_REQ;
+ msg.data[0] = svc;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sign
+ *
+ * Description:
+ * Sign with a key held in the key store. The key is named by identifier,
+ * never handed over, so this is the only way to use it.
+ *
+ * Input Parameters:
+ * svc - an open signature generation handle
+ * key_id - identifier returned by imx9_ele_generate_key()
+ * algo - the algorithm, which must be the one the key permits
+ * digest - true if input is already hashed, false to let the enclave hash
+ * in - message or digest, cache line aligned
+ * inlen - its length
+ * out - buffer for the signature, cache line aligned
+ * outlen - its length, 2 * key bytes + 1 for ECDSA
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sign(uint32_t svc, uint32_t key_id, uint32_t algo, bool digest,
+ void *in, size_t inlen, void *out, size_t outlen,
+ uint32_t *rsp)
+{
+ struct ele_sign_s cmd;
+
+ uintptr_t in_pa;
+ uintptr_t out_pa;
+ size_t in_span;
+ size_t out_span;
+
+ if (in == NULL || out == NULL || inlen == 0 || outlen == 0)
+ {
+ return -EINVAL;
+ }
+
+ /* A signature is never a whole number of cache lines. */
+
+ if (!IS_ALIGNED((uintptr_t)in, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED((uintptr_t)out, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ in_span = ALIGN_UP(inlen, ARMV8A_DCACHE_LINESIZE);
+ out_span = ALIGN_UP(outlen, ARMV8A_DCACHE_LINESIZE);
+
+ in_pa = imx9_ele_buffer_pa(in);
+ out_pa = imx9_ele_buffer_pa(out);
+ if (in_pa == 0 || out_pa == 0 ||
+ in_pa > UINT32_MAX - inlen || out_pa > UINT32_MAX - outlen)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.sig_gen_handle = svc;
+ cmd.key_identifier = key_id;
+ cmd.message_addr = (uint32_t)in_pa;
+ cmd.signature_addr = (uint32_t)out_pa;
+ cmd.message_size = (uint32_t)inlen;
+ cmd.signature_size = (uint16_t)outlen;
+ cmd.flags = digest ? ELE_SIG_FLAG_INPUT_DIGEST
+ : ELE_SIG_FLAG_INPUT_MESSAGE;
+ cmd.scheme_id = algo;
+
+ up_flush_dcache((uintptr_t)in, (uintptr_t)in + in_span);
+ up_flush_dcache((uintptr_t)out, (uintptr_t)out + out_span);
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SIGNATURE_GEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ up_invalidate_dcache((uintptr_t)out, (uintptr_t)out + out_span);
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_poll_msg
+ *
+ * Description:
+ * Receive a message the enclave sent on its own initiative, rather than a
+ * reply to something this side asked for. Persisting a key store works
+ * that way round: the enclave asks the host to store the blob. Unlike
+ * imx9_ele_receivemsg() this gives up instead of spinning forever, because
+ * a wrong guess about whether a message is coming would otherwise hang the
+ * caller.
+ *
+ * Input Parameters:
+ * timeout_us - how long to wait for the header
+ *
+ * Output Parameters:
+ * msg_ptr - the received message
+ *
+ * Returned Value:
+ * Zero (OK) on success, -ETIMEDOUT if nothing arrived.
+ *
+ ****************************************************************************/
+
+int imx9_ele_poll_msg(struct ele_msg *msg_ptr, uint32_t timeout_us)
+{
+ uint32_t waited;
+ int i;
+
+ if (msg_ptr == NULL)
+ {
+ return -EINVAL;
+ }
+
+ for (waited = 0; !(getreg32(ELE_MU_RSR) & 1); waited += ELE_POLL_SLEEP_US)
+ {
+ if (waited >= timeout_us)
+ {
+ return -ETIMEDOUT;
+ }
+
+ up_udelay(ELE_POLL_SLEEP_US);
Review Comment:
same, 1us
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -171,10 +380,205 @@ static uintptr_t imx9_ele_buffer_pa(void *va)
#endif
}
+/****************************************************************************
+ * Name: imx9_ele_service_request
+ *
+ * Description:
+ * Answer a request the enclave sent while a command of this side's was in
+ * flight. Having been asked to sync a key store it asks back where to put
+ * the blob, then whether it was kept, and the command that provoked those
+ * does not reply until they are answered. An unrecognised request is
+ * refused, so it fails rather than hangs.
+ *
+ ****************************************************************************/
+
+static int imx9_ele_blob_slot(uint32_t id, uint32_t id_ext, bool allocate)
+{
+ int free_slot = -1;
+ int i;
+
+ for (i = 0; i < ELE_BLOB_SLOTS; i++)
+ {
+ if (g_ele_blob[i].valid &&
+ g_ele_blob[i].id == id && g_ele_blob[i].id_ext == id_ext)
+ {
+ return i;
+ }
+
+ if (!g_ele_blob[i].valid && free_slot < 0)
+ {
+ free_slot = i;
+ }
+ }
+
+ return allocate ? free_slot : -1;
+}
+
+static void imx9_ele_service_request(struct ele_msg *req)
+{
+ /* A kilobyte does not belong on the caller's stack. */
+
+ static struct ele_msg rsp;
+ uint32_t handle = req->data[0];
+ uintptr_t paddr;
+ int slot;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.header.version = req->header.version;
+ rsp.header.tag = ELE_RESP_TAG;
+ rsp.header.command = req->header.command;
+
+ rsp.header.size = 2;
+ rsp.data[0] = ELE_STORAGE_FAILURE;
+
+ switch (req->header.command)
+ {
+ case ELE_STORAGE_EXPORT_START:
+
+ /* data[1] is the size it will write; a smaller buffer overruns. */
+
+ slot = imx9_ele_blob_slot(ELE_BLOB_MASTER_ID, 0, true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = ELE_BLOB_MASTER_ID;
+ g_ele_blob[slot].id_ext = 0;
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ /* The enclave writes behind the cache. */
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] + ELE_BLOB_SIZE);
+
+ rsp.header.size = 4;
+ rsp.data[0] = handle;
+ rsp.data[1] = ELE_OK;
+ rsp.data[2] = (uint32_t)paddr;
+ break;
+
+ case ELE_STORAGE_CHUNK_EXPORT:
+
+ /* One key group. data[1] is its size, data[2] and data[3] name it. */
+
+ slot = imx9_ele_blob_slot(req->data[2], req->data[3], true);
+
+ if (slot < 0 || req->data[1] > ELE_BLOB_SIZE)
+ {
+ break;
+ }
+
+ paddr = imx9_ele_buffer_pa(g_ele_blob_data[slot]);
+ if (paddr == 0)
+ {
+ break;
+ }
+
+ g_ele_blob[slot].id = req->data[2];
+ g_ele_blob[slot].id_ext = req->data[3];
+ g_ele_blob[slot].len = req->data[1];
+ g_ele_blob[slot].pending = true;
+
+ up_flush_dcache((uintptr_t)g_ele_blob_data[slot],
+ (uintptr_t)g_ele_blob_data[slot] + ELE_BLOB_SIZE);
+
+ rsp.header.size = 3;
+ rsp.data[0] = ELE_OK;
+ rsp.data[1] = (uint32_t)paddr;
+ break;
+
+ case ELE_STORAGE_EXPORT_FINISH:
+
+ /* Only the pieces this export wrote are settled by it. */
+
+ for (slot = 0; slot < ELE_BLOB_SLOTS; slot++)
+ {
+ if (!g_ele_blob[slot].pending)
Review Comment:
pending is cpu only, data gets invalidated right below
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -577,3 +989,818 @@ int imx9_ele_commit(uint32_t info, uint32_t *response)
return -EIO;
}
+
+/****************************************************************************
+ * Name: imx9_ele_session_open
+ *
+ * Description:
+ * Open an ELE session. Every key store service hangs off one of these, and
+ * the enclave holds it until it is closed.
+ *
+ * Output Parameters:
+ * session - handle for the opened session
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_sab_init
+ *
+ * Description:
+ * Start the enclave's security services. Every key store command answers
+ * "not ready" until this has been done once.
+ *
+ * Output Parameters:
+ * rsp - the raw ELE response word, or NULL
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_update_crc
+ *
+ * Description:
+ * Fill the trailing crc word of a key store command. The enclave refuses
+ * these commands with rating 0xb9 without it. It is the exclusive or of
+ * every word of the message, the header included, except the crc word
+ * itself, which is the last one.
+ *
+ ****************************************************************************/
+
+static void imx9_ele_update_crc(struct ele_msg *msg_ptr)
+{
+ uint32_t *words = (uint32_t *)msg_ptr;
+ uint32_t crc = 0;
+ unsigned int i;
+
+ for (i = 0; i < msg_ptr->header.size - 1; i++)
+ {
+ crc ^= words[i];
+ }
+
+ msg_ptr->data[msg_ptr->header.size - 2] = crc;
+}
+
+int imx9_ele_sab_init(uint32_t *rsp)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1;
+ msg.header.command = ELE_SAB_INIT_REQ;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+int imx9_ele_session_open_rsp(uint32_t *session, uint32_t *rsp)
+{
+ struct ele_session_open_s cmd;
+
+ if (session == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SESSION_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *session = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_session_open(uint32_t *session)
+{
+ return imx9_ele_session_open_rsp(session, NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_session_close
+ *
+ * Description:
+ * Close a session opened by imx9_ele_session_open().
+ *
+ * Input Parameters:
+ * session - the session handle
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_session_close(uint32_t session)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SESSION_CLOSE_REQ;
+ msg.data[0] = session;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_open
+ *
+ * Description:
+ * Open a key store, creating it if asked. A key store is where a generated
+ * key lives, and the private half has no command that returns it.
+ *
+ * Input Parameters:
+ * session - an open session
+ * id - caller-chosen key store identifier
+ * nonce - authentication nonce for the store
+ * flags - ELE_KEY_STORE_FLAG_*, none of them to load an existing store
+ *
+ * Output Parameters:
+ * store - handle for the opened key store
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_open_rsp(uint32_t session, uint32_t id,
+ uint32_t nonce, uint8_t flags,
+ uint32_t *store, uint32_t *rsp)
+{
+ struct ele_key_store_open_s cmd;
+
+ if (store == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.session_handle = session;
+ cmd.key_store_id = id;
+ cmd.auth_nonce = nonce;
+
+ /* Asking for SYNC is asking the enclave to hand the store back. */
+
+ cmd.flags = flags;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_STORE_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *store = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_store_open(uint32_t session, uint32_t id, uint32_t nonce,
+ uint8_t flags, uint32_t *store)
+{
+ return imx9_ele_key_store_open_rsp(session, id, nonce, flags, store,
+ NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_close
+ *
+ * Description:
+ * Close a key store opened by imx9_ele_key_store_open().
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_close(uint32_t store)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_STORE_CLOSE_REQ;
+ msg.data[0] = store;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_mgmt_open / imx9_ele_key_mgmt_close
+ *
+ * Description:
+ * Open a key management service on a key store. Generating a key needs one
+ * of these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_mgmt_open(uint32_t store, uint32_t *mgmt, uint32_t *rsp)
+{
+ struct ele_key_mgmt_open_s cmd;
+
+ if (mgmt == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_MGMT_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *mgmt = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_mgmt_close(uint32_t mgmt)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_MGMT_CLOSE_REQ;
+ msg.data[0] = mgmt;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_generate_key
+ *
+ * Description:
+ * Generate a key pair inside the enclave. The public half is written to
+ * the caller's buffer; the private half stays in the key store and there
+ * is no command that returns it. Withholding the export usage is what
+ * makes that true rather than merely unimplemented.
+ *
+ * Input Parameters:
+ * mgmt - an open key management handle
+ * key_type - ELE_KEY_TYPE_ECC_PAIR_SECP_R1 and friends
+ * key_bits - key size in bits
+ * algo - the one algorithm this key is permitted to perform
+ * lifecycle - the device lifecycle the key may be used in
+ * pubkey - buffer for the public half, cache line aligned and sized
+ * pubkey_len- its length
+ *
+ * Output Parameters:
+ * key_id - identifier of the generated key
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_generate_key(uint32_t mgmt, uint16_t key_type,
+ uint16_t key_bits, uint32_t algo,
+ uint32_t lifecycle,
+ void *pubkey, size_t pubkey_len,
+ uint32_t *key_id, uint32_t *rsp)
+{
+ struct ele_generate_key_s cmd;
+
+ uintptr_t paddr;
+
+ if (pubkey == NULL || key_id == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* A neighbour sharing an end cache line would lose its contents. */
+
+ if (!IS_ALIGNED((uintptr_t)pubkey, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED(pubkey_len, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ paddr = imx9_ele_buffer_pa(pubkey);
+ if (paddr == 0 || paddr > UINT32_MAX - pubkey_len)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_mgmt_handle = mgmt;
+ cmd.public_key_size = (uint16_t)pubkey_len;
+ cmd.key_group = ELE_KEY_GROUP_PERSISTENT;
+ cmd.key_type = key_type;
+ cmd.key_size = key_bits;
+ cmd.key_lifetime = ELE_KEY_LIFETIME_PERSISTENT;
+
+ /* Sign only, and no export: the private half has no way out. */
+
+ cmd.key_usage = ELE_KEY_USAGE_SIGN_HASH;
+ cmd.permitted_algo = algo;
+ cmd.key_lifecycle = lifecycle;
+
+ /* The lifetime is intent; this is what writes the key to the store. */
+
+ cmd.flags = ELE_KEY_FLAG_STRICT;
+ cmd.public_key_addr = (uint32_t)paddr;
+
+ up_flush_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_GENERATE_KEY_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ up_invalidate_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ *key_id = msg.data[1];
+ return 0;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sig_gen_open / imx9_ele_sig_gen_close
+ *
+ * Description:
+ * Open a signature generation service on a key store. Signing needs one of
+ * these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sig_gen_open(uint32_t store, uint32_t *svc, uint32_t *rsp)
+{
+ struct ele_sig_gen_open_s cmd;
+
+ if (svc == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SIG_GEN_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *svc = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_sig_gen_close(uint32_t svc)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SIG_GEN_CLOSE_REQ;
+ msg.data[0] = svc;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sign
+ *
+ * Description:
+ * Sign with a key held in the key store. The key is named by identifier,
+ * never handed over, so this is the only way to use it.
+ *
+ * Input Parameters:
+ * svc - an open signature generation handle
+ * key_id - identifier returned by imx9_ele_generate_key()
+ * algo - the algorithm, which must be the one the key permits
+ * digest - true if input is already hashed, false to let the enclave hash
+ * in - message or digest, cache line aligned
+ * inlen - its length
+ * out - buffer for the signature, cache line aligned
+ * outlen - its length, 2 * key bytes + 1 for ECDSA
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sign(uint32_t svc, uint32_t key_id, uint32_t algo, bool digest,
+ void *in, size_t inlen, void *out, size_t outlen,
+ uint32_t *rsp)
+{
+ struct ele_sign_s cmd;
+
+ uintptr_t in_pa;
+ uintptr_t out_pa;
+ size_t in_span;
+ size_t out_span;
+
+ if (in == NULL || out == NULL || inlen == 0 || outlen == 0)
+ {
+ return -EINVAL;
+ }
+
+ /* A signature is never a whole number of cache lines. */
+
+ if (!IS_ALIGNED((uintptr_t)in, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED((uintptr_t)out, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ in_span = ALIGN_UP(inlen, ARMV8A_DCACHE_LINESIZE);
+ out_span = ALIGN_UP(outlen, ARMV8A_DCACHE_LINESIZE);
+
+ in_pa = imx9_ele_buffer_pa(in);
+ out_pa = imx9_ele_buffer_pa(out);
+ if (in_pa == 0 || out_pa == 0 ||
+ in_pa > UINT32_MAX - inlen || out_pa > UINT32_MAX - outlen)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.sig_gen_handle = svc;
+ cmd.key_identifier = key_id;
+ cmd.message_addr = (uint32_t)in_pa;
+ cmd.signature_addr = (uint32_t)out_pa;
+ cmd.message_size = (uint32_t)inlen;
+ cmd.signature_size = (uint16_t)outlen;
+ cmd.flags = digest ? ELE_SIG_FLAG_INPUT_DIGEST
+ : ELE_SIG_FLAG_INPUT_MESSAGE;
+ cmd.scheme_id = algo;
+
+ up_flush_dcache((uintptr_t)in, (uintptr_t)in + in_span);
Review Comment:
yep
##########
arch/arm64/src/imx9/imx9_ele.c:
##########
@@ -577,3 +989,818 @@ int imx9_ele_commit(uint32_t info, uint32_t *response)
return -EIO;
}
+
+/****************************************************************************
+ * Name: imx9_ele_session_open
+ *
+ * Description:
+ * Open an ELE session. Every key store service hangs off one of these, and
+ * the enclave holds it until it is closed.
+ *
+ * Output Parameters:
+ * session - handle for the opened session
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_sab_init
+ *
+ * Description:
+ * Start the enclave's security services. Every key store command answers
+ * "not ready" until this has been done once.
+ *
+ * Output Parameters:
+ * rsp - the raw ELE response word, or NULL
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_ele_update_crc
+ *
+ * Description:
+ * Fill the trailing crc word of a key store command. The enclave refuses
+ * these commands with rating 0xb9 without it. It is the exclusive or of
+ * every word of the message, the header included, except the crc word
+ * itself, which is the last one.
+ *
+ ****************************************************************************/
+
+static void imx9_ele_update_crc(struct ele_msg *msg_ptr)
+{
+ uint32_t *words = (uint32_t *)msg_ptr;
+ uint32_t crc = 0;
+ unsigned int i;
+
+ for (i = 0; i < msg_ptr->header.size - 1; i++)
+ {
+ crc ^= words[i];
+ }
+
+ msg_ptr->data[msg_ptr->header.size - 2] = crc;
+}
+
+int imx9_ele_sab_init(uint32_t *rsp)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1;
+ msg.header.command = ELE_SAB_INIT_REQ;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+int imx9_ele_session_open_rsp(uint32_t *session, uint32_t *rsp)
+{
+ struct ele_session_open_s cmd;
+
+ if (session == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SESSION_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *session = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_session_open(uint32_t *session)
+{
+ return imx9_ele_session_open_rsp(session, NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_session_close
+ *
+ * Description:
+ * Close a session opened by imx9_ele_session_open().
+ *
+ * Input Parameters:
+ * session - the session handle
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_session_close(uint32_t session)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SESSION_CLOSE_REQ;
+ msg.data[0] = session;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_open
+ *
+ * Description:
+ * Open a key store, creating it if asked. A key store is where a generated
+ * key lives, and the private half has no command that returns it.
+ *
+ * Input Parameters:
+ * session - an open session
+ * id - caller-chosen key store identifier
+ * nonce - authentication nonce for the store
+ * flags - ELE_KEY_STORE_FLAG_*, none of them to load an existing store
+ *
+ * Output Parameters:
+ * store - handle for the opened key store
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_open_rsp(uint32_t session, uint32_t id,
+ uint32_t nonce, uint8_t flags,
+ uint32_t *store, uint32_t *rsp)
+{
+ struct ele_key_store_open_s cmd;
+
+ if (store == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.session_handle = session;
+ cmd.key_store_id = id;
+ cmd.auth_nonce = nonce;
+
+ /* Asking for SYNC is asking the enclave to hand the store back. */
+
+ cmd.flags = flags;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_STORE_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *store = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_store_open(uint32_t session, uint32_t id, uint32_t nonce,
+ uint8_t flags, uint32_t *store)
+{
+ return imx9_ele_key_store_open_rsp(session, id, nonce, flags, store,
+ NULL);
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_store_close
+ *
+ * Description:
+ * Close a key store opened by imx9_ele_key_store_open().
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_store_close(uint32_t store)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_STORE_CLOSE_REQ;
+ msg.data[0] = store;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_key_mgmt_open / imx9_ele_key_mgmt_close
+ *
+ * Description:
+ * Open a key management service on a key store. Generating a key needs one
+ * of these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_key_mgmt_open(uint32_t store, uint32_t *mgmt, uint32_t *rsp)
+{
+ struct ele_key_mgmt_open_s cmd;
+
+ if (mgmt == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_KEY_MGMT_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *mgmt = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_key_mgmt_close(uint32_t mgmt)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_KEY_MGMT_CLOSE_REQ;
+ msg.data[0] = mgmt;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_generate_key
+ *
+ * Description:
+ * Generate a key pair inside the enclave. The public half is written to
+ * the caller's buffer; the private half stays in the key store and there
+ * is no command that returns it. Withholding the export usage is what
+ * makes that true rather than merely unimplemented.
+ *
+ * Input Parameters:
+ * mgmt - an open key management handle
+ * key_type - ELE_KEY_TYPE_ECC_PAIR_SECP_R1 and friends
+ * key_bits - key size in bits
+ * algo - the one algorithm this key is permitted to perform
+ * lifecycle - the device lifecycle the key may be used in
+ * pubkey - buffer for the public half, cache line aligned and sized
+ * pubkey_len- its length
+ *
+ * Output Parameters:
+ * key_id - identifier of the generated key
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_generate_key(uint32_t mgmt, uint16_t key_type,
+ uint16_t key_bits, uint32_t algo,
+ uint32_t lifecycle,
+ void *pubkey, size_t pubkey_len,
+ uint32_t *key_id, uint32_t *rsp)
+{
+ struct ele_generate_key_s cmd;
+
+ uintptr_t paddr;
+
+ if (pubkey == NULL || key_id == NULL)
+ {
+ return -EINVAL;
+ }
+
+ /* A neighbour sharing an end cache line would lose its contents. */
+
+ if (!IS_ALIGNED((uintptr_t)pubkey, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED(pubkey_len, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ paddr = imx9_ele_buffer_pa(pubkey);
+ if (paddr == 0 || paddr > UINT32_MAX - pubkey_len)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_mgmt_handle = mgmt;
+ cmd.public_key_size = (uint16_t)pubkey_len;
+ cmd.key_group = ELE_KEY_GROUP_PERSISTENT;
+ cmd.key_type = key_type;
+ cmd.key_size = key_bits;
+ cmd.key_lifetime = ELE_KEY_LIFETIME_PERSISTENT;
+
+ /* Sign only, and no export: the private half has no way out. */
+
+ cmd.key_usage = ELE_KEY_USAGE_SIGN_HASH;
+ cmd.permitted_algo = algo;
+ cmd.key_lifecycle = lifecycle;
+
+ /* The lifetime is intent; this is what writes the key to the store. */
+
+ cmd.flags = ELE_KEY_FLAG_STRICT;
+ cmd.public_key_addr = (uint32_t)paddr;
+
+ up_flush_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_GENERATE_KEY_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ up_invalidate_dcache((uintptr_t)pubkey, (uintptr_t)pubkey + pubkey_len);
+
+ *key_id = msg.data[1];
+ return 0;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sig_gen_open / imx9_ele_sig_gen_close
+ *
+ * Description:
+ * Open a signature generation service on a key store. Signing needs one of
+ * these, and it is another handle to close.
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sig_gen_open(uint32_t store, uint32_t *svc, uint32_t *rsp)
+{
+ struct ele_sig_gen_open_s cmd;
+
+ if (svc == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.key_store_handle = store;
+
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 1 + (sizeof(cmd) / sizeof(uint32_t));
+ msg.header.command = ELE_SIG_GEN_OPEN_REQ;
+ memcpy(msg.data, &cmd, sizeof(cmd));
+ imx9_ele_update_crc(&msg);
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ if (rsp != NULL)
+ {
+ *rsp = msg.data[0];
+ }
+
+ if ((msg.data[0] & 0xff) != ELE_OK)
+ {
+ return -EIO;
+ }
+
+ *svc = msg.data[1];
+ return 0;
+}
+
+int imx9_ele_sig_gen_close(uint32_t svc)
+{
+ msg.header.version = ELE_VERSION_FW;
+ msg.header.tag = ELE_CMD_TAG;
+ msg.header.size = 2;
+ msg.header.command = ELE_SIG_GEN_CLOSE_REQ;
+ msg.data[0] = svc;
+
+ imx9_ele_sendmsg(&msg);
+ imx9_ele_receivemsg(&msg);
+
+ return ((msg.data[0] & 0xff) == ELE_OK) ? 0 : -EIO;
+}
+
+/****************************************************************************
+ * Name: imx9_ele_sign
+ *
+ * Description:
+ * Sign with a key held in the key store. The key is named by identifier,
+ * never handed over, so this is the only way to use it.
+ *
+ * Input Parameters:
+ * svc - an open signature generation handle
+ * key_id - identifier returned by imx9_ele_generate_key()
+ * algo - the algorithm, which must be the one the key permits
+ * digest - true if input is already hashed, false to let the enclave hash
+ * in - message or digest, cache line aligned
+ * inlen - its length
+ * out - buffer for the signature, cache line aligned
+ * outlen - its length, 2 * key bytes + 1 for ECDSA
+ *
+ * Returned Value:
+ * Zero (OK) is returned for success. A negated errno value is returned on
+ * failure.
+ *
+ ****************************************************************************/
+
+int imx9_ele_sign(uint32_t svc, uint32_t key_id, uint32_t algo, bool digest,
+ void *in, size_t inlen, void *out, size_t outlen,
+ uint32_t *rsp)
+{
+ struct ele_sign_s cmd;
+
+ uintptr_t in_pa;
+ uintptr_t out_pa;
+ size_t in_span;
+ size_t out_span;
+
+ if (in == NULL || out == NULL || inlen == 0 || outlen == 0)
+ {
+ return -EINVAL;
+ }
+
+ /* A signature is never a whole number of cache lines. */
+
+ if (!IS_ALIGNED((uintptr_t)in, ARMV8A_DCACHE_LINESIZE) ||
+ !IS_ALIGNED((uintptr_t)out, ARMV8A_DCACHE_LINESIZE))
+ {
+ return -EINVAL;
+ }
+
+ in_span = ALIGN_UP(inlen, ARMV8A_DCACHE_LINESIZE);
+ out_span = ALIGN_UP(outlen, ARMV8A_DCACHE_LINESIZE);
+
+ in_pa = imx9_ele_buffer_pa(in);
+ out_pa = imx9_ele_buffer_pa(out);
+ if (in_pa == 0 || out_pa == 0 ||
+ in_pa > UINT32_MAX - inlen || out_pa > UINT32_MAX - outlen)
+ {
+ return -EFAULT;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.sig_gen_handle = svc;
+ cmd.key_identifier = key_id;
+ cmd.message_addr = (uint32_t)in_pa;
+ cmd.signature_addr = (uint32_t)out_pa;
+ cmd.message_size = (uint32_t)inlen;
+ cmd.signature_size = (uint16_t)outlen;
+ cmd.flags = digest ? ELE_SIG_FLAG_INPUT_DIGEST
+ : ELE_SIG_FLAG_INPUT_MESSAGE;
+ cmd.scheme_id = algo;
+
+ up_flush_dcache((uintptr_t)in, (uintptr_t)in + in_span);
+ up_flush_dcache((uintptr_t)out, (uintptr_t)out + out_span);
Review Comment:
invalidate would eat whatever shares the tail line. went with an aligned
bounce buffer, fixes the after-invalidate too
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]