SPCI: Add a buffer of len PAGE_SIZE to each CPU.

The buffers are used to store a copy of the contents of the Tx buffer
when handling an architected message. This is mostly relevant for
memory sharing.
There exists a single buffer per CPU.

Change-Id: I60c4eab865b01fb73825308439faa72c8af85fb2
diff --git a/inc/hf/cpu.h b/inc/hf/cpu.h
index d44d68e..56f7982 100644
--- a/inc/hf/cpu.h
+++ b/inc/hf/cpu.h
@@ -119,6 +119,8 @@
 bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg);
 void cpu_off(struct cpu *c);
 struct cpu *cpu_find(cpu_id_t id);
+uint8_t *cpu_get_buffer(cpu_id_t cpu_id);
+uint32_t cpu_get_buffer_size(cpu_id_t cpu_id);
 
 struct vcpu_locked vcpu_lock(struct vcpu *vcpu);
 void vcpu_unlock(struct vcpu_locked *locked);
diff --git a/src/api.c b/src/api.c
index 98c0827..1fed670 100644
--- a/src/api.c
+++ b/src/api.c
@@ -936,11 +936,9 @@
 		 * Buffer holding the internal copy of the shared memory
 		 * regions.
 		 */
-		/* TODO: Buffer is temporarily in the stack. */
-		uint8_t message_buffer
-			[sizeof(struct spci_architected_message_header) +
-			 sizeof(struct spci_memory_region_constituent) +
-			 sizeof(struct spci_memory_region)];
+		uint8_t *message_buffer = cpu_get_buffer(current->cpu->id);
+		uint32_t message_buffer_size =
+			cpu_get_buffer_size(current->cpu->id);
 
 		struct spci_architected_message_header *architected_header =
 			spci_get_architected_message_header(from->mailbox.send);
@@ -948,7 +946,7 @@
 		const struct spci_architected_message_header
 			*architected_message_replica;
 
-		if (from_msg_replica.length > sizeof(message_buffer)) {
+		if (from_msg_replica.length > message_buffer_size) {
 			ret = SPCI_INVALID_PARAMETERS;
 			goto out;
 		}
@@ -960,7 +958,7 @@
 		}
 
 		/* Copy the architected message into an internal buffer. */
-		memcpy_s(message_buffer, sizeof(message_buffer),
+		memcpy_s(message_buffer, message_buffer_size,
 			 architected_header, from_msg_replica.length);
 
 		architected_message_replica =
diff --git a/src/cpu.c b/src/cpu.c
index 37de1de..43efa26 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -34,6 +34,31 @@
 /* The stack to be used by the CPUs. */
 alignas(2 * sizeof(uintreg_t)) static char callstacks[MAX_CPUS][STACK_SIZE];
 
+/**
+ * Internal buffer used to store SPCI messages from a VM Tx. Its usage prevents
+ * TOCTOU issues while Hafnium performs actions on information that would
+ * otherwise be re-writable by the VM.
+ *
+ * Each buffer is owned by a single cpu. The buffer can only be used for
+ * spci_msg_send. The information stored in the buffer is only valid during the
+ * spci_msg_send request is performed.
+ */
+alignas(PAGE_SIZE) uint8_t cpu_message_buffer[MAX_CPUS][PAGE_SIZE];
+
+uint8_t *cpu_get_buffer(cpu_id_t cpu_id)
+{
+	CHECK(cpu_id < MAX_CPUS);
+
+	return cpu_message_buffer[cpu_id];
+}
+
+uint32_t cpu_get_buffer_size(cpu_id_t cpu_id)
+{
+	CHECK(cpu_id < MAX_CPUS);
+
+	return sizeof(cpu_message_buffer[cpu_id]);
+}
+
 /* State of all supported CPUs. The stack of the first one is initialized. */
 struct cpu cpus[MAX_CPUS] = {
 	{