1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  * All rights reserved.
5  */
6 
7 #include <fcntl.h>
8 #include <math.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <strings.h>
14 #include <sys/ioctl.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <ta_crypto_perf.h>
19 #include <tee_client_api.h>
20 #include <tee_client_api_extensions.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <assert.h>
24 
25 #include "crypto_common.h"
26 #include "xtest_helpers.h"
27 #include "xtest_test.h"
28 
29 #ifdef CFG_SECURE_DATA_PATH
30 #include "sdp_basic.h"
31 
32 static int input_sdp_fd;
33 static int output_sdp_fd;
34 
35 static const char *heap_name = DEFAULT_HEAP_NAME;
36 #endif /* CFG_SECURE_DATA_PATH */
37 
38 /*
39  * Type of buffer used for the performance tests
40  *
41  * BUFFER_UNSPECIFIED		test did not specify target buffer to use
42  * BUFFER_SHM_ALLOCATED		buffer allocated in TEE SHM.
43  * BUFFER_SECURE_REGISTER	secure buffer, registered to TEE at TA invoc.
44  * BUFFER_SECURE_PREREGISTERED	secure buffer, registered once to TEE.
45  */
46 enum buffer_types {
47 	BUFFER_UNSPECIFIED = 0,
48 	BUFFER_SHM_ALLOCATED,
49 	BUFFER_SECURE_REGISTER,		/* requires SDP */
50 	BUFFER_SECURE_PREREGISTERED,	/* requires SDP */
51 };
52 
53 static enum buffer_types input_buffer = BUFFER_UNSPECIFIED;
54 static enum buffer_types output_buffer = BUFFER_UNSPECIFIED;
55 
buf_type_str(int buf_type)56 static const char *buf_type_str(int buf_type)
57  {
58 	static const char sec_prereg[] = "Secure memory, registered once to TEE";
59 	static const char sec_reg[] = "Secure memory, registered at each TEE invoke";
60 	static const char ns_alloc[] = "Non secure memory";
61 	static const char inval[] = "UNEXPECTED";
62 
63 	switch (buf_type) {
64 	case BUFFER_SECURE_PREREGISTERED:
65 		return sec_prereg;
66 	case BUFFER_SECURE_REGISTER:
67 		return sec_reg;
68 	case BUFFER_SHM_ALLOCATED:
69 		return ns_alloc;
70 	default:
71 		return inval;
72 	}
73 }
74 
75 /* Are we running a SDP test: default to NO (is_sdp_test == 0) */
76 static int is_sdp_test;
77 
78 /*
79  * TEE client stuff
80  */
81 
82 static TEEC_Context ctx;
83 static TEEC_Session sess;
84 /*
85  * in_shm and out_shm are both IN/OUT to support dynamically choosing
86  * in_place == 1 or in_place == 0.
87  */
88 static TEEC_SharedMemory in_shm = {
89 	.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT
90 };
91 static TEEC_SharedMemory out_shm = {
92 	.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT
93 };
94 
errx(const char * msg,TEEC_Result res,uint32_t * orig)95 static void errx(const char *msg, TEEC_Result res, uint32_t *orig)
96 {
97 	fprintf(stderr, "%s: 0x%08x", msg, res);
98 	if (orig)
99 		fprintf(stderr, " (orig=%d)", (int)*orig);
100 	fprintf(stderr, "\n");
101 	exit (1);
102 }
103 
check_res(TEEC_Result res,const char * errmsg,uint32_t * orig)104 static void check_res(TEEC_Result res, const char *errmsg, uint32_t *orig)
105 {
106 	if (res != TEEC_SUCCESS)
107 		errx(errmsg, res, orig);
108 }
109 
open_ta(void)110 static void open_ta(void)
111 {
112 	TEEC_Result res = TEEC_ERROR_GENERIC;
113 	TEEC_UUID uuid = TA_CRYPTO_PERF_UUID;
114 	uint32_t err_origin = 0;
115 
116 	res = TEEC_InitializeContext(NULL, &ctx);
117 	check_res(res, "TEEC_InitializeContext", NULL);
118 
119 	res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
120 			       NULL, &err_origin);
121 	check_res(res, "TEEC_OpenSession", &err_origin);
122 }
123 
124 /*
125  * Statistics
126  *
127  * We want to compute min, max, mean and standard deviation of processing time
128  */
129 
130 struct statistics {
131 	int n;
132 	double m;
133 	double M2;
134 	double min;
135 	double max;
136 	int initialized;
137 };
138 
139 /* Take new sample into account (Knuth/Welford algorithm) */
update_stats(struct statistics * s,uint64_t t)140 static void update_stats(struct statistics *s, uint64_t t)
141 {
142 	double x = (double)t;
143 	double delta = x - s->m;
144 
145 	s->n++;
146 	s->m += delta/s->n;
147 	s->M2 += delta*(x - s->m);
148 	if (!s->initialized) {
149 		s->min = s->max = x;
150 		s->initialized = 1;
151 	} else {
152 		if (s->min > x)
153 			s->min = x;
154 		if (s->max < x)
155 			s->max = x;
156 	}
157 }
158 
stddev(struct statistics * s)159 static double stddev(struct statistics *s)
160 {
161 	if (s->n < 2)
162 		return NAN;
163 	return sqrt(s->M2/s->n);
164 }
165 
cipher_str(uint32_t algo)166 static const char *cipher_str(uint32_t algo)
167 {
168 	switch (algo) {
169 	case TA_AES_ECB:
170 	case TA_AES_CBC:
171 	case TA_AES_CTR:
172 	case TA_AES_XTS:
173 	case TA_AES_GCM:
174 		return "AES";
175 	case TA_SM4_ECB:
176 	case TA_SM4_CBC:
177 	case TA_SM4_CTR:
178 	case TA_SM4_XTS:
179 		return "SM4";
180 	default:
181 		return "???";
182 	}
183 }
184 
mode_str(uint32_t algo)185 static const char *mode_str(uint32_t algo)
186 {
187 	switch (algo) {
188 	case TA_AES_ECB:
189 	case TA_SM4_ECB:
190 		return "ECB";
191 	case TA_AES_CBC:
192 	case TA_SM4_CBC:
193 		return "CBC";
194 	case TA_AES_CTR:
195 	case TA_SM4_CTR:
196 		return "CTR";
197 	case TA_AES_XTS:
198 	case TA_SM4_XTS:
199 		return "XTS";
200 	case TA_AES_GCM:
201 		return "GCM";
202 	default:
203 		return "???";
204 	}
205 }
206 
207 #define _TO_STR(x) #x
208 #define TO_STR(x) _TO_STR(x)
209 
usage(const char * applet_optname,int keysize,int algo,size_t size,size_t unit,int warmup,unsigned int l,unsigned int n)210 static void usage(const char *applet_optname, int keysize, int algo,
211 		  size_t size, size_t unit, int warmup, unsigned int l,
212 		  unsigned int n)
213 {
214 	fprintf(stderr, "Usage: %s %s [-h]\n", xtest_progname, applet_optname);
215 	fprintf(stderr, "Usage: %s %s [-d] [-i] [-k SIZE]", xtest_progname, applet_optname);
216 	fprintf(stderr, " [-l LOOP] [-c CIPHER] [-m MODE] [-n LOOP] [-r|--no-inited] [-s SIZE]");
217 	fprintf(stderr, " [-v [-v]] [-w SEC]");
218 #ifdef CFG_SECURE_DATA_PATH
219 	fprintf(stderr, " [--sdp [-Id|-Ir|-IR] [-Od|-Or|-OR]]");
220 #endif
221 	fprintf(stderr, "\n");
222 	fprintf(stderr, "AES/SM4 performance testing tool for OP-TEE\n");
223 	fprintf(stderr, "\n");
224 	fprintf(stderr, "Options:\n");
225 	fprintf(stderr, "  -d            Test AES decryption instead of encryption\n");
226 	fprintf(stderr, "  -h|--help     Print this help and exit\n");
227 	fprintf(stderr, "  -i|--in-place Use same buffer for input and output (decrypt in place)\n");
228 	fprintf(stderr, "  -k SIZE       Key size in bits: 128, 192 or 256 [%u]\n", keysize);
229 	fprintf(stderr, "  -l LOOP       Inner loop iterations [%u]\n", l);
230 	fprintf(stderr, "  -c CIPHER     cipher: AES, SM4 [%s]\n", cipher_str(algo));
231 	fprintf(stderr, "  -m MODE       mode: ECB, CBC, CTR, XTS, GCM [%s]\n", mode_str(algo));
232 	fprintf(stderr, "  -n LOOP       Outer test loop iterations [%u]\n", n);
233 	fprintf(stderr, "  --not-inited  Do not initialize input buffer content.\n");
234 	fprintf(stderr, "  -r|--random   Get input data from /dev/urandom (default: all zeros)\n");
235 	fprintf(stderr, "  -s SIZE       Test buffer size in bytes [%zu]\n", size);
236 	fprintf(stderr, "  -u UNIT       Divide buffer in UNIT-byte increments (+ remainder)\n");
237 	fprintf(stderr, "                (0 to ignore) [%zu]\n", unit);
238 	fprintf(stderr, "  -v            Be verbose (use twice for greater effect)\n");
239 	fprintf(stderr, "  -w|--warmup SEC  Warm-up time in seconds: execute a busy loop before\n");
240 	fprintf(stderr, "                   the test to mitigate the effects of cpufreq etc. [%u]\n", warmup);
241 #ifdef CFG_SECURE_DATA_PATH
242 	fprintf(stderr, "Secure data path specific options:\n");
243 	fprintf(stderr, "  --sdp            Run the AES test in the scope fo a Secure Data Path test TA\n");
244 	fprintf(stderr, "  --heap-name NAME	Set heap name where to allocate secure buffers [%s]\n", heap_name);
245 	fprintf(stderr, "  -I...          	AES input test buffer management:\n");
246 	fprintf(stderr, "      -Id         	allocate a non secure buffer (default)\n");
247 	fprintf(stderr, "      -Ir         	allocate a secure buffer, registered at each TA invocation\n");
248 	fprintf(stderr, "      -IR         	allocate a secure buffer, registered once in TEE\n");
249 	fprintf(stderr, "  -O...          	AES output test buffer management:\n");
250 	fprintf(stderr, "      -Od         	allocate a non secure buffer (default if \"--sdp\" is not set)\n");
251 	fprintf(stderr, "      -Or         	allocate a secure buffer, registered at each TA invocation\n");
252 	fprintf(stderr, "      -OR         	allocate a secure buffer, registered once in TEE (default if \"--sdp\")\n");
253 #endif
254 }
255 
256 #ifdef CFG_SECURE_DATA_PATH
register_shm(TEEC_SharedMemory * shm,int fd)257 static void register_shm(TEEC_SharedMemory *shm, int fd)
258 {
259 	TEEC_Result res = TEEC_RegisterSharedMemoryFileDescriptor(&ctx, shm, fd);
260 
261 	check_res(res, "TEEC_RegisterSharedMemoryFileDescriptor", NULL);
262 }
263 #endif
264 
allocate_shm(TEEC_SharedMemory * shm,size_t sz)265 static void allocate_shm(TEEC_SharedMemory *shm, size_t sz)
266 {
267 	TEEC_Result res = TEEC_ERROR_GENERIC;
268 
269 	shm->buffer = NULL;
270 	shm->size = sz;
271 	res = TEEC_AllocateSharedMemory(&ctx, shm);
272 	check_res(res, "TEEC_AllocateSharedMemory", NULL);
273 }
274 
275 /* initial test buffer allocation (eventual registering to TEEC) */
alloc_buffers(size_t sz,int in_place,int verbosity)276 static void alloc_buffers(size_t sz, int in_place, int verbosity)
277 {
278 	(void)verbosity;
279 
280 	if (input_buffer == BUFFER_SHM_ALLOCATED)
281 		allocate_shm(&in_shm, sz);
282 #ifdef CFG_SECURE_DATA_PATH
283 	else {
284 		input_sdp_fd = allocate_buffer(sz, heap_name, verbosity);
285 		if (input_buffer == BUFFER_SECURE_PREREGISTERED) {
286 			register_shm(&in_shm, input_sdp_fd);
287 			close(input_sdp_fd);
288 		}
289 	}
290 #endif
291 
292 	if (in_place)
293 		return;
294 
295 	if (output_buffer == BUFFER_SHM_ALLOCATED)
296 		allocate_shm(&out_shm, sz);
297 #ifdef CFG_SECURE_DATA_PATH
298 	else {
299 		output_sdp_fd = allocate_buffer(sz, heap_name, verbosity);
300 		if (output_buffer == BUFFER_SECURE_PREREGISTERED) {
301 			register_shm(&out_shm, output_sdp_fd);
302 			close(output_sdp_fd);
303 		}
304 	}
305 #endif
306 }
307 
free_shm(int in_place)308 static void free_shm(int in_place)
309 {
310 	(void)in_place;
311 
312 	if (input_buffer == BUFFER_SHM_ALLOCATED &&
313 	    output_buffer == BUFFER_SHM_ALLOCATED) {
314 		TEEC_ReleaseSharedMemory(&in_shm);
315 		TEEC_ReleaseSharedMemory(&out_shm);
316 		return;
317 	}
318 
319 #ifdef CFG_SECURE_DATA_PATH
320 	if (input_buffer == BUFFER_SECURE_PREREGISTERED)
321 		close(input_sdp_fd);
322 	if (input_buffer != BUFFER_SECURE_REGISTER)
323 		TEEC_ReleaseSharedMemory(&in_shm);
324 
325 	if (in_place)
326 		return;
327 
328 	if (output_buffer == BUFFER_SECURE_PREREGISTERED)
329 		close(output_sdp_fd);
330 	if (output_buffer != BUFFER_SECURE_REGISTER)
331 		TEEC_ReleaseSharedMemory(&out_shm);
332 #endif /* CFG_SECURE_DATA_PATH */
333 }
334 
read_random(void * in,size_t rsize)335 static ssize_t read_random(void *in, size_t rsize)
336 {
337 	static int rnd;
338 	ssize_t s = 0;
339 
340 	if (!rnd) {
341 		rnd = open("/dev/urandom", O_RDONLY);
342 		if (rnd < 0) {
343 			perror("open");
344 			return 1;
345 		}
346 	}
347 	s = read(rnd, in, rsize);
348 	if (s < 0) {
349 		perror("read");
350 		return 1;
351 	}
352 	if ((size_t)s != rsize) {
353 		printf("read: requested %zu bytes, got %zd\n", rsize, s);
354 	}
355 
356 	return 0;
357 }
358 
get_current_time(struct timespec * ts)359 static void get_current_time(struct timespec *ts)
360 {
361 	if (clock_gettime(CLOCK_MONOTONIC, ts) < 0) {
362 		perror("clock_gettime");
363 		exit(1);
364 	}
365 }
366 
timespec_to_ns(struct timespec * ts)367 static uint64_t timespec_to_ns(struct timespec *ts)
368 {
369 	return ((uint64_t)ts->tv_sec * 1000000000) + ts->tv_nsec;
370 }
371 
timespec_diff_ns(struct timespec * start,struct timespec * end)372 static uint64_t timespec_diff_ns(struct timespec *start, struct timespec *end)
373 {
374 	return timespec_to_ns(end) - timespec_to_ns(start);
375 }
376 
prepare_key(int decrypt,int keysize,int algo)377 static void prepare_key(int decrypt, int keysize, int algo)
378 {
379 	TEEC_Result res = TEEC_ERROR_GENERIC;
380 	uint32_t ret_origin = 0;
381 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
382 	uint32_t cmd = TA_CRYPTO_PERF_CMD_CIPHER_PREPARE_KEY;
383 
384 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT,
385 					 TEEC_NONE, TEEC_NONE);
386 	op.params[0].value.a = decrypt;
387 	op.params[0].value.b = keysize;
388 	op.params[1].value.a = algo;
389 	res = TEEC_InvokeCommand(&sess, cmd, &op,
390 				 &ret_origin);
391 	check_res(res, "TEEC_InvokeCommand", &ret_origin);
392 }
393 
do_warmup(int warmup)394 static void do_warmup(int warmup)
395 {
396 	struct timespec t0 = { };
397 	struct timespec t = { };
398 	int i = 0;
399 
400 	get_current_time(&t0);
401 	do {
402 		for (i = 0; i < 100000; i++)
403 			;
404 		get_current_time(&t);
405 	} while (timespec_diff_ns(&t0, &t) < (uint64_t)warmup * 1000000000);
406 }
407 
yesno(int v)408 static const char *yesno(int v)
409 {
410 	return (v ? "yes" : "no");
411 }
412 
mb_per_sec(size_t size,double usec)413 static double mb_per_sec(size_t size, double usec)
414 {
415 	return (1000000000/usec)*((double)size/(1024*1024));
416 }
417 
feed_input(void * in,size_t size,int random)418 static void feed_input(void *in, size_t size, int random)
419 {
420 	if (random)
421 		read_random(in, size);
422 	else
423 		memset(in, 0, size);
424 }
425 
run_feed_input(void * in,size_t size,int random)426 static void run_feed_input(void *in, size_t size, int random)
427 {
428 	if (!is_sdp_test) {
429 		feed_input(in, size, random);
430 		return;
431 	}
432 
433 #ifdef CFG_SECURE_DATA_PATH
434 	if (input_buffer == BUFFER_SHM_ALLOCATED) {
435 		feed_input(in, size, random);
436 	} else {
437 		char *data = mmap(NULL, size, PROT_WRITE, MAP_SHARED,
438 						input_sdp_fd, 0);
439 
440 		if (data == MAP_FAILED) {
441 			perror("failed to map input buffer");
442 			exit(-1);
443 		}
444 		feed_input(data, size, random);
445 		munmap(data, size);
446 	}
447 #endif
448 }
449 
450 
aes_perf_run_test(int algo,int keysize,int decrypt,size_t size,size_t unit,unsigned int n,unsigned int l,int input_data_init,int in_place,int warmup,int verbosity)451 void aes_perf_run_test(int algo, int keysize, int decrypt, size_t size, size_t unit,
452 				unsigned int n, unsigned int l, int input_data_init,
453 				int in_place, int warmup, int verbosity)
454 {
455 	struct statistics stats = { };
456 	struct timespec ts = { };
457 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
458 	int n0 = n;
459 	double sd = 0;
460 	uint32_t cmd = is_sdp_test ? TA_CRYPTO_PERF_CMD_CIPHER_PROCESS_SDP :
461 				     TA_CRYPTO_PERF_CMD_CIPHER_PROCESS;
462 
463 	if (input_buffer == BUFFER_UNSPECIFIED)
464 		input_buffer = BUFFER_SHM_ALLOCATED;
465 
466 	if (output_buffer == BUFFER_UNSPECIFIED) {
467 		if (is_sdp_test)
468 			output_buffer = BUFFER_SECURE_PREREGISTERED;
469 		else
470 			output_buffer = BUFFER_SHM_ALLOCATED;
471 	}
472 
473 	if (clock_getres(CLOCK_MONOTONIC, &ts) < 0) {
474 		perror("clock_getres");
475 		return;
476 	}
477 	vverbose("Clock resolution is %jd ns\n",
478 		 (intmax_t)ts.tv_sec * 1000000000 + ts.tv_nsec);
479 
480 	vverbose("input test buffer:  %s\n", buf_type_str(input_buffer));
481 	vverbose("output test buffer: %s\n", buf_type_str(output_buffer));
482 
483 	open_ta();
484 	prepare_key(decrypt, keysize, algo);
485 
486 	alloc_buffers(size, in_place, verbosity);
487 	if (input_data_init == CRYPTO_USE_ZEROS)
488 		run_feed_input(in_shm.buffer, size, 0);
489 
490 	/* Using INOUT to handle the case in_place == 1 */
491 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
492 					 TEEC_MEMREF_PARTIAL_INOUT,
493 					 TEEC_VALUE_INPUT, TEEC_NONE);
494 	op.params[0].memref.parent = &in_shm;
495 	op.params[0].memref.size = size;
496 	op.params[1].memref.parent = in_place ? &in_shm : &out_shm;
497 	op.params[1].memref.size = size;
498 	op.params[2].value.a = l;
499 	op.params[2].value.b = unit;
500 
501 	verbose("Starting test: %s, %scrypt, keysize=%u bits, size=%zu bytes, ",
502 		mode_str(algo), (decrypt ? "de" : "en"), keysize, size);
503 	verbose("random=%s, ", yesno(input_data_init == CRYPTO_USE_RANDOM));
504 	verbose("in place=%s, ", yesno(in_place));
505 	verbose("inner loops=%u, loops=%u, warm-up=%u s, ", l, n, warmup);
506 	verbose("unit=%zu\n", unit);
507 
508 	if (warmup)
509 		do_warmup(warmup);
510 
511 	while (n-- > 0) {
512 		TEEC_Result res = TEEC_ERROR_GENERIC;
513 		uint32_t ret_origin = 0;
514 		struct timespec t0 = { };
515 		struct timespec t1 = { };
516 
517 		if (input_data_init == CRYPTO_USE_RANDOM)
518 			run_feed_input(in_shm.buffer, size, 1);
519 
520 		get_current_time(&t0);
521 
522 #ifdef CFG_SECURE_DATA_PATH
523 		if (input_buffer == BUFFER_SECURE_REGISTER)
524 			register_shm(&in_shm, input_sdp_fd);
525 		if (output_buffer == BUFFER_SECURE_REGISTER)
526 			register_shm(&out_shm, output_sdp_fd);
527 #endif
528 
529 		res = TEEC_InvokeCommand(&sess, cmd,
530 					 &op, &ret_origin);
531 		check_res(res, "TEEC_InvokeCommand", &ret_origin);
532 
533 #ifdef CFG_SECURE_DATA_PATH
534 		if (input_buffer == BUFFER_SECURE_REGISTER)
535 			TEEC_ReleaseSharedMemory(&in_shm);
536 		if (output_buffer == BUFFER_SECURE_REGISTER)
537 			TEEC_ReleaseSharedMemory(&out_shm);
538 #endif
539 
540 		get_current_time(&t1);
541 
542 		update_stats(&stats, timespec_diff_ns(&t0, &t1));
543 		if (n % (n0 / 10) == 0)
544 			vverbose("#");
545 	}
546 	vverbose("\n");
547 	sd = stddev(&stats);
548 	printf("min=%gus max=%gus mean=%gus stddev=%gus (cv %g%%) (%gMiB/s)\n",
549 	       stats.min / 1000, stats.max / 1000, stats.m / 1000,
550 	       sd / 1000, 100 * sd / stats.m, mb_per_sec(size, stats.m));
551 	verbose("2-sigma interval: %g..%gus (%g..%gMiB/s)\n",
552 		(stats.m - 2 * sd) / 1000, (stats.m + 2 * sd) / 1000,
553 		mb_per_sec(size, stats.m + 2 * sd),
554 		mb_per_sec(size, stats.m - 2 * sd));
555 	free_shm(in_place);
556 }
557 
558 #define NEXT_ARG(i) \
559 	do { \
560 		if (++i == argc) { \
561 			fprintf(stderr, "%s %s: %s: missing argument\n", \
562 				xtest_progname, argv[0], argv[i - 1]); \
563 			return 1; \
564 		} \
565 	} while (0);
566 
567 #define USAGE() usage(argv[0], keysize, algo, size, unit, warmup, l, n)
568 
get_symm_algo(int cipher,int mode)569 static int get_symm_algo(int cipher, int mode)
570 {
571 	if (cipher == AES) {
572 		switch (mode) {
573 		case ECB:
574 			return TA_AES_ECB;
575 		case CBC:
576 			return TA_AES_CBC;
577 		case CTR:
578 			return TA_AES_CTR;
579 		case XTS:
580 			return TA_AES_XTS;
581 		case GCM:
582 			return TA_AES_GCM;
583 		default:
584 			return -1;
585 		}
586 	} else if (cipher == SM4) {
587 		switch (mode) {
588 		case ECB:
589 			return TA_SM4_ECB;
590 		case CBC:
591 			return TA_SM4_CBC;
592 		case CTR:
593 			return TA_SM4_CTR;
594 		case XTS:
595 			return TA_SM4_XTS;
596 		default:
597 			return -1;
598 		}
599 	} else {
600 		return -1;
601 	}
602 }
603 
aes_perf_runner_cmd_parser(int argc,char * argv[])604 int aes_perf_runner_cmd_parser(int argc, char *argv[])
605 {
606 	int i = 0;
607 	/*
608 	* Command line parameters
609 	*/
610 	size_t size = 1024;	/* Buffer size (-s) */
611 	size_t unit = CRYPTO_DEF_UNIT_SIZE; /* Divide buffer (-u) */
612 	unsigned int n = CRYPTO_DEF_COUNT; /*Number of measurements (-n)*/
613 	unsigned int l = CRYPTO_DEF_LOOPS; /* Inner loops (-l) */
614 	int verbosity = CRYPTO_DEF_VERBOSITY;	/* Verbosity (-v) */
615 	int decrypt = 0;		/* Encrypt by default, -d to decrypt */
616 	int keysize = AES_128;	/* AES key size (-k) */
617 	int cipher = AES;
618 	int mode = ECB;
619 	int algo = -1;
620 	/* Get input data from /dev/urandom (-r) */
621 	int input_data_init = CRYPTO_USE_ZEROS;
622 	/* Use same buffer for in and out (-i) */
623 	int in_place = AES_PERF_INPLACE;
624 	int warmup = CRYPTO_DEF_WARMUP;	/* Start with a 2-second busy loop (-w) */
625 
626 	/* Parse command line */
627 	for (i = 1; i < argc; i++) {
628 		if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
629 			USAGE();
630 			return 0;
631 		}
632 	}
633 	for (i = 1; i < argc; i++) {
634 		if (!strcmp(argv[i], "-d")) {
635 			decrypt = 1;
636 		} else if (!strcmp(argv[i], "--in-place") ||
637 			   !strcmp(argv[i], "-i")) {
638 			in_place = 1;
639 		} else if (!strcmp(argv[i], "-k")) {
640 			NEXT_ARG(i);
641 			keysize = atoi(argv[i]);
642 			if (keysize != AES_128 && keysize != AES_192 &&
643 				keysize != AES_256) {
644 				fprintf(stderr, "%s %s: invalid key size\n",
645 					xtest_progname, argv[0]);
646 				USAGE();
647 				return 1;
648 			}
649 		} else if (!strcmp(argv[i], "-l")) {
650 			NEXT_ARG(i);
651 			l = atoi(argv[i]);
652 		} else if (!strcmp(argv[i], "-c")) {
653 			NEXT_ARG(i);
654 			if (!strcasecmp(argv[i], "SM4"))
655 				cipher = SM4;
656 			else if (!strcasecmp(argv[i], "AES"))
657 				cipher = AES;
658 			else {
659 				fprintf(stderr, "%s %s, invalid cipher\n",
660 					xtest_progname, argv[0]);
661 				USAGE();
662 				return 1;
663 			}
664 		} else if (!strcmp(argv[i], "-m")) {
665 			NEXT_ARG(i);
666 			if (!strcasecmp(argv[i], "ECB"))
667 				mode = ECB;
668 			else if (!strcasecmp(argv[i], "CBC"))
669 				mode = CBC;
670 			else if (!strcasecmp(argv[i], "CTR"))
671 				mode = CTR;
672 			else if (!strcasecmp(argv[i], "XTS"))
673 				mode = XTS;
674 			else if (!strcasecmp(argv[i], "GCM"))
675 				mode = GCM;
676 			else {
677 				fprintf(stderr, "%s %s, invalid mode\n",
678 					xtest_progname, argv[0]);
679 				USAGE();
680 				return 1;
681 			}
682 		} else if (!strcmp(argv[i], "-n")) {
683 			NEXT_ARG(i);
684 			n = atoi(argv[i]);
685 		} else if (!strcmp(argv[i], "--random") ||
686 			   !strcmp(argv[i], "-r")) {
687 			if (input_data_init == CRYPTO_NOT_INITED) {
688 				perror("--random is not compatible with --not-inited\n");
689 				USAGE();
690 				return 1;
691 			}
692 			input_data_init = CRYPTO_USE_RANDOM;
693 		} else if (!strcmp(argv[i], "--not-inited")) {
694 			if (input_data_init == CRYPTO_USE_RANDOM) {
695 				perror("--random is not compatible with --not-inited\n");
696 				USAGE();
697 				return 1;
698 			}
699 			input_data_init = CRYPTO_NOT_INITED;
700 		} else if (!strcmp(argv[i], "-s")) {
701 			NEXT_ARG(i);
702 			size = atoi(argv[i]);
703 #ifdef CFG_SECURE_DATA_PATH
704 		} else if (!strcmp(argv[i], "--sdp")) {
705 			is_sdp_test = 1;
706 		} else if (!strcmp(argv[i], "-IR")) {
707 			input_buffer = BUFFER_SECURE_PREREGISTERED;
708 		} else if (!strcmp(argv[i], "-OR")) {
709 			output_buffer = BUFFER_SECURE_PREREGISTERED;
710 		} else if (!strcmp(argv[i], "-Ir")) {
711 			input_buffer = BUFFER_SECURE_REGISTER;
712 		} else if (!strcmp(argv[i], "-Or")) {
713 			output_buffer = BUFFER_SECURE_REGISTER;
714 		} else if (!strcmp(argv[i], "-Id")) {
715 			input_buffer = BUFFER_SHM_ALLOCATED;
716 		} else if (!strcmp(argv[i], "-Od")) {
717 			output_buffer = BUFFER_SHM_ALLOCATED;
718 		} else if (!strcmp(argv[i], "--heap-name")) {
719 			NEXT_ARG(i);
720 			heap_name = argv[i];
721 #endif // CFG_SECURE_DATA_PATH
722 		} else if (!strcmp(argv[i], "-u")) {
723 			NEXT_ARG(i);
724 			unit = atoi(argv[i]);
725 		} else if (!strcmp(argv[i], "-v")) {
726 			verbosity++;
727 		} else if (!strcmp(argv[i], "--warmup") ||
728 			   !strcmp(argv[i], "-w")) {
729 			NEXT_ARG(i);
730 			warmup = atoi(argv[i]);
731 		} else {
732 			fprintf(stderr, "%s %s: invalid argument: %s\n",
733 				xtest_progname, argv[0], argv[i]);
734 			USAGE();
735 			return 1;
736 		}
737 	}
738 
739 	algo = get_symm_algo(cipher, mode);
740 	assert(algo != -1);
741 
742 	if (size & (16 - 1)) {
743 		fprintf(stderr, "invalid buffer size argument, must be a multiple of 16\n\n");
744 		USAGE();
745 		return 1;
746 	}
747 
748 
749 	aes_perf_run_test(algo, keysize, decrypt, size, unit, n, l,
750 			  input_data_init, in_place, warmup, verbosity);
751 
752 	return 0;
753 }
754