blob: 7f987c05996f01b3d5883df58b0c885bc587d48b [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>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02008#include <assert.h>
9#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000010#include <drivers/arm/arm_gic.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020011#include <irq.h>
12#include <mmio.h>
13#include <nvm.h>
14#include <plat_topology.h>
15#include <platform.h>
16#include <platform_def.h>
17#include <power_management.h>
18#include <psci.h>
19#include <sgi.h>
20#include <string.h>
21#include <sys/types.h>
22#include <tftf.h>
23#include <tftf_lib.h>
24#include <timer.h>
25
26/* version information for TFTF */
27extern const char version_string[];
28
29unsigned int lead_cpu_mpid;
30
31/* Defined in hotplug.c */
32extern volatile test_function_t test_entrypoint[PLATFORM_CORE_COUNT];
33
34/* Per-CPU results for the current test */
35static test_result_t test_results[PLATFORM_CORE_COUNT];
36
37/* Context ID passed to tftf_psci_cpu_on() */
38static u_register_t cpu_on_ctx_id_arr[PLATFORM_CORE_COUNT];
39
40static unsigned int test_is_rebooting;
41
42static inline const test_suite_t *current_testsuite(void)
43{
44 test_ref_t test_to_run;
45 tftf_get_test_to_run(&test_to_run);
46 return &testsuites[test_to_run.testsuite_idx];
47}
48
49static inline const test_case_t *current_testcase(void)
50{
51 test_ref_t test_to_run;
52 tftf_get_test_to_run(&test_to_run);
53 return &testsuites[test_to_run.testsuite_idx].
54 testcases[test_to_run.testcase_idx];
55}
56
57/*
58 * Identify the next test in the tests list and update the NVM data to point to
59 * that test.
60 * If there is no more tests to execute, return NULL.
61 * Otherwise, return the test case.
62 */
63static const test_case_t *advance_to_next_test(void)
64{
65 test_ref_t test_to_run;
66 const test_case_t *testcase;
67 unsigned int testcase_idx;
68 unsigned int testsuite_idx;
69
70#if DEBUG
71 test_progress_t progress;
72 tftf_get_test_progress(&progress);
73 assert(progress == TEST_COMPLETE);
74#endif
75
76 tftf_get_test_to_run(&test_to_run);
77 testcase_idx = test_to_run.testcase_idx;
78 testsuite_idx = test_to_run.testsuite_idx;
79
80 /* Move to the next test case in the current test suite */
81 ++testcase_idx;
82 testcase = &testsuites[testsuite_idx].testcases[testcase_idx];
83
84 if (testcase->name == NULL) {
85 /*
86 * There's no more test cases in the current test suite so move
87 * to the first test case of the next test suite.
88 */
89 const test_suite_t *testsuite;
90 testcase_idx = 0;
91 ++testsuite_idx;
92 testsuite = &testsuites[testsuite_idx];
93 testcase = &testsuite->testcases[0];
94
95 if (testsuite->name == NULL) {
96 /*
97 * This was the last test suite so there's no more tests
98 * at all.
99 */
100 return NULL;
101 }
102 }
103
104 VERBOSE("Moving to test (%u,%u)\n", testsuite_idx, testcase_idx);
105 test_to_run.testsuite_idx = testsuite_idx;
106 test_to_run.testcase_idx = testcase_idx;
107 tftf_set_test_to_run(test_to_run);
108 tftf_set_test_progress(TEST_READY);
109
110 return testcase;
111}
112
113/*
114 * This function is executed only by the lead CPU.
115 * It prepares the environment for the next test to run.
116 */
117static void prepare_next_test(void)
118{
119 unsigned int mpid;
120 unsigned int core_pos;
121 unsigned int cpu_node;
122
123 /* This function should be called by the lead CPU only */
124 assert((read_mpidr_el1() & MPID_MASK) == lead_cpu_mpid);
125
126 /*
127 * Only the lead CPU should be powered on at this stage. All other CPUs
128 * should be powered off or powering off. If some CPUs are not powered
129 * off yet, wait for them to power off.
130 */
131 for_each_cpu(cpu_node) {
132 mpid = tftf_get_mpidr_from_node(cpu_node);
133 if (mpid == lead_cpu_mpid)
134 assert(tftf_is_cpu_online(mpid));
135 else
136 while (tftf_psci_affinity_info(mpid, MPIDR_AFFLVL0)
137 == PSCI_STATE_ON)
138 ;
139 }
140
141 /* No CPU should have entered the test yet */
142 assert(tftf_get_ref_cnt() == 0);
143
144 /* Populate the test entrypoint for the lead CPU */
145 core_pos = platform_get_core_pos(lead_cpu_mpid);
146 test_entrypoint[core_pos] = (test_function_t) current_testcase()->test;
147
148 for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; ++i)
149 test_results[i] = TEST_RESULT_NA;
150
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100151 /* If we're starting a new testsuite, announce it. */
152 test_ref_t test_to_run;
153 tftf_get_test_to_run(&test_to_run);
154 if (test_to_run.testcase_idx == 0) {
155 print_testsuite_start(current_testsuite());
156 }
157
158 print_test_start(current_testcase());
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200159
160 /* Program the watchdog */
161 tftf_platform_watchdog_set();
162
163 /* TODO: Take a 1st timestamp to be able to measure test duration */
164
165 tftf_set_test_progress(TEST_IN_PROGRESS);
166}
167
168/*
169 * Go through individual CPUs' test results and determine the overall
170 * test result from that.
171 */
172static test_result_t get_overall_test_result(void)
173{
174 test_result_t result = TEST_RESULT_NA;
175 unsigned int cpu_mpid;
176 unsigned int cpu_node;
177 unsigned int core_pos;
178
179 for_each_cpu(cpu_node) {
180 cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
181 core_pos = platform_get_core_pos(cpu_mpid);
182
183 switch (test_results[core_pos]) {
184 case TEST_RESULT_NA:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200185 /* Ignoring */
186 break;
187
188 case TEST_RESULT_SKIPPED:
189 /*
190 * If at least one CPU skipped the test, consider the
191 * whole test as skipped as well.
192 */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200193 return TEST_RESULT_SKIPPED;
194
195 case TEST_RESULT_SUCCESS:
196 result = TEST_RESULT_SUCCESS;
197 break;
198
199 case TEST_RESULT_FAIL:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200200 return TEST_RESULT_FAIL;
201
202 case TEST_RESULT_CRASHED:
203 /*
204 * Means the CPU never returned from the test whereas it
205 * was supposed to. Either there is a bug in the test's
206 * implementation or some sort of unexpected crash
207 * happened.
208 * If at least one CPU crashed, consider the whole test
209 * as crashed as well.
210 */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200211 return TEST_RESULT_CRASHED;
212
213 default:
214 ERROR("Unknown test result value: %u\n",
215 test_results[core_pos]);
216 panic();
217 }
218 }
219
220 /*
221 * At least one CPU (i.e. the lead CPU) should have participated in the
222 * test.
223 */
224 assert(result != TEST_RESULT_NA);
225 return result;
226}
227
228/*
229 * This function is executed by the last CPU to exit the test only.
230 * It does the necessary bookkeeping and reports the overall test result.
231 * If it was the last test, it will also generate the final test report.
232 * Otherwise, it will reset the platform, provided that the platform
233 * supports reset from non-trusted world. This ensures that the next test
234 * runs in a clean environment
235 *
236 * Return 1 if this was the last test, 0 otherwise.
237 */
238static unsigned int close_test(void)
239{
240 const test_case_t *next_test;
241
242#if DEBUG
243 /*
244 * Check that the test didn't pretend resetting the platform, when in
245 * fact it returned into the framework.
246 *
247 * If that happens, the test implementation should be fixed.
248 * However, it is not a fatal error so just flag the problem in debug
249 * builds.
250 */
251 test_progress_t progress;
252 tftf_get_test_progress(&progress);
253 assert(progress != TEST_REBOOTING);
254#endif /* DEBUG */
255
256 tftf_set_test_progress(TEST_COMPLETE);
257 test_is_rebooting = 0;
258
259 /* TODO: Take a 2nd timestamp and compute test duration */
260
261 /* Reset watchdog */
262 tftf_platform_watchdog_reset();
263
264 /* Ensure no CPU is still executing the test */
265 assert(tftf_get_ref_cnt() == 0);
266
267 /* Save test result in NVM */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200268 tftf_testcase_set_result(current_testcase(),
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100269 get_overall_test_result(),
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200270 0);
271
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100272 print_test_end(current_testcase());
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200273
274 /* The test is finished, let's move to the next one (if any) */
275 next_test = advance_to_next_test();
276
277 /* If this was the last test then report all results */
278 if (!next_test) {
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100279 print_tests_summary();
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200280 tftf_clean_nvm();
281 return 1;
282 } else {
283#if (PLAT_SUPPORTS_NS_RESET && !NEW_TEST_SESSION && USE_NVM)
284 /*
285 * Reset the platform so that the next test runs in a clean
286 * environment.
287 */
288 INFO("Reset platform before executing next test:%p\n",
289 (void *) &(next_test->test));
290 tftf_plat_reset();
291 bug_unreachable();
292#endif
293 }
294
295 return 0;
296}
297
298/*
299 * Hand over to lead CPU, i.e.:
300 * 1) Power on lead CPU
301 * 2) Power down calling CPU
302 */
303static void __dead2 hand_over_to_lead_cpu(void)
304{
305 int ret;
306 unsigned int mpid = read_mpidr_el1() & MPID_MASK;
307 unsigned int core_pos = platform_get_core_pos(mpid);
308
309 VERBOSE("CPU%u: Hand over to lead CPU%u\n", core_pos,
310 platform_get_core_pos(lead_cpu_mpid));
311
312 /*
313 * Power on lead CPU.
314 * The entry point address passed as the 2nd argument of tftf_cpu_on()
315 * doesn't matter because it will be overwritten by prepare_next_test().
316 * Pass a NULL pointer to easily catch the problem in case something
317 * goes wrong.
318 */
319 ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
320 if (ret != PSCI_E_SUCCESS) {
321 ERROR("CPU%u: Failed to power on lead CPU%u (%d)\n",
322 core_pos, platform_get_core_pos(lead_cpu_mpid), ret);
323 panic();
324 }
325
326 /* Wait for lead CPU to be actually powered on */
327 while (!tftf_is_cpu_online(lead_cpu_mpid))
328 ;
329
330 /*
331 * Lead CPU has successfully booted, let's now power down the calling
332 * core.
333 */
334 tftf_cpu_off();
335 panic();
336}
337
338void __dead2 run_tests(void)
339{
340 unsigned int mpid = read_mpidr_el1() & MPID_MASK;
341 unsigned int core_pos = platform_get_core_pos(mpid);
342 unsigned int test_session_finished;
343 unsigned int cpus_cnt;
344
345 while (1) {
346 if (mpid == lead_cpu_mpid && (tftf_get_ref_cnt() == 0))
347 prepare_next_test();
348
349 /*
350 * Increment the reference count to indicate that the CPU is
351 * participating in the test.
352 */
353 tftf_inc_ref_cnt();
354
355 /*
356 * Mark the CPU's test result as "crashed". This is meant to be
357 * overwritten by the actual test result when the CPU returns
358 * from the test function into the framework. In case the CPU
359 * crashes in the test (and thus, never returns from it), this
360 * variable will hold the right value.
361 */
362 test_results[core_pos] = TEST_RESULT_CRASHED;
363
364 /*
365 * Jump to the test entrypoint for this core.
366 * - For the lead CPU, it has been populated by
367 * prepare_next_test()
368 * - For other CPUs, it has been populated by tftf_cpu_on() or
369 * tftf_try_cpu_on()
370 */
371 while (test_entrypoint[core_pos] == 0)
372 ;
373
374 test_results[core_pos] = test_entrypoint[core_pos]();
375 test_entrypoint[core_pos] = 0;
376
377 /*
378 * Decrement the reference count to indicate that the CPU is not
379 * participating in the test any longer.
380 */
381 cpus_cnt = tftf_dec_ref_cnt();
382
383 /*
384 * Last CPU to exit the test gets to do the necessary
385 * bookkeeping and to report the overall test result.
386 * Other CPUs shut down.
387 */
388 if (cpus_cnt == 0) {
389 test_session_finished = close_test();
390 if (test_session_finished)
391 break;
392
393 if (mpid != lead_cpu_mpid) {
394 hand_over_to_lead_cpu();
395 bug_unreachable();
396 }
397 } else {
398 tftf_cpu_off();
399 panic();
400 }
401 }
402
403 tftf_exit();
404
405 /* Should never reach this point */
406 bug_unreachable();
407}
408
409u_register_t tftf_get_cpu_on_ctx_id(unsigned int core_pos)
410{
411 assert(core_pos < PLATFORM_CORE_COUNT);
412
413 return cpu_on_ctx_id_arr[core_pos];
414}
415
416void tftf_set_cpu_on_ctx_id(unsigned int core_pos, u_register_t context_id)
417{
418 assert(core_pos < PLATFORM_CORE_COUNT);
419
420 cpu_on_ctx_id_arr[core_pos] = context_id;
421}
422
423unsigned int tftf_is_rebooted(void)
424{
425 return test_is_rebooting;
426}
427
428/*
429 * Return 0 if the test session can be resumed
430 * -1 otherwise.
431 */
432static int resume_test_session(void)
433{
434 test_ref_t test_to_run;
435 test_progress_t test_progress;
436 const test_case_t *next_test;
437
438 /* Get back on our feet. Where did we stop? */
439 tftf_get_test_to_run(&test_to_run);
440 tftf_get_test_progress(&test_progress);
441 assert(TEST_PROGRESS_IS_VALID(test_progress));
442
443 switch (test_progress) {
444 case TEST_READY:
445 /*
446 * The TFTF has reset in the framework code, before the test
447 * actually started.
448 * Nothing to update, just start the test from scratch.
449 */
450 break;
451
452 case TEST_IN_PROGRESS:
453 /*
454 * The test crashed, i.e. it couldn't complete.
455 * Update the test result in NVM then move to the next test.
456 */
457 INFO("Test has crashed, moving to the next one\n");
458 tftf_testcase_set_result(current_testcase(),
459 TEST_RESULT_CRASHED,
460 0);
461 next_test = advance_to_next_test();
462 if (!next_test) {
463 INFO("No more tests\n");
464 return -1;
465 }
466 break;
467
468 case TEST_COMPLETE:
469 /*
470 * The TFTF has reset in the framework code, after the test had
471 * completed but before we finished the framework maintenance
472 * required to move to the next test.
473 *
474 * In this case, we don't know the exact state of the data:
475 * maybe we had the time to update the test result,
476 * maybe we had the time to move to the next test.
477 * We can't be sure so let's stay on the safe side and just
478 * restart the test session from the beginning...
479 */
480 NOTICE("The test framework has been interrupted in the middle "
481 "of critical maintenance operations.\n");
482 NOTICE("Can't recover execution.\n");
483 return -1;
484
485 case TEST_REBOOTING:
486 /*
487 * Nothing to update about the test session, as we want to
488 * re-enter the same test. Just remember that the test is
489 * rebooting in case it queries this information.
490 */
491 test_is_rebooting = 1;
492 break;
493
494 default:
495 bug_unreachable();
496 }
497
498 return 0;
499}
500
501/*
502 * C entry point in the TFTF.
503 * This function is executed by the primary CPU only.
504 */
505void __dead2 tftf_cold_boot_main(void)
506{
507 STATUS status;
508 int rc;
509
510 NOTICE("%s\n", TFTF_WELCOME_STR);
511 NOTICE("%s\n", build_message);
512 NOTICE("%s\n\n", version_string);
513
514#ifndef AARCH32
515 NOTICE("Running at NS-EL%u\n", IS_IN_EL(1) ? 1 : 2);
516#else
517 NOTICE("Running in AArch32 HYP mode\n");
518#endif
519
520 tftf_arch_setup();
521 tftf_platform_setup();
522 tftf_init_topology();
523
524 tftf_irq_setup();
525
526 rc = tftf_initialise_timer();
527 if (rc != 0) {
528 ERROR("Failed to initialize the timer subsystem (%d).\n", rc);
529 tftf_exit();
530 }
531
532 /* Enable the SGI used by the timer management framework */
533 tftf_irq_enable(IRQ_WAKE_SGI, GIC_HIGHEST_NS_PRIORITY);
534 enable_irq();
535
536 if (new_test_session()) {
537 NOTICE("Starting a new test session\n");
538 status = tftf_init_nvm();
539 if (status != STATUS_SUCCESS) {
540 /*
541 * TFTF will have an undetermined behavior if its data
542 * structures have not been initialised. There's no
543 * point in continuing execution.
544 */
545 ERROR("FATAL: Failed to initialise internal data structures in NVM.\n");
546 tftf_clean_nvm();
547 tftf_exit();
548 }
549 } else {
550 NOTICE("Resuming interrupted test session\n");
551 rc = resume_test_session();
552 if (rc < 0) {
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100553 print_tests_summary();
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200554 tftf_clean_nvm();
555 tftf_exit();
556 }
557 }
558
559 /* Initialise the CPUs status map */
560 tftf_init_cpus_status_map();
561
562 /*
563 * Detect power state format and get power state information for
564 * a platform.
565 */
566 tftf_init_pstate_framework();
567
568 /* The lead CPU is always the primary core. */
569 lead_cpu_mpid = read_mpidr_el1() & MPID_MASK;
570
571 /*
572 * Hand over to lead CPU if required.
573 * If the primary CPU is not the lead CPU for the first test then:
574 * 1) Power on the lead CPU
575 * 2) Power down the primary CPU
576 */
577 if ((read_mpidr_el1() & MPID_MASK) != lead_cpu_mpid) {
578 hand_over_to_lead_cpu();
579 bug_unreachable();
580 }
581
582 /* Enter the test session */
583 run_tests();
584
585 /* Should never reach this point */
586 bug_unreachable();
587}
588
589void __dead2 tftf_exit(void)
590{
591 NOTICE("Exiting tests.\n");
592
593 /* Let the platform code clean up if required */
594 tftf_platform_end();
595
596 while (1)
597 wfi();
598}