SPCI: memory relinquish.
The relinquish mechnism implementation accepts a single memory region
with a single constituent.
Multiple memory region and constituent support will be introduced in
a later commit.
Change-Id: I9588ae597fd56336da135522b74e4a42e4514042
diff --git a/inc/vmapi/hf/spci.h b/inc/vmapi/hf/spci.h
index 99664ed..a6d9c68 100644
--- a/inc/vmapi/hf/spci.h
+++ b/inc/vmapi/hf/spci.h
@@ -48,6 +48,7 @@
/* Architected memory sharing message IDs. */
enum spci_memory_share {
+ SPCI_MEMORY_RELINQUISH = 0x1,
SPCI_MEMORY_DONATE = 0x2,
};
@@ -288,3 +289,26 @@
spci_memory_region_add(message, handle, region_constituents,
num_elements);
}
+
+/**
+ * Construct the SPCI memory region relinquish message.
+ * A set of memory regions can be given back to the owner.
+ */
+static inline void spci_memory_relinquish(
+ struct spci_message *message, spci_vm_id_t target_vm_id,
+ spci_vm_id_t source_vm_id,
+ struct spci_memory_region_constituent *region_constituents,
+ uint64_t num_elements, uint32_t handle)
+{
+ int32_t message_length;
+
+ message_length = sizeof(struct spci_architected_message_header);
+
+ /* Fill in the details on the common message header. */
+ spci_architected_message_init(message, message_length, target_vm_id,
+ source_vm_id, SPCI_MEMORY_RELINQUISH);
+
+ /* Create single memory region. */
+ spci_memory_region_add(message, handle, region_constituents,
+ num_elements);
+}
diff --git a/src/spci_architected_message.c b/src/spci_architected_message.c
index 0905531..0b47fb3 100644
--- a/src/spci_architected_message.c
+++ b/src/spci_architected_message.c
@@ -81,6 +81,23 @@
memory_share_size, to_mode, message_type);
break;
+ case SPCI_MEMORY_RELINQUISH:
+
+ memory_region = (struct spci_memory_region *)
+ architected_message_replica->payload;
+
+ memory_share_size =
+ from_msg_replica->length -
+ sizeof(struct spci_architected_message_header);
+
+ to_mode = MM_MODE_R | MM_MODE_W | MM_MODE_X;
+
+ ret = spci_validate_call_share_memory(
+ to_locked, from_locked, memory_region,
+ memory_share_size, to_mode, message_type);
+
+ break;
+
default:
dlog("Invalid memory sharing message.\n");
return SPCI_INVALID_PARAMETERS;
@@ -208,6 +225,30 @@
.to_mode = 0,
},
};
+
+ static const struct spci_mem_transitions relinquish_transitions[] = {
+ {
+ /* 1) {!O-EA, O-NA} -> {!O-NA, O-EA} */
+ .orig_from_mode = MM_MODE_UNOWNED,
+ .orig_to_mode = MM_MODE_INVALID,
+ .from_mode = MM_MODE_INVALID | MM_MODE_UNOWNED |
+ MM_MODE_SHARED,
+ .to_mode = 0,
+ },
+ {
+ /* 2) {!O-SA, O-SA} -> {!O-NA, O-EA} */
+ .orig_from_mode = MM_MODE_UNOWNED | MM_MODE_SHARED,
+ .orig_to_mode = MM_MODE_SHARED,
+ .from_mode = MM_MODE_INVALID | MM_MODE_UNOWNED |
+ MM_MODE_SHARED,
+ .to_mode = 0,
+ },
+ };
+
+ static const uint32_t size_relinquish_transitions =
+ sizeof(relinquish_transitions) /
+ sizeof(struct spci_mem_transitions);
+
static const uint32_t size_donate_transitions =
ARRAY_SIZE(donate_transitions);
@@ -232,6 +273,11 @@
transition_table_size = size_donate_transitions;
break;
+ case SPCI_MEMORY_RELINQUISH:
+ mem_transition_table = relinquish_transitions;
+ transition_table_size = size_relinquish_transitions;
+ break;
+
default:
return false;
}