blob: 34ef19f42bd6eb5337ff54da058aeaa97f1973a1 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <assert.h>
9#include <debug.h>
10#include <nvm.h>
11#include <platform.h>
12#include <spinlock.h>
13#include <stdarg.h>
14#include <string.h>
15
16/*
17 * Temporary buffer to store 1 test output.
18 * This will eventually be saved into NVM at the end of the execution
19 * of this test.
20 */
21static char testcase_output[TESTCASE_OUTPUT_MAX_SIZE];
22/*
23 * A test output can be written in several pieces by calling
24 * tftf_testcase_printf() multiple times. testcase_output_idx keeps the position
25 * of the last character written in testcase_output buffer and allows to easily
26 * append a new string at next call to tftf_testcase_printf().
27 */
28static unsigned int testcase_output_idx;
29
30/* Lock to avoid concurrent accesses to the testcase output buffer */
31static spinlock_t testcase_output_lock;
32
33static tftf_state_t tftf_init_state = {
34 .build_message = "",
35 .test_to_run = {
36 .testsuite_idx = 0,
37 .testcase_idx = 0,
38 },
39 .test_progress = TEST_READY,
40 .testcase_buffer = { 0 },
41 .testcase_results = {
42 {
43 .result = TEST_RESULT_NA,
44 .duration = 0,
45 .output_offset = 0,
46 .output_size = 0,
47 }
48 },
49 .result_buffer_size = 0,
50 .result_buffer = NULL,
51};
52
53unsigned int new_test_session(void)
54{
55/* NEW_TEST_SESSION == 1 => we always want to start a new session */
56#if NEW_TEST_SESSION
57 INFO("Always starting a new test session (NEW_TEST_SESSION == 1)\n");
58 return 1;
59#endif
60 char saved_build_msg[BUILD_MESSAGE_SIZE];
61
62 /*
63 * Check the validity of the build message stored in NVM.
64 * It is invalid when it doesn't match with the TFTF binary currently
65 * executing.
66 */
67 tftf_nvm_read(TFTF_STATE_OFFSET(build_message), saved_build_msg,
68 BUILD_MESSAGE_SIZE);
69 return !!strncmp(build_message, saved_build_msg, BUILD_MESSAGE_SIZE);
70}
71
72STATUS tftf_init_nvm(void)
73{
74 INFO("Initialising NVM\n");
75
76 /* Copy the build message to identify the TFTF */
77 strncpy(tftf_init_state.build_message, build_message, BUILD_MESSAGE_SIZE);
78 return tftf_nvm_write(0, &tftf_init_state, sizeof(tftf_init_state));
79}
80
81STATUS tftf_clean_nvm(void)
82{
83 unsigned char corrupt_build_message = '\0';
84
85 /*
86 * This will cause TFTF to re-initialise its data structures next time
87 * it runs.
88 */
89 return tftf_nvm_write(TFTF_STATE_OFFSET(build_message),
90 &corrupt_build_message,
91 sizeof(corrupt_build_message));
92}
93
94STATUS tftf_set_test_to_run(const test_ref_t test_to_run)
95{
96 return tftf_nvm_write(TFTF_STATE_OFFSET(test_to_run), &test_to_run,
97 sizeof(test_to_run));
98}
99
100STATUS tftf_get_test_to_run(test_ref_t *test_to_run)
101{
102 assert(test_to_run != NULL);
103 return tftf_nvm_read(TFTF_STATE_OFFSET(test_to_run), test_to_run,
104 sizeof(*test_to_run));
105}
106
107STATUS tftf_set_test_progress(test_progress_t test_progress)
108{
109 return tftf_nvm_write(TFTF_STATE_OFFSET(test_progress), &test_progress,
110 sizeof(test_progress));
111}
112
113STATUS tftf_get_test_progress(test_progress_t *test_progress)
114{
115 assert(test_progress != NULL);
116 return tftf_nvm_read(TFTF_STATE_OFFSET(test_progress), test_progress,
117 sizeof(*test_progress));
118}
119
120STATUS tftf_testcase_set_result(const test_case_t *testcase,
121 test_result_t result,
122 unsigned long long duration)
123{
124 STATUS status;
125 unsigned result_buffer_size = 0;
126 TESTCASE_RESULT test_result;
127
128 assert(testcase != NULL);
129
130 /* Initialize Test case result */
131 test_result.result = result;
132 test_result.duration = duration;
133 test_result.output_offset = 0;
134 test_result.output_size = strlen(testcase_output);
135
136 /* Does the test have an output? */
137 if (test_result.output_size != 0) {
138 /* Get the size of the buffer containing all tests outputs */
139 status = tftf_nvm_read(TFTF_STATE_OFFSET(result_buffer_size),
140 &result_buffer_size, sizeof(unsigned));
141 if (status != STATUS_SUCCESS)
142 goto reset_test_output;
143
144 /*
145 * Write the output buffer at the end of the string buffer in
146 * NVM
147 */
148 test_result.output_offset = result_buffer_size;
149 status = tftf_nvm_write(
150 TFTF_STATE_OFFSET(result_buffer) + result_buffer_size,
151 testcase_output, test_result.output_size + 1);
152 if (status != STATUS_SUCCESS)
153 goto reset_test_output;
154
155 /* And update the buffer size into NVM */
156 result_buffer_size += test_result.output_size + 1;
157 status = tftf_nvm_write(TFTF_STATE_OFFSET(result_buffer_size),
158 &result_buffer_size, sizeof(unsigned));
159 if (status != STATUS_SUCCESS)
160 goto reset_test_output;
161 }
162
163 /* Write the test result into NVM */
164 status = tftf_nvm_write(TFTF_STATE_OFFSET(testcase_results) +
165 (testcase->index * sizeof(TESTCASE_RESULT)),
166 &test_result, sizeof(TESTCASE_RESULT));
167
168reset_test_output:
169 /* Reset test output buffer for the next test */
170 testcase_output_idx = 0;
171 testcase_output[0] = 0;
172
173 return status;
174}
175
176STATUS tftf_testcase_get_result(const test_case_t *testcase,
177 TESTCASE_RESULT *result,
178 char *test_output)
179{
180 STATUS status;
181 unsigned output_size;
182
183 assert(testcase != NULL);
184 assert(result != NULL);
185 assert(test_output != NULL);
186
187 status = tftf_nvm_read(TFTF_STATE_OFFSET(testcase_results)
188 + (testcase->index * sizeof(TESTCASE_RESULT)),
189 result, sizeof(TESTCASE_RESULT));
190 if (status != STATUS_SUCCESS) {
191 return status;
192 }
193
194 output_size = result->output_size;
195
196 if (output_size != 0) {
197 status = tftf_nvm_read(TFTF_STATE_OFFSET(result_buffer)
198 + result->output_offset,
199 test_output, output_size);
200 if (status != STATUS_SUCCESS)
201 return status;
202 }
203
204 test_output[output_size] = 0;
205
206 return STATUS_SUCCESS;
207}
208
209int tftf_testcase_printf(const char *format, ...)
210{
211 va_list ap;
212 int available;
213 int written = -1;
214
215 spin_lock(&testcase_output_lock);
216
217 assert(sizeof(testcase_output) >= testcase_output_idx);
218 available = sizeof(testcase_output) - testcase_output_idx;
219 if (available == 0) {
220 ERROR("%s: Output buffer is full ; the string won't be printed.\n",
221 __func__);
222 ERROR("%s: Consider increasing TESTCASE_OUTPUT_MAX_SIZE value.\n",
223 __func__);
224 goto release_lock;
225 }
226
227 va_start(ap, format);
228 written = vsnprintf(&testcase_output[testcase_output_idx], available,
229 format, ap);
230 va_end(ap);
231
232 if (written < 0) {
233 ERROR("%s: Output error (%d)", __func__, written);
234 goto release_lock;
235 }
236 /*
237 * If vsnprintf() truncated the string due to the size limit passed as
238 * an argument then its return value is the number of characters (not
239 * including the trailing '\0') which would have been written to the
240 * final string if enough space had been available. Thus, a return value
241 * of size or more means that the output was truncated.
242 *
243 * Adjust the value of 'written' to reflect what has been actually
244 * written.
245 */
246 if (written >= available) {
247 ERROR("%s: String has been truncated (%u/%u bytes written).\n",
248 __func__, available - 1, written);
249 ERROR("%s: Consider increasing TESTCASE_OUTPUT_MAX_SIZE value.\n",
250 __func__);
251 written = available - 1;
252 }
253
254 /*
255 * Update testcase_output_idx to point to the '\0' of the buffer.
256 * The next call of tftf_testcase_printf() will overwrite '\0' to
257 * append its new string to the buffer.
258 */
259 testcase_output_idx += written;
260
261release_lock:
262 spin_unlock(&testcase_output_lock);
263 return written;
264}
265
266void tftf_notify_reboot(void)
267{
268#if DEBUG
269 /* This function must be called by tests, not by the framework */
270 test_progress_t test_progress;
271 tftf_get_test_progress(&test_progress);
272 assert(test_progress == TEST_IN_PROGRESS);
273#endif /* DEBUG */
274
275 VERBOSE("Test intends to reset\n");
276 tftf_set_test_progress(TEST_REBOOTING);
277}