blob: 71bc260c087aeee3543c3c4213b42e846c0807ee [file] [log] [blame]
#line 2 "suites/target_test.function"
#include "greentea-client/test_env.h"
/**
* \brief Increments pointer and asserts that it does not overflow.
*
* \param p Pointer to byte array
* \param start Pointer to start of byte array
* \param len Length of byte array
* \param step Increment size
*
*/
#define INCR_ASSERT(p, start, len, step) \
do { \
TEST_HELPER_ASSERT((p) >= (start)); \
TEST_HELPER_ASSERT(sizeof(*(p)) == sizeof(*(start))); \
/* <= is checked to support use inside a loop where \
pointer is incremented after reading data. */ \
TEST_HELPER_ASSERT((uint32_t)(((p) - (start)) + (step)) <= (len)); \
(p) += (step); \
} while (0)
/**
* \brief 4 byte align unsigned char pointer
*
* \param p Pointer to byte array
* \param start Pointer to start of byte array
* \param len Length of byte array
*
*/
#define ALIGN_32BIT(p, start, len) \
do { \
uint32_t align = (-(uintptr_t)(p)) % 4; \
INCR_ASSERT((p), (start), (len), align); \
} while (0)
/**
* \brief Verify dependencies. Dependency identifiers are
* encoded in the buffer as 8 bit unsigned integers.
*
* \param count Number of dependencies.
* \param dep_p Pointer to buffer.
*
* \return DEPENDENCY_SUPPORTED if success else DEPENDENCY_NOT_SUPPORTED.
*/
int verify_dependencies(uint8_t count, uint8_t *dep_p)
{
uint8_t i;
for (i = 0; i < count; i++) {
if (dep_check((int)(dep_p[i])) != DEPENDENCY_SUPPORTED)
return DEPENDENCY_NOT_SUPPORTED;
}
return DEPENDENCY_SUPPORTED;
}
/**
* \brief Receives hex string on serial interface, and converts to a byte.
*
* \param none
*
* \return unsigned int8
*/
uint8_t receive_byte()
{
uint8_t byte;
uint8_t c[3];
size_t len;
c[0] = greentea_getc();
c[1] = greentea_getc();
c[2] = '\0';
TEST_HELPER_ASSERT(mbedtls_test_unhexify(&byte, sizeof(byte), c, &len) ==
0);
TEST_HELPER_ASSERT(len != 2);
return byte;
}
/**
* \brief Receives unsigned integer on serial interface.
* Integers are encoded in network order, and sent as hex ascii string.
*
* \param none
*
* \return unsigned int
*/
uint32_t receive_uint32()
{
uint32_t value;
size_t len;
const uint8_t c_be[8] = { greentea_getc(), greentea_getc(), greentea_getc(),
greentea_getc(), greentea_getc(), greentea_getc(),
greentea_getc(), greentea_getc() };
const uint8_t c[9] = { c_be[6], c_be[7], c_be[4], c_be[5], c_be[2],
c_be[3], c_be[0], c_be[1], '\0' };
TEST_HELPER_ASSERT(
mbedtls_test_unhexify((uint8_t *)&value, sizeof(value), c, &len) == 0);
TEST_HELPER_ASSERT(len != 8);
return value;
}
/**
* \brief Parses out an unsigned 32 int value from the byte array.
* Integers are encoded in network order.
*
* \param p Pointer to byte array
*
* \return unsigned int
*/
uint32_t parse_uint32(uint8_t *p)
{
uint32_t value;
value = *p++ << 24;
value |= *p++ << 16;
value |= *p++ << 8;
value |= *p;
return value;
}
/**
* \brief Receives test data on serial as greentea key,value pair:
* {{<length>;<byte array>}}
*
* \param data_len Out pointer to hold received data length.
*
* \return Byte array.
*/
uint8_t *receive_data(uint32_t *data_len)
{
uint32_t i = 0, errors = 0;
char c;
uint8_t *data = NULL;
/* Read opening braces */
i = 0;
while (i < 2) {
c = greentea_getc();
/* Ignore any prevous CR LF characters */
if (c == '\n' || c == '\r')
continue;
i++;
if (c != '{')
return NULL;
}
/* Read data length */
*data_len = receive_uint32();
data = (uint8_t *)malloc(*data_len);
TEST_HELPER_ASSERT(data != NULL);
greentea_getc(); // read ';' received after key i.e. *data_len
for (i = 0; i < *data_len; i++)
data[i] = receive_byte();
/* Read closing braces */
for (i = 0; i < 2; i++) {
c = greentea_getc();
if (c != '}') {
errors++;
break;
}
}
if (errors) {
free(data);
data = NULL;
*data_len = 0;
}
return data;
}
/**
* \brief Parse the received byte array and count the number of arguments
* to the test function passed as type hex.
*
* \param count Parameter count
* \param data Received Byte array
* \param data_len Byte array length
*
* \return count of hex params
*/
uint32_t find_hex_count(uint8_t count, uint8_t *data, uint32_t data_len)
{
uint32_t i = 0, sz = 0;
char c;
uint8_t *p = NULL;
uint32_t hex_count = 0;
p = data;
for (i = 0; i < count; i++) {
c = (char)*p;
INCR_ASSERT(p, data, data_len, 1);
/* Align p to 4 bytes for int, expression, string len or hex length */
ALIGN_32BIT(p, data, data_len);
/* Network to host conversion */
sz = (int32_t)parse_uint32(p);
INCR_ASSERT(p, data, data_len, sizeof(int32_t));
if (c == 'H' || c == 'S') {
INCR_ASSERT(p, data, data_len, sz);
hex_count += (c == 'H') ? 1 : 0;
}
}
return hex_count;
}
/**
* \brief Parses received byte array for test parameters.
*
* \param count Parameter count
* \param data Received Byte array
* \param data_len Byte array length
* \param error Parsing error out variable.
*
* \return Array of parsed parameters allocated on heap.
* Note: Caller has the responsibility to delete
* the memory after use.
*/
void **
parse_parameters(uint8_t count, uint8_t *data, uint32_t data_len, int *error)
{
uint32_t i = 0, hex_count = 0;
char c;
void **params = NULL;
void **cur = NULL;
uint8_t *p = NULL;
hex_count = find_hex_count(count, data, data_len);
params = (void **)malloc(sizeof(void *) * (count + hex_count));
TEST_HELPER_ASSERT(params != NULL);
cur = params;
p = data;
/* Parameters */
for (i = 0; i < count; i++) {
c = (char)*p;
INCR_ASSERT(p, data, data_len, 1);
/* Align p to 4 bytes for int, expression, string len or hex length */
ALIGN_32BIT(p, data, data_len);
/* Network to host conversion */
*((int32_t *)p) = (int32_t)parse_uint32(p);
switch (c) {
case 'E':
{
if (get_expression(*((int32_t *)p), (int32_t *)p)) {
*error = KEY_VALUE_MAPPING_NOT_FOUND;
goto exit;
}
} /* Intentional fall through */
case 'I':
{
*cur++ = (void *)p;
INCR_ASSERT(p, data, data_len, sizeof(int32_t));
}
break;
case 'H': /* Intentional fall through */
case 'S':
{
uint32_t *sz = (uint32_t *)p;
INCR_ASSERT(p, data, data_len, sizeof(int32_t));
*cur++ = (void *)p;
if (c == 'H')
*cur++ = (void *)sz;
INCR_ASSERT(p, data, data_len, (*sz));
}
break;
default:
{
*error = DISPATCH_INVALID_TEST_DATA;
goto exit;
}
break;
}
}
exit:
if (*error) {
free(params);
params = NULL;
}
return params;
}
/**
* \brief Sends greentea key and int value pair to host.
*
* \param key key string
* \param value integer value
*
* \return void
*/
void send_key_integer(char *key, int value)
{
char str[50];
snprintf(str, sizeof(str), "%d", value);
greentea_send_kv(key, str);
}
/**
* \brief Sends test setup failure to the host.
*
* \param failure Test set failure
*
* \return void
*/
void send_failure(int failure)
{
send_key_integer("F", failure);
}
/**
* \brief Sends test status to the host.
*
* \param status Test status (PASS=0/FAIL=!0)
*
* \return void
*/
void send_status(int status)
{
send_key_integer("R", status);
}
/**
* \brief Embedded implementation of execute_tests().
* Ignores command line and received test data
* on serial.
*
* \param argc not used
* \param argv not used
*
* \return Program exit status.
*/
int execute_tests(int args, const char **argv)
{
int ret = 0;
uint32_t data_len = 0;
uint8_t count = 0, function_id;
void **params = NULL;
uint8_t *data = NULL, *p = NULL;
GREENTEA_SETUP(800, "mbedtls_test");
greentea_send_kv("GO", " ");
while (1) {
ret = 0;
mbedtls_test_info_reset();
data_len = 0;
data = receive_data(&data_len);
if (data == NULL)
continue;
p = data;
do {
/* Read dependency count */
count = *p;
TEST_HELPER_ASSERT(count < data_len);
INCR_ASSERT(p, data, data_len, sizeof(uint8_t));
ret = verify_dependencies(count, p);
if (ret != DEPENDENCY_SUPPORTED)
break;
if (count)
INCR_ASSERT(p, data, data_len, count);
/* Read function id */
function_id = *p;
INCR_ASSERT(p, data, data_len, sizeof(uint8_t));
if ((ret = check_test(function_id)) != DISPATCH_TEST_SUCCESS)
break;
/* Read number of parameters */
count = *p;
INCR_ASSERT(p, data, data_len, sizeof(uint8_t));
/* Parse parameters if present */
if (count) {
params =
parse_parameters(count, p, data_len - (p - data), &ret);
if (ret)
break;
}
ret = dispatch_test(function_id, params);
} while (0);
if (data) {
free(data);
data = NULL;
}
if (params) {
free(params);
params = NULL;
}
if (ret)
send_failure(ret);
else
send_status(mbedtls_test_info.result);
}
return 0;
}