fix(manifest): add checks for boot order values
FF-A spec (versions 1.0-1.2 ALP0) requires that boot order property must
be a unique value per partition (FF-A v1.2 Chapter 5, Table 5.1
"Partition properties"). Add check in manifest parsing for this
requirement and add corresponding unit test.
Also check that value given is within supported range.
Also fix existing test SPs to fit this requirement.
Signed-off-by: Kathleen Capella <kathleen.capella@arm.com>
Change-Id: Id2a2297ec9c3e6f2f866bab9f53032f8b01f7266
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index ea3bc23..a974498 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -86,6 +86,7 @@
MANIFEST_ERROR_ILLEGAL_NS_INT_ACTION,
MANIFEST_ERROR_INTERRUPT_ID_NOT_IN_LIST,
MANIFEST_ERROR_ILLEGAL_OTHER_S_INT_ACTION,
+ MANIFEST_ERROR_INVALID_BOOT_ORDER,
};
enum manifest_return_code manifest_init(struct mm_stage1_locked stage1_locked,
diff --git a/src/manifest.c b/src/manifest.c
index 9de465d..c6add64 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -46,6 +46,12 @@
(HF_OTHER_WORLD_ID < HF_VM_ID_BASE),
"TrustZone VM ID clashes with normal VM range.");
+/* Bitmap to track boot order values in use. */
+#define BOOT_ORDER_ENTRY_BITS (sizeof(uint64_t) * 8)
+#define BOOT_ORDER_MAP_ENTRIES \
+ ((DEFAULT_BOOT_ORDER + (BOOT_ORDER_ENTRY_BITS - 1)) / \
+ BOOT_ORDER_ENTRY_BITS)
+
/**
* A struct to keep track of the partitions properties during early boot
* manifest parsing:
@@ -62,6 +68,7 @@
*/
struct mem_range
mem_regions[PARTITION_MAX_MEMORY_REGIONS * MAX_VMS + MAX_VMS];
+ uint64_t boot_order_values[BOOT_ORDER_MAP_ENTRIES];
};
/**
@@ -76,6 +83,33 @@
/* Index used to track the number of memory regions allocated. */
static size_t allocated_mem_regions_index = 0;
+static bool check_boot_order(uint16_t boot_order)
+{
+ uint16_t i;
+ uint64_t boot_order_mask;
+
+ if (boot_order == DEFAULT_BOOT_ORDER) {
+ return true;
+ }
+ if (boot_order > DEFAULT_BOOT_ORDER) {
+ dlog_error("Boot order should not exceed %x",
+ DEFAULT_BOOT_ORDER);
+ return false;
+ }
+
+ i = boot_order / BOOT_ORDER_ENTRY_BITS;
+ boot_order_mask = 1 << (boot_order % BOOT_ORDER_ENTRY_BITS);
+
+ if ((boot_order_mask & manifest_data->boot_order_values[i]) != 0U) {
+ dlog_error("Boot order must be a unique value.");
+ return false;
+ }
+
+ manifest_data->boot_order_values[i] |= boot_order_mask;
+
+ return true;
+}
+
/**
* Allocates and clear memory for the manifest data in the given memory pool.
* Returns true if the memory is successfully allocated.
@@ -262,7 +296,6 @@
uint64_t value;
TRY(read_uint64(node, property, &value));
-
if (value > UINT16_MAX) {
return MANIFEST_ERROR_INTEGER_OVERFLOW;
}
@@ -283,7 +316,7 @@
return MANIFEST_SUCCESS;
}
- return MANIFEST_SUCCESS;
+ return ret;
}
static enum manifest_return_code read_uint8(const struct fdt_node *node,
@@ -1014,7 +1047,13 @@
TRY(read_optional_uint16(&root, "boot-order", DEFAULT_BOOT_ORDER,
&vm->partition.boot_order));
- dlog_verbose(" Boot order %#u\n", vm->partition.boot_order);
+ if (vm->partition.boot_order != DEFAULT_BOOT_ORDER) {
+ dlog_verbose(" Boot order %#u\n", vm->partition.boot_order);
+ }
+
+ if (!check_boot_order(vm->partition.boot_order)) {
+ return MANIFEST_ERROR_INVALID_BOOT_ORDER;
+ }
TRY(read_optional_uint8(&root, "xlat-granule", 0,
(uint8_t *)&vm->partition.xlat_granule));
@@ -1453,6 +1492,9 @@
case MANIFEST_ERROR_MEM_REGION_INVALID:
return "Memory region must within memory ranges defined "
"in the SPMC manifest.";
+ case MANIFEST_ERROR_INVALID_BOOT_ORDER:
+ return "Boot order should be a unique value less than "
+ "default largest value";
}
panic("Unexpected manifest return code.");
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 9587459..a4e9d33 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -248,6 +248,12 @@
return *this;
}
+ ManifestDtBuilder &FfaLoadAddress(uint64_t value)
+ {
+ Integer64Property("load-address", value);
+ return *this;
+ }
+
private:
ManifestDtBuilder &StringProperty(const std::string_view &name,
const std::string_view &value)
@@ -351,6 +357,15 @@
Partition_package(const std::vector<char> &vec)
{
+ init(vec);
+ }
+
+ Partition_package()
+ {
+ }
+
+ void init(const std::vector<char> &vec)
+ {
// Initialise header field
spkg.magic = SP_PKG_HEADER_MAGIC;
spkg.version = SP_PKG_HEADER_VERSION_2;
@@ -1752,4 +1767,75 @@
MANIFEST_ERROR_INTERRUPT_ID_NOT_IN_LIST);
}
+TEST_F(manifest, ffa_boot_order_not_unique)
+{
+ struct_manifest *m;
+ struct memiter it;
+ struct mm_stage1_locked mm_stage1_locked;
+ struct boot_params params;
+ Partition_package spkg_1;
+ Partition_package spkg_2;
+
+ /* clang-format off */
+ std::vector<char> dtb1 = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+ .FfaLoadAddress((uint64_t)&spkg_1)
+ .Property("execution-ctx-count", "<1>")
+ .Property("exception-level", "<1>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("xlat-granule", "<0>")
+ .Property("boot-order", "<1>")
+ .Property("messaging-method", "<1>")
+ .Property("ns-interrupts-action", "<0>")
+ .Build();
+
+ std::vector<char> dtb2 = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1daaa>")
+ .FfaLoadAddress((uint64_t)&spkg_2)
+ .Property("execution-ctx-count", "<1>")
+ .Property("exception-level", "<1>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("xlat-granule", "<0>")
+ .Property("boot-order", "<1>")
+ .Property("messaging-method", "<1>")
+ .Property("ns-interrupts-action", "<0>")
+ .Build();
+
+ /* clang-format on */
+ spkg_1.init(dtb1);
+ spkg_2.init(dtb2);
+
+ /* clang-format off */
+ std::vector<char> core_dtb = ManifestDtBuilder()
+ .StartChild("hypervisor")
+ .Compatible()
+ .StartChild("vm1")
+ .DebugName("ffa_partition_1")
+ .FfaPartition()
+ .LoadAddress((uint64_t)&spkg_1)
+ .VcpuCount(1)
+ .MemSize(0x10000000)
+ .EndChild()
+ .StartChild("vm2")
+ .DebugName("ffa_partition_2")
+ .FfaPartition()
+ .LoadAddress((uint64_t)&spkg_2)
+ .VcpuCount(1)
+ .MemSize(0x10000000)
+ .EndChild()
+ .EndChild()
+ .Build();
+ /* clang-format on */
+
+ boot_params_init(¶ms, nullptr);
+ memiter_init(&it, core_dtb.data(), core_dtb.size());
+ ASSERT_EQ(manifest_init(mm_stage1_locked, &m, &it, ¶ms, &ppool),
+ MANIFEST_ERROR_INVALID_BOOT_ORDER);
+}
} /* namespace */
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/partition_manifest_service_sp_third.dts b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/partition_manifest_service_sp_third.dts
index a7bc696..6bbb5ca 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/partition_manifest_service_sp_third.dts
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/partition_manifest_service_sp_third.dts
@@ -21,8 +21,8 @@
load-address = <0x6280000>;
entrypoint-offset = <0x2000>;
xlat-granule = <0>; /* 4KiB */
+ boot-order = <3>;
messaging-method = <0x7>; /* Supports direct and indirect requests. */
- boot-order = <1>;
notification-support; /* Receipt of notifications. */
ns-interrupts-action = <0>; /* Non secure interrupts are queued. */
other-s-interrupts-action = <0>; /* Other S-Interrupts are queued. */
diff --git a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp2.dts b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp2.dts
index ad79a09..119a0ad 100644
--- a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp2.dts
+++ b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp2.dts
@@ -22,7 +22,7 @@
entrypoint-offset = <0x2000>;
xlat-granule = <0>; /* 4KiB */
messaging-method = <0x7>; /* Supports direct and indirect requests. */
- boot-order = <1>;
+ boot-order = <2>;
notification-support; /* Receipt of notifications. */
gp-register-num = <0>;
diff --git a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp3.dts b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp3.dts
index ab26cec..b3c48fe 100644
--- a/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp3.dts
+++ b/test/vmapi/primary_with_secondaries/services/arch/aarch64/secure/partition_manifest_service_sp3.dts
@@ -22,7 +22,7 @@
entrypoint-offset = <0x2000>;
xlat-granule = <0>; /* 4KiB */
messaging-method = <0x7>; /* Supports direct and indirect requests. */
- boot-order = <1>;
+ boot-order = <3>;
notification-support; /* Receipt of notifications. */
gp-register-num = <0>;