blob: 2c21a58db04ba6876d5f60b8e0430382747612fe [file] [log] [blame]
/***************************************************************************//**
* @file em_se.c
* @brief Secure Element API
* @version 5.6.0
*******************************************************************************
* # License
* <b>Copyright 2017 Silicon Laboratories, Inc. http://www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.@n
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.@n
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#include "em_device.h"
#if defined(SEMAILBOX_PRESENT)
#include "em_se.h"
#include "em_assert.h"
/***************************************************************************//**
* @addtogroup emlib
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup SE
* @{
******************************************************************************/
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Add input data to a command
*
* @details
* This function adds a buffer of input data to the given SE command structure
* The buffer gets appended by reference at the end of the list of already
* added buffers.
*
* @note
* Note that this function does not copy either the data buffer or the buffer
* structure, so make sure to keep the data object in scope until the command
* has been executed by the secure element.
*
* @param[in] command
* Pointer to an SE command structure.
*
* @param[in] data
* Pointer to a data transfer structure.
******************************************************************************/
void SE_addDataInput(SE_Command_t *command, SE_DataTransfer_t *data)
{
if (command->data_in == NULL) {
command->data_in = data;
} else {
SE_DataTransfer_t *next = command->data_in;
while (next->next != (void*)SE_DATATRANSFER_STOP) {
next = (SE_DataTransfer_t*)next->next;
}
next->next = data;
}
}
/***************************************************************************//**
* @brief
* Add output data to a command
*
* @details
* This function adds a buffer of output data to the given SE command structure
* The buffer gets appended by reference at the end of the list of already
* added buffers.
*
* @note
* Note that this function does not copy either the data buffer or the buffer
* structure, so make sure to keep the data object in scope until the command
* has been executed by the secure element.
*
* @param[in] command
* Pointer to an SE command structure.
*
* @param[in] data
* Pointer to a data transfer structure.
******************************************************************************/
void SE_addDataOutput(SE_Command_t *command,
SE_DataTransfer_t *data)
{
if (command->data_out == NULL) {
command->data_out = data;
} else {
SE_DataTransfer_t *next = command->data_out;
while (next->next != (void*)SE_DATATRANSFER_STOP) {
next = (SE_DataTransfer_t*)next->next;
}
next->next = data;
}
}
/***************************************************************************//**
* @brief
* Add a parameter to a command
*
* @details
* This function adds a parameter word to the passed command.
*
* @note
* Make sure to not exceed @ref SE_MAX_PARAMETERS.
*
* @param[in] command
* Pointer to a filled-out SE command structure.
* @param[in] parameter
* Parameter to add.
******************************************************************************/
void SE_addParameter(SE_Command_t *command, uint32_t parameter)
{
if (command->num_parameters >= SE_MAX_PARAMETERS) {
EFM_ASSERT(command->num_parameters < SE_MAX_PARAMETERS);
return;
}
command->parameters[command->num_parameters] = parameter;
command->num_parameters += 1;
}
/***************************************************************************//**
* @brief
* Execute the passed command
*
* @details
* This function starts the execution of the passed command by the secure
* element. When started, wait for the RXINT interrupt flag, or call
* @ref SE_waitCommandCompletion to busy-wait. After completion, you have to
* call @ref SE_readCommandResponse to get the command's execution status.
*
* @param[in] command
* Pointer to a filled-out SE command structure.
******************************************************************************/
void SE_executeCommand(SE_Command_t *command)
{
// Don't overflow our struct
if (command->num_parameters > SE_MAX_PARAMETERS) {
EFM_ASSERT(command->num_parameters <= SE_MAX_PARAMETERS);
return;
}
// Wait for room available in the mailbox
while (!(SEMAILBOX_HOST->TX_STATUS & SEMAILBOX_TX_STATUS_TXINT)) ;
// Write header to start transaction
SEMAILBOX_HOST->TX_HEADER = sizeof(uint32_t) * (4 + command->num_parameters);
// Write command into FIFO
SEMAILBOX_HOST->FIFO[0].DATA = command->command;
// Write DMA descriptors into FIFO
SEMAILBOX_HOST->FIFO[0].DATA = (uint32_t)command->data_in;
SEMAILBOX_HOST->FIFO[0].DATA = (uint32_t)command->data_out;
// Write applicable parameters into FIFO
for (size_t i = 0; i < command->num_parameters; i++) {
SEMAILBOX_HOST->FIFO[0].DATA = command->parameters[i];
}
return;
}
/***************************************************************************//**
* @brief
* Writes data to User Data section in MTP. Write data must be aligned to words
* and contain a number of bytes that is divisable by four.
* @note
* It is recommended to erase the flash page before performing a write.
*
* @param[in] offset
* Offset to the flash word to write to. Must be aligned to words.
* @param[in] data
* Data to write to flash.
* @param[in] numBytes
* Number of bytes to write to flash. NB: Must be divisable by four.
* @return
* One of the SE_RESPONSE return codes:
* SE_RESPONSE_OK when the command was executed successfully or a signature
* was successfully verified,
* SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
* SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
* SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
* SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command, e.g.
* because of conflicting Secure/Non-Secure memory accesses,
* SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
* SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
******************************************************************************/
SE_Response_t SE_writeUserData(uint32_t offset,
void *data,
uint32_t numBytes)
{
/* SE command structures */
SE_Command_t command = SE_COMMAND_DEFAULT(SE_COMMAND_WRITE_USER_DATA);
SE_DataTransfer_t userData = SE_DATATRANSFER_DEFAULT(data, numBytes);
SE_addDataInput(&command, &userData);
SE_addParameter(&command, offset);
SE_addParameter(&command, numBytes);
SE_executeCommand(&command);
SE_Response_t res = SE_readCommandResponse();
return res;
}
/***************************************************************************//**
* @brief
* Erases User Data section in MTP.
* @return
* One of the SE_RESPONSE return codes:
* SE_RESPONSE_OK when the command was executed successfully or a signature
* was successfully verified,
* SE_RESPONSE_INVALID_COMMAND when the command ID was not recognized,
* SE_RESPONSE_AUTHORIZATION_ERROR when the command is not authorized,
* SE_RESPONSE_INVALID_SIGNATURE when signature verification failed,
* SE_RESPONSE_BUS_ERROR when a bus error was thrown during the command, e.g.
* because of conflicting Secure/Non-Secure memory accesses,
* SE_RESPONSE_CRYPTO_ERROR on an internal SE failure, or
* SE_RESPONSE_INVALID_PARAMETER when an invalid parameter was passed
******************************************************************************/
SE_Response_t SE_eraseUserData()
{
/* SE command structures */
SE_Command_t command = SE_COMMAND_DEFAULT(SE_COMMAND_ERASE_USER_DATA);
SE_addParameter(&command, SE_COMMAND_OPTION_ERASE_UD);
SE_executeCommand(&command);
SE_Response_t res = SE_readCommandResponse();
return res;
}
/** @} (end addtogroup SE) */
/** @} (end addtogroup emlib) */
#endif /* defined(SEMAILBOX_PRESENT) */