xtest: add SM4 perf test

Add perf test for SM4 algorithm

Signed-off-by: Zexi Yu <yuzexi@hisilicon.com>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
diff --git a/Android.mk b/Android.mk
index 6c3b947..51a817a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -42,7 +42,6 @@
 	adbg/src/adbg_log.c \
 	adbg/src/adbg_run.c \
 	adbg/src/security_utils_hex.c \
-	aes_perf.c \
 	asym_perf.c \
 	benchmark_1000.c \
 	benchmark_2000.c \
@@ -55,6 +54,7 @@
 	regression_8100.c \
 	hash_perf.c \
 	stats.c \
+	symm_cipher_perf.c \
 	xtest_helpers.c \
 	xtest_main.c \
 	xtest_test.c \
diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt
index df6484a..0fb5f3a 100644
--- a/host/xtest/CMakeLists.txt
+++ b/host/xtest/CMakeLists.txt
@@ -45,7 +45,6 @@
 	adbg/src/adbg_log.c
 	adbg/src/adbg_run.c
 	adbg/src/security_utils_hex.c
-	aes_perf.c
 	asym_perf.c
 	benchmark_1000.c
 	benchmark_2000.c
@@ -59,6 +58,7 @@
 	regression_8100.c
 	hash_perf.c
 	stats.c
+	symm_cipher_perf.c
 	xtest_helpers.c
 	xtest_main.c
 	xtest_test.c
diff --git a/host/xtest/Makefile b/host/xtest/Makefile
index 477ec06..bdab2f6 100644
--- a/host/xtest/Makefile
+++ b/host/xtest/Makefile
@@ -57,7 +57,6 @@
 	adbg/src/adbg_log.c \
 	adbg/src/adbg_run.c \
 	adbg/src/security_utils_hex.c \
-	aes_perf.c \
 	asym_perf.c \
 	benchmark_1000.c \
 	benchmark_2000.c \
@@ -70,6 +69,7 @@
 	regression_8100.c \
 	hash_perf.c \
 	stats.c \
+	symm_cipher_perf.c \
 	xtest_helpers.c \
 	xtest_main.c \
 	xtest_test.c \
diff --git a/host/xtest/aes_perf.c b/host/xtest/symm_cipher_perf.c
similarity index 88%
rename from host/xtest/aes_perf.c
rename to host/xtest/symm_cipher_perf.c
index c2f381e..906391b 100644
--- a/host/xtest/aes_perf.c
+++ b/host/xtest/symm_cipher_perf.c
@@ -20,6 +20,7 @@
 #include <tee_client_api_extensions.h>
 #include <time.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include "crypto_common.h"
 #include "xtest_helpers.h"
@@ -162,16 +163,39 @@
 	return sqrt(s->M2/s->n);
 }
 
