TF-RMM Release v0.1.0

This is the first external release of TF-RMM and provides a reference
implementation of Realm Management Monitor (RMM) as specified by the
RMM Beta0 specification[1].

The `docs/readme.rst` has more details about the project and
`docs/getting_started/getting-started.rst` has details on how to get
started with TF-RMM.

[1] https://developer.arm.com/documentation/den0137/1-0bet0/?lang=en

Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Change-Id: I205ef14c015e4a37ae9ae1a64e4cd22eb8da746e
diff --git a/lib/allocator/CMakeLists.txt b/lib/allocator/CMakeLists.txt
new file mode 100644
index 0000000..25e531e
--- /dev/null
+++ b/lib/allocator/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+add_library(rmm-lib-allocator)
+
+target_link_libraries(rmm-lib-allocator
+  PRIVATE
+    rmm-lib-arch
+    rmm-lib-common
+    rmm-lib-debug
+    rmm-lib-libc
+    rmm-lib-rmm_el3_ifc
+    MbedTLS::Crypto
+    t_cose)
+
+target_include_directories(rmm-lib-allocator
+    PUBLIC "include")
+
+target_sources(rmm-lib-allocator
+    PRIVATE "src/memory_alloc.c")
diff --git a/lib/allocator/include/memory_alloc.h b/lib/allocator/include/memory_alloc.h
new file mode 100644
index 0000000..5346395
--- /dev/null
+++ b/lib/allocator/include/memory_alloc.h
@@ -0,0 +1,61 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef MEMORY_ALLOC_H
+#define MEMORY_ALLOC_H
+
+#include <stddef.h>
+
+struct _memory_header;
+typedef struct memory_header_s memory_header_t;
+
+/*
+ * Number of pages per REC to be allocated. MbedTLS needs 8K of heap
+ * for attestation usecases.
+ */
+#define REC_HEAP_PAGES		2
+
+struct buffer_alloc_ctx {
+	unsigned char		*buf;
+	size_t			len;
+	memory_header_t		*first;
+	memory_header_t		*first_free;
+	int			verify;
+};
+
+struct memory_header_s {
+	size_t			magic1;
+	size_t			size;
+	size_t			alloc;
+	memory_header_t		*prev;
+	memory_header_t		*next;
+	memory_header_t		*prev_free;
+	memory_header_t		*next_free;
+	size_t			magic2;
+};
+
+
+/*
+ * Function to assign a heap context to the current CPU for
+ * use by the MbedCrypto. In case the heap needs to be isolated
+ * to the CPU executing a realm , this function must to be
+ * called before entering a Realm. This will ensure that any
+ * crypto operations triggered via RSI will used the assigned
+ * heap.
+ * Arguments:
+ *  ctx - Pointer to a valid context for the memory allocator.
+ * Returns:
+ *  0 on success or a POSIX error code or error.
+ */
+int buffer_alloc_ctx_assign(struct buffer_alloc_ctx *ctx);
+
+/*
+ * Function to unasign a heap context from the current CPU.
+ * In case the heap was isolated to the CPU executing a realm,
+ * this function must to be called after exiting a Realm.
+ */
+void buffer_alloc_ctx_unassign(void);
+
+#endif /* MEMORY_ALLOC_H */
diff --git a/lib/allocator/src/memory_alloc.c b/lib/allocator/src/memory_alloc.c
new file mode 100644
index 0000000..8c536e8
--- /dev/null
+++ b/lib/allocator/src/memory_alloc.c
@@ -0,0 +1,455 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * SPDX-FileCopyrightText: Copyright The Mbed TLS Contributors
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cpuid.h>
+#include <debug.h>
+#include <errno.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/platform.h>
+#include <memory_alloc.h>
+#include <sizes.h>
+#include <string.h>
+
+#define MAGIC1		UL(0xFF00AA55)
+#define MAGIC2		UL(0xEE119966)
+#define MAX_BT		20
+
+#if defined(MBEDTLS_MEMORY_DEBUG)
+#error MBEDTLS_MEMORY_DEBUG is not supported by this allocator.
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+/*
+ * If MBEDTLS_MEMORY_BUFFER_ALLOC_C is defined then the allocator from mbedTLS
+ * is going to be used, which is not desired.
+ */
+#error MBEDTLS_MEMORY_BUFFER_ALLOC_C is defined
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
+
+#if defined(MBEDTLS_MEMORY_BACKTRACE)
+#error MBEDTLS_MEMORY_BACKTRACE is not supported by this allocator.
+#endif /* MBEDTLS_MEMORY_BACKTRACE */
+
+#if defined(MBEDTLS_THREADING_C)
+/*
+ * This allocator doesn't support multithreading. On the other hand it
+ * handles multiple heaps
+ */
+#error MBEDTLS_THREADING_C is not supported by this allocator.
+#endif /* MBEDTLS_THREADING_C */
+
+#if defined(MBEDTLS_SELF_TEST)
+#error MBEDTLS_SELF_TEST is not supported by this allocator.
+#endif /* MBEDTLS_SELF_TEST */
+
+/* Array of heaps per CPU */
+static struct buffer_alloc_ctx *ctx_per_cpu[MAX_CPUS];
+
+static inline struct buffer_alloc_ctx *get_heap_ctx(void)
+{
+	struct buffer_alloc_ctx *ctx;
+	unsigned int cpu_id = my_cpuid();
+
+	assert(cpu_id < MAX_CPUS);
+
+	ctx = ctx_per_cpu[cpu_id];
+	/* Programming error if heap is not assigned */
+	if (ctx == NULL) {
+		ERROR(" No heap assigned to this CPU %u\n", cpu_id);
+		panic();
+	}
+
+	return ctx;
+}
+
+static int verify_header(struct memory_header_s *hdr)
+{
+	if (hdr->magic1 != MAGIC1) {
+		return 1;
+	}
+
+	if (hdr->magic2 != MAGIC2) {
+		return 1;
+	}
+
+	if (hdr->alloc > 1UL) {
+		return 1;
+	}
+
+	if (hdr->prev != NULL && hdr->prev == hdr->next) {
+		return 1;
+	}
+
+	if (hdr->prev_free != NULL && hdr->prev_free == hdr->next_free)	{
+		return 1;
+	}
+
+	return 0;
+}
+
+static int verify_chain(struct buffer_alloc_ctx *heap)
+{
+	struct memory_header_s *prv = heap->first;
+	struct memory_header_s *cur;
+
+	if (prv == NULL || verify_header(prv) != 0) {
+		return 1;
+	}
+
+	if (heap->first->prev != NULL) {
+		return 1;
+	}
+
+	cur = heap->first->next;
+
+	while (cur != NULL) {
+		if (verify_header(cur) != 0) {
+			return 1;
+		}
+
+		if (cur->prev != prv) {
+			return 1;
+		}
+
+		prv = cur;
+		cur = cur->next;
+	}
+
+	return 0;
+}
+
+static void *buffer_alloc_calloc_with_heap(struct buffer_alloc_ctx *heap,
+					   size_t n,
+					   size_t size)
+{
+	struct memory_header_s *new;
+	struct memory_header_s *cur = heap->first_free;
+	unsigned char *p;
+	void *ret;
+	size_t original_len, len;
+
+	if (heap->buf == NULL || heap->first == NULL) {
+		return NULL;
+	}
+
+	original_len = len = n * size;
+
+	if (n == 0UL || size == 0UL || len / n != size) {
+		return NULL;
+	} else if (len > (size_t)-MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
+		return NULL;
+	}
+
+	if ((len % MBEDTLS_MEMORY_ALIGN_MULTIPLE) != 0) {
+		len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
+		len += MBEDTLS_MEMORY_ALIGN_MULTIPLE;
+	}
+
+	/* Find block that fits */
+	while (cur != NULL) {
+		if (cur->size >= len) {
+			break;
+		}
+		cur = cur->next_free;
+	}
+
+	if (cur == NULL) {
+		return NULL;
+	}
+
+	if (cur->alloc != 0UL) {
+		assert(false);
+	}
+
+	/* Found location, split block if > memory_header + 4 room left */
+	if ((cur->size - len) <
+	    (sizeof(struct memory_header_s) + MBEDTLS_MEMORY_ALIGN_MULTIPLE)) {
+		cur->alloc = 1UL;
+
+		/* Remove from free_list */
+		if (cur->prev_free != NULL) {
+			cur->prev_free->next_free = cur->next_free;
+		} else {
+			heap->first_free = cur->next_free;
+		}
+
+		if (cur->next_free != NULL) {
+			cur->next_free->prev_free = cur->prev_free;
+		}
+
+		cur->prev_free = NULL;
+		cur->next_free = NULL;
+
+		if (heap->verify & MBEDTLS_MEMORY_VERIFY_ALLOC) {
+			assert(verify_chain(heap) == 0);
+		}
+
+		ret = (unsigned char *) cur + sizeof(struct memory_header_s);
+		memset(ret, 0, original_len);
+
+		return ret;
+	}
+
+	p = ((unsigned char *) cur) + sizeof(struct memory_header_s) + len;
+	new = (struct memory_header_s *) p;
+
+	new->size = cur->size - len - sizeof(struct memory_header_s);
+	new->alloc = 0;
+	new->prev = cur;
+	new->next = cur->next;
+	new->magic1 = MAGIC1;
+	new->magic2 = MAGIC2;
+
+	if (new->next != NULL) {
+		new->next->prev = new;
+	}
+
+	/* Replace cur with new in free_list */
+	new->prev_free = cur->prev_free;
+	new->next_free = cur->next_free;
+	if (new->prev_free != NULL) {
+		new->prev_free->next_free = new;
+	} else {
+		heap->first_free = new;
+	}
+
+	if (new->next_free != NULL) {
+		new->next_free->prev_free = new;
+	}
+
+	cur->alloc = 1;
+	cur->size = len;
+	cur->next = new;
+	cur->prev_free = NULL;
+	cur->next_free = NULL;
+
+	if ((heap->verify & MBEDTLS_MEMORY_VERIFY_ALLOC) != 0) {
+		assert(verify_chain(heap) == 0);
+	}
+
+	ret = (unsigned char *) cur + sizeof(struct memory_header_s);
+	memset(ret, 0, original_len);
+
+	return ret;
+}
+
+void *buffer_alloc_calloc(size_t n, size_t size)
+{
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	assert(heap);
+	return buffer_alloc_calloc_with_heap(heap, n, size);
+}
+
+static void buffer_alloc_free_with_heap(struct buffer_alloc_ctx *heap,
+					void *ptr)
+{
+	struct memory_header_s *hdr;
+	struct memory_header_s *old = NULL;
+	unsigned char *p = (unsigned char *) ptr;
+
+	if (ptr == NULL || heap->buf == NULL || heap->first == NULL) {
+		return;
+	}
+
+	if (p < heap->buf || p >= heap->buf + heap->len) {
+		assert(0);
+	}
+
+	p -= sizeof(struct memory_header_s);
+	hdr = (struct memory_header_s *) p;
+
+	assert(verify_header(hdr) == 0);
+
+	if (hdr->alloc != 1) {
+		assert(0);
+	}
+
+	hdr->alloc = 0;
+
+	/* Regroup with block before */
+	if (hdr->prev != NULL && hdr->prev->alloc == 0UL) {
+		hdr->prev->size += sizeof(struct memory_header_s) + hdr->size;
+		hdr->prev->next = hdr->next;
+		old = hdr;
+		hdr = hdr->prev;
+
+		if (hdr->next != NULL) {
+			hdr->next->prev = hdr;
+		}
+
+		memset(old, 0, sizeof(struct memory_header_s));
+	}
+
+	/* Regroup with block after */
+	if (hdr->next != NULL && hdr->next->alloc == 0UL) {
+		hdr->size += sizeof(struct memory_header_s) + hdr->next->size;
+		old = hdr->next;
+		hdr->next = hdr->next->next;
+
+		if (hdr->prev_free != NULL || hdr->next_free != NULL) {
+			if (hdr->prev_free != NULL) {
+				hdr->prev_free->next_free = hdr->next_free;
+			} else {
+				heap->first_free = hdr->next_free;
+			}
+			if (hdr->next_free != NULL) {
+				hdr->next_free->prev_free = hdr->prev_free;
+			}
+		}
+
+		hdr->prev_free = old->prev_free;
+		hdr->next_free = old->next_free;
+
+		if (hdr->prev_free != NULL) {
+			hdr->prev_free->next_free = hdr;
+		} else {
+			heap->first_free = hdr;
+		}
+
+		if (hdr->next_free != NULL) {
+			hdr->next_free->prev_free = hdr;
+		}
+
+		if (hdr->next != NULL) {
+			hdr->next->prev = hdr;
+		}
+
+		memset(old, 0, sizeof(struct memory_header_s));
+	}
+
+	/*
+	 * Prepend to free_list if we have not merged
+	 * (Does not have to stay in same order as prev / next list)
+	 */
+	if (old == NULL) {
+		hdr->next_free = heap->first_free;
+		if (heap->first_free != NULL) {
+			heap->first_free->prev_free = hdr;
+		}
+		heap->first_free = hdr;
+	}
+
+	if (heap->verify & MBEDTLS_MEMORY_VERIFY_FREE) {
+		assert(verify_chain(heap));
+	}
+}
+
+void buffer_alloc_free(void *ptr)
+{
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	assert(heap);
+	buffer_alloc_free_with_heap(heap, ptr);
+}
+
+int buffer_alloc_ctx_assign(struct buffer_alloc_ctx *ctx)
+{
+	unsigned int cpuid = my_cpuid();
+
+	assert(cpuid < MAX_CPUS);
+
+	if (ctx == NULL) {
+		return -EINVAL;
+	}
+
+	if (ctx_per_cpu[cpuid] != NULL) {
+		/* multiple assign */
+		return -EINVAL;
+	}
+
+	ctx_per_cpu[cpuid] = ctx;
+
+	return 0;
+}
+
+void buffer_alloc_ctx_unassign(void)
+{
+	unsigned int cpuid = my_cpuid();
+
+	assert(cpuid < MAX_CPUS);
+
+	/* multiple unassign */
+	assert(ctx_per_cpu[cpuid] != NULL);
+
+	ctx_per_cpu[cpuid] = NULL;
+}
+
+void mbedtls_memory_buffer_set_verify(int verify)
+{
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	/* this seems to be dead code */
+	assert(false);
+
+	assert(heap);
+	heap->verify = verify;
+}
+
+int mbedtls_memory_buffer_alloc_verify(void)
+{
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	assert(heap);
+	return verify_chain(heap);
+}
+
+void mbedtls_memory_buffer_alloc_init(unsigned char *buf, size_t len)
+{
+	/* The heap structure is obtained from the REC
+	 * while the buffer is passed in the init function.
+	 * This way the interface can remain the same.
+	 */
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	assert(heap);
+
+	memset(heap, 0, sizeof(struct buffer_alloc_ctx));
+
+	if (len < sizeof(struct memory_header_s) +
+	    MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
+		return;
+	} else if ((size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE)	{
+		/* Adjust len first since buf is used in the computation */
+		len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE
+			- ((size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE);
+		buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE
+			- ((size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE);
+	}
+
+	memset(buf, 0, len);
+
+	heap->buf = buf;
+	heap->len = len;
+
+	heap->first = (struct memory_header_s *)buf;
+	heap->first->size = len - sizeof(struct memory_header_s);
+	heap->first->magic1 = MAGIC1;
+	heap->first->magic2 = MAGIC2;
+	heap->first_free = heap->first;
+}
+
+void mbedtls_memory_buffer_alloc_free(void)
+{
+	struct buffer_alloc_ctx *heap = get_heap_ctx();
+
+	assert(heap);
+	memset(heap, 0, sizeof(struct buffer_alloc_ctx));
+}