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_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;
+}
+