-static const char *mode_str(uint32_t mode)
+static const char *cipher_str(uint32_t algo)
 {
-	switch (mode) {
+	switch (algo) {
 	case TA_AES_ECB:
+	case TA_AES_CBC:
+	case TA_AES_CTR:
+	case TA_AES_XTS:
+	case TA_AES_GCM:
+		return "AES";
+	case TA_SM4_ECB:
+	case TA_SM4_CBC:
+	case TA_SM4_CTR:
+	case TA_SM4_XTS:
+		return "SM4";
+	default:
+		return "???";
+	}
+}
+
+static const char *mode_str(uint32_t algo)
+{
+	switch (algo) {
+	case TA_AES_ECB:
+	case TA_SM4_ECB:
 		return "ECB";
 	case TA_AES_CBC:
+	case TA_SM4_CBC:
 		return "CBC";
 	case TA_AES_CTR:
+	case TA_SM4_CTR:
 		return "CTR";
 	case TA_AES_XTS:
+	case TA_SM4_XTS:
 		return "XTS";
 	case TA_AES_GCM:
 		return "GCM";
@@ -183,19 +207,19 @@
 #define _TO_STR(x) #x
 #define TO_STR(x) _TO_STR(x)
 
-static void usage(const char *applet_optname, int keysize, int mode,
+static void usage(const char *applet_optname, int keysize, int algo,
 		  size_t size, size_t unit, int warmup, unsigned int l,
 		  unsigned int n)
 {
 	fprintf(stderr, "Usage: %s %s [-h]\n", xtest_progname, applet_optname);
 	fprintf(stderr, "Usage: %s %s [-d] [-i] [-k SIZE]", xtest_progname, applet_optname);
-	fprintf(stderr, " [-l LOOP] [-m MODE] [-n LOOP] [-r|--no-inited] [-s SIZE]");
+	fprintf(stderr, " [-l LOOP] [-c CIPHER] [-m MODE] [-n LOOP] [-r|--no-inited] [-s SIZE]");
 	fprintf(stderr, " [-v [-v]] [-w SEC]");
 #ifdef CFG_SECURE_DATA_PATH
 	fprintf(stderr, " [--sdp [-Id|-Ir|-IR] [-Od|-Or|-OR]]");
 #endif
 	fprintf(stderr, "\n");
-	fprintf(stderr, "AES performance testing tool for OP-TEE\n");
+	fprintf(stderr, "AES/SM4 performance testing tool for OP-TEE\n");
 	fprintf(stderr, "\n");
 	fprintf(stderr, "Options:\n");
 	fprintf(stderr, "  -d            Test AES decryption instead of encryption\n");
@@ -203,7 +227,8 @@
 	fprintf(stderr, "  -i|--in-place Use same buffer for input and output (decrypt in place)\n");
 	fprintf(stderr, "  -k SIZE       Key size in bits: 128, 192 or 256 [%u]\n", keysize);
 	fprintf(stderr, "  -l LOOP       Inner loop iterations [%u]\n", l);
-	fprintf(stderr, "  -m MODE       AES mode: ECB, CBC, CTR, XTS, GCM [%s]\n", mode_str(mode));
+	fprintf(stderr, "  -c CIPHER     cipher: AES, SM4 [%s]\n", cipher_str(algo));
+	fprintf(stderr, "  -m MODE       mode: ECB, CBC, CTR, XTS, GCM [%s]\n", mode_str(algo));
 	fprintf(stderr, "  -n LOOP       Outer test loop iterations [%u]\n", n);
 	fprintf(stderr, "  --not-inited  Do not initialize input buffer content.\n");
 	fprintf(stderr, "  -r|--random   Get input data from /dev/urandom (default: all zeros)\n");
@@ -349,7 +374,7 @@
 	return timespec_to_ns(end) - timespec_to_ns(start);
 }
 
-static void prepare_key(int decrypt, int keysize, int mode)
+static void prepare_key(int decrypt, int keysize, int algo)
 {
 	TEEC_Result res = TEEC_ERROR_GENERIC;
 	uint32_t ret_origin = 0;
@@ -360,7 +385,7 @@
 					 TEEC_NONE, TEEC_NONE);
 	op.params[0].value.a = decrypt;
 	op.params[0].value.b = keysize;
-	op.params[1].value.a = mode;
+	op.params[1].value.a = algo;
 	res = TEEC_InvokeCommand(&sess, cmd, &op,
 				 &ret_origin);
 	check_res(res, "TEEC_InvokeCommand", &ret_origin);
@@ -423,7 +448,7 @@
 }
 
 
-void aes_perf_run_test(int mode, int keysize, int decrypt, size_t size, size_t unit,
+void 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)
 {
@@ -456,7 +481,7 @@
 	vverbose("output test buffer: %s\n", buf_type_str(output_buffer));
 
 	open_ta();
-	prepare_key(decrypt, keysize, mode);
+	prepare_key(decrypt, keysize, algo);
 
 	alloc_buffers(size, in_place, verbosity);
 	if (input_data_init == CRYPTO_USE_ZEROS)
@@ -474,7 +499,7 @@
 	op.params[2].value.b = unit;
 
 	verbose("Starting test: %s, %scrypt, keysize=%u bits, size=%zu bytes, ",
-		mode_str(mode), (decrypt ? "de" : "en"), keysize, size);
+		mode_str(algo), (decrypt ? "de" : "en"), keysize, size);
 	verbose("random=%s, ", yesno(input_data_init == CRYPTO_USE_RANDOM));
 	verbose("in place=%s, ", yesno(in_place));
 	verbose("inner loops=%u, loops=%u, warm-up=%u s, ", l, n, warmup);
@@ -539,7 +564,42 @@
 		} \
 	} while (0);
 
-#define USAGE() usage(argv[0], keysize, mode, size, unit, warmup, l, n)
+#define USAGE() usage(argv[0], keysize, algo, size, unit, warmup, l, n)
+
+static int get_symm_algo(int cipher, int mode)
+{
+	if (cipher == AES) {
+		switch (mode) {
+		case ECB:
+			return TA_AES_ECB;
+		case CBC:
+			return TA_AES_CBC;
+		case CTR:
+			return TA_AES_CTR;
+		case XTS:
+			return TA_AES_XTS;
+		case GCM:
+			return TA_AES_GCM;
+		default:
+			return -1;
+		}
+	} else if (cipher == SM4) {
+		switch (mode) {
+		case ECB:
+			return TA_SM4_ECB;
+		case CBC:
+			return TA_SM4_CBC;
+		case CTR:
+			return TA_SM4_CTR;
+		case XTS:
+			return TA_SM4_XTS;
+		default:
+			return -1;
+		}
+	} else {
+		return -1;
+	}
+}
 
 int aes_perf_runner_cmd_parser(int argc, char *argv[])
 {
@@ -554,7 +614,9 @@
 	int verbosity = CRYPTO_DEF_VERBOSITY;	/* Verbosity (-v) */
 	int decrypt = 0;		/* Encrypt by default, -d to decrypt */
 	int keysize = AES_128;	/* AES key size (-k) */
-	int mode = TA_AES_ECB;	/* AES mode (-m) */
+	int cipher = AES;
+	int mode = ECB;
+	int algo = -1;
 	/* Get input data from /dev/urandom (-r) */
 	int input_data_init = CRYPTO_USE_ZEROS;
 	/* Use same buffer for in and out (-i) */
@@ -587,18 +649,30 @@
 		} else if (!strcmp(argv[i], "-l")) {
 			NEXT_ARG(i);
 			l = atoi(argv[i]);
+		} else if (!strcmp(argv[i], "-c")) {
+			NEXT_ARG(i);
+			if (!strcasecmp(argv[i], "SM4"))
+				cipher = SM4;
+			else if (!strcasecmp(argv[i], "AES"))
+				cipher = AES;
+			else {
+				fprintf(stderr, "%s %s, invalid cipher\n",
+					xtest_progname, argv[0]);
+				USAGE();
+				return 1;
+			}
 		} else if (!strcmp(argv[i], "-m")) {
 			NEXT_ARG(i);
 			if (!strcasecmp(argv[i], "ECB"))
-				mode = TA_AES_ECB;
+				mode = ECB;
 			else if (!strcasecmp(argv[i], "CBC"))
-				mode = TA_AES_CBC;
+				mode = CBC;
 			else if (!strcasecmp(argv[i], "CTR"))
-				mode = TA_AES_CTR;
+				mode = CTR;
 			else if (!strcasecmp(argv[i], "XTS"))
-				mode = TA_AES_XTS;
+				mode = XTS;
 			else if (!strcasecmp(argv[i], "GCM"))
-				mode = TA_AES_GCM;
+				mode = GCM;
 			else {
 				fprintf(stderr, "%s %s, invalid mode\n",
 					xtest_progname, argv[0]);
@@ -662,6 +736,9 @@
 		}
 	}
 
+	algo = get_symm_algo(cipher, mode);
+	assert(algo != -1);
+
 	if (size & (16 - 1)) {
 		fprintf(stderr, "invalid buffer size argument, must be a multiple of 16\n\n");
 		USAGE();
@@ -669,7 +746,7 @@
 	}
 
 
-	aes_perf_run_test(mode, keysize, decrypt, size, unit, n, l,
+	aes_perf_run_test(algo, keysize, decrypt, size, unit, n, l,
 			  input_data_init, in_place, warmup, verbosity);
 
 	return 0;
diff --git a/ta/crypto_perf/include/ta_crypto_perf.h b/ta/crypto_perf/include/ta_crypto_perf.h
index 1d5acc8..4d0b6c0 100644
--- a/ta/crypto_perf/include/ta_crypto_perf.h
+++ b/ta/crypto_perf/include/ta_crypto_perf.h
@@ -36,6 +36,10 @@
 #define TA_AES_CTR	2
 #define TA_AES_XTS	3
 #define TA_AES_GCM	4
+#define TA_SM4_ECB	5
+#define TA_SM4_CBC	6
+#define TA_SM4_CTR	7
+#define TA_SM4_XTS	8
 
 /*
  * AES key sizes
@@ -91,6 +95,19 @@
 #define DH_MAX_SIZE 4096
 #define DH_G_SIZE 1
 
+enum symm_cipher {
+	AES = 0,
+	SM4 = 1,
+};
+
+enum symm_mode {
+	ECB = 0,
+	CBC = 1,
+	CTR = 2,
+	XTS = 3,
+	GCM = 4,
+};
+
 enum asym_algorithm {
 	ALGO_DH = 1,
 	ALGO_RSA = 2,
diff --git a/ta/crypto_perf/ta_crypto_perf.c b/ta/crypto_perf/ta_crypto_perf.c
index af616d3..df52d02 100644
--- a/ta/crypto_perf/ta_crypto_perf.c
+++ b/ta/crypto_perf/ta_crypto_perf.c
@@ -236,6 +236,27 @@
 		objectType = TEE_TYPE_AES;
 		use_iv = 1;
 		break;
+	case TA_SM4_ECB:
+		algo = TEE_ALG_SM4_ECB_NOPAD;
+		objectType = TEE_TYPE_SM4;
+		use_iv = 0;
+		break;
+	case TA_SM4_CBC:
+		algo = TEE_ALG_SM4_CBC_NOPAD;
+		objectType = TEE_TYPE_SM4;
+		use_iv = 1;
+		break;
+	case TA_SM4_CTR:
+		algo = TEE_ALG_SM4_CTR;
+		objectType = TEE_TYPE_SM4;
+		use_iv = 1;
+		break;
+	case TA_SM4_XTS:
+		algo = TEE_ALG_SM4_XTS;
+		objectType = TEE_TYPE_SM4;
+		use_iv = 1;
+		op_keysize *= 2;
+		break;
 	default:
 		return TEE_ERROR_BAD_PARAMETERS;
 	}
@@ -255,7 +276,7 @@
 	res = TEE_PopulateTransientObject(hkey, &attr, 1);
 	CHECK(res, "TEE_PopulateTransientObject", return res;);
 
-	if (algo == TEE_ALG_AES_XTS) {
+	if (algo == TEE_ALG_AES_XTS || algo == TEE_ALG_SM4_XTS) {
 		res = TEE_AllocateTransientObject(objectType, keysize, &hkey2);
 		CHECK(res, "TEE_AllocateTransientObject", return res;);