aboutsummaryrefslogtreecommitdiff
path: root/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
blob: 7c70de2c3941e5846cfdfd9b42290b62ed3d6ce2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * Copyright (c) 2021, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <cactus_test_cmds.h>
#include <ffa_endpoints.h>
#include <ffa_helpers.h>
#include <test_helpers.h>
#include <timer.h>

static volatile int timer_irq_received;

#define SENDER		HYP_ID
#define RECEIVER	SP_ID(1)
#define SLEEP_TIME	200U

static const struct ffa_uuid expected_sp_uuids[] = {
		{PRIMARY_UUID}
	};

/*
 * ISR for the timer interrupt. Update a global variable to check it has been
 * called.
 */
static int timer_handler(void *data)
{
	assert(timer_irq_received == 0);
	timer_irq_received = 1;
	return 0;
}

/*
 * @Test_Aim@ Test non-secure interrupts while executing Secure Partition.
 *
 * 1. Enable managed exit interrupt by sending interrupt_enable command to
 *    Cactus.
 *
 * 2. Register a handler for the non-secure timer interrupt. Program it to fire
 *    in a certain time.
 *
 * 3. Send a blocking request to Cactus to execute in busy loop.
 *
 * 4. While executing in busy loop, the non-secure timer should
 *    fire and trap into SPM running at S-EL2 as FIQ.
 *
 * 5. SPM injects a managed exit virtual FIQ into Cactus (as configured in the
 *    interrupt enable call), causing it to run its interrupt handler.
 *
 * 6. Cactus's managed exit handler acknowledges interrupt arrival by
 *    requesting the interrupt id to the SPMC, and check if it is the
 *    MANAGED_EXIT_INTERRUPT_ID.
 *
 * 7. Check whether the pending non-secure timer interrupt successfully got
 *    handled in TFTF.
 *
 * 8. Send a direct message request command to resume Cactus's execution.
 *    It resumes in the sleep loop and completes it. It then returns with
 *    a direct message response. Check if time lapsed is greater than
 *    sleeping time.
 *
 */
test_result_t test_ffa_ns_interrupt(void)
{
	int ret;
	smc_ret_values ret_values;

	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);

	/* Enable managed exit interrupt as FIQ in the secure side. */
	ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
					  true, INTERRUPT_TYPE_FIQ);

	if (!is_ffa_direct_response(ret_values)) {
		return TEST_RESULT_FAIL;
	}

	if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
		ERROR("Failed to enable Managed exit interrupt\n");
		return TEST_RESULT_FAIL;
	}

	/* Program timer */
	timer_irq_received = 0;
	tftf_timer_register_handler(timer_handler);

	ret = tftf_program_timer(100);
	if (ret < 0) {
		ERROR("Failed to program timer (%d)\n", ret);
		return TEST_RESULT_FAIL;
	}

	/* Send request to primary Cactus to sleep for 200ms */
	ret_values = cactus_sleep_cmd(SENDER, RECEIVER, SLEEP_TIME);

	if (!is_ffa_direct_response(ret_values)) {
		return TEST_RESULT_FAIL;
	}

	/*
	 * Managed exit interrupt occurs during this time, Cactus
	 * will respond with interrupt ID.
	 */
	if (cactus_get_response(ret_values) != MANAGED_EXIT_INTERRUPT_ID) {
		ERROR("Managed exit interrupt did not occur!\n");
		return TEST_RESULT_FAIL;
	}

	/* Check that the timer interrupt has been handled in NS-world (TFTF) */
	tftf_cancel_timer();
	tftf_timer_unregister_handler();

	if (timer_irq_received == 0) {
		ERROR("Timer interrupt hasn't actually been handled.\n");
		return TEST_RESULT_FAIL;
	}

	/*
	 * Send a dummy direct message request to relinquish CPU cycles.
	 * This resumes Cactus in the sleep routine.
	 */
	ret_values = ffa_msg_send_direct_req64(SENDER, RECEIVER,
		0, 0, 0, 0, 0);

	if (!is_ffa_direct_response(ret_values)) {
		return TEST_RESULT_FAIL;
	}

	/* Make sure elapsed time not less than sleep time */
	if (cactus_get_response(ret_values) < SLEEP_TIME) {
		ERROR("Lapsed time less than requested sleep time\n");
		return TEST_RESULT_FAIL;
	}

	/* Disable Managed exit interrupt */
	ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
					  false, 0);

	if (!is_ffa_direct_response(ret_values)) {
		return TEST_RESULT_FAIL;
	}

	if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
		ERROR("Failed to disable Managed exit interrupt\n");
		return TEST_RESULT_FAIL;
	}

	return TEST_RESULT_SUCCESS;
}