feat(rmm-eac4): modify RSI_ATTESTATION_TOKEN commands

Modifies RSI_ATTESTATION_TOKEN_INIT and
RSI_ATTESTATION_TOKEN_CONTINUE commands as per
RMM Specification 1.0-eac4.
Number of 4K pages allocated for attestation
buffer is defined by RMM_ATTEST_BUFFER_PAGES
in CommonConfigs.cmake and set to 1 by default.

Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
Change-Id: Icda7f26e291a19b143ae14a291c03cc7bda0e076
diff --git a/cmake/CommonConfigs.cmake b/cmake/CommonConfigs.cmake
index 7e1e9a4..d212c06 100644
--- a/cmake/CommonConfigs.cmake
+++ b/cmake/CommonConfigs.cmake
@@ -53,6 +53,15 @@
     ELSE OFF)
 
 #
+# The number of 4K pages allocated for attestation buffer.
+#
+arm_config_option(
+    NAME RMM_CCA_TOKEN_BUFFER
+    HELP "Number of pages to allocate in Aux granules for Realm CCA token"
+    TYPE STRING
+    DEFAULT 1)
+
+#
 # Introduce a pseudo-library purely for applying flags to RMM's libraries.
 # This is applied to any targets created after this point.
 #
@@ -91,6 +100,9 @@
         INTERFACE "RMM_FPU_USE_AT_REL2=1")
 endif()
 
+target_compile_definitions(rmm-common
+    INTERFACE "RMM_CCA_TOKEN_BUFFER=U(${RMM_CCA_TOKEN_BUFFER})")
+
 #
 # Project name and version
 #
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index a14200c..af2f797 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -250,6 +250,7 @@
    RMM_MAX_SIZE			,			,0x0			,"Maximum size for RMM image"
    MAX_CPUS			,			,16			,"Maximum number of CPUs supported by RMM"
    GRANULE_SHIFT		,			,12			,"Granule Shift used by RMM"
+   RMM_CCA_TOKEN_BUFFER		,			,1			,"Number of pages to allocate in Aux granules for Realm CCA token"
    RMM_DOCS			,ON | OFF		,OFF			,"RMM Documentation build"
    CMAKE_BUILD_TYPE		,Debug | Release	,Release		,"CMake Build type"
    CMAKE_CONFIGURATION_TYPES	,Debug & Release	,Debug & Release	,"Multi-generator configuration types"
diff --git a/lib/allocator/include/memory_alloc.h b/lib/allocator/include/memory_alloc.h
index 06f381a..eb7da95 100644
--- a/lib/allocator/include/memory_alloc.h
+++ b/lib/allocator/include/memory_alloc.h
@@ -11,12 +11,12 @@
 typedef struct memory_header_s memory_header_t;
 
 /* MbedTLS needs 8K of heap for attestation usecases */
-#define REC_HEAP_PAGES		2U
-#define REC_HEAP_SIZE		(REC_HEAP_PAGES * SZ_4K)
+#define REC_HEAP_PAGES			2U
+#define REC_HEAP_SIZE			(REC_HEAP_PAGES * SZ_4K)
 
 /* Number of pages per REC for PMU state */
-#define REC_PMU_PAGES		1U
-#define REC_PMU_SIZE		(REC_PMU_PAGES * SZ_4K)
+#define REC_PMU_PAGES			1U
+#define REC_PMU_SIZE			(REC_PMU_PAGES * SZ_4K)
 
 /*
  * SIMD context that holds FPU/SVE registers. Space to save max arch supported
@@ -27,18 +27,22 @@
  * Size of other status registers         :   32 bytes
  * Total size is ~3 Pages (rounded up to page size).
  */
-#define REC_SIMD_PAGES		3U
-#define REC_SIMD_SIZE		(REC_SIMD_PAGES * SZ_4K)
+#define REC_SIMD_PAGES			3U
+#define REC_SIMD_SIZE			(REC_SIMD_PAGES * SZ_4K)
 
 /* Number of pages per REC for 'rec_attest_data' structure */
