feat(rme): add dummy platform token to RMMD

Add a dummy platform token to RMMD and return it on request. The
platform token is requested with an SMC with the following parameters:
    * Fid (0xC40001B3).
    * Platform token PA (the platform token is copied at this address by
      the monitor). The challenge object needs to be passed by
      the caller in this buffer.
    * Platform token len.
    * Challenge object len.

When calling the SMC, the platform token buffer received by EL3 contains
the challenge object. It is not used on the FVP and is only printed to
the log.

Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
Signed-off-by: Subhasish Ghosh <subhasish.ghosh@arm.com>
Change-Id: I8b2f1d54426c04e76d7a3baa6b0fbc40b0116348
diff --git a/services/std_svc/rmmd/rmmd.mk b/services/std_svc/rmmd/rmmd.mk
index bac0a9f..bcf54e1 100644
--- a/services/std_svc/rmmd/rmmd.mk
+++ b/services/std_svc/rmmd/rmmd.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -12,7 +12,8 @@
 
 RMMD_SOURCES	+=	$(addprefix services/std_svc/rmmd/,	\
 			${ARCH}/rmmd_helpers.S			\
-			rmmd_main.c)
+			rmmd_main.c				\
+			rmmd_attest.c)
 
 # Let the top-level Makefile know that we intend to include RMM image
 NEED_RMM	:=	yes
diff --git a/services/std_svc/rmmd/rmmd_attest.c b/services/std_svc/rmmd/rmmd_attest.c
new file mode 100644
index 0000000..d111b88
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_attest.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+#include <string.h>
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include "rmmd_private.h"
+#include <services/rmmd_svc.h>
+
+static spinlock_t lock;
+
+/* For printing Realm attestation token hash */
+#define DIGITS_PER_BYTE				2UL
+#define LENGTH_OF_TERMINATING_ZERO_IN_BYTES	1UL
+#define BYTES_PER_LINE_BASE			4UL
+
+static void print_challenge(uint8_t *hash, size_t hash_size)
+{
+	size_t leftover;
+	/*
+	 * bytes_per_line is always a power of two, so it can be used to
+	 * construct mask with it when it is necessary to count remainder.
+	 *
+	 */
+	const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE;
+	char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE +
+		LENGTH_OF_TERMINATING_ZERO_IN_BYTES];
+	const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+				  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+	unsigned int i;
+
+	for (i = 0U; i < hash_size; ++i) {
+		hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] =
+			hex_chars[hash[i] >> 4];
+		hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] =
+			hex_chars[hash[i] & 0x0f];
+		if (((i + 1) & (bytes_per_line - 1)) == 0U) {
+			hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0';
+			VERBOSE("hash part %u = %s\n",
+				(i >> BYTES_PER_LINE_BASE) + 1, hash_text);
+		}
+	}
+
+	leftover = (size_t)i & (bytes_per_line - 1);
+
+	if (leftover != 0UL) {
+		hash_text[leftover * DIGITS_PER_BYTE] = '\0';
+		VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1,
+			hash_text);
+	}
+}
+
+/*
+ * TODO: Have different error codes for different errors so that the caller can
+ * differentiate various error cases.
+ */
+int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_len, uint64_t challenge_hash_len)
+{
+	int err;
+	uintptr_t va;
+	uint8_t temp_buf[SHA512_DIGEST_SIZE];
+
+	/*
+	 * TODO: Currently we don't validate incoming buf_pa. This is a
+	 * prototype and we will need to allocate static buffer for EL3-RMM
+	 * communication.
+	 */
+
+	/* We need a page of buffer to pass data */
+	if (*buf_len != PAGE_SIZE) {
+		ERROR("Invalid buffer length\n");
+		return RMMD_ERR_INVAL;
+	}
+
+	if ((challenge_hash_len != SHA256_DIGEST_SIZE) &&
+	    (challenge_hash_len != SHA384_DIGEST_SIZE) &&
+	    (challenge_hash_len != SHA512_DIGEST_SIZE)) {
+		ERROR("Invalid hash size: %lu\n", challenge_hash_len);
+		return RMMD_ERR_INVAL;
+	}
+
+	spin_lock(&lock);
+
+	/* Map the buffer that was provided by the RMM. */
+	err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE,
+					       MT_RW_DATA | MT_REALM);
+	if (err != 0) {
+		ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n"
+		      , err, (void *)buf_pa);
+		spin_unlock(&lock);
+		return RMMD_ERR_NOMEM;
+	}
+
+	(void)memcpy(temp_buf, (void *)va, challenge_hash_len);
+
+	print_challenge((uint8_t *)temp_buf, challenge_hash_len);
+
+	/* Get the platform token. */
+	err = plat_get_cca_attest_token(va,
+		buf_len, (uintptr_t)temp_buf, challenge_hash_len);
+
+	if (err != 0) {
+		ERROR("Failed to get platform token: %d.\n", err);
+		err = RMMD_ERR_UNK;
+	}
+
+	/* Unmap RMM memory. */
+	(void)mmap_remove_dynamic_region(va, PAGE_SIZE);
+	spin_unlock(&lock);
+
+	return err;
+}
+
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index 7f4a010..c59e68a 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -372,6 +372,9 @@
 	case RMMD_GTSI_UNDELEGATE:
 		ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM);
 		SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1));
+	case RMMD_ATTEST_GET_PLAT_TOKEN:
+		ret = rmmd_attest_get_platform_token(x1, &x2, x3);
+		SMC_RET2(handle, ret, x2);
 	default:
 		WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid);
 		SMC_RET1(handle, SMC_UNK);
diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h
index ca2c37c..d7ef4e1 100644
--- a/services/std_svc/rmmd/rmmd_private.h
+++ b/services/std_svc/rmmd/rmmd_private.h
@@ -51,6 +51,10 @@
 uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *ctx);
 __dead2 void rmmd_rmm_sync_exit(uint64_t rc);
 
+/* Functions implementing attestation utilities for RMM */
+int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_len,
+				   uint64_t challenge_hash_len);
+
 /* Assembly helpers */
 uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);
 void __dead2 rmmd_rmm_exit(uint64_t c_rt_ctx, uint64_t ret);