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/common/CMakeLists.txt b/lib/common/CMakeLists.txt
new file mode 100644
index 0000000..d4a980b
--- /dev/null
+++ b/lib/common/CMakeLists.txt
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+add_library(rmm-lib-common INTERFACE)
+
+target_include_directories(rmm-lib-common
+ INTERFACE "include"
+ INTERFACE "include/${RMM_ARCH}")
diff --git a/lib/common/include/aarch64/import_sym.h b/lib/common/include/aarch64/import_sym.h
new file mode 100644
index 0000000..49b84a2
--- /dev/null
+++ b/lib/common/include/aarch64/import_sym.h
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef IMPORT_SYM_H
+#define IMPORT_SYM_H
+
+/*
+ * Import an assembly or linker symbol as a C expression with the specified
+ * type
+ */
+#define IMPORT_SYM(type, sym, name) \
+ extern unsigned long sym;\
+ static const __attribute__((unused)) type name = (type) (void *)(&sym)
+
+#endif /* IMPORT_SYM_H */
diff --git a/lib/common/include/bitmap.h b/lib/common/include/bitmap.h
new file mode 100644
index 0000000..0b93e25
--- /dev/null
+++ b/lib/common/include/bitmap.h
@@ -0,0 +1,33 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#include <sizes.h>
+
+/*
+ * Returns the index of the first bit set in @bitmap from @start inclusive.
+ * The index is zero-based from LSB (0) to MSB (63).
+ * When no such bits are set, returns BITS_PER_UL (64).
+ */
+static inline unsigned long bitmap_find_next_set_bit(unsigned long bitmap,
+ unsigned long start)
+{
+ if (start < BITS_PER_UL) {
+ bitmap &= ~0UL << start;
+ if (bitmap != 0UL) {
+ return (unsigned long)(__builtin_ffsl(bitmap) - 1);
+ }
+ }
+ return BITS_PER_UL;
+}
+
+#define bitmap_for_each_set_bit(_bit, _bitmap, _max) \
+ for ((_bit) = find_next_set_bit((_bitmap), 0); \
+ (_bit) < (_max); \
+ (_bit) = find_next_set_bit((_bitmap), (_bit) + 1))
+
+#endif /* BITMAP_H */
diff --git a/lib/common/include/fake_host/host_harness.h b/lib/common/include/fake_host/host_harness.h
new file mode 100644
index 0000000..f926491
--- /dev/null
+++ b/lib/common/include/fake_host/host_harness.h
@@ -0,0 +1,94 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+#ifndef HOST_HARNESS_H
+#define HOST_HARNESS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <types.h>
+
+/* Forward declaration of buffer_slot */
+enum buffer_slot;
+
+/* Fake host wrapper to read and write sysregs */
+u_register_t host_read_sysreg(char *reg_name);
+void host_write_sysreg(char *reg_name, u_register_t v);
+
+struct spinlock_s;
+/* Fake host harness to lock and release spin lock */
+void host_spinlock_acquire(struct spinlock_s *l);
+void host_spinlock_release(struct spinlock_s *l);
+
+/*
+ * Fake host Wrapper to copy data from NS into Realm memory. The function
+ * returns true if the copy succeeds. If the access to the NS memory generates
+ * a fault, false is returned to the caller. In case of failure
+ * (when false is returned), partial data may have been written to the
+ * destination buffer.
+ *
+ * Args:
+ * dest - The address of buffer in Realm memory to write into.
+ * ns_src - The address of buffer in NS memory to read from.
+ * size - The number of bytes to copy.
+ * All arguments must be aligned to 8 bytes.
+ */
+
+bool host_memcpy_ns_read(void *dest, const void *ns_src, unsigned long size);
+
+/*
+ * Fake host wrapper to copy data from Realm into NS memory.The function
+ * returns true if the copy succeeds. If the access to the NS memory generates
+ * a fault, false is returned to the caller. In case of failure (when false is
+ * returned), partial data may have been written to the destination buffer.
+ *
+ * Args:
+ * ns_dest - The address of buffer in NS memory to write into.
+ * src - The address of buffer in Realm memory to read from.
+ * size - The number of bytes to copy.
+ * All arguments must be aligned to 8 bytes.
+ */
+bool host_memcpy_ns_write(void *ns_dest, const void *src, unsigned long size);
+
+/*
+ * Fake host wrapper to run a realm.
+ * Args:
+ * regs - pointer to GP regs to be restored/save when entering/exiting
+ * Realm
+ * Return: Realm exception syndrome return.
+ */
+int host_run_realm(unsigned long *regs);
+
+/*
+ * Fake Host wrapper for monitor_call.
+ */
+unsigned long host_monitor_call(unsigned long id, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5);
+
+struct smc_result;
+/*
+ * Fake Host wrapper for monitor_call_with_res.
+ */
+void host_monitor_call_with_res(unsigned long id, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5,
+ struct smc_result *res);
+
+/*
+ * Fake host wrapper to map a given PA.
+ *
+ * It returns the VA to which the buffer is mapped.
+ */
+void *host_buffer_arch_map(enum buffer_slot slot,
+ unsigned long addr, bool ns);
+
+/*
+ * Fake host wrapper to unmap a buffer slot correspondig to the VA passed
+ * in `buf`.
+ */
+void host_buffer_arch_unmap(void *buf);
+
+#endif /* HOST_HARNESS_H */
diff --git a/lib/common/include/fake_host/import_sym.h b/lib/common/include/fake_host/import_sym.h
new file mode 100644
index 0000000..6ff5a2d
--- /dev/null
+++ b/lib/common/include/fake_host/import_sym.h
@@ -0,0 +1,27 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef IMPORT_SYM_H
+#define IMPORT_SYM_H
+
+/*
+ * Define dummy symbols for fake_host build.
+ * These must be defined as constant qualifiers for IMPORT_SYM to work.
+ */
+#define rmm_text_start 0x10000000UL
+#define rmm_text_end 0x20000000UL
+#define rmm_ro_start 0x20000000UL
+#define rmm_ro_end 0x40000000UL
+#define rmm_rw_start 0x40000000UL
+#define rmm_rw_end 0x50000000UL
+
+/*
+ * Emulates the import of an assembly or linker symbol as a C expression
+ * with the specified type.
+ */
+#define IMPORT_SYM(type, sym, name) \
+ static const __attribute__((unused)) type name = (type)(sym)
+
+#endif /* IMPORT_SYM_H */
diff --git a/lib/common/include/platform_api.h b/lib/common/include/platform_api.h
new file mode 100644
index 0000000..6b26ac1
--- /dev/null
+++ b/lib/common/include/platform_api.h
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+#ifndef PLATFORM_API_H
+#define PLATFORM_API_H
+
+#include <stdint.h>
+
+void plat_warmboot_setup(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3);
+void plat_setup(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3);
+
+/*
+ * Takes an aligned granule address, validates it and if valid returns the
+ * index in the struct granules array or UINT64_MAX in case of an error.
+ *
+ * This function also validates that the granule address is a valid
+ * page address.
+ */
+unsigned long plat_granule_addr_to_idx(unsigned long addr);
+
+/*
+ * Takes an index in the struct granules array and returns the aligned granule
+ * address. The index must be within the number of granules expected by the
+ * platform.
+ */
+unsigned long plat_granule_idx_to_addr(unsigned long idx);
+
+#endif /* PLATFORM_API_H */
diff --git a/lib/common/include/sizes.h b/lib/common/include/sizes.h
new file mode 100644
index 0000000..f1b4f36
--- /dev/null
+++ b/lib/common/include/sizes.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef SIZES_H
+#define SIZES_H
+
+#include <utils_def.h>
+
+#define SZ_1K (UL(1) << 10)
+#define SZ_1M (UL(1) << 20)
+#define SZ_1G (UL(1) << 30)
+
+#define SZ_4K (UL(4) * SZ_1K)
+#define SZ_16K (UL(16) * SZ_1K)
+#define SZ_64K (UL(64) * SZ_1K)
+
+#define SZ_2G (UL(2) * SZ_1G)
+#define SZ_2M (UL(2) * SZ_1M)
+
+#ifndef __ASSEMBLER__
+#define BITS_PER_UL (8 * sizeof(unsigned long))
+#endif
+
+#endif /* SIZES_H */
diff --git a/lib/common/include/types.h b/lib/common/include/types.h
new file mode 100644
index 0000000..0a0e6c7
--- /dev/null
+++ b/lib/common/include/types.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <stdint.h>
+
+typedef uint64_t u_register_t;
+typedef int64_t register_t;
+
+#endif /* TYPES_H */
diff --git a/lib/common/include/utils_def.h b/lib/common/include/utils_def.h
new file mode 100644
index 0000000..2dc310a
--- /dev/null
+++ b/lib/common/include/utils_def.h
@@ -0,0 +1,226 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ * SPDX-FileCopyrightText: Copyright NVIDIA Corporation.
+ */
+
+#ifndef UTILS_DEF_H
+#define UTILS_DEF_H
+
+#if !(defined(__ASSEMBLER__) || defined(__LINKER__))
+#include <stdint.h>
+#endif
+
+/*
+ * For those constants to be shared between C and other sources, apply a 'U',
+ * 'UL', 'ULL', 'L' or 'LL' suffix to the argument only in C, to avoid
+ * undefined or unintended behaviour.
+ *
+ * The GNU assembler and linker do not support these suffixes (it causes the
+ * build process to fail) therefore the suffix is omitted when used in linker
+ * scripts and assembler files.
+ */
+#if defined(__ASSEMBLER__) || defined(__LINKER__)
+# define U(_x) (_x)
+# define UL(_x) (_x)
+# define ULL(_x) (_x)
+# define L(_x) (_x)
+# define LL(_x) (_x)
+#else
+# define U_(_x) (_x##U)
+# define U(_x) U_(_x)
+# define UL(_x) (_x##UL)
+# define ULL(_x) (_x##ULL)
+# define L(_x) (_x##L)
+# define LL(_x) (_x##LL)
+#endif /* __ASSEMBLER__ */
+
+/* Short forms for commonly used attributes */
+#define __dead2 __attribute__((__noreturn__))
+#define __deprecated __attribute__((__deprecated__))
+#define __packed __attribute__((__packed__))
+#define __used __attribute__((__used__))
+#define __unused __attribute__((__unused__))
+#define __aligned(x) __attribute__((__aligned__(x)))
+#define __section(x) __attribute__((__section__(x)))
+
+#define __printflike(fmtarg, firstvararg) \
+ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
+
+/*
+ * The round_up() macro rounds up a value to the given boundary in a
+ * type-agnostic yet type-safe manner. The boundary must be a power of two.
+ * In other words, it computes the smallest multiple of boundary which is
+ * greater than or equal to value.
+ *
+ * round_down() is similar but rounds the value down instead.
+ */
+#define round_boundary(value, boundary) \
+ ((__typeof__(value))((boundary) - 1))
+
+#define round_up(value, boundary) \
+ ((((value) - 1) | round_boundary(value, boundary)) + 1)
+
+#define round_down(value, boundary) \
+ ((value) & ~round_boundary(value, boundary))
+
+/* Compute the number of elements in the given array */
+#define ARRAY_SIZE(a) \
+ (sizeof(a) / sizeof((a)[0]))
+
+#define ARRAY_LEN(_a) \
+ ((sizeof(_a) / sizeof(_a[0])) + CHECK_TYPE_IS_ARRAY(_a))
+
+/*
+ * Macro checks types of array and variable/value to write
+ * and reports compilation error if they mismatch.
+ */
+#define CHECK_ARRAY_TYPE(_a, _v) \
+ _Static_assert(__builtin_types_compatible_p(typeof(_a[0]), typeof(_v)), \
+ "array type mismatch")
+
+/*
+ * Array read/write macros with boundary and types checks
+ * _a: name of array
+ * _i: index
+ * _v: variable/value to write
+ */
+#define ARRAY_READ(_a, _i, _v) \
+({ \
+ CHECK_ARRAY_TYPE(_a, _v); \
+ if (_i >= ARRAY_SIZE(_a)) { \
+ panic(); \
+ } \
+ _v = _a[_i]; \
+})
+
+#define ARRAY_WRITE(_a, _i, _v) \
+({ \
+ CHECK_ARRAY_TYPE(_a, _v); \
+ if (_i >= ARRAY_SIZE(_a)) { \
+ panic(); \
+ } \
+ _a[_i] = _v; \
+})
+
+#define COMPILER_ASSERT(_condition) extern char compiler_assert[(_condition) ? 1 : -1]
+
+/*
+ * If _expr is false, this will result in a compile time error as it tries to
+ * define a bitfield of size -1 in that case. Otherwise, it will define a
+ * bitfield of size 0, which is valid, and not create a compiler warning.
+ *
+ * The return value is only relevant when the compilation succeeds, and by
+ * subtracting the size of the same struct, this should always return 0 as a
+ * value and can be included in other expressions.
+ */
+#define COMPILER_ASSERT_ZERO(_expr) (sizeof(struct { char: (-!(_expr)); }) \
+ - sizeof(struct { char: 0; }))
+
+#define CHECK_TYPE_IS_ARRAY(_v) \
+ COMPILER_ASSERT_ZERO(!__builtin_types_compatible_p(typeof(_v), typeof(&(_v[0]))))
+
+#define IS_POWER_OF_TWO(x) \
+ ((((x) + UL(0)) & ((x) - UL(1))) == UL(0))
+
+#define COMPILER_BARRIER() __asm__ volatile ("" ::: "memory")
+
+#define ALIGNED(_size, _alignment) (((unsigned long)(_size) % (_alignment)) == UL(0))
+
+#define GRANULE_ALIGNED(_addr) ALIGNED((void *)(_addr), GRANULE_SIZE)
+#define GRANULE_SHIFT (UL(12))
+#define GRANULE_MASK (~0xfffUL)
+
+#define HAS_MPAM 0
+
+#if HAS_MPAM
+#define MPAM(_x...) _x
+#else
+#define MPAM(_x...)
+#endif
+
+#define HAS_SPE 0
+
+#if HAS_SPE
+#define SPE(_x...) _x
+#else
+#define SPE(_x...)
+#endif
+
+#if !(defined(__ASSEMBLER__) || defined(__LINKER__))
+
+/*
+ * System register field definitions.
+ *
+ * For any register field we define:
+ * - <register>_<field>_SHIFT
+ * The bit offset of the LSB of the field.
+ * - <register>_<field>_WIDTH
+ * The width of the field in bits.
+ *
+ * For single bit fields, we define:
+ * - <register>_<field>_BIT
+ * The in-place value of the field with the bit set.
+ *
+ * For multi-bit fields, we define:
+ * - <register>_<field>_<enum>
+ * The in-place value of the field set to the value corresponding to the
+ * enumeration name.
+ *
+ * For any register field, we define:
+ * - INPLACE(<register>_<field>, val)
+ * The in-place value of the field set to val, handling any necessary type
+ * promotion to avoid truncation of val.
+ * - MASK(<register>_<field)
+ * An in-place bitmask covering all bits of the field.
+ * - EXTRACT(<register_field> <register_value>)
+ * A macro to extract the value of a register field shifted down so the
+ * value can be evaluated directly.
+ * - EXTRACT_BIT(<register_field> <register_value>)
+ * A macro to extract the value of a register bit shifted down so the
+ * value can be evaluated directly.
+ */
+#define INPLACE(regfield, val) \
+ (((val) + UL(0)) << (regfield##_SHIFT))
+
+#define MASK(regfield) \
+ ((~0UL >> (64UL - (regfield##_WIDTH))) << (regfield##_SHIFT))
+
+#define EXTRACT(regfield, reg) \
+ (((reg) & MASK(regfield)) >> (regfield##_SHIFT))
+
+#define EXTRACT_BIT(regfield, reg) \
+ (((reg) >> (regfield##_SHIFT)) & UL(1))
+
+/*
+ * Generates an unsigned long long (64-bit) value where the bits @_msb
+ * through @_lsb (inclusive) are set to one and all other bits are zero. The
+ * parameters can hold values from 0 through 63 and if _msb == _lsb a single bit
+ * is set at that location.
+ */
+#define BIT_MASK_ULL(_msb, _lsb) \
+ ((~ULL(0) >> (63UL - (_msb))) & (~ULL(0) << (_lsb)))
+
+/*
+ * Stringify the result of expansion of a macro argument
+ */
+#ifndef __XSTRING
+#define __STRING(x) #x
+#define __XSTRING(x) __STRING(x)
+#endif
+
+/*
+ * Defines member of structure and reserves space
+ * for the next member with specified offset.
+ */
+#define SET_MEMBER(member, start, end) \
+ union { \
+ member; \
+ unsigned char reserved##end[end - start]; \
+ }
+
+#define FALLTHROUGH __attribute__((fallthrough))
+
+#endif /* !(defined(__ASSEMBLER__) || defined(__LINKER__)) */
+
+#endif /* UTILS_DEF_H */