-#define REC_ATTEST_PAGES	1U
-#define REC_ATTEST_SIZE		(REC_ATTEST_PAGES * SZ_4K)
+#define REC_ATTEST_PAGES		1U
+#define REC_ATTEST_SIZE			(REC_ATTEST_PAGES * SZ_4K)
+
+/* Number of pages per REC for attestation buffer */
+#define REC_ATTEST_TOKEN_BUF_SIZE	(RMM_CCA_TOKEN_BUFFER * SZ_4K)
 
 /* Number of pages per REC to be allocated */
 #define REC_NUM_PAGES		(REC_HEAP_PAGES	  + \
 				 REC_PMU_PAGES	  + \
 				 REC_SIMD_PAGES	  + \
-				 REC_ATTEST_PAGES)
+				 REC_ATTEST_PAGES + \
+				 RMM_CCA_TOKEN_BUFFER)
 
 struct buffer_alloc_ctx {
 	unsigned char		*buf;
diff --git a/lib/attestation/include/attestation_token.h b/lib/attestation/include/attestation_token.h
index 807d0b5..6093e4f 100644
--- a/lib/attestation/include/attestation_token.h
+++ b/lib/attestation/include/attestation_token.h
@@ -44,7 +44,7 @@
 enum attest_token_gen_state_t {
 	ATTEST_SIGN_NOT_STARTED,
 	ATTEST_SIGN_IN_PROGRESS,
-	ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS,
+	ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS
 };
 
 /*
@@ -84,8 +84,13 @@
 	 */
 	enum attest_token_gen_state_t state;
 	struct attest_token_encode_ctx ctx;
-	/* Data saved in the first iteration */
-	unsigned long token_ipa;
+
+	/* Number of CCA token bytes left to copy to the Realm */
+	size_t cca_token_len;
+
+	/* Number of CCA token bytes copied to the Realm */
+	size_t copied_len;
+
 	unsigned char challenge[ATTEST_CHALLENGE_SIZE];
 };
 
diff --git a/lib/realm/include/rec.h b/lib/realm/include/rec.h
index d39819d..49c516d 100644
--- a/lib/realm/include/rec.h
+++ b/lib/realm/include/rec.h
@@ -131,6 +131,9 @@
 
 	/* Pointer to attestation-related data */
 	struct rec_attest_data *attest_data;
