aboutsummaryrefslogtreecommitdiff
path: root/tftf/tests/runtime_services/mm_service/test_secure_service_interrupts.c
blob: 50c3df6707c9c686f7c182d2a61cd1781ed0c129 (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
/*
 * Copyright (c) 2018, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include <mm_svc.h>
#include <secure_partition.h>
#include <smccc.h>
#include <spm_svc.h>
#include <string.h>
#include <test_helpers.h>
#include <tftf_lib.h>
#include <timer.h>
#include <xlat_tables_v2.h>

static volatile int timer_irq_received;

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


/*
 * @Test_Aim@ Test that non-secure interrupts do not interrupt secure service
 * requests.
 *
 * 1. Register a handler for the non-secure timer interrupt.
 *
 * 2. Program the non-secure timer to fire in 500 ms.
 *
 * 3. Make a long-running (> 500 ms) fast secure service request.
 *    This is achieved by requesting the timer sleep service in Cactus
 *    with a 1 second sleep delay.
 *
 * 4. While servicing the timer sleep request, the non-secure timer should
 *    fire but not interrupt Cactus.
 *
 * 5. Once back in TFTF, check the response from Cactus, which shows whether the
 *    secure service indeed ran to completion.
 *
 * 6. Also check whether the pending non-secure timer interrupt successfully got
 *    handled in TFTF.
 */
test_result_t test_secure_partition_interrupt_by_ns(void)
{
	secure_partition_request_info_t *sps_request;
	test_result_t result = TEST_RESULT_FAIL;

	SKIP_TEST_IF_MM_VERSION_LESS_THAN(1, 0);

	VERBOSE("Mapping NS<->SP shared buffer\n");

	int rc = mmap_add_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE,
					 ARM_SECURE_SERVICE_BUFFER_BASE,
					 ARM_SECURE_SERVICE_BUFFER_SIZE,
					 MT_MEMORY | MT_RW | MT_NS);
	if (rc != 0) {
		tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n",
				     __LINE__, rc);
		return TEST_RESULT_FAIL;
	}

	timer_irq_received = 0;
	tftf_timer_register_handler(timer_handler);

	NOTICE("Programming the timer...\n");
	rc = tftf_program_timer(500);
	if (rc < 0) {
		tftf_testcase_printf("Failed to program timer (%d)\n", rc);
		goto exit_test;
	}

	INFO("Sending MM_COMMUNICATE_AARCH64 to Cactus\n");

	uint8_t timer_delay = 1;
	sps_request = create_sps_request(SPS_TIMER_SLEEP,
					 &timer_delay, sizeof(timer_delay));
	smc_args mm_communicate_smc = {
		MM_COMMUNICATE_AARCH64,
		0, /* cookie, MBZ */
		(uintptr_t) sps_request,
		0
	};

	smc_ret_values smc_ret = tftf_smc(&mm_communicate_smc);

	INFO("Returned from Cactus, MM_COMMUNICATE_AARCH64 handling complete\n");

	/*
	 * If MM_COMMUNICATE gets interrupted, SPM will return SPM_QUEUED, which
	 * is normally not a valid return value for MM_COMMUNICATE.
	 */
	if ((uint32_t) smc_ret.ret0 != SPM_SUCCESS) {
		tftf_testcase_printf("Cactus returned: 0x%x\n",
				     (uint32_t) smc_ret.ret0);
		goto exit_test;
	}

	uint32_t cactus_response;
	memcpy(&cactus_response, sps_request->data, sizeof(cactus_response));
	if (cactus_response != CACTUS_FAST_REQUEST_SUCCESS) {
		tftf_testcase_printf("Error code from the timer secure service: 0x%x\n",
				     cactus_response);
		goto exit_test;
	}

	/*
	 * If the timer interrupt is still pending, make sure it is taken right
	 * now.
	 */
	isb();

	if (timer_irq_received == 1)
		result = TEST_RESULT_SUCCESS;

exit_test:
	tftf_cancel_timer();
	tftf_timer_unregister_handler();

	VERBOSE("Unmapping NS<->SP shared buffer\n");

	mmap_remove_dynamic_region(ARM_SECURE_SERVICE_BUFFER_BASE,
				   ARM_SECURE_SERVICE_BUFFER_SIZE);

	return result;
}