Add hw TRNG from SEL0 SP
Intgrates the FVP TRNG into the crypto sp to provide a hw
entropy source. Includes tests that check SP device
region configuration loading and MMIO access within the
region.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ia9af8b044596e1c7d194f039fdf64c2468bb3221
diff --git a/components/app/remote-test-runner/remote_test_runner.cpp b/components/app/remote-test-runner/remote_test_runner.cpp
index 681c746..b819779 100644
--- a/components/app/remote-test-runner/remote_test_runner.cpp
+++ b/components/app/remote-test-runner/remote_test_runner.cpp
@@ -136,6 +136,8 @@
else if (results[i].run_state == TEST_RUN_STATE_FAILED) {
printf("error\n");
+ printf("\tline number: %d\n", results[i].failure.line_num);
+ printf("\tinfo: 0x%016lx\n", results[i].failure.info);
}
else {
diff --git a/components/config/interface/platform_config.h b/components/config/interface/platform_config.h
index d11f0eb..3f7eb94 100644
--- a/components/config/interface/platform_config.h
+++ b/components/config/interface/platform_config.h
@@ -46,6 +46,13 @@
*/
int platform_config_device_add(const struct device_region *device_region);
+/**
+ * \brief Returns a count of the number of device regions
+ *
+ * \return 0 if successful
+ */
+unsigned int platform_config_device_region_count(void);
+
#ifdef __cplusplus
}
diff --git a/components/config/loader/sp/component.cmake b/components/config/loader/sp/component.cmake
new file mode 100644
index 0000000..82b9fbd
--- /dev/null
+++ b/components/config/loader/sp/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sp_config_loader.c"
+ )
+
diff --git a/components/config/loader/sp/sp_config_loader.c b/components/config/loader/sp/sp_config_loader.c
new file mode 100644
index 0000000..a1c8804
--- /dev/null
+++ b/components/config/loader/sp/sp_config_loader.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <string.h>
+#include <config/interface/platform_config.h>
+#include <platform/interface/device_region.h>
+#include "sp_config_loader.h"
+
+
+struct sp_param_device_region
+{
+ char name[16];
+ uintptr_t location;
+ size_t size;
+};
+
+/**
+ * Loads externally provided configuration data originating from
+ * theh SP manifest.
+ */
+void sp_config_load(struct ffa_init_info *init_info)
+{
+ /* Load deployment specific configuration */
+ for (size_t param_index = 0; param_index < init_info->count; param_index++) {
+
+ if (!strcmp((const char *)init_info->nvp[param_index].name,"DEVICE_REGIONS")) {
+
+ struct sp_param_device_region *d = (struct sp_param_device_region *)init_info->nvp[param_index].value;
+
+ /*Iterate over the device regions*/
+ while ((uintptr_t)d < (init_info->nvp[param_index].value + init_info->nvp[param_index].size)) {
+
+ struct device_region device_region;
+
+ strcpy(device_region.dev_class, d->name);
+ device_region.dev_instance = 0;
+ device_region.base_addr = d->location;
+ device_region.io_region_size = d->size;
+
+ platform_config_device_add(&device_region);
+
+ ++d;
+ }
+ }
+ }
+}
diff --git a/components/config/loader/sp/sp_config_loader.h b/components/config/loader/sp/sp_config_loader.h
new file mode 100644
index 0000000..a1c8bf0
--- /dev/null
+++ b/components/config/loader/sp/sp_config_loader.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP_CONFIG_LOADER_H
+#define SP_CONFIG_LOADER_H
+
+#include <ffa_api.h>
+
+/**
+ * Loads the secure partition specific configuration passed as
+ * SP initialization parameters.
+ */
+void sp_config_load(struct ffa_init_info *init_info);
+
+
+#endif /* SP_CONFIG_LOADER_H */
diff --git a/components/config/ramstore/config_ramstore.c b/components/config/ramstore/config_ramstore.c
index 548ba4b..2e24645 100644
--- a/components/config/ramstore/config_ramstore.c
+++ b/components/config/ramstore/config_ramstore.c
@@ -114,3 +114,18 @@
{
free(device_region);
}
+
+unsigned int platform_config_device_region_count(void)
+{
+ unsigned int count = 0;
+
+ const struct config_container *container = ramstore.device_region_list;
+
+ while (container) {
+
+ ++count;
+ container = container->next;
+ }
+
+ return count;
+}
diff --git a/components/config/ramstore/test/ramstore_tests.cpp b/components/config/ramstore/test/ramstore_tests.cpp
index c597b57..aadb62b 100644
--- a/components/config/ramstore/test/ramstore_tests.cpp
+++ b/components/config/ramstore/test/ramstore_tests.cpp
@@ -38,7 +38,7 @@
/* This would be external configuration, obtained say from device tree */
strcpy(config.dev_class, "fs");
config.dev_instance = 2;
- config.base_addr = (uint8_t*)0x0f000010;
+ config.base_addr = (uintptr_t)0x0f000010;
config.io_region_size = 0x100;
/* Add the configuration object */
@@ -65,7 +65,7 @@
strcpy(config1.dev_class, "flash");
config1.dev_instance = 0;
- config1.base_addr = (uint8_t*)0x0f000010;
+ config1.base_addr = (uintptr_t)0x0f000010;
config1.io_region_size = 0x100;
status = platform_config_device_add(&config1);
@@ -76,12 +76,14 @@
strcpy(config2.dev_class, "flash");
config2.dev_instance = 1;
- config2.base_addr = (uint8_t*)0x0f000010;
+ config2.base_addr = (uintptr_t)0x0f000010;
config2.io_region_size = 0x100;
status = platform_config_device_add(&config2);
CHECK_EQUAL(0, status);
+ CHECK_EQUAL(2, platform_config_device_region_count());
+
/* Expect queries for both objects to work */
struct device_region *query1_result = platform_config_device_query(config1.dev_class, config1.dev_instance);
CHECK(query1_result);
diff --git a/components/config/test/sp/component.cmake b/components/config/test/sp/component.cmake
new file mode 100644
index 0000000..9869e73
--- /dev/null
+++ b/components/config/test/sp/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/sp_config_tests.c"
+ )
+
diff --git a/components/config/test/sp/sp_config_tests.c b/components/config/test/sp/sp_config_tests.c
new file mode 100644
index 0000000..94ba268
--- /dev/null
+++ b/components/config/test/sp/sp_config_tests.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <service/test_runner/provider/backend/simple_c/simple_c_test_runner.h>
+#include <config/interface/platform_config.h>
+#include <stdint.h>
+
+/**
+ * Secure Partition configuration tests for checking configuartion
+ * data passed to an SP at initialisation. These tests assume
+ * use of the FFA manifest for any SP deployments of
+ * deployments/env_test.
+ */
+
+/*
+ * Check that the loaded configuration includes one or more
+ * device regions.
+ */
+static bool check_device_region_loaded(struct test_failure *failure)
+{
+ return platform_config_device_region_count() > 0;
+}
+
+/*
+ * Check that a device region for a 'trng' device has been loaded
+ * and that values are as expected.
+ */
+static bool check_trng_device_region_loaded(struct test_failure *failure)
+{
+ bool passed = false;
+ struct device_region *dev_region = platform_config_device_query("trng", 0);
+
+ if (dev_region) {
+
+ passed =
+ (dev_region->dev_instance == 0) &&
+ (dev_region->io_region_size == 0x1000);
+ }
+
+ platform_config_device_query_free(dev_region);
+
+ return passed;
+}
+
+/*
+ * Check access to some trng registers
+ */
+static bool check_trng_register_access(struct test_failure *failure)
+{
+ bool passed = false;
+
+ struct device_region *dev_region = platform_config_device_query("trng", 0);
+
+ if (dev_region) {
+
+ /* Expect reset values to be read from a selection of TRNG registers */
+ uint32_t reg_val;
+ passed = true;
+
+ /* PID4 */
+ if (passed) {
+ reg_val = *((volatile uint32_t*)((uint8_t*)dev_region->base_addr + 0xfd0));
+ passed = (reg_val == 0x00000004);
+ failure->line_num = __LINE__;
+ failure->info = reg_val;
+ }
+
+ /* PID0 */
+ if (passed) {
+ reg_val = *((volatile uint32_t*)((uint8_t*)dev_region->base_addr + 0xfe0));
+ passed = (reg_val == 0x000000aa);
+ failure->line_num = __LINE__;
+ failure->info = reg_val;
+ }
+ }
+
+ return passed;
+}
+
+
+/**
+ * Define an register test group
+ */
+void sp_config_tests_register(void)
+{
+ static const struct simple_c_test_case sp_config_tests[] = {
+ {.name = "DevRegionLoaded", .test_func = check_device_region_loaded},
+ {.name = "TrngDevRegionLoaded", .test_func = check_trng_device_region_loaded},
+ {.name = "TrngRegAccess", .test_func = check_trng_register_access}
+ };
+
+ static const struct simple_c_test_group sp_config_test_group =
+ {
+ .group = "SpConfigTests",
+ .num_test_cases = sizeof(sp_config_tests)/sizeof(struct simple_c_test_case),
+ .test_cases = sp_config_tests
+ };
+
+ simple_c_test_runner_register_group(&sp_config_test_group);
+}
\ No newline at end of file
diff --git a/components/config/test/sp/sp_config_tests.h b/components/config/test/sp/sp_config_tests.h
new file mode 100644
index 0000000..516d2b1
--- /dev/null
+++ b/components/config/test/sp/sp_config_tests.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP_CONFIG_TESTS_H
+#define SP_CONFIG_TESTS_H
+
+void sp_config_tests_register(void);
+
+#endif /* SP_CONFIG_TESTS_H */
diff --git a/components/service/crypto/provider/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c b/components/service/crypto/provider/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
index 29628d1..1b9f1d2 100644
--- a/components/service/crypto/provider/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
+++ b/components/service/crypto/provider/mbedcrypto/trng_adapter/platform/platform_trng_adapter.c
@@ -4,7 +4,6 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <mbedtls/entropy.h>
-#include <mbedtls/entropy_poll.h>
#include <platform/interface/trng.h>
#include <service/crypto/provider/mbedcrypto/trng_adapter/trng_adapter.h>
#include <config/interface/platform_config.h>
diff --git a/components/service/crypto/provider/mbedcrypto/trng_adapter/test/component.cmake b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/component.cmake
new file mode 100644
index 0000000..4aa4321
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/trng_env_tests.c"
+ )
+
diff --git a/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.c b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.c
new file mode 100644
index 0000000..d297821
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <service/test_runner/provider/backend/simple_c/simple_c_test_runner.h>
+#include <service/crypto/provider/mbedcrypto/trng_adapter/trng_adapter.h>
+#include <string.h>
+#include <stddef.h>
+
+/**
+ * Tests the hw TRNG provided by the environment or underlying platform.
+ */
+
+/* Declaration for mbedtls function to avoid complicated conditional
+ * compilation problems in mbedtls header files.
+ */
+int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen);
+
+/*
+ * Check the trng create/destroy lifecycle
+ */
+static bool check_trng_lifecycle(struct test_failure *failure)
+{
+ int status = trng_adapter_init(0);
+ failure->info = status;
+ trng_adapter_deinit();
+
+ return (status == 0);
+}
+
+/*
+ * Check the trng hardware poll function used by mbedcrypto to
+ * access a hardware entropy source,
+ */
+static bool check_hw_poll(struct test_failure *failure)
+{
+ bool passed;
+ uint8_t output[2][10];
+ size_t expected_len = 10;
+
+ passed = (trng_adapter_init(0) == 0);
+
+ memset(output, 0, sizeof(output));
+
+ for (int round = 0; passed && round < 5; ++round) {
+
+ size_t olen;
+ int status = mbedtls_hardware_poll(NULL, &output[round & 1][0], expected_len, &olen);
+
+ /* Check results of call - expect a different byte stream on each call */
+ passed = passed && (status == 0);
+ passed = passed && (olen == expected_len);
+ passed = passed && (memcmp(&output[round & 1][0], &output[!(round & 1)][0], expected_len) != 0);
+
+ /* capture most recent output in case of failure */
+ memcpy(&failure->info, &output[round & 1][0], sizeof(failure->info));
+ }
+
+ trng_adapter_deinit();
+
+ return passed;
+}
+
+/**
+ * Define an register test group
+ */
+void trng_env_tests_register(void)
+{
+ static const struct simple_c_test_case trng_env_tests[] = {
+ {.name = "TrngLifecycle", .test_func = check_trng_lifecycle},
+ {.name = "TrngHwPoll", .test_func = check_hw_poll}
+ };
+
+ static const struct simple_c_test_group trng_env_test_group =
+ {
+ .group = "TrngEnvTests",
+ .num_test_cases = sizeof(trng_env_tests)/sizeof(struct simple_c_test_case),
+ .test_cases = trng_env_tests
+ };
+
+ simple_c_test_runner_register_group(&trng_env_test_group);
+}
\ No newline at end of file
diff --git a/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.h b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.h
new file mode 100644
index 0000000..36c4103
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/trng_adapter/test/trng_env_tests.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRNG_ENV_TESTS_H
+#define TRNG_ENV_TESTS_H
+
+void trng_env_tests_register(void);
+
+#endif /* TRNG_ENV_TESTS_H */
diff --git a/components/service/test_runner/client/cpp/test_runner_client.cpp b/components/service/test_runner/client/cpp/test_runner_client.cpp
index a780002..b1b2784 100644
--- a/components/service/test_runner/client/cpp/test_runner_client.cpp
+++ b/components/service/test_runner/client/cpp/test_runner_client.cpp
@@ -211,9 +211,9 @@
memcpy(&packed_result, value_buf, fixed_size);
result.run_state = (enum test_run_state)packed_result.run_state;
- result.fail_line = packed_result.fail_line;
result.name[0] = 0;
result.group[0] = 0;
+ result.failure = {0};
/* Deserialize name and group if present */
struct tlv_const_iterator req_iter;
@@ -238,6 +238,17 @@
result.group[decoded_record.length] = 0;
}
}
+
+ if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE, &decoded_record)) {
+
+ if (decoded_record.length == sizeof(ts_test_runner_test_failure)) {
+
+ struct ts_test_runner_test_failure deserialized_failure;
+ memcpy(&deserialized_failure, decoded_record.value, decoded_record.length);
+ result.failure.line_num = deserialized_failure.line_num;
+ result.failure.info = deserialized_failure.info;
+ }
+ }
}
else {
/* Invalid test result */
diff --git a/components/service/test_runner/common/test_runner.h b/components/service/test_runner/common/test_runner.h
index c891918..ffc6243 100644
--- a/components/service/test_runner/common/test_runner.h
+++ b/components/service/test_runner/common/test_runner.h
@@ -4,10 +4,11 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef CPPUTEST_TEST_RUNNER_H
-#define CPPUTEST_TEST_RUNNER_H
+#ifndef TEST_RUNNER_H
+#define TEST_RUNNER_H
#include <protocols/service/test_runner/packed-c/test_result.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -33,10 +34,10 @@
*/
struct test_summary
{
- int num_tests; /* Number of qualifying tests */
- int num_results; /* Number of available test result objects */
- int num_passed; /* Number that ran and passed */
- int num_failed; /* Number that ran and failed */
+ unsigned int num_tests; /* Number of qualifying tests */
+ unsigned int num_results; /* Number of available test result objects */
+ unsigned int num_passed; /* Number that ran and passed */
+ unsigned int num_failed; /* Number that ran and failed */
};
/**
@@ -50,6 +51,15 @@
};
/**
+ * Test failue to describe a failure
+ */
+struct test_failure
+{
+ unsigned int line_num; /* Source line where test assertion failed */
+ uint64_t info; /* Provides test specific information about the failure */
+};
+
+/**
* The result for a particular test case.
*/
struct test_result
@@ -57,11 +67,11 @@
char name[TEST_NAME_MAX_LEN];
char group[TEST_GROUP_MAX_LEN];
enum test_run_state run_state;
- unsigned int fail_line;
+ struct test_failure failure;
};
#ifdef __cplusplus
} /* extern "C" */
#endif
-#endif /* CPPUTEST_TEST_RUNNER_H */
+#endif /* TEST_RUNNER_H */
diff --git a/components/service/test_runner/provider/backend/mock/mock_test_runner.c b/components/service/test_runner/provider/backend/mock/mock_test_runner.c
index 4b6cde8..275457d 100644
--- a/components/service/test_runner/provider/backend/mock/mock_test_runner.c
+++ b/components/service/test_runner/provider/backend/mock/mock_test_runner.c
@@ -8,8 +8,18 @@
#include <string.h>
/* Mock test test functions */
-static bool test_that_passes(void) { return true; }
-static bool test_that_fails(void) { return false; }
+static bool test_that_passes(struct test_failure *failure)
+{
+ (void)failure;
+ return true;
+}
+
+static bool test_that_fails(struct test_failure *failure)
+{
+ failure->line_num = __LINE__;
+ failure->info = 27;
+ return false;
+}
/**
* The mock backend is a test_runner that provides some mock test cases
diff --git a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
index 0ab190c..fb66d75 100644
--- a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
+++ b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.c
@@ -80,11 +80,12 @@
if (does_qualify(spec->name, test_case->name)) {
enum test_run_state run_state = TEST_RUN_STATE_NOT_RUN;
+ struct test_failure failure = {0};
/* Run the qualifying test case if we're not just listing tests */
if (!list_only) {
- if (test_case->test_func()) {
+ if (test_case->test_func(&failure)) {
run_state = TEST_RUN_STATE_PASSED;
++summary->num_passed;
@@ -102,7 +103,7 @@
struct test_result *new_result = &results[summary->num_results];
new_result->run_state = run_state;
- new_result->fail_line = 0;
+ new_result->failure = failure;
strcpy(new_result->group, test_group->group);
strcpy(new_result->name, test_case->name);
diff --git a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.h b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.h
index 3875c42..1292547 100644
--- a/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.h
+++ b/components/service/test_runner/provider/backend/simple_c/simple_c_test_runner.h
@@ -7,6 +7,7 @@
#ifndef SIMPLE_C_TEST_RUNNER_H
#define SIMPLE_C_TEST_RUNNER_H
+#include <service/test_runner/common/test_runner.h>
#include <stdbool.h>
#include <stddef.h>
@@ -30,7 +31,7 @@
const char *name;
/* The test function that results true for a pass, false for a fail. */
- bool (*test_func)(void);
+ bool (*test_func)(struct test_failure *test_failure);
};
/**
diff --git a/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c b/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
index 577bfdc..5892502 100644
--- a/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
+++ b/components/service/test_runner/provider/serializer/packed-c/packedc_test_runner_provider_serializer.c
@@ -55,6 +55,8 @@
if (name_len) required_space += tlv_required_space(name_len);
if (group_len) required_space += tlv_required_space(group_len);
+ if (result->run_state == TEST_RUN_STATE_FAILED)
+ required_space += tlv_required_space(sizeof(struct ts_test_runner_test_failure));
*serialized_len = required_space;
@@ -64,7 +66,6 @@
struct ts_test_runner_test_result result_msg;
result_msg.run_state = result->run_state;
- result_msg.fail_line = result->fail_line;
memcpy(out_buf, &result_msg, fixed_len);
@@ -88,6 +89,19 @@
record.value = result->group;
tlv_encode(&tlv_iter, &record);
}
+
+ if (result->run_state == TEST_RUN_STATE_FAILED) {
+
+ struct ts_test_runner_test_failure serialized_failure;
+ serialized_failure.line_num = result->failure.line_num;
+ serialized_failure.info = result->failure.info;
+
+ struct tlv_record record;
+ record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE;
+ record.length = sizeof(serialized_failure);
+ record.value = (const uint8_t*)&serialized_failure;
+ tlv_encode(&tlv_iter, &record);
+ }
}
return out_buf;
diff --git a/components/service/test_runner/test/service/test_runner_service_tests.cpp b/components/service/test_runner/test/service/test_runner_service_tests.cpp
index c4ba0e0..8d68bca 100644
--- a/components/service/test_runner/test/service/test_runner_service_tests.cpp
+++ b/components/service/test_runner/test/service/test_runner_service_tests.cpp
@@ -128,6 +128,7 @@
CHECK(strcmp(results[2].group, "ConfigTests") == 0);
CHECK(strcmp(results[2].name, "ValidateConfig") == 0);
CHECK_EQUAL(TEST_RUN_STATE_FAILED, results[2].run_state);
+ CHECK_EQUAL(27, results[2].failure.info);
CHECK(strcmp(results[3].group, "ConfigTests") == 0);
CHECK(strcmp(results[3].name, "ApplyConfig") == 0);