feat(el3-spmc): add support to map S-EL0 SP device regions
Add the support to parse SP manifest to get device regions, create xlat
table entries for the SP.
SP running at SEL-0 does not have enough privilege to map the regions
itself.
Signed-off-by: Nishant Sharma <nishant.sharma@arm.com>
Change-Id: I600f51ee62a33443fe7f1c4e007cc6c5ab45222f
diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c
index 61ee0c6..609d968 100644
--- a/services/std_svc/spm/el3_spmc/spmc_setup.c
+++ b/services/std_svc/spm/el3_spmc/spmc_setup.c
@@ -44,6 +44,13 @@
#define SP_MEM_READ_ONLY SP_MEM_READ
#define SP_MEM_READ_WRITE (SP_MEM_READ | SP_MEM_WRITE)
+/* Type of the memory region in SP's manifest. */
+enum sp_memory_region_type {
+ SP_MEM_REGION_DEVICE,
+ SP_MEM_REGION_MEMORY,
+ SP_MEM_REGION_NOT_SPECIFIED
+};
+
/*
* This function creates a initialization descriptor in the memory reserved
* for passing boot information to an SP. It then copies the partition manifest
@@ -192,28 +199,41 @@
/*******************************************************************************
* This function will parse the Secure Partition Manifest for fetching secure
- * partition specific memory region details. It will find base address, size,
- * memory attributes for each memory region and then add the respective region
+ * partition specific memory/device region details. It will find base address,
+ * size, memory attributes for each region and then add the respective region
* into secure parition's translation context.
******************************************************************************/
-static void populate_sp_mem_regions(struct secure_partition_desc *sp,
- void *sp_manifest,
- int node)
+static void populate_sp_regions(struct secure_partition_desc *sp,
+ void *sp_manifest, int node,
+ enum sp_memory_region_type type)
{
uintptr_t base_address;
uint32_t mem_attr, mem_region, size;
- struct mmap_region sp_mem_regions;
+ struct mmap_region sp_mem_regions = {0};
int32_t offset, ret;
+ char *compatibility[SP_MEM_REGION_NOT_SPECIFIED] = {
+ "arm,ffa-manifest-device-regions",
+ "arm,ffa-manifest-memory-regions"
+ };
char description[10];
char *property;
+ char *region[SP_MEM_REGION_NOT_SPECIFIED] = {
+ "device regions",
+ "memory regions"
+ };
- if (fdt_node_check_compatible(sp_manifest, node,
- "arm,ffa-manifest-memory-regions") != 0) {
- WARN("Incompatible memory region node in manifest\n");
+ if (type >= SP_MEM_REGION_NOT_SPECIFIED) {
+ WARN("Invalid region type\n");
return;
}
+ INFO("Mapping SP's %s\n", region[type]);
+
- INFO("Mapping SP's memory regions\n");
+ if (fdt_node_check_compatible(sp_manifest, node,
+ compatibility[type]) != 0) {
+ WARN("Incompatible region node in manifest\n");
+ return;
+ }
for (offset = fdt_first_subnode(sp_manifest, node), mem_region = 0;
offset >= 0;
@@ -247,13 +267,19 @@
}
sp_mem_regions.attr = MT_USER;
- if ((mem_attr & SP_MEM_EXECUTE) == SP_MEM_EXECUTE) {
- sp_mem_regions.attr |= MT_CODE;
- } else if ((mem_attr & SP_MEM_READ_ONLY) == SP_MEM_READ_ONLY) {
- sp_mem_regions.attr |= MT_RO_DATA;
- } else if ((mem_attr & SP_MEM_READ_WRITE) ==
- SP_MEM_READ_WRITE) {
- sp_mem_regions.attr |= MT_RW_DATA;
+ if (type == SP_MEM_REGION_DEVICE) {
+ sp_mem_regions.attr |= MT_EXECUTE_NEVER;
+ } else {
+ sp_mem_regions.attr |= MT_MEMORY;
+ if ((mem_attr & SP_MEM_EXECUTE) == SP_MEM_EXECUTE) {
+ sp_mem_regions.attr &= ~MT_EXECUTE_NEVER;
+ } else {
+ sp_mem_regions.attr |= MT_EXECUTE_NEVER;
+ }
+ }
+
+ if ((mem_attr & SP_MEM_READ_WRITE) == SP_MEM_READ_WRITE) {
+ sp_mem_regions.attr |= MT_RW;
}
if ((mem_attr & SP_MEM_NON_SECURE) == SP_MEM_NON_SECURE) {
@@ -265,7 +291,18 @@
sp_mem_regions.base_pa = base_address;
sp_mem_regions.base_va = base_address;
sp_mem_regions.size = size;
- sp_mem_regions.granularity = XLAT_BLOCK_SIZE(3);
+
+ INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx attr:0x%x\n",
+ sp_mem_regions.base_pa,
+ sp_mem_regions.base_va,
+ sp_mem_regions.size,
+ sp_mem_regions.attr);
+
+ if (type == SP_MEM_REGION_DEVICE) {
+ sp_mem_regions.granularity = XLAT_BLOCK_SIZE(1);
+ } else {
+ sp_mem_regions.granularity = XLAT_BLOCK_SIZE(3);
+ }
mmap_add_region_ctx(sp->xlat_ctx_handle, &sp_mem_regions);
}
}
@@ -399,6 +436,20 @@
}
/*
+ * Parse the manifest for any device regions that the SP wants to be
+ * mapped in its translation regime.
+ */
+ node = fdt_subnode_offset_namelen(sp_manifest, offset,
+ "device-regions",
+ sizeof("device-regions") - 1);
+ if (node < 0) {
+ WARN("Not found device-region configuration for SP.\n");
+ } else {
+ populate_sp_regions(sp, sp_manifest, node,
+ SP_MEM_REGION_DEVICE);
+ }
+
+ /*
* Parse the manifest for any memory regions that the SP wants to be
* mapped in its translation regime.
*/
@@ -408,7 +459,8 @@
if (node < 0) {
WARN("Not found memory-region configuration for SP.\n");
} else {
- populate_sp_mem_regions(sp, sp_manifest, node);
+ populate_sp_regions(sp, sp_manifest, node,
+ SP_MEM_REGION_MEMORY);
}
spmc_el0_sp_setup_system_registers(sp, ctx);