summaryrefslogtreecommitdiff
path: root/test-app.c
blob: 2484f8de2cb2b51307daff7010c9e6aa686962ce (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// SPDX-License-Identifier: BSD-3-Clause
/*
 * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
 *
 * Description:
 * File containing various unit tests for the Corstone-700 test platform.
 * The contents of this file utilize handling of the transmitted commands
 * on respectively the ES and SE sides.
 * Test verification is not performed by this program. Instead, all test
 * variables are printed to the console, which will then be used to externally
 * verify the test.
 * Tests may be selected by providing the test index as an argument of this
 * program.
 */

#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

enum test_apps {
	INVALID,
	ES_RELEASE_CPU_WAIT,
	ES_MHU,
	SE_MHU,
	SE_TIMER,
	ES_RESET_TEST,
	NUM_TEST_APPS
};

enum es_command {
	ES_NONE,
	/*
	 * Send the value to the PE, the PE will then increment the value
	 * and send it back to here (Host)
	 */
	ES_INC_RETURN,
	/*
	 * Send the value to the ES, the ES will then increment the value
	 * and send it to Secure enclave
	 */
	ES_INC_SEND_TO_SE,
	/*
	 * Send the value to the ES, make the ES send this value to the secure
	 * enclave, and make the secure enclave increment and echo the value
	 * back to the ES
	 */
	ES_INC_ECHO_SE,
	ES_NUM_COMMANDS,
};

/*
 * Macros for executing API commands, which will fail the test if the
 * command fails.
 */
#define TRY_OPEN(FD, DEVICE, ...)						\
	int FD = open(DEVICE, ##__VA_ARGS__);					\
	if (FD == -1) {								\
		printf("Could not open " DEVICE " device, exiting...\n");	\
		return 1;							\
	}									\

#define TRY_CLOSE(FD, ...)								\
do {											\
	FD = close(FD, ##__VA_ARGS__);							\
	if (FD == -1) {									\
		printf("Could not close file descriptor " #FD " device, exiting...\n");	\
		return 1;								\
	}										\
} while (0)										\

#define TRY_IOCTL(STATUS, FD, ...)									\
do {													\
	STATUS = ioctl(FD, ##__VA_ARGS__);								\
	if (STATUS != 0) {										\
		printf("ioctl on file descriptor '" #FD "' failed with status code: %d", STATUS);	\
		return 1;										\
	}												\
} while (0)
/**
 * struct rpmsg_endpoint_info - endpoint info representation
 * @name: name of service
 * @src: local address
 * @dst: destination address
 */
struct rpmsg_endpoint_info {
	char name[32];
	u_int32_t src;
	u_int32_t dst;
};

#define RPMSG_CREATE_EPT_IOCTL _IOW(0xb5, 0x1, struct rpmsg_endpoint_info)
#define RPMSG_DESTROY_EPT_IOCTL _IO(0xb5, 0x2)

#define EXTSYS_CPU_WAIT_DISABLE 0x0
#define EXTSYS_RESET_REQ        0x1

/* MHU test command encoding */
#define BITMASK(x) ((unsigned int)-1 >> ((sizeof(int) * CHAR_BIT) - x))
#define CMD_WIDTH 4
#define COMMAND(message) (message & BITMASK(CMD_WIDTH))
#define VALUE(message) ((unsigned int)message >> CMD_WIDTH)
#define ENCODE(command, value) ((command & BITMASK(CMD_WIDTH)) | \
				(value << CMD_WIDTH))

enum se_command {
	SE_NONE,
	/*
	 * Send the value to the PE, the PE will then increment the value
	 * and send it back to here (Host)
	 */
	SE_INC_RETURN,
	/* Start single-shot timer which will be routed to the boot processor */
	SE_TIMER_ONCE,
	SE_NUM_COMMANDS
};

/* Desassert the cpuwait signal of the external system#0 harness */
static int es_release_cpuwait_test(void)
{
	int status;
	/* Bring external system out of reset */
	TRY_OPEN(fd_sdk, "/dev/extsys_ctrl", O_RDWR);
	TRY_IOCTL(status, fd_sdk, EXTSYS_CPU_WAIT_DISABLE, 0);
	TRY_CLOSE(fd_sdk);
	return 0;
}

/*
 * Test MHU connection between HOST <=> ES0 MHU 0 and 1,
 * and SE <=> ES0 MHU 0 and 1
 */
static int es_mhu_test(void)
{
	int status;
	int message;
	int epts[2];
	const int value = 0xABCDEF;

	struct rpmsg_endpoint_info es0mhu0_eptinfo = {"es0mhu0", 0XFFFFFFFF,
							0xFFFFFFFF};
	struct rpmsg_endpoint_info es0mhu1_eptinfo = {"es0mhu1", 0XFFFFFFFF,
							0xFFFFFFFF};

	TRY_OPEN(fd, "/dev/rpmsg_ctrl0", O_RDWR);
	/* Create endpoint interfaces for each MHU */
	/* /dev/rpmsg0 is created */
	TRY_IOCTL(status, fd, RPMSG_CREATE_EPT_IOCTL, &es0mhu0_eptinfo);
	/* /dev/rpmsg1 is created */
	TRY_IOCTL(status, fd, RPMSG_CREATE_EPT_IOCTL, &es0mhu1_eptinfo);

	/* create endpoints for each mhu */
	TRY_OPEN(fd_es0mhu0_ept, "/dev/rpmsg0", O_RDWR);
	TRY_OPEN(fd_es0mhu1_ept, "/dev/rpmsg1", O_RDWR);
	epts[0] = fd_es0mhu0_ept;
	epts[1] = fd_es0mhu1_ept;

	/* Bring external system out of reset */
	es_release_cpuwait_test();

	/*
	 * Await ES system boot. Currently there is no signalling mechanism for
	 * this, so revert to sleeping
	 */
	sleep(1);

	/* External system test */
	for (int i = 0; i < 2; i++) {
		int ept = epts[i];
		char *name;
		/* ========== ES < = > HOST TESTS ========== */
		/* Make ES echo the value back to host with incremented value */
		message = ENCODE(ES_INC_RETURN, value);
		write(ept, &message, sizeof(message));
		/*
		 * External system cannot execute the test command within an
		 * interrupt handler. Since no command buffering has been
		 * implemented on the ES, a sleep allows the ES to process
		 * a command before the host transmits subsequent commands.
		 */
		sleep(1);
		/* Read the data transmitted by the previous command */
		read(ept, &message, sizeof(message));
		printf("Received %x from %s\n", message,
		ept == fd_es0mhu0_ept ? "es0mhu0" : "es0mhu1");
		/* ================== ES < = > SE ================== */
		/* Make ES send a message to the SE with incremented value */
		message = ENCODE(ES_INC_SEND_TO_SE, value);
		write(ept, &message, sizeof(message));
		sleep(1);
	}

	/* destroy endpoints */
	TRY_IOCTL(status, fd_es0mhu0_ept, RPMSG_DESTROY_EPT_IOCTL);
	TRY_IOCTL(status, fd_es0mhu1_ept, RPMSG_DESTROY_EPT_IOCTL);
	TRY_CLOSE(fd_es0mhu0_ept);
	TRY_CLOSE(fd_es0mhu1_ept);
	TRY_CLOSE(fd);
	return 0;
}

/* Test MHU connection between HOST <=> BP MHU 1 */
static int se_mhu_test(void)
{
	int status;
	int message;
	const int value = 0xABCDEF;
	struct rpmsg_endpoint_info semhu1_eptinfo = {"semhu1", 0XFFFFFFFF,
							0xFFFFFFFF};

	TRY_OPEN(fd, "/dev/rpmsg_ctrl0", O_RDWR);

	/* Create endpoint interface */
	/* /dev/rpmsg0 is created */
	TRY_IOCTL(status, fd, RPMSG_CREATE_EPT_IOCTL, &semhu1_eptinfo);

	/* create endpoint */
	TRY_OPEN(fd_semhu1_ept, "/dev/rpmsg0", O_RDWR);

	/* ========== BP < = > HOST TESTS ========== */
	message = ENCODE(SE_INC_RETURN, value);
	write(fd_semhu1_ept, &message, sizeof(message));
	sleep(1);
	read(fd_semhu1_ept, &message, sizeof(message));
	printf("Received %x from boot processor\n", message);

	/* destroy endpoints */
	TRY_IOCTL(status, fd_semhu1_ept, RPMSG_DESTROY_EPT_IOCTL);

	TRY_CLOSE(fd_semhu1_ept);
	TRY_CLOSE(fd);
	return 0;
}

/* Test timer and interrupt driver in boot processor */
static int se_timer_test(void)
{
	int status;
	int message = ENCODE(SE_TIMER_ONCE, 0);
	struct rpmsg_endpoint_info semhu1_eptinfo = {"semhu1", 0XFFFFFFFF,
							0xFFFFFFFF};

	TRY_OPEN(fd, "/dev/rpmsg_ctrl0", O_RDWR);

	/* Create endpoint interface */
	/* /dev/rpmsg0 is created */
	TRY_IOCTL(status, fd, RPMSG_CREATE_EPT_IOCTL, &semhu1_eptinfo);

	/* create endpoint */
	TRY_OPEN(fd_semhu1_ept, "/dev/rpmsg0", O_RDWR);

	write(fd_semhu1_ept, &message, sizeof(message));
	printf("Sent timer: %d, test command to boot processor\n", message);

	/* destroy endpoints */
	TRY_IOCTL(status, fd_semhu1_ept, RPMSG_DESTROY_EPT_IOCTL);
	TRY_CLOSE(fd_semhu1_ept);
	TRY_CLOSE(fd);
	return 0;
}

/* Desassert the reset signal of the external system#0 harness */
static int es_reset_test(void)
{
	int status;

	/* Bring external system out of reset */
	TRY_OPEN(fd_sdk, "/dev/extsys_ctrl", O_RDWR);
	TRY_IOCTL(status, fd_sdk, EXTSYS_RESET_REQ, 0);
	TRY_CLOSE(fd_sdk);
	return 0;
}

int main(int argc, char *argv[])
{
	if (argc != 2) {
		printf("Usage: ./test-app <test app number>\n");
		printf("  test app number : 1 for External System reset.\n");
		printf("    This test resets the External System\n");
		printf("  test app number : 2 for External System MHU.\n");
		printf("    This tests MHU communication between External System <=> Boot Processor\n");
		printf("    and also between External System <=> Host System\n");
		printf("  test app number : 3 for Boot Processor MHU.\n");
		printf("    This tests MHU communication between Boot Processor <=> Host System\n");
		printf("  test app number : 4 for Boot Processor Timer.\n");
		printf("    This test Host Timer usage on Boot Processor\n");
		printf("    using interrupt router and interrupt collator\n");

		return 1;
	}

	switch (atoi(argv[1])) {
	default:
	case INVALID:
		printf("Invalid test app specified\n");
		printf("%d test apps are available\n", NUM_TEST_APPS - 1);
		break;
	case ES_RELEASE_CPU_WAIT:
		return es_release_cpuwait_test();
	case ES_MHU:
		return es_mhu_test();
	case SE_MHU:
		return se_mhu_test();
	case SE_TIMER:
		return se_timer_test();
	case ES_RESET_TEST:
		return es_reset_test();
	}

	return 0;
}