+
+	/* Address of the attestation token buffer */
+	uintptr_t cca_token_buf;
 };
 
 struct rec {
diff --git a/plat/host/host_build/src/host_setup.c b/plat/host/host_build/src/host_setup.c
index fadc4ee..443592b 100644
--- a/plat/host/host_build/src/host_setup.c
+++ b/plat/host/host_build/src/host_setup.c
@@ -25,6 +25,7 @@
 	RMM_EL3_IFC_MAKE_VERSION(RMM_EL3_IFC_VERS_MAJOR, RMM_EL3_IFC_VERS_MINOR)
 #define RMM_EL3_MAX_CPUS		(1U)
 #define REALM_BUFFER_IPA		0x1000
+#define ATTEST_TOKEN_BUFFER_SIZE	0x100
 
 #define CHECK_RMI_RESULT() \
 ({  \
@@ -79,11 +80,16 @@
 {
 	INFO("RSI Version is 0x%lx\n", regs[1]);
 
+	if (regs[0] != RSI_SUCCESS) {
+		ERROR("RSI_VERSION command failed 0x%lx\n", regs[0]);
+		return 0;
+	}
+
 	srand((int)time(NULL));
 
 	/* Add dummy Realm Attestation RSI calls */
 	regs[0] = SMC_RSI_ATTEST_TOKEN_INIT;
-	regs[1] = REALM_BUFFER_IPA;
+	regs[1] = rand();
 	regs[2] = rand();
 	regs[3] = rand();
 	regs[4] = rand();
@@ -91,7 +97,6 @@
 	regs[6] = rand();
 	regs[7] = rand();
 	regs[8] = rand();
-	regs[9] = rand();
 
 	return host_util_rsi_helper(realm_continue_1);
 }
@@ -109,17 +114,25 @@
 	/* Continue Realm Attestation RSI calls */
 	regs[0] = SMC_RSI_ATTEST_TOKEN_CONTINUE;
 	regs[1] = REALM_BUFFER_IPA;
+	regs[2] = 0;
+	regs[3] = ATTEST_TOKEN_BUFFER_SIZE;
 	return host_util_rsi_helper(realm_continue_2);
-
 }
 
 static int realm_continue_2(unsigned long *regs)
 {
+	static unsigned long offset;
+
 	if (regs[0] == RSI_INCOMPLETE) {
 		INFO("Realm Token Attestation creation is pre-empted by interrupt.\n");
+
+		offset += regs[1];
+
 		/* Continue Realm Attestation RSI calls */
 		regs[0] = SMC_RSI_ATTEST_TOKEN_CONTINUE;
 		regs[1] = REALM_BUFFER_IPA;
+		regs[2] = offset;
+		regs[3] = ATTEST_TOKEN_BUFFER_SIZE;
 		return host_util_rsi_helper(realm_continue_2);
 	}
 
diff --git a/runtime/rmi/rec.c b/runtime/rmi/rec.c
index c7d2c49..7537fb7 100644
--- a/runtime/rmi/rec.c
+++ b/runtime/rmi/rec.c
@@ -185,12 +185,13 @@
 	 * - REC_PMU_PAGES for PMU state
 	 * - REC_SIMD_PAGES for SIMD state
 	 * - REC_ATTEST_PAGES for 'rec_attest_data' structure
+	 * - REC_ATTEST_BUFFER_PAGES for attestation buffer
 	 */
 	assert(r->num_rec_aux >= REC_NUM_PAGES);
 
 	/*
 	 * Assign base address for attestation heap, PMU, SIMD, attestation
-	 * data
+	 * data and buffer.
 	 */
 	aux_data = &r->aux_data;
 	aux_data->attest_heap_buf = (uint8_t *)rec_aux;
@@ -200,6 +201,8 @@
 		((uint8_t *)aux_data->pmu + REC_PMU_SIZE);
 	aux_data->attest_data = (struct rec_attest_data *)
 		((uint8_t *)aux_data->simd_ctx + REC_SIMD_SIZE);
+	aux_data->cca_token_buf = (uintptr_t)aux_data->attest_data +
+		REC_ATTEST_SIZE;
 
 	rec_attestation_heap_init(r);
 	rec_simd_state_init(r);
diff --git a/runtime/rsi/logger.c b/runtime/rsi/logger.c
index 5db269d..21792a4 100644
--- a/runtime/rsi/logger.c
+++ b/runtime/rsi/logger.c
@@ -41,8 +41,8 @@
 	RSI_FUNCTION(FEATURES, 1U, 1U),			/* 0xC4000191 */
 	RSI_FUNCTION(MEASUREMENT_READ, 1U, 8U),		/* 0xC4000192 */
 	RSI_FUNCTION(MEASUREMENT_EXTEND, 10U, 0U),	/* 0xC4000193 */
-	RSI_FUNCTION(ATTEST_TOKEN_INIT, 9U, 0U),	/* 0xC4000194 */
-	RSI_FUNCTION(ATTEST_TOKEN_CONTINUE, 1U, 1U),	/* 0xC4000195 */
+	RSI_FUNCTION(ATTEST_TOKEN_INIT, 8U, 0U),	/* 0xC4000194 */
+	RSI_FUNCTION(ATTEST_TOKEN_CONTINUE, 3U, 1U),	/* 0xC4000195 */
 	RSI_FUNCTION(REALM_CONFIG, 1U, 0U),		/* 0xC4000196 */
 	RSI_FUNCTION(IPA_STATE_SET, 4U, 2U),		/* 0xC4000197 */
 	RSI_FUNCTION(IPA_STATE_GET, 1U, 1U),		/* 0xC4000198 */
diff --git a/runtime/rsi/realm_attest.c b/runtime/rsi/realm_attest.c
index 485bf71..58e71c1 100644
--- a/runtime/rsi/realm_attest.c
+++ b/runtime/rsi/realm_attest.c
@@ -31,30 +31,6 @@
 }
 
 /*
- * Save the input parameters in the context for later iterations to check for
- * consistency.
- */
-static void save_input_parameters(struct rec *rec)
-{
-	struct rec_attest_data *attest_data = rec->aux_data.attest_data;
-
-	attest_data->token_sign_ctx.token_ipa = rec->regs[1];
-	(void)memcpy(attest_data->token_sign_ctx.challenge, &rec->regs[2],
-		     ATTEST_CHALLENGE_SIZE);
-}
-
-/*
- * Verify that in all the iterations the input parameters are the same
- * as in the initial call.
- */
-static bool verify_input_parameters_consistency(struct rec *rec)
-{
-	struct rec_attest_data *attest_data = rec->aux_data.attest_data;
-
-	return attest_data->token_sign_ctx.token_ipa == rec->regs[1];
-}
-
-/*
  * Function to continue with the sign operation
  */
 static void attest_token_continue_sign_state(
@@ -67,7 +43,6 @@
 	enum attest_token_err_t ret =
 		attest_realm_token_sign(&(attest_data->token_sign_ctx.ctx),
 					&(attest_data->rmm_realm_token_len));
-
 	if ((ret == ATTEST_TOKEN_ERR_COSE_SIGN_IN_PROGRESS) ||
 		(ret == ATTEST_TOKEN_ERR_SUCCESS)) {
 		/*
@@ -96,12 +71,15 @@
 					      struct rsi_result *res)
 {
 	struct granule *gr;
-	uint8_t *realm_att_token;
+	uintptr_t realm_att_token;
 	unsigned long realm_att_token_ipa = rec->regs[1];
+	unsigned long offset = rec->regs[2];
+	unsigned long size = rec->regs[3];
 	enum s2_walk_status walk_status;
 	struct s2_walk_result walk_res = { 0UL };
-	size_t attest_token_len;
+	size_t attest_token_len, length;
 	struct rec_attest_data *attest_data = rec->aux_data.attest_data;
+	uintptr_t cca_token_buf = rec->aux_data.cca_token_buf;
 
 	/*
 	 * Translate realm granule IPA to PA. If returns with
@@ -127,38 +105,72 @@
 		return;
 	}
 
+	if (size == 0UL) {
+		res->smc_res.x[0] = RSI_SUCCESS;
+		return;
+	}
+
 	/* Map realm data granule to RMM address space */
 	gr = find_granule(walk_res.pa);
-	realm_att_token = granule_map(gr, SLOT_RSI_CALL);
-	assert(realm_att_token != NULL);
+	realm_att_token = (uintptr_t)granule_map(gr, SLOT_RSI_CALL);
+	assert(realm_att_token != 0UL);
 
-	attest_token_len = attest_cca_token_create(realm_att_token,
-						ATTEST_TOKEN_BUFFER_SIZE,
-						&attest_data->rmm_realm_token_buf,
-						attest_data->rmm_realm_token_len);
+	if (attest_data->token_sign_ctx.copied_len == 0UL) {
+		attest_token_len = attest_cca_token_create(
+					(void *)cca_token_buf,
+					REC_ATTEST_TOKEN_BUF_SIZE,
+					&attest_data->rmm_realm_token_buf,
+					attest_data->rmm_realm_token_len);
 
+		if (attest_token_len == 0UL) {
+			res->smc_res.x[0] = RSI_ERROR_INPUT;
+
+			/* The signing has failed. Reset the state. */
+			attest_data->token_sign_ctx.state =
+						ATTEST_SIGN_NOT_STARTED;
+			goto out_unmap;
+		}
+
+		attest_data->token_sign_ctx.cca_token_len = attest_token_len;
+	} else {
+		attest_token_len = attest_data->token_sign_ctx.cca_token_len;
+	}
+
+	length = (size < attest_token_len) ? size : attest_token_len;
+
+	/* Copy attestation token */
+	(void)memcpy((void *)(realm_att_token + offset),
+		     (void *)(cca_token_buf +
+				attest_data->token_sign_ctx.copied_len),
+		     length);
+
+	attest_token_len -= length;
+
+	if (attest_token_len != 0UL) {
+		attest_data->token_sign_ctx.cca_token_len = attest_token_len;
+		attest_data->token_sign_ctx.copied_len += length;
+
+		res->smc_res.x[0] = RSI_INCOMPLETE;
+	} else {
+
+		/* The signing has succeeded. Reset the state. */
+		attest_data->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
+		res->smc_res.x[0] = RSI_SUCCESS;
+	}
+
+	res->smc_res.x[1] = length;
+
+out_unmap:
 	/* Unmap realm granule */
-	buffer_unmap(realm_att_token);
+	buffer_unmap((void *)realm_att_token);
 
 	/* Unlock last level page table (walk_res.g_llt) */
 	granule_unlock(walk_res.llt);
-
-	/* Write output parameters */
-	if (attest_token_len == 0UL) {
-		res->smc_res.x[0] = RSI_ERROR_INPUT;
-	} else {
-		res->smc_res.x[0] = RSI_SUCCESS;
-		res->smc_res.x[1] = attest_token_len;
-	}
-
-	/* The signing has either succeeded or failed. Reset the state. */
-	attest_data->token_sign_ctx.state = ATTEST_SIGN_NOT_STARTED;
 }
 
 void handle_rsi_attest_token_init(struct rec *rec, struct rsi_result *res)
 {
-	struct rd *rd = NULL;
-	unsigned long realm_buf_ipa;
+	struct rd *rd;
 	struct rec_attest_data *attest_data;
 	void *rpv_ptr;
 	size_t rpv_len;
@@ -166,9 +178,7 @@
 
 	assert(rec != NULL);
 
-	realm_buf_ipa = rec->regs[1];
 	attest_data = rec->aux_data.attest_data;
-
 	res->action = UPDATE_REC_RETURN_TO_REALM;
 
 	/*
@@ -188,11 +198,6 @@
 		}
 	}
 
-	if (!GRANULE_ALIGNED(realm_buf_ipa)) {
-		res->smc_res.x[0] = RSI_ERROR_INPUT;
-		return;
-	}
-
 	/*
 	 * rd lock is acquired so that measurement cannot be updated
 	 * simultaneously by another rec
@@ -201,16 +206,10 @@
 	rd = granule_map(rec->realm_info.g_rd, SLOT_RD);
 	assert(rd != NULL);
 
-	if (!addr_in_par(rd, realm_buf_ipa)) {
-		res->smc_res.x[0] = RSI_ERROR_INPUT;
-		goto out_unmap_rd;
-	}
-
-	/*
-	 * Save the input parameters in the context for later iterations
-	 * to check.
-	 */
-	save_input_parameters(rec);
+	/* Save challenge value in the context */
+	(void)memcpy((void *)attest_data->token_sign_ctx.challenge,
+		     (const void *)&rec->regs[1],
+		     ATTEST_CHALLENGE_SIZE);
 
 	get_rpv(rd, &rpv_ptr, &rpv_len);
 	att_ret = attest_realm_token_create(rd->algorithm, rd->measurement,
@@ -220,17 +219,18 @@
 					    &attest_data->token_sign_ctx,
 					    attest_data->rmm_realm_token_buf,
 					    sizeof(attest_data->rmm_realm_token_buf));
+	buffer_unmap(rd);
+	granule_unlock(rec->realm_info.g_rd);
+
 	if (att_ret != 0) {
 		ERROR("FATAL_ERROR: Realm token creation failed\n");
 		panic();
 	}
 
+	attest_data->token_sign_ctx.copied_len = 0UL;
 	attest_data->token_sign_ctx.state = ATTEST_SIGN_IN_PROGRESS;
-	res->smc_res.x[0] = RSI_SUCCESS;
 
-out_unmap_rd:
-	buffer_unmap(rd);
-	granule_unlock(rec->realm_info.g_rd);
+	res->smc_res.x[0] = RSI_SUCCESS;
 }
 
 /*
@@ -247,6 +247,7 @@
 				      struct rsi_result *res)
 {
 	struct rec_attest_data *attest_data;
+	unsigned long realm_buf_ipa, offset, size;
 
 	assert(rec != NULL);
 	assert(rec_exit != NULL);
@@ -254,47 +255,47 @@
 	attest_data = rec->aux_data.attest_data;
 	res->action = UPDATE_REC_RETURN_TO_REALM;
 
-	if (!verify_input_parameters_consistency(rec)) {
+	realm_buf_ipa = rec->regs[1];
+	offset = rec->regs[2];
+	size = rec->regs[3];
+
+	if (!GRANULE_ALIGNED(realm_buf_ipa) ||
+	    (offset >= GRANULE_SIZE) ||
+	   ((offset + size) > GRANULE_SIZE) ||
+	   ((offset + size) < offset)) {
 		res->smc_res.x[0] = RSI_ERROR_INPUT;
 		return;
 	}
 
-	while (true) {
-		switch (attest_data->token_sign_ctx.state) {
-		case ATTEST_SIGN_NOT_STARTED:
-			/*
-			 * Before this call the initial attestation token call
-			 * (SMC_RSI_ATTEST_TOKEN_INIT) must have been executed
-			 * successfully.
-			 */
-			res->smc_res.x[0] = RSI_ERROR_STATE;
-			break;
-		case ATTEST_SIGN_IN_PROGRESS:
-			attest_token_continue_sign_state(attest_data, res);
-			break;
-		case ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS:
-			attest_token_continue_write_state(rec, res);
-			break;
-		default:
-			/* Any other state is considered an error */
-			panic();
-		}
+	if (!addr_in_rec_par(rec, realm_buf_ipa)) {
+		res->smc_res.x[0] = RSI_ERROR_INPUT;
+		return;
+	}
 
-		if (res->smc_res.x[0] == RSI_INCOMPLETE) {
-			if (check_pending_irq()) {
-				res->action = UPDATE_REC_EXIT_TO_HOST;
-				res->smc_res.x[0] = RSI_INCOMPLETE;
-				rec_exit->exit_reason = RMI_EXIT_IRQ;
-				break;
-			}
-			if (((unsigned int)res->action &
-						FLAG_EXIT_TO_HOST) != 0U) {
-				break;
-			}
-		} else {
-			break;
+	if (attest_data->token_sign_ctx.state == ATTEST_SIGN_NOT_STARTED) {
+		/*
+		 * Before this call the initial attestation token call
+		 * (SMC_RSI_ATTEST_TOKEN_INIT) must have been executed
+		 * successfully.
+		 */
+		res->smc_res.x[0] = RSI_ERROR_STATE;
+		return;
+	}
+
+	while (attest_data->token_sign_ctx.state == ATTEST_SIGN_IN_PROGRESS) {
+		attest_token_continue_sign_state(attest_data, res);
+		if (check_pending_irq()) {
+			res->action = UPDATE_REC_EXIT_TO_HOST;
+			rec_exit->exit_reason = RMI_EXIT_IRQ;
+			return;
 		}
 	}
+
+	/* Any other state is considered an error */
+	assert(attest_data->token_sign_ctx.state ==
+					ATTEST_SIGN_TOKEN_WRITE_IN_PROGRESS);
+
+	attest_token_continue_write_state(rec, res);
 }
 
 void handle_rsi_measurement_extend(struct rec *rec, struct rsi_result *res)
@@ -391,11 +392,11 @@
 	cnt = (unsigned int)(measurement_get_size(rd->algorithm) /
 						sizeof(unsigned long));
 
-	assert(cnt >= SMC_RESULT_REGS - 1U);
+	assert(cnt >= (SMC_RESULT_REGS - 1U));
 	assert(cnt < ARRAY_LEN(rec->regs));
 
 	/* Copy the part of the measurement to res->smc_res.x[] */
-	for (i = 0U; i < SMC_RESULT_REGS - 1U; i++) {
+	for (i = 0U; i < (SMC_RESULT_REGS - 1U); i++) {
 		measurement_value_part = (unsigned long *)
 			&(rd->measurement[idx][i * sizeof(unsigned long)]);
 		res->smc_res.x[i + 1U] = *measurement_value_part;