feat(spm): update MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 interface

Update MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 interface
correspondant to FF-A v1.3 memory management protocol's
FFA_MEM_PERM_GET interface [0].

This adds one input/output parameter with page_count
to set search range and get the range having same permssion from
base_va.

This change is backward compatible.

Links: https://developer.arm.com/documentation/den0140/latest/
Change-Id: Ib1b19dd433ad018f0c39af3a9ac8dda41358fb02
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
diff --git a/docs/components/secure-partition-manager-mm.rst b/docs/components/secure-partition-manager-mm.rst
index d9b2b1b..589a362 100644
--- a/docs/components/secure-partition-manager-mm.rst
+++ b/docs/components/secure-partition-manager-mm.rst
@@ -652,6 +652,13 @@
     There are no alignment restrictions on the Base Address. The permission
     attributes of the translation granule it lies in are returned.
 
+  - **uint32** Input Page Count
+
+    This parameter is the number of translation granule size pages from
+    *Base Address* whose permission should be returned.
+    This is calculated as *Input Page count + 1*.
+    (i.e. If Input Page Count is 0, then it is calculated as 1).
+
 - Return parameters
 
   - **int32** - Memory Attributes/Return Code
@@ -687,6 +694,16 @@
     See `Error Codes`_ for integer values that are associated with each return
     code.
 
+  - **uint32** - Output Page Count
+
+    On success, the number of translation granule size pages from
+    the *Base address* whose permissions match those returned in the
+    *Memory Attributes* output parameter.
+    This is calculated as *Output Page count + 1*.
+    (i.e. If Output Page Count is 0, It is calculated as 1).
+
+    On failure, It must be zero:
+
 - Usage
 
   This function is used to request the permission attributes for S-EL0 on a
diff --git a/services/std_svc/spm/spm_mm/spm_mm_main.c b/services/std_svc/spm/spm_mm/spm_mm_main.c
index 60b34d2..c204987 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_main.c
+++ b/services/std_svc/spm/spm_mm/spm_mm_main.c
@@ -312,6 +312,9 @@
 			 uint64_t flags)
 {
 	unsigned int ns;
+	int32_t ret;
+	uint32_t attr;
+	uint32_t page_count;
 
 	/* Determine which security state this SMC originated from */
 	ns = is_caller_non_secure(flags);
@@ -340,9 +343,17 @@
 				WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
 				SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
 			}
-			SMC_RET1(handle,
-				 spm_memory_attributes_get_smc_handler(
-					 &sp_ctx, x1));
+
+			/* x2 = page_count - 1 */
+			page_count = x2 + 1;
+
+			ret = spm_memory_attributes_get_smc_handler(
+					&sp_ctx, x1, &page_count, &attr);
+			if (ret != SPM_MM_SUCCESS) {
+				SMC_RET1(handle, ret);
+			} else {
+				SMC_RET2(handle, attr, --page_count);
+			}
 
 		case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
 			INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
diff --git a/services/std_svc/spm/spm_mm/spm_mm_private.h b/services/std_svc/spm/spm_mm/spm_mm_private.h
index 3a52a3e..473d84d 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_private.h
+++ b/services/std_svc/spm/spm_mm/spm_mm_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -56,7 +56,9 @@
 void spm_sp_setup(sp_context_t *sp_ctx);
 
 int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
-					      uintptr_t base_va);
+					      uintptr_t base_va,
+					      uint32_t *page_count,
+					      uint32_t *attr);
 int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx,
 					  u_register_t page_address,
 					  u_register_t pages_count,
diff --git a/services/std_svc/spm/spm_mm/spm_mm_xlat.c b/services/std_svc/spm/spm_mm/spm_mm_xlat.c
index 3e13e90..32eda3a 100644
--- a/services/std_svc/spm/spm_mm/spm_mm_xlat.c
+++ b/services/std_svc/spm/spm_mm/spm_mm_xlat.c
@@ -88,22 +88,61 @@
 }
 
 int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
-					      uintptr_t base_va)
+					      uintptr_t base_va,
+					      uint32_t *page_count,
+					      uint32_t *attr)
 {
-	uint32_t attributes;
+	uint32_t cur_attr;
+	uint32_t table_level;
+	uint32_t count;
+	int rc;
+
+	assert((page_count != NULL) && (*page_count > 0));
+	assert(attr != NULL);
+
+	base_va &= ~(PAGE_SIZE_MASK);
 
 	spin_lock(&mem_attr_smc_lock);
 
-	int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
-				     base_va, &attributes, NULL);
+	rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+				     base_va, attr, &table_level);
+	if (rc != 0) {
+		goto err_out;
+	}
 
+	/*
+	 * Caculate how many pages in this block entry from base_va including
+	 * its page.
+	 */
+	count = ((XLAT_BLOCK_SIZE(table_level) -
+				(base_va & XLAT_BLOCK_MASK(table_level))) >> PAGE_SIZE_SHIFT);
+	base_va += XLAT_BLOCK_SIZE(table_level);
+
+	while ((count < *page_count) && (base_va != 0x00)) {
+		rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+					     base_va, &cur_attr, &table_level);
+		if (rc != 0) {
+			goto err_out;
+		}
+
+		if (*attr != cur_attr) {
+			*page_count = count;
+			break;
+		}
+
+		base_va += XLAT_BLOCK_SIZE(table_level);
+		count += (XLAT_BLOCK_SIZE(table_level) >> PAGE_SIZE_SHIFT);
+	}
+
+	*attr = smc_mmap_to_smc_attr(*attr);
+
+err_out:
 	spin_unlock(&mem_attr_smc_lock);
-
 	/* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
 	assert((rc == 0) || (rc == -EINVAL));
 
 	if (rc == 0) {
-		return (int32_t) smc_mmap_to_smc_attr(attributes);
+		return SPM_MM_SUCCESS;
 	} else {
 		return SPM_MM_INVALID_PARAMETER;
 	}