Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/***************************************************************************//**
 * @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) */