blob: e7453b51fc6cf025bc9047e3a3f79d349dc822b3 [file] [log] [blame]
/*******************************************************************************
* (c) Copyright 2012 Microsemi SoC Products Group. All rights reserved.
*
* SmartFusion2 system services.
*
* SVN $Revision: 5615 $
* SVN $Date: 2013-04-05 14:48:10 +0100 (Fri, 05 Apr 2013) $
*/
#include "mss_sys_services.h"
#include "mss_comblk.h"
#include "../../CMSIS/mss_assert.h"
#include <string.h>
/*==============================================================================
*
*/
/*
* Service request command opcodes:
*/
#define DEVICE_CERTIFICATE_REQUEST_CMD 0u
#define SERIAL_NUMBER_REQUEST_CMD 1u
#define FLASH_FREEZE_REQUEST_CMD 2u
#define AES128_REQUEST_CMD 3u
#define USERCODE_REQUEST_CMD 4u
#define DESIGNVER_REQUEST_CMD 5u
#define AES256_REQUEST_CMD 6u
#define KEYTREE_REQUEST_CMD 9u
#define SHA256_REQUEST_CMD 10u
#define HMAC_REQUEST_CMD 12u
#define PPUF_CHALLENGE_RESP_REQUEST_CMD 14u
#define ISP_PROGRAMMING_REQUEST_CMD 21u
#define DIGEST_CHECK_REQUEST_CMD 23u
#define NRBG_SELF_TEST_REQUEST_CMD 40u
#define NRBG_INSTANTIATE_REQUEST_CMD 41u
#define NRBG_GENERATE_REQUEST_CMD 42u
#define NRBG_RESEED_REQUEST_CMD 43u
#define NRBG_UNINSTANTIATE_REQUEST_CMD 44u
#define NRBG_RESET_REQUEST_CMD 45u
#define FLASHFREEZE_SHUTDOWN_CMD 224u
#define ZEROIZATION_REQUEST_CMD 240u
#define POWER_ON_RESET_DIGEST_ERROR_CMD 241u
/*
* System Services requests length:
*/
#define FLASH_FREEZE_REQUEST_LENGTH 2u
/*
* Service response lengths:
*/
#define STANDARD_SERV_RESP_LENGTH 6u
#define SERIAL_NUMBER_SERV_RESP_LENGTH 6u
#define USERCODE_SERV_RESP_LENGTH 6u
#define DESIGNVER_SERV_RESP_LENGTH 6u
#define DEVICE_CERT_SERV_RESP_LENGTH 6u
#define ISP_PROG_SERV_RESP_LENGTH 2u
#define NRBG_RESET_SERV_RESP_LENGTH 2u
#define NRBG_SELF_TEST_SERV_RESP_LENGTH 2u
#define NRBG_UNINST_SERV_RESP_LENGTH 3u
#define DIGEST_CHECK_SERV_RESP_LENGTH 2u
#define FLASH_FREEZE_SERV_RESP_LENGTH 2u
/*
* Non Deterministic Random Bit Generator defines:
*/
#define INVALID_NRBG_HANDLE 0xFFu
/*
* RTC_WAKEUP_CR system register bit masks:
*/
#define RTC_WAKEUP_G4C_EN_MASK 0x00000004u
#define RTC_WAKEUP_FAB_EN_MASK 0x00000002u
/*==============================================================================
* Local functions.
*/
static void request_completion_handler(uint8_t * p_response, uint16_t response_size);
static void signal_request_start(void);
static uint16_t wait_for_request_completion(void);
static uint8_t execute_service
(
uint8_t cmd_opcode,
uint8_t * cmd_params_ptr,
uint8_t * response,
uint16_t response_length
);
static void asynchronous_event_handler(uint8_t event_opcode);
static void write_ptr_value_into_array
(
const uint8_t * pointer,
uint8_t target_array[],
uint32_t array_index
);
/*==============================================================================
* Global variables
*/
static volatile uint8_t g_request_in_progress = 0u;
static volatile uint16_t g_last_response_length = 0u;
static sys_serv_async_event_handler_t g_event_handler = 0;
/*==============================================================================
*
*/
void MSS_SYS_init(sys_serv_async_event_handler_t event_handler)
{
MSS_COMBLK_init(asynchronous_event_handler);
g_event_handler = event_handler;
g_request_in_progress = 0u;
g_last_response_length = 0u;
}
/*==============================================================================
*
*/
static void asynchronous_event_handler(uint8_t event_opcode)
{
if(g_event_handler != 0)
{
switch(event_opcode)
{
case FLASH_FREEZE_SHUTDOWN_OPCODE:
case FLASH_FREEZE_EXIT_OPCODE:
g_event_handler(event_opcode);
break;
default:
/* Ignore all other events. */
break;
}
}
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_get_serial_number
(
uint8_t * p_serial_number
)
{
uint8_t response[SERIAL_NUMBER_SERV_RESP_LENGTH];
uint8_t status;
status = execute_service(SERIAL_NUMBER_REQUEST_CMD,
p_serial_number,
response,
SERIAL_NUMBER_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_get_user_code
(
uint8_t * p_user_code
)
{
uint8_t response[USERCODE_SERV_RESP_LENGTH];
uint8_t status;
status = execute_service(USERCODE_REQUEST_CMD,
p_user_code,
response,
USERCODE_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_get_design_version
(
uint8_t * p_design_version
)
{
uint8_t response[DESIGNVER_SERV_RESP_LENGTH];
uint8_t status;
status = execute_service(DESIGNVER_REQUEST_CMD,
p_design_version,
response,
DESIGNVER_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_get_device_certificate
(
uint8_t * p_device_certificate
)
{
uint8_t response[DEVICE_CERT_SERV_RESP_LENGTH];
uint8_t status;
status = execute_service(DEVICE_CERTIFICATE_REQUEST_CMD,
p_device_certificate,
response,
DEVICE_CERT_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_flash_freeze(uint8_t options)
{
uint8_t status;
uint16_t actual_response_length;
uint8_t flash_freeze_req[FLASH_FREEZE_REQUEST_LENGTH];
uint8_t response[FLASH_FREEZE_SERV_RESP_LENGTH];
/*
* The Flash Freeze system service is not available on M2S050 rev A and rev B.
*/
ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION);
ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION);
/*
* Enable RTC wake-up interrupt to System Controller and FPGA fabric.
*/
SYSREG->RTC_WAKEUP_CR |= (RTC_WAKEUP_G4C_EN_MASK | RTC_WAKEUP_FAB_EN_MASK);
signal_request_start();
flash_freeze_req[0] = FLASH_FREEZE_REQUEST_CMD;
flash_freeze_req[1] = options;
MSS_COMBLK_send_cmd(flash_freeze_req, /* p_cmd */
FLASH_FREEZE_REQUEST_LENGTH, /* cmd_size */
0, /* p_data */
0u, /* data_size */
response, /* p_response */
FLASH_FREEZE_SERV_RESP_LENGTH, /* response_size */
request_completion_handler); /* completion_handler */
actual_response_length = wait_for_request_completion();
if((FLASH_FREEZE_SERV_RESP_LENGTH == actual_response_length) &&
(FLASH_FREEZE_REQUEST_CMD == response[0]))
{
status = response[1];
}
else
{
status = MSS_SYS_UNEXPECTED_ERROR;
}
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
#define AES128_KEY_LENGTH 16u
#define IV_LENGTH 16u
#define AES256_KEY_LENGTH 32u
#define HMAC_KEY_LENGTH 32u
uint8_t MSS_SYS_128bit_aes
(
const uint8_t * key,
const uint8_t * iv,
uint16_t nb_blocks,
uint8_t mode,
uint8_t * dest_addr,
const uint8_t * src_addr)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t params[44];
uint8_t status;
memcpy(&params[0], key, AES128_KEY_LENGTH);
memcpy(&params[16], iv, IV_LENGTH);
params[32] = (uint8_t)nb_blocks;
params[33] = (uint8_t)(nb_blocks >> 8u);
params[34] = mode;
params[35] = 0u;
#if 1
write_ptr_value_into_array(dest_addr, params, 36u);
write_ptr_value_into_array(src_addr, params, 40u);
#else
params[36] = (uint8_t)((uint32_t)dest_addr);
params[37] = (uint8_t)((uint32_t)dest_addr >> 8u);
params[38] = (uint8_t)((uint32_t)dest_addr >> 16u);
params[39] = (uint8_t)((uint32_t)dest_addr >> 24u);
params[40] = (uint8_t)((uint32_t)src_addr);
params[41] = (uint8_t)((uint32_t)src_addr >> 8u);
params[42] = (uint8_t)((uint32_t)src_addr >> 16u);
params[43] = (uint8_t)((uint32_t)src_addr >> 24u);
#endif
status = execute_service(AES128_REQUEST_CMD,
params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_256bit_aes
(
const uint8_t * key,
const uint8_t * iv,
uint16_t nb_blocks,
uint8_t mode,
uint8_t * dest_addr,
const uint8_t * src_addr
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t params[60];
uint8_t status;
memcpy(&params[0], key, AES256_KEY_LENGTH);
memcpy(&params[32], iv, IV_LENGTH);
params[48] = (uint8_t)nb_blocks;
params[49] = (uint8_t)(nb_blocks >> 8u);
params[50] = mode;
params[51] = 0u;
#if 1
write_ptr_value_into_array(dest_addr, params, 52u);
write_ptr_value_into_array(src_addr, params, 56u);
#else
params[52] = (uint8_t)((uint32_t)dest_addr);
params[53] = (uint8_t)((uint32_t)dest_addr >> 8u);
params[54] = (uint8_t)((uint32_t)dest_addr >> 16u);
params[55] = (uint8_t)((uint32_t)dest_addr >> 24u);
params[56] = (uint8_t)((uint32_t)src_addr);
params[57] = (uint8_t)((uint32_t)src_addr >> 8u);
params[58] = (uint8_t)((uint32_t)src_addr >> 16u);
params[59] = (uint8_t)((uint32_t)src_addr >> 24u);
#endif
status = execute_service(AES256_REQUEST_CMD,
params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_sha256
(
const uint8_t * p_data_in,
uint32_t length,
uint8_t * result
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t params[12];
uint8_t status;
params[0] = (uint8_t)((uint32_t)length);
params[1] = (uint8_t)((uint32_t)length >> 8u);
params[2] = (uint8_t)((uint32_t)length >> 16u);
params[3] = (uint8_t)((uint32_t)length >> 24u);
#if 1
write_ptr_value_into_array(result, params, 4u);
write_ptr_value_into_array(p_data_in, params, 8u);
#else
params[4] = (uint8_t)((uint32_t)result);
params[5] = (uint8_t)((uint32_t)result >> 8u);
params[6] = (uint8_t)((uint32_t)result >> 16u);
params[7] = (uint8_t)((uint32_t)result >> 24u);
params[8] = (uint8_t)((uint32_t)p_data_in);
params[9] = (uint8_t)((uint32_t)p_data_in >> 8u);
params[10] = (uint8_t)((uint32_t)p_data_in >> 16u);
params[11] = (uint8_t)((uint32_t)p_data_in >> 24u);
#endif
status = execute_service(SHA256_REQUEST_CMD,
params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_hmac
(
const uint8_t * key,
const uint8_t * p_data_in,
uint32_t length,
uint8_t * p_result
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t params[58];
uint8_t status;
memcpy(&params[0], key, HMAC_KEY_LENGTH);
params[32] = (uint8_t)((uint32_t)length);
params[33] = (uint8_t)((uint32_t)length >> 8u);
params[34] = (uint8_t)((uint32_t)length >> 16u);
params[35] = (uint8_t)((uint32_t)length >> 24u);
#if 1
write_ptr_value_into_array(p_data_in, params, 36u);
write_ptr_value_into_array(p_result, params, 40u);
#else
params[36] = (uint8_t)((uint32_t)p_data_in);
params[37] = (uint8_t)((uint32_t)p_data_in >> 8u);
params[38] = (uint8_t)((uint32_t)p_data_in >> 16u);
params[39] = (uint8_t)((uint32_t)p_data_in >> 24u);
params[40] = (uint8_t)((uint32_t)p_result);
params[41] = (uint8_t)((uint32_t)p_result >> 8u);
params[42] = (uint8_t)((uint32_t)p_result >> 16u);
params[43] = (uint8_t)((uint32_t)p_result >> 24u);
#endif
status = execute_service(HMAC_REQUEST_CMD,
params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_nrbg_self_test(void)
{
uint8_t status;
uint16_t actual_response_length;
uint8_t self_test;
uint8_t response[NRBG_SELF_TEST_SERV_RESP_LENGTH];
signal_request_start();
self_test = NRBG_SELF_TEST_REQUEST_CMD;
MSS_COMBLK_send_cmd(&self_test, /* p_cmd */
sizeof(self_test), /* cmd_size */
0, /* p_data */
0, /* data_size */
response, /* p_response */
NRBG_SELF_TEST_SERV_RESP_LENGTH, /* response_size */
request_completion_handler); /* completion_handler */
actual_response_length = wait_for_request_completion();
if((NRBG_SELF_TEST_SERV_RESP_LENGTH == actual_response_length) &&
(NRBG_SELF_TEST_REQUEST_CMD == response[0]))
{
status = response[1];
}
else
{
status = MSS_SYS_UNEXPECTED_ERROR;
}
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_nrbg_instantiate
(
const uint8_t * personalization_str,
uint16_t personalization_str_length,
uint8_t * p_nrbg_handle
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t intantiate_params[7];
uint8_t status;
#if 1
write_ptr_value_into_array(personalization_str, intantiate_params, 0u);
#else
intantiate_params[0] = (uint8_t)((uint32_t)personalization_str);
intantiate_params[1] = (uint8_t)((uint32_t)personalization_str >> 8u);
intantiate_params[2] = (uint8_t)((uint32_t)personalization_str >> 16u);
intantiate_params[3] = (uint8_t)((uint32_t)personalization_str >> 24u);
#endif
intantiate_params[4] = (uint8_t)personalization_str_length;
intantiate_params[5] = (uint8_t)(personalization_str_length >> 8u);
intantiate_params[6] = INVALID_NRBG_HANDLE;
status = execute_service(NRBG_INSTANTIATE_REQUEST_CMD,
intantiate_params,
response,
STANDARD_SERV_RESP_LENGTH);
if(MSS_SYS_SUCCESS == status)
{
*p_nrbg_handle = intantiate_params[6];
}
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_nrbg_generate
(
const uint8_t * p_requested_data,
const uint8_t * p_additional_input,
uint8_t requested_length,
uint8_t additional_input_length,
uint8_t pr_req,
uint8_t nrbg_handle
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t generate_params[12];
uint8_t status;
#if 1
write_ptr_value_into_array(p_requested_data, generate_params, 0u);
write_ptr_value_into_array(p_additional_input, generate_params, 4u);
#else
generate_params[0] = (uint8_t)((uint32_t)p_requested_data);
generate_params[1] = (uint8_t)((uint32_t)p_requested_data >> 8u);
generate_params[2] = (uint8_t)((uint32_t)p_requested_data >> 16u);
generate_params[3] = (uint8_t)((uint32_t)p_requested_data >> 24u);
generate_params[4] = (uint8_t)((uint32_t)p_additional_input);
generate_params[5] = (uint8_t)((uint32_t)p_additional_input >> 8u);
generate_params[6] = (uint8_t)((uint32_t)p_additional_input >> 16u);
generate_params[7] = (uint8_t)((uint32_t)p_additional_input >> 24u);
#endif
generate_params[8] = requested_length;
generate_params[9] = additional_input_length;
generate_params[10] = pr_req;
generate_params[11] = nrbg_handle;
status = execute_service(NRBG_GENERATE_REQUEST_CMD,
generate_params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_nrbg_reseed
(
const uint8_t * p_additional_input,
uint8_t additional_input_length,
uint8_t nrbg_handle
)
{
uint8_t response[STANDARD_SERV_RESP_LENGTH];
uint8_t params[6];
uint8_t status;
#if 1
write_ptr_value_into_array(p_additional_input, params, 0u);
#else
params[0] = (uint8_t)((uint32_t)p_additional_input);
params[1] = (uint8_t)((uint32_t)p_additional_input >> 8u);
params[2] = (uint8_t)((uint32_t)p_additional_input >> 16u);
params[3] = (uint8_t)((uint32_t)p_additional_input >> 24u);
#endif
params[4] = (uint8_t)additional_input_length;
params[5] = nrbg_handle;
status = execute_service(NRBG_RESEED_REQUEST_CMD,
params,
response,
STANDARD_SERV_RESP_LENGTH);
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_nrbg_uninstantiate
(
uint8_t nrbg_handle
)
{
uint8_t status;
uint16_t actual_response_length;
uint8_t uninstantiate_req[2];
uint8_t response[NRBG_UNINST_SERV_RESP_LENGTH];
signal_request_start();
uninstantiate_req[0] = NRBG_UNINSTANTIATE_REQUEST_CMD;
uninstantiate_req[1] = nrbg_handle;
MSS_COMBLK_send_cmd(uninstantiate_req, /* p_cmd */
sizeof(uninstantiate_req), /* cmd_size */
0, /* p_data */
0, /* data_size */
response, /* p_response */
NRBG_UNINST_SERV_RESP_LENGTH, /* response_size */
request_completion_handler); /* completion_handler */
actual_response_length = wait_for_request_completion();
if((NRBG_UNINST_SERV_RESP_LENGTH == actual_response_length) &&
(NRBG_UNINSTANTIATE_REQUEST_CMD == response[0]))
{
status = response[1];
}
else
{
status = MSS_SYS_UNEXPECTED_ERROR;
}
return status;
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
static uint8_t g_isp_response[ISP_PROG_SERV_RESP_LENGTH];
void (*g_isp_completion_handler)(uint32_t) = 0;
static void isp_sys_completion_handler
(
uint8_t * p_response,
uint16_t length
)
{
if(g_isp_completion_handler != 0)
{
g_isp_completion_handler(p_response[1]);
}
}
void MSS_SYS_start_isp
(
uint8_t mode,
uint32_t (*page_read_handler)(uint8_t const **),
void (*isp_completion_handler)(uint32_t)
)
{
uint8_t isp_prog_request[2];
signal_request_start();
isp_prog_request[0] = ISP_PROGRAMMING_REQUEST_CMD;
isp_prog_request[1] = mode;
g_isp_completion_handler = isp_completion_handler;
MSS_COMBLK_send_paged_cmd(isp_prog_request, /* p_cmd */
sizeof(isp_prog_request), /* cmd_size */
g_isp_response, /* p_response */
ISP_PROG_SERV_RESP_LENGTH, /* response_size */
page_read_handler, /* page_handler */
isp_sys_completion_handler); /* completion_handler */
}
/*==============================================================================
* See mss_sys_services.h for details.
*/
uint8_t MSS_SYS_check_digest
(
uint8_t options
)
{
uint8_t status;
uint16_t actual_response_length;
uint8_t digest_check_req[2];
uint8_t response[DIGEST_CHECK_SERV_RESP_LENGTH];
signal_request_start();
digest_check_req[0] = DIGEST_CHECK_REQUEST_CMD;
digest_check_req[1] = options;
MSS_COMBLK_send_cmd(digest_check_req, /* p_cmd */
sizeof(digest_check_req), /* cmd_size */
0, /* p_data */
0u, /* data_size */
response, /* p_response */
DIGEST_CHECK_SERV_RESP_LENGTH, /* response_size */
request_completion_handler); /* completion_handler */
actual_response_length = wait_for_request_completion();
if((DIGEST_CHECK_SERV_RESP_LENGTH == actual_response_length) &&
(DIGEST_CHECK_REQUEST_CMD == response[0]))
{
status = response[1];
}
else
{
status = MSS_SYS_UNEXPECTED_ERROR;
}
return status;
}
/*==============================================================================
*
*/
static uint8_t execute_service
(
uint8_t cmd_opcode,
uint8_t * cmd_params_ptr,
uint8_t * response,
uint16_t response_length
)
{
uint8_t status;
uint16_t actual_response_length;
signal_request_start();
MSS_COMBLK_send_cmd_with_ptr(cmd_opcode, /* cmd_opcode */
(uint32_t)cmd_params_ptr, /* cmd_params_ptr */
response, /* p_response */
response_length, /* response_size */
request_completion_handler); /* completion_handler */
actual_response_length = wait_for_request_completion();
if((response_length == actual_response_length) && (cmd_opcode == response[0]))
{
status = response[1];
}
else
{
status = MSS_SYS_UNEXPECTED_ERROR;
}
return status;
}
/*==============================================================================
*
*/
static void request_completion_handler
(
uint8_t * p_response,
uint16_t response_size
)
{
g_request_in_progress = 0u;
g_last_response_length = response_size;
}
/*==============================================================================
*
*/
static void signal_request_start(void)
{
/* Wait for current request to complete. */
while(g_request_in_progress)
{
;
}
g_request_in_progress = 1u;
g_last_response_length = 0u;
}
/*==============================================================================
*
*/
static uint16_t wait_for_request_completion(void)
{
while(g_request_in_progress)
{
;
}
return g_last_response_length;
}
/*==============================================================================
*
*/
static void write_ptr_value_into_array
(
const uint8_t * pointer,
uint8_t target_array[],
uint32_t array_index
)
{
target_array[array_index] = (uint8_t)((uint32_t)pointer);
target_array[array_index + 1] = (uint8_t)((uint32_t)pointer >> 8u);
target_array[array_index + 2] = (uint8_t)((uint32_t)pointer >> 16u);
target_array[array_index + 3] = (uint8_t)((uint32_t)pointer >> 24u);
}