feat: power management field manifest addition
Add the power-management-messages field to SP's manifests [1].
The intent is for a MP S-EL1 SP to register power management events such
as cpu on or off events relayed by the SPMD to the SPMC.
UP partitions are forced to not handle power management messages in the
current state of the implementation.
[1] https://trustedfirmware-a.readthedocs.io/en/latest/components/ffa-manifest-binding.html#partition-properties
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I2a70afd9b7fa6736215dc4d489bf33cadfb8ac57
diff --git a/src/load.c b/src/load.c
index 243d95a..df18403 100644
--- a/src/load.c
+++ b/src/load.c
@@ -167,6 +167,8 @@
vm_locked.vm->smc_whitelist = manifest_vm->smc_whitelist;
vm_locked.vm->uuid = manifest_vm->partition.uuid;
+ vm_locked.vm->power_management =
+ manifest_vm->partition.power_management;
/* Populate the interrupt descriptor for current VM. */
for (uint16_t i = 0; i < PARTITION_MAX_DEVICE_REGIONS; i++) {
diff --git a/src/manifest.c b/src/manifest.c
index bac21a5..7f01179 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -1014,6 +1014,21 @@
vm->partition.boot_info = false;
}
+ TRY(read_optional_uint32(
+ &root, "power-management-messages",
+ MANIFEST_POWER_MANAGEMENT_CPU_OFF_SUPPORTED |
+ MANIFEST_POWER_MANAGEMENT_CPU_ON_SUPPORTED,
+ &vm->partition.power_management));
+ vm->partition.power_management &= MANIFEST_POWER_MANAGEMENT_ALL_MASK;
+ if (vm->partition.execution_ctx_count == 1 ||
+ vm->partition.run_time_el == S_EL0) {
+ vm->partition.power_management =
+ MANIFEST_POWER_MANAGEMENT_NONE_MASK;
+ }
+
+ dlog_verbose(" Power management messages %#x\n",
+ vm->partition.power_management);
+
/* Parse memory-regions */
ffa_node = root;
if (fdt_find_child(&ffa_node, &mem_region_node_name)) {
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index c738aac..cc78660 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -975,6 +975,87 @@
MANIFEST_ERROR_ILLEGAL_OTHER_S_INT_ACTION);
}
+TEST_F(manifest, power_management)
+{
+ struct manifest_vm *vm;
+ struct_manifest *m;
+
+ /* S-EL1 partition power management field can set bit 0. */
+ /* clang-format off */
+ std::vector<char> dtb = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+ .Property("execution-ctx-count", "<8>")
+ .Property("exception-level", "<2>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("messaging-method", "<1>")
+ .Property("power-management-messages", "<1>")
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
+ vm = &m->vm[0];
+ ASSERT_EQ(vm->partition.power_management, 1);
+ manifest_dealloc();
+
+ /* S-EL1 partition power management field can set bit 3. */
+ /* clang-format off */
+ dtb = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+ .Property("execution-ctx-count", "<8>")
+ .Property("exception-level", "<2>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("messaging-method", "<1>")
+ .Property("power-management-messages", "<8>")
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
+ vm = &m->vm[0];
+ ASSERT_EQ(vm->partition.power_management, 8);
+ manifest_dealloc();
+
+ /* S-EL1 partition power management field can only set bits 0 and 3. */
+ /* clang-format off */
+ dtb = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+ .Property("execution-ctx-count", "<8>")
+ .Property("exception-level", "<2>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("messaging-method", "<1>")
+ .Property("power-management-messages", "<0xf>")
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
+ vm = &m->vm[0];
+ ASSERT_EQ(vm->partition.power_management, 9);
+ manifest_dealloc();
+
+ /* S-EL0 partition power management field is forced to 0. */
+ /* clang-format off */
+ dtb = ManifestDtBuilder()
+ .Compatible({ "arm,ffa-manifest-1.0" })
+ .Property("ffa-version", "<0x10001>")
+ .Property("uuid", "<0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>")
+ .Property("execution-ctx-count", "<1>")
+ .Property("exception-level", "<1>")
+ .Property("execution-state", "<0>")
+ .Property("entrypoint-offset", "<0x00002000>")
+ .Property("messaging-method", "<1>")
+ .Property("power-management-messages", "<0xff>")
+ .Build();
+ /* clang-format on */
+ ASSERT_EQ(ffa_manifest_from_vec(&m, dtb), MANIFEST_SUCCESS);
+ vm = &m->vm[0];
+ ASSERT_EQ(vm->partition.power_management, 0);
+}
+
TEST_F(manifest, ffa_validate_rxtx_info)
{
struct_manifest *m;