jlaitine commented on code in PR #20343:
URL: https://github.com/apache/nuttx/pull/20343#discussion_r4116278327
##########
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:
What is the need for 100us udelay here? Previous implementation was just
straight polling. I understand the wish to have the timeout functionality, but
would just e.g. 1us between polls be enough here?
##########
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:
Perhaps just "clean" and invalidate later when reading the resp? Cache being
invalid risks cache prefetch filling cache before the read.
##########
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:
Should probably invalidate cache accross all slots here, before accessing
members like "valid" to be safe?
##########
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:
Are you sure that blobs in cache are up to date without invalidating before
accessing "pending"?
##########
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:
I quess this just needs to be invalidate ( you want the receive buffer to be
invalid before receive, but you don't need to push the existing cache data to
memory if it is dirty ? )
##########
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 comment as above
##########
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:
Just clean?
##########
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:
Just invalidate?
##########
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:
The same comment about 100us delay, perhaps unnecessarily coarse?
--
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]