summaryrefslogtreecommitdiff
path: root/cactus
diff options
context:
space:
mode:
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>2017-11-06 17:16:26 +0000
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>2017-11-06 17:22:14 +0000
commit222992feee0f726042948d851b9c663ecb47a137 (patch)
tree2996bde747e632286b1249b499a1657175c4c15f /cactus
parentf1a9a019fa1ed40db15014897c3f3c2152ce6d5d (diff)
Cactus: Introduce a test Secure Payload
This image performs some boot tests to make sure that the Secure Partition Manager works correctly. It is introduced as an example of how to implement and build a Secure Partition using the Trusted Firmware build system. This image uses position-independent code so that it can be placed in all places where the Trusted Firmware supports having a Secure Partition. This image is only available for fvp in AArch64 mode. To compile it: CROSS_COMPILE=aarch64-linux-gnu- make PLAT=fvp cactus Change-Id: I636b5e3299ecd4dbae2815a08c7f343a24053568 Co-authored-by: Sandrine Bailleux <sandrine.bailleux@arm.com> Co-authored-by: Douglas Raillard <douglas.raillard@arm.com> Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com> Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Diffstat (limited to 'cactus')
-rw-r--r--cactus/aarch64/cactus_arch_helpers.S14
-rw-r--r--cactus/aarch64/cactus_entrypoint.S119
-rw-r--r--cactus/cactus.h28
-rw-r--r--cactus/cactus.ld.S52
-rw-r--r--cactus/cactus.mk32
-rw-r--r--cactus/cactus_helpers.c55
-rw-r--r--cactus/cactus_helpers.h40
-rw-r--r--cactus/cactus_main.c73
-rw-r--r--cactus/cactus_tests.h46
-rw-r--r--cactus/cactus_tests_memory_attributes.c238
-rw-r--r--cactus/cactus_tests_misc.c38
-rw-r--r--cactus/cactus_tests_system_setup.c77
12 files changed, 812 insertions, 0 deletions
diff --git a/cactus/aarch64/cactus_arch_helpers.S b/cactus/aarch64/cactus_arch_helpers.S
new file mode 100644
index 0000000..2b69883
--- /dev/null
+++ b/cactus/aarch64/cactus_arch_helpers.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .globl cactus_svc
+
+func cactus_svc
+ svc #0
+ ret
+endfunc cactus_svc
diff --git a/cactus/aarch64/cactus_entrypoint.S b/cactus/aarch64/cactus_entrypoint.S
new file mode 100644
index 0000000..a9f1920
--- /dev/null
+++ b/cactus/aarch64/cactus_entrypoint.S
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <secure_partition.h>
+#include <spm_svc.h>
+#include <xlat_tables.h>
+
+ .globl cactus_entrypoint
+
+func cactus_entrypoint
+
+ /*
+ * All the information needed to remap the memory of the Secure
+ * Partition is in the buffer whose pointer is passed on X0 and size on
+ * X1. If the size is 0, return with an error.
+ */
+ cmp x1, #0
+ beq .return_error
+
+ /* Save the base address and size of the buffer. */
+ mov x20, x0
+ mov x21, x1
+ /* Size of the Secure Partition image. */
+ ldr x22, [x20, SP_BOOT_INFO_IMAGE_SIZE_OFFSET]
+
+ /*
+ * Remap all sections of the image before doing anything else.
+ *
+ * Not even the console can be initialized before because it needs to
+ * initialize variables (that can only be modified after remapping that
+ * region as RW).
+ *
+ * If any of the calls fails, loop, as there is no console to print an
+ * error message to.
+ */
+ .macro set_sp_mem_attributes
+ cmp x2, #0 /* If size is 0, skip the call. */
+ beq 1f
+ mov_imm x0, SP_MEM_ATTRIBUTES_SET_AARCH64
+ svc #0
+ cmp x0, #0
+ bne .return_error
+1:
+ .endm
+
+ adr x1, __TEXT_START__
+ adr x2, __TEXT_END__
+ sub x2, x2, x1 /* __TEXT_SIZE__ */
+ lsr x2, x2, PAGE_SIZE_SHIFT /* __TEXT_SIZE__ in pages */
+ mov x3, SP_MEM_ATTR_ACCESS_RO | SP_MEM_ATTR_EXEC
+ set_sp_mem_attributes
+
+ adr x1, __RODATA_START__
+ adr x2, __RODATA_END__
+ sub x2, x2, x1 /* __RODATA_SIZE__ */
+ lsr x2, x2, PAGE_SIZE_SHIFT /* __RODATA_SIZE__ in pages */
+ mov x3, SP_MEM_ATTR_ACCESS_RO | SP_MEM_ATTR_NON_EXEC
+ set_sp_mem_attributes
+
+ adr x1, __RWDATA_START__
+ adr x2, __RWDATA_END__
+ sub x2, x2, x1 /* __RWDATA_SIZE__ */
+ lsr x2, x2, PAGE_SIZE_SHIFT /* __RWDATA_SIZE__ in pages */
+ mov x3, SP_MEM_ATTR_ACCESS_RW | SP_MEM_ATTR_NON_EXEC
+ set_sp_mem_attributes
+
+ /*
+ * To avoid accessing it by mistake, prevent EL0 from accessing the rest
+ * of the memory reserved for the Secure Partition.
+ *
+ * Unused size = Total size - Used size
+ * = Total size - (__RWDATA_END__ - __TEXT_START__)
+ */
+ adr x1, __RWDATA_END__
+ adr x2, __TEXT_START__
+ sub x2, x1, x2 /* x2 = Used size, x22 = Total size */
+ sub x2, x22, x2 /* x2 = Unused size */
+ lsr x2, x2, PAGE_SIZE_SHIFT /* Unused size in pages */
+ mov x3, SP_MEM_ATTR_ACCESS_NOACCESS | SP_MEM_ATTR_NON_EXEC
+ set_sp_mem_attributes
+
+ adr x0, __BSS_START__
+ adr x1, __BSS_END__
+ sub x1, x1, x0
+ bl zeromem16
+
+ /* Setup the stack pointer. */
+ ldr x0, [x20, SP_BOOT_INFO_STACK_BASE_OFFSET]
+ ldr x1, [x20, SP_BOOT_INFO_PCPU_STACK_SIZE_OFFSET]
+ add x0, x0, x1
+ mov sp, x0
+
+ /* And do the rest in C code */
+ mov x0, x20
+ mov x1, x21
+ bl cactus_main
+
+ /* Tell SPM that we are done initialising */
+ mov_imm x0, SP_EVENT_COMPLETE_AARCH64
+ mov x1, #0
+ svc #0
+
+ /* Loop forever */
+ b .
+
+.return_error:
+ /* Tell SPM that the initialization failed. */
+ mov_imm x0, SP_EVENT_COMPLETE_AARCH64
+ mov x1, #1
+ svc #0
+
+ /* Loop forever */
+ b .
+
+endfunc cactus_entrypoint
diff --git a/cactus/cactus.h b/cactus/cactus.h
new file mode 100644
index 0000000..976fe62
--- /dev/null
+++ b/cactus/cactus.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CACTUS_H__
+#define __CACTUS_H__
+
+#include <types.h>
+
+extern uintptr_t __TEXT_START__, __TEXT_END__;
+#define CACTUS_TEXT_START ((uintptr_t)&__TEXT_START__)
+#define CACTUS_TEXT_END ((uintptr_t)&__TEXT_END__)
+
+extern uintptr_t __RODATA_START__, __RODATA_END__;
+#define CACTUS_RODATA_START ((uintptr_t)&__RODATA_START__)
+#define CACTUS_RODATA_END ((uintptr_t)&__RODATA_END__)
+
+extern uintptr_t __RWDATA_START__, __RWDATA_END__;
+#define CACTUS_RWDATA_START ((uintptr_t)&__RWDATA_START__)
+#define CACTUS_RWDATA_END ((uintptr_t)&__RWDATA_END__)
+
+extern uintptr_t __BSS_START__, __BSS_END__;
+#define CACTUS_BSS_START ((uintptr_t)&__BSS_START__)
+#define CACTUS_BSS_END ((uintptr_t)&__BSS_END__)
+
+#endif /* __CACTUS_H__ */
diff --git a/cactus/cactus.ld.S b/cactus/cactus.ld.S
new file mode 100644
index 0000000..3ff11e8
--- /dev/null
+++ b/cactus/cactus.ld.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+#include <xlat_tables.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(cactus_entrypoint)
+
+SECTIONS
+{
+ ASSERT(. == ALIGN(PAGE_SIZE),
+ "TEXT_START address is not aligned to PAGE_SIZE.")
+
+ .text : {
+ __TEXT_START__ = .;
+ *cactus_entrypoint.o(.text*)
+ *(.text*)
+ *(.vectors)
+ . = NEXT(PAGE_SIZE);
+ __TEXT_END__ = .;
+ }
+
+ .rodata : {
+ . = ALIGN(PAGE_SIZE);
+ __RODATA_START__ = .;
+ *(.rodata*)
+ . = NEXT(PAGE_SIZE);
+ __RODATA_END__ = .;
+ }
+
+
+ .data : {
+ . = ALIGN(PAGE_SIZE);
+ __RWDATA_START__ = .;
+ *(.data*)
+ }
+
+ .bss : {
+ . = ALIGN(16);
+ __BSS_START__ = .;
+ *(SORT_BY_ALIGNMENT(.bss*))
+ *(COMMON)
+ . = NEXT(PAGE_SIZE);
+ __BSS_END__ = .;
+ __RWDATA_END__ = .;
+ }
+}
diff --git a/cactus/cactus.mk b/cactus/cactus.mk
new file mode 100644
index 0000000..5c37276
--- /dev/null
+++ b/cactus/cactus.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+INCLUDES += -I cactus
+
+CACTUS_SOURCES := cactus/aarch64/cactus_entrypoint.S \
+ cactus/aarch64/cactus_arch_helpers.S \
+ cactus/cactus_helpers.c \
+ cactus/cactus_main.c \
+ cactus/cactus_tests_memory_attributes.c \
+ cactus/cactus_tests_misc.c \
+ cactus/cactus_tests_system_setup.c \
+ drivers/arm/pl011/${ARCH}/pl011_console.S \
+ framework/${ARCH}/asm_debug.S \
+ lib/${ARCH}/cache_helpers.S \
+ lib/${ARCH}/misc_helpers.S \
+ lib/stdlib/assert.c \
+ lib/stdlib/putchar.c \
+ lib/stdlib/printf.c \
+ lib/stdlib/rand.c \
+ lib/stdlib/strlen.c \
+ lib/stdlib/subr_prf.c \
+ plat/common/${ARCH}/platform_helpers.S
+
+CACTUS_LINKERFILE := cactus/cactus.ld.S
+
+# Position-independent code
+ASFLAGS_aarch64 += -fpie
+TFTF_CFLAGS_aarch64 += -fpie
diff --git a/cactus/cactus_helpers.c b/cactus/cactus_helpers.c
new file mode 100644
index 0000000..7b646bc
--- /dev/null
+++ b/cactus/cactus_helpers.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+uintptr_t bound_rand(uintptr_t min, uintptr_t max)
+{
+ /*
+ * This is not ideal as some numbers will never be generated because of
+ * the integer arithmetic rounding.
+ */
+ return ((rand() * (UINT64_MAX/RAND_MAX)) % (max - min)) + min;
+}
+
+/*******************************************************************************
+ * Test framework helpers
+ ******************************************************************************/
+
+void expect(int expr, int expected)
+{
+ if (expr != expected) {
+ ERROR("Expected value %i, got %i\n", expected, expr);
+ while (1)
+ continue;
+ }
+}
+
+void announce_test_section_start(const char *test_sect_desc)
+{
+ INFO("========================================\n");
+ INFO("Starting %s tests\n", test_sect_desc);
+ INFO("========================================\n");
+}
+void announce_test_section_end(const char *test_sect_desc)
+{
+ INFO("========================================\n");
+ INFO("End of %s tests\n", test_sect_desc);
+ INFO("========================================\n");
+}
+
+void announce_test_start(const char *test_desc)
+{
+ INFO("[+] %s\n", test_desc);
+}
+
+void announce_test_end(const char *test_desc)
+{
+ INFO("Test \"%s\" passed.\n", test_desc);
+}
+
diff --git a/cactus/cactus_helpers.h b/cactus/cactus_helpers.h
new file mode 100644
index 0000000..f4c766c
--- /dev/null
+++ b/cactus/cactus_helpers.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CACTUS_HELPERS_H__
+#define __CACTUS_HELPERS_H__
+
+#include <stdint.h>
+
+/*
+ * Helper functions
+ */
+uint64_t cactus_svc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7);
+
+/*
+ * Choose a pseudo-random number within the [min,max] range (both limits are
+ * inclusive).
+ */
+uintptr_t bound_rand(uintptr_t min, uintptr_t max);
+
+/*
+ * Check that expr == expected.
+ * If not, loop forever.
+ */
+void expect(int expr, int expected);
+
+/*
+ * Test framework functions
+ */
+
+void announce_test_section_start(const char *test_sect_desc);
+void announce_test_section_end(const char *test_sect_desc);
+
+void announce_test_start(const char *test_desc);
+void announce_test_end(const char *test_desc);
+
+#endif /* __CACTUS_HELPERS_H__ */
diff --git a/cactus/cactus_main.c b/cactus/cactus_main.c
new file mode 100644
index 0000000..a67d1fe
--- /dev/null
+++ b/cactus/cactus_main.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <console.h>
+#include <debug.h>
+#include <pl011.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include <secure_partition.h>
+#include <std_svc.h>
+
+#include "cactus.h"
+#include "cactus_tests.h"
+
+extern const char build_message[];
+extern const char version_string[];
+
+static void cactus_print_memory_layout(secure_partition_boot_info_t *boot_info)
+{
+ NOTICE("Secure Partition memory layout:\n");
+ NOTICE(" Secure Partition image : %p - %p\n",
+ (void *) boot_info->sp_image_base,
+ (void *)(boot_info->sp_image_base + boot_info->sp_image_size));
+ NOTICE(" Text region : %p - %p\n",
+ (void *) CACTUS_TEXT_START, (void *) CACTUS_TEXT_END);
+ NOTICE(" Read-only data region : %p - %p\n",
+ (void *) CACTUS_RODATA_START, (void *) CACTUS_RODATA_END);
+ NOTICE(" Read-write data region : %p - %p\n",
+ (void *) CACTUS_RWDATA_START, (void *) CACTUS_RWDATA_END);
+ NOTICE(" BSS region : %p - %p\n",
+ (void *) CACTUS_BSS_START, (void *) CACTUS_BSS_END);
+ NOTICE(" Unused SP image space : %p - %p\n",
+ (void *) CACTUS_BSS_END,
+ (void *)(boot_info->sp_image_base + boot_info->sp_image_size));
+ NOTICE(" EL3-EL0 shared buffer : %p - %p\n",
+ (void *) boot_info->sp_shared_buf_base,
+ (void *)(boot_info->sp_shared_buf_base + boot_info->sp_shared_buf_size));
+ NOTICE(" S-NS shared buffer : %p - %p\n",
+ (void *) boot_info->sp_ns_comm_buf_base,
+ (void *)(boot_info->sp_ns_comm_buf_base + boot_info->sp_ns_comm_buf_size));
+ NOTICE(" Stack region : %p - %p\n",
+ (void *) boot_info->sp_stack_base,
+ (void *)(boot_info->sp_stack_base +
+ (boot_info->sp_pcpu_stack_size * boot_info->num_cpus)));
+ NOTICE(" Heap region : %p - %p\n",
+ (void *) boot_info->sp_heap_base,
+ (void *)(boot_info->sp_heap_base + boot_info->sp_heap_size));
+ NOTICE("Total memory : %p - %p\n",
+ (void *) boot_info->sp_mem_base, (void *) boot_info->sp_mem_limit);
+}
+
+int cactus_main(void *el3_el0_buffer, size_t el3_el0_buffer_size)
+{
+ console_init(PLAT_ARM_UART_BASE,
+ PLAT_ARM_UART_CLK_IN_HZ,
+ PL011_BAUDRATE);
+
+ NOTICE("Booting test Secure Partition Cactus\n");
+ NOTICE("%s\n", build_message);
+ NOTICE("%s\n", version_string);
+ NOTICE("Running at S-EL0\n");
+
+ cactus_print_memory_layout(el3_el0_buffer);
+
+ misc_tests();
+ system_setup_tests();
+ mem_attr_changes_tests((secure_partition_boot_info_t *)el3_el0_buffer);
+
+ return 0;
+}
diff --git a/cactus/cactus_tests.h b/cactus/cactus_tests.h
new file mode 100644
index 0000000..85261a9
--- /dev/null
+++ b/cactus/cactus_tests.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CACTUS_TESTS_H__
+#define __CACTUS_TESTS_H__
+
+#include <secure_partition.h>
+
+/*
+ * Test functions
+ */
+
+/*
+ * Test other things like the version number returned by SPM.
+ */
+void misc_tests(void);
+
+/*
+ * The Arm TF is responsible for setting up system registers on behalf of the
+ * Secure Partition. For example, TF is supposed to allow Secure Partitions to
+ * perform cache maintenance operations (by setting the SCTLR_EL1.UCI bit).
+ *
+ * This function attempts to verify that we indeed have access to these system
+ * features from S-EL0. These tests report their results on the UART. They do
+ * not recover from a failure : when an error is encountered they will most
+ * likely trigger an exception into S-EL1.
+ */
+void system_setup_tests(void);
+
+/*
+ * Exercise the SP_MEM_ATTRIBUTES_SET_AARCH64 SMC interface. A variety of valid
+ * and invalid requests to change memory attributes are tested.
+ *
+ * These tests report their results on the UART. They do not recover from a
+ * failure : when an error is encountered they endlessly loop.
+ *
+ * The argument is a pointer to a secure_partition_boot_info_t struct that has
+ * been filled by EL3 with the information about the memory map of this Secure
+ * Partition.
+ */
+void mem_attr_changes_tests(const secure_partition_boot_info_t *boot_info);
+
+#endif /* __CACTUS_TESTS_H__ */
diff --git a/cactus/cactus_tests_memory_attributes.c b/cactus/cactus_tests_memory_attributes.c
new file mode 100644
index 0000000..ac15f7e
--- /dev/null
+++ b/cactus/cactus_tests_memory_attributes.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <secure_partition.h>
+#include <spm_svc.h>
+#include <stdio.h>
+#include <types.h>
+#include <xlat_tables.h>
+
+#include "cactus.h"
+#include "cactus_helpers.h"
+#include "cactus_tests.h"
+
+/* This is filled at runtime. */
+static uintptr_t cactus_tests_start;
+static uintptr_t cactus_tests_end;
+static uintptr_t cactus_tests_size;
+
+/*
+ * Given the required instruction and data access permissions,
+ * create a memory access controls value that is formatted as expected
+ * by the SP_MEM_ATTRIBUTES_SET_AARCH64 SMC.
+ */
+static inline uint32_t mem_access_perm(int instr_access_perm,
+ int data_access_perm)
+{
+ return instr_access_perm |
+ ((data_access_perm & SP_MEM_ATTR_ACCESS_MASK)
+ << SP_MEM_ATTR_ACCESS_SHIFT);
+}
+
+/*
+ * Send an SP_MEM_ATTRIBUTES_SET_AARCH64 SVC with the given arguments.
+ * Return the return value of the SVC.
+ */
+static int32_t request_mem_attr_changes(uintptr_t base_address,
+ int pages_count,
+ uint32_t memory_access_controls)
+{
+ INFO("Requesting memory attributes change\n");
+ INFO(" Start address : %p\n", (void *) base_address);
+ INFO(" Number of pages: %i\n", pages_count);
+ INFO(" Attributes : 0x%x\n", memory_access_controls);
+
+ uint64_t ret = cactus_svc(SP_MEM_ATTRIBUTES_SET_AARCH64,
+ base_address,
+ pages_count,
+ memory_access_controls,
+ 0, 0, 0, 0);
+
+ return (int32_t) ret;
+}
+
+/*
+ * Send an SP_MEM_ATTRIBUTES_GET_AARCH64 SVC with the given arguments.
+ * Return the return value of the SVC.
+ */
+static int32_t request_get_mem_attr(uintptr_t base_address)
+{
+ INFO("Requesting memory attributes\n");
+ INFO(" Base address : %p\n", (void *) base_address);
+
+ uint64_t ret = cactus_svc(SP_MEM_ATTRIBUTES_GET_AARCH64,
+ base_address,
+ 0, 0, 0, 0, 0, 0);
+
+ return (int32_t) ret;
+}
+
+/*
+ * This function expects a base address and number of pages identifying the
+ * extents of some memory region mapped as non-executable, read-only.
+ *
+ * 1) It changes its data access permissions to read-write.
+ * 2) It checks this memory can now be written to.
+ * 3) It restores the original data access permissions.
+ *
+ * If any check fails, it loops forever. It could also trigger a permission
+ * fault while trying to write to the memory.
+ */
+static void mem_attr_changes_unittest(uintptr_t addr, int pages_count)
+{
+ int32_t ret;
+ uintptr_t end_addr = addr + pages_count * PAGE_SIZE;
+ uint32_t old_attr, new_attr;
+
+ char test_desc[50];
+
+ snprintf(test_desc, sizeof(test_desc),
+ "RO -> RW (%i page(s) from address 0x%lx)", pages_count, addr);
+ announce_test_start(test_desc);
+
+ /*
+ * Ensure we don't change the attributes of some random memory
+ * location
+ */
+ assert(addr >= cactus_tests_start);
+ assert(end_addr < (cactus_tests_start + cactus_tests_size));
+
+ old_attr = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RO);
+ /* Memory was read-only, let's try changing that to RW */
+ new_attr = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+
+ ret = request_mem_attr_changes(addr, pages_count, new_attr);
+ expect(ret, SPM_SUCCESS);
+ printf("Successfully changed memory attributes\n");
+
+ /* The attributes should be the ones we have just written. */
+ ret = request_get_mem_attr(addr);
+ expect(ret, new_attr);
+
+ /* If it worked, we should be able to write to this memory now! */
+ for (unsigned char *data = (unsigned char *) addr;
+ (uintptr_t) data != end_addr;
+ ++data) {
+ *data = 42;
+ }
+ printf("Successfully wrote to the memory\n");
+
+ /* Let's revert back to the original attributes for the next test */
+ ret = request_mem_attr_changes(addr, pages_count, old_attr);
+ expect(ret, SPM_SUCCESS);
+ printf("Successfully restored the old attributes\n");
+
+ /* The attributes should be the original ones again. */
+ ret = request_get_mem_attr(addr);
+ expect(ret, old_attr);
+
+ announce_test_end(test_desc);
+}
+
+/*
+ * Exercise the ability of the Trusted Firmware to change the data access
+ * permissions and instruction execution permissions of some memory region.
+ */
+void mem_attr_changes_tests(const secure_partition_boot_info_t *boot_info)
+{
+ uint32_t attributes;
+ int32_t ret;
+ uintptr_t addr;
+
+ cactus_tests_start = CACTUS_BSS_END;
+ cactus_tests_end = boot_info->sp_image_base + boot_info->sp_image_size;
+ cactus_tests_size = cactus_tests_end - cactus_tests_start;
+
+ const char *test_sect_desc = "memory attributes changes";
+
+ announce_test_section_start(test_sect_desc);
+ /*
+ * Start with error cases, i.e. requests that are expected to be denied
+ */
+ const char *test_desc1 = "Read-write, executable";
+
+ announce_test_start(test_desc1);
+ attributes = mem_access_perm(SP_MEM_ATTR_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ ret = request_mem_attr_changes(CACTUS_RWDATA_START, 1, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc1);
+
+ const char *test_desc2 = "Size == 0";
+
+ announce_test_start(test_desc2);
+ attributes = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ ret = request_mem_attr_changes(CACTUS_RWDATA_START, 0, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc2);
+
+ const char *test_desc3 = "Unaligned address";
+
+ announce_test_start(test_desc3);
+ attributes = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ /* Choose an address not aligned to a page boundary. */
+ addr = cactus_tests_start + 5;
+ ret = request_mem_attr_changes(addr, 1, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc3);
+
+ const char *test_desc4 = "Unmapped memory region";
+
+ announce_test_start(test_desc4);
+ addr = boot_info->sp_mem_limit + 2 * PAGE_SIZE;
+ attributes = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ ret = request_mem_attr_changes(addr, 3, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc4);
+
+ const char *test_desc5 = "Partially unmapped memory region";
+
+ announce_test_start(test_desc5);
+ addr = boot_info->sp_mem_base - 2 * PAGE_SIZE;
+ attributes = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ ret = request_mem_attr_changes(addr, 6, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc5);
+
+ const char *test_desc6 = "Memory region mapped with the wrong granularity";
+
+ announce_test_start(test_desc6);
+ /*
+ * The Secure Partition is placed in DRAM, so there is a lot of
+ * remaining space that doesn't have any restrictions when it is mapped.
+ * It has most likely been mapped with a granularity of 2MB.
+ */
+ addr = boot_info->sp_mem_limit - 2 * PAGE_SIZE;
+ attributes = mem_access_perm(SP_MEM_ATTR_NON_EXEC, SP_MEM_ATTR_ACCESS_RW);
+ ret = request_mem_attr_changes(addr, 1, attributes);
+ expect(ret, SPM_INVALID_PARAMETER);
+ announce_test_end(test_desc6);
+
+ const char *test_desc7 = "Try some valid memory change requests";
+
+ announce_test_start(test_desc7);
+ for (unsigned int i = 0; i < 20; ++i) {
+ /*
+ * Choose some random address in the pool of memory reserved
+ * for these tests.
+ */
+ const int pages_max = cactus_tests_size / PAGE_SIZE;
+ int pages_count = bound_rand(1, pages_max);
+
+ addr = bound_rand(
+ cactus_tests_start,
+ cactus_tests_end - (pages_count * PAGE_SIZE));
+ /* Align to PAGE_SIZE. */
+ addr &= ~(PAGE_SIZE - 1);
+
+ mem_attr_changes_unittest(addr, pages_count);
+ }
+ announce_test_end(test_desc7);
+
+ announce_test_section_end(test_sect_desc);
+}
diff --git a/cactus/cactus_tests_misc.c b/cactus/cactus_tests_misc.c
new file mode 100644
index 0000000..785c157
--- /dev/null
+++ b/cactus/cactus_tests_misc.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <spm_svc.h>
+#include <types.h>
+
+#include "cactus.h"
+#include "cactus_helpers.h"
+#include "cactus_tests.h"
+
+/*
+ * Miscellaneous SPM tests.
+ */
+void misc_tests(void)
+{
+ int32_t ret;
+
+ const char *test_sect_desc = "miscellaneous";
+
+ announce_test_section_start(test_sect_desc);
+
+ const char *test_version = "SPM version check";
+
+ announce_test_start(test_version);
+ ret = cactus_svc(SPM_VERSION_AARCH32, 0, 0, 0, 0, 0, 0, 0);
+ INFO("Version = 0x%x (%u.%u)\n", ret,
+ (ret >> 16) & 0x7FFF, ret & 0xFFFF);
+ expect(ret, SPM_VERSION_COMPILED);
+ announce_test_end(test_version);
+
+ announce_test_section_end(test_sect_desc);
+}
diff --git a/cactus/cactus_tests_system_setup.c b/cactus/cactus_tests_system_setup.c
new file mode 100644
index 0000000..e761540
--- /dev/null
+++ b/cactus/cactus_tests_system_setup.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <types.h>
+
+#include "cactus.h"
+#include "cactus_helpers.h"
+
+extern uintptr_t __TEXT_START__;
+
+void system_setup_tests(void)
+{
+ const char *test_sect_desc = "system setup";
+
+ announce_test_section_start(test_sect_desc);
+
+ /*
+ * Try accessing CTR_EL0 register. This should work if SCTLR_EL1.UCT bit
+ * has been correctly setup by TF.
+ */
+ const char *test_desc1 = "Read CTR_EL0 register";
+
+ announce_test_start(test_desc1);
+
+ uint32_t ctr __unused = read_ctr_el0();
+
+ INFO("CTR_EL0 = 0x%x\n", ctr);
+ announce_test_end(test_desc1);
+
+ /*
+ * Try to execute a cache maintenance instruction. This should work if
+ * SCTLR_EL1.UCI bit has been correctly setup by TF.
+ */
+ const char *test_desc2 = "Access to cache maintenance operations";
+
+ announce_test_start(test_desc2);
+ flush_dcache_range((uintptr_t)&__TEXT_START__, 1);
+ announce_test_end(test_desc2);
+
+#if 0
+ /*
+ * Try accessing a floating point register. This is supposed to trap to
+ * S-EL1, so the test is not enabled by default.
+ *
+ * Expected ESR_EL1 value: 0x1FE00000
+ * i.e. error code = b000111 ("Access to SVE, Advanced SIMD, or
+ * floating-point functionality trapped by CPACR_EL1.FPEN").
+ */
+ const char *test_desc3 = "Access to FP regs";
+
+ announce_test_start(test_desc3);
+ /*
+ * Can't use the 'double' type here because Cactus (like the rest of
+ * the TF code) is compiled with GCC's -mgeneral-regs-only compiler flag
+ * that disables floating point support in GCC.
+ */
+ uint64_t fp_reg;
+
+ __asm__ volatile("fmov %0, d0" : "=r" (fp_reg) :: "d0");
+ INFO("D0 = 0x%lx\n", fp_reg);
+ __asm__ volatile(
+ "fmov d0, #1.0 \n\t"
+ "fmov %0, d0 \n\t"
+ : "=r" (fp_reg)
+ :
+ : "d0");
+ INFO("D0 = 0x%lx\n", fp_reg);
+ announce_test_end(test_desc3);
+#endif
+
+ announce_test_section_end(test_sect_desc);
+}