diff options
Diffstat (limited to 'spm')
-rw-r--r-- | spm/cactus_mm/aarch64/cactus_mm_entrypoint.S | 111 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm.h | 36 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm.ld.S | 52 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm.mk | 60 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_main.c | 126 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_service_loop.c | 141 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_tests.h | 46 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_tests_memory_attributes.c | 236 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_tests_misc.c | 39 | ||||
-rw-r--r-- | spm/cactus_mm/cactus_mm_tests_system_setup.c | 71 |
10 files changed, 918 insertions, 0 deletions
diff --git a/spm/cactus_mm/aarch64/cactus_mm_entrypoint.S b/spm/cactus_mm/aarch64/cactus_mm_entrypoint.S new file mode 100644 index 000000000..a657aabcc --- /dev/null +++ b/spm/cactus_mm/aarch64/cactus_mm_entrypoint.S @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <secure_partition.h> +#include <spm_svc.h> +#include <xlat_tables_defs.h> + + .globl cactus_mm_entrypoint + +func cactus_mm_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_MEMORY_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_MEMORY_ATTRIBUTES_ACCESS_RO | SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_ACCESS_RO | SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_ACCESS_RW | SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_ACCESS_NOACCESS | SP_MEMORY_ATTRIBUTES_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 + b cactus_main + +.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_mm_entrypoint diff --git a/spm/cactus_mm/cactus_mm.h b/spm/cactus_mm/cactus_mm.h new file mode 100644 index 000000000..1e0f24d60 --- /dev/null +++ b/spm/cactus_mm/cactus_mm.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __CACTUS_H__ +#define __CACTUS_H__ + +#include <secure_partition.h> +#include <stdint.h> + +/* Linker symbols used to figure out the memory layout of Cactus. */ +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__) + +/* + * Once Cactus has finished its initialisation, this is the function it will + * jump to to handle runtime services for the rest of its lifetime. + */ +__dead2 void secure_services_loop(void); + +#endif /* __CACTUS_H__ */ diff --git a/spm/cactus_mm/cactus_mm.ld.S b/spm/cactus_mm/cactus_mm.ld.S new file mode 100644 index 000000000..4ab822192 --- /dev/null +++ b/spm/cactus_mm/cactus_mm.ld.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> +#include <xlat_tables_defs.h> + +OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) +OUTPUT_ARCH(PLATFORM_LINKER_ARCH) +ENTRY(cactus_mm_entrypoint) + +SECTIONS +{ + ASSERT(. == ALIGN(PAGE_SIZE), + "TEXT_START address is not aligned to PAGE_SIZE.") + + .text : { + __TEXT_START__ = .; + *cactus_mm_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/spm/cactus_mm/cactus_mm.mk b/spm/cactus_mm/cactus_mm.mk new file mode 100644 index 000000000..f00d0399f --- /dev/null +++ b/spm/cactus_mm/cactus_mm.mk @@ -0,0 +1,60 @@ +# +# Copyright (c) 2018-2019, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +CACTUS_MM_INCLUDES := \ + -Iinclude \ + -Iinclude/common \ + -Iinclude/common/${ARCH} \ + -Iinclude/drivers \ + -Iinclude/drivers/arm \ + -Iinclude/lib \ + -Iinclude/lib/${ARCH} \ + -Iinclude/lib/utils \ + -Iinclude/lib/xlat_tables \ + -Iinclude/runtime_services \ + -Iinclude/runtime_services/secure_el0_payloads \ + -Ispm/cactus_mm \ + -Ispm/common \ + +CACTUS_MM_SOURCES := \ + $(addprefix spm/cactus_mm/, \ + aarch64/cactus_mm_entrypoint.S \ + cactus_mm_main.c \ + cactus_mm_service_loop.c \ + cactus_mm_tests_memory_attributes.c \ + cactus_mm_tests_misc.c \ + cactus_mm_tests_system_setup.c \ + ) \ + $(addprefix spm/common/, \ + aarch64/sp_arch_helpers.S \ + sp_helpers.c \ + ) \ + +# TODO: Remove dependency on TFTF files. +CACTUS_MM_SOURCES += \ + tftf/framework/debug.c \ + +CACTUS_MM_SOURCES += \ + drivers/arm/pl011/${ARCH}/pl011_console.S \ + lib/${ARCH}/cache_helpers.S \ + lib/${ARCH}/misc_helpers.S \ + ${STDLIB_SOURCES} + +CACTUS_MM_LINKERFILE := spm/cactus_mm/cactus_mm.ld.S + +CACTUS_MM_DEFINES := + +# TODO: Assertions are disabled because they add several TFTF files as +# dependencies. It is needed to break the dependencies and remove this line when +# that is done. +CACTUS_MM_DEFINES += -DENABLE_ASSERTIONS=0 + +$(eval $(call add_define,CACTUS_MM_DEFINES,DEBUG)) +$(eval $(call add_define,CACTUS_MM_DEFINES,LOG_LEVEL)) +$(eval $(call add_define,CACTUS_MM_DEFINES,PLAT_${PLAT})) +$(eval $(call add_define,CACTUS_MM_DEFINES,AARCH64)) + +cactus_mm: ${AUTOGEN_DIR}/tests_list.h diff --git a/spm/cactus_mm/cactus_mm_main.c b/spm/cactus_mm/cactus_mm_main.c new file mode 100644 index 000000000..8452e656f --- /dev/null +++ b/spm/cactus_mm/cactus_mm_main.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <console.h> +#include <debug.h> +#include <pl011.h> +#include <platform_def.h> +#include <secure_partition.h> +#include <sp_helpers.h> +#include <spm_svc.h> +#include <std_svc.h> + +#include "cactus_mm.h" +#include "cactus_mm_tests.h" + + +/* Host machine information injected by the build system in the ELF file. */ +extern const char build_message[]; +extern const char version_string[]; + +/* + * The ARM Trusted Firmware passes a description of the memory resources + * allocated to the secure partition through the x0 register. This maps to + * a secure_partition_boot_info_t structure type. + * + * This functions prints the information stored in this structure. + */ +static void cactus_print_memory_layout(const 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)); + + assert(boot_info->sp_ns_comm_buf_base == ARM_SECURE_SERVICE_BUFFER_BASE); + assert(boot_info->sp_ns_comm_buf_size == ARM_SECURE_SERVICE_BUFFER_SIZE); + + NOTICE(" Stacks region (%u CPUS) : %p - %p\n", + boot_info->num_cpus, + (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); +} + + +void __dead2 cactus_main(void *el3_el0_buffer, size_t el3_el0_buffer_size) +{ + console_init(PL011_UART2_BASE, + PL011_UART2_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"); + + const secure_partition_boot_info_t *boot_info = + (const secure_partition_boot_info_t *) el3_el0_buffer; + + if (el3_el0_buffer_size < sizeof(secure_partition_boot_info_t)) { + ERROR("The memory buffer shared between EL3/S-EL0 is too small\n"); + ERROR("It is %lu bytes, it should be at least %lu bytes\n", + el3_el0_buffer_size, + sizeof(secure_partition_boot_info_t)); + panic(); + } + + if ((CACTUS_TEXT_START != boot_info->sp_image_base) || + (CACTUS_RWDATA_END > boot_info->sp_image_base + + boot_info->sp_image_size)) { + ERROR("Cactus does not fit in the buffer allocated for the secure partition\n"); + panic(); + } + + cactus_print_memory_layout(boot_info); + + + /* + * Run some initial tests. + * + * These are executed when the system is still booting, just after SPM + * has handed over to Cactus. + */ + misc_tests(); + system_setup_tests(); + /* + * TODO: The following tests fail in the CI: + * mem_attr_changes_tests(boot_info); + */ + + /* + * Handle secure service requests. + */ + secure_services_loop(); +} diff --git a/spm/cactus_mm/cactus_mm_service_loop.c b/spm/cactus_mm/cactus_mm_service_loop.c new file mode 100644 index 000000000..0ad60b62b --- /dev/null +++ b/spm/cactus_mm/cactus_mm_service_loop.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <mm_svc.h> +#include <secure_partition.h> +#include <sp_helpers.h> +#include <spm_svc.h> +#include <string.h> + + +/* + * Handle a fast secure service request, i.e. one made through an MM_COMMUNICATE + * call. + * + * cc + * Calling convention. If MM_COMMUNICATE has been invoked using the SMC32 + * calling convention, this argument must be 32, else 64. + * + * sps + * Communication buffer attached to the secure partition service request. + */ +static int32_t cactus_handle_fast_request(int cc, + secure_partition_request_info_t *sps) +{ + assert(cc == 32 || cc == 64); + + /* No SMC32 is supported at the moment. Just ignore them. */ + if (cc == 32) { + INFO("Ignoring MM_COMMUNICATE_AARCH32 call\n"); + return SPM_SUCCESS; + } + + /* See secure_partition.h for possible ID values. */ + switch (sps->id) { + case SPS_TIMER_SLEEP: { + if (sps->data_size != 1) { + ERROR("Invalid payload size for SPM_SPS_TIMER_SLEEP request (%llu)\n", + sps->data_size); + return SPM_INVALID_PARAMETER; + } + int duration_sec = sps->data[0]; + sp_sleep(duration_sec); + + /* + * Write back to the communication buffer to acknowledge the + * request has been successfully handled. + */ + uint32_t response = CACTUS_FAST_REQUEST_SUCCESS; + memcpy(sps->data, &response, sizeof(response)); + return SPM_SUCCESS; + } + + case SPS_CHECK_ALIVE: + return SPM_SUCCESS; + + default: + INFO("Unsupported MM_COMMUNICATE_AARCH64 call with service ID 0x%x, ignoring it\n", + sps->id); + return SPM_INVALID_PARAMETER; + } +} + +__dead2 void secure_services_loop(void) +{ + int32_t event_status_code; + svc_args svc_values = { 0 }; + + /* + * The first time this loop is executed corresponds to when Cactus has + * finished initialising its run time environment and is ready to handle + * secure service requests. + */ + NOTICE("Cactus: Signal end of init to SPM\n"); + event_status_code = SPM_SUCCESS; + + while (1) { + svc_values.fid = SP_EVENT_COMPLETE_AARCH64; + svc_values.arg1 = event_status_code; + int32_t event_id = sp_svc(&svc_values); + + switch (event_id) { + case MM_COMMUNICATE_AARCH64: + { + uint64_t ctx_addr = svc_values.arg1; + uint32_t ctx_size = svc_values.arg2; + uint64_t cookie = svc_values.arg3; + + NOTICE("Cactus: Received MM_COMMUNICATE_AARCH64 call\n"); + NOTICE("Cactus: Context address: 0x%llx\n", ctx_addr); + NOTICE("Cactus: Context size : %u\n", ctx_size); + NOTICE("Cactus: Cookie : 0x%llx\n", cookie); + + if (ctx_addr == 0) { + ERROR("Context address is invalid\n"); + event_status_code = SPM_INVALID_PARAMETER; + continue; + } + + secure_partition_request_info_t *sps = (void *)(uintptr_t) ctx_addr; + NOTICE("Received fast secure service request with ID #%u\n", + sps->id); + event_status_code = cactus_handle_fast_request(64, sps); + break; + } + + case MM_COMMUNICATE_AARCH32: + { + uint32_t ctx_addr = svc_values.arg1; + uint32_t ctx_size = svc_values.arg2; + uint32_t cookie = svc_values.arg3; + + NOTICE("Cactus: Received MM_COMMUNICATE_AARCH32 call\n"); + NOTICE("Cactus: Context address: 0x%x\n", ctx_addr); + NOTICE("Cactus: Context size : %u\n", ctx_size); + NOTICE("Cactus: Cookie : 0x%x\n", cookie); + + if (ctx_addr == 0) { + ERROR("Context address is invalid\n"); + event_status_code = SPM_INVALID_PARAMETER; + continue; + } + + secure_partition_request_info_t *sps = (void *)(uintptr_t) ctx_addr; + NOTICE("Received fast secure service request with ID #%u\n", + sps->id); + event_status_code = cactus_handle_fast_request(32, sps); + break; + } + + default: + NOTICE("Unhandled Service ID 0x%x\n", event_id); + event_status_code = SPM_NOT_SUPPORTED; + break; + } + } +} diff --git a/spm/cactus_mm/cactus_mm_tests.h b/spm/cactus_mm/cactus_mm_tests.h new file mode 100644 index 000000000..d0e11dcba --- /dev/null +++ b/spm/cactus_mm/cactus_mm_tests.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Arm Limited. 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_MEMORY_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/spm/cactus_mm/cactus_mm_tests_memory_attributes.c b/spm/cactus_mm/cactus_mm_tests_memory_attributes.c new file mode 100644 index 000000000..1a87f6cfa --- /dev/null +++ b/spm/cactus_mm/cactus_mm_tests_memory_attributes.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <errno.h> +#include <platform_def.h> +#include <secure_partition.h> +#include <sp_helpers.h> +#include <spm_svc.h> +#include <stdint.h> +#include <stdio.h> +#include <xlat_tables_defs.h> + +#include "cactus_mm.h" +#include "cactus_mm_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_MEMORY_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_MEMORY_ATTRIBUTES_ACCESS_MASK) + << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT); +} + +/* + * Send an SP_MEMORY_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); + + svc_args svc_values = { SP_MEMORY_ATTRIBUTES_SET_AARCH64, + base_address, + pages_count, + memory_access_controls }; + return sp_svc(&svc_values); +} + +/* + * Send an SP_MEMORY_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); + + svc_args svc_values = { SP_MEMORY_ATTRIBUTES_GET_AARCH64, + base_address }; + return sp_svc(&svc_values); +} + +/* + * 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_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RO); + /* Memory was read-only, let's try changing that to RW */ + new_attr = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_EXEC, SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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); + /* + * This address is usually mapped at a 2 MiB granularity. By using as + * test address the block after the console we make sure that in case + * the attributes of the block actually changed, the console would work + * and we would get the error message. + */ + addr = ((uintptr_t)PLAT_ARM_UART_BASE + 0x200000ULL) & ~(0x200000ULL - 1ULL); + attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_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/spm/cactus_mm/cactus_mm_tests_misc.c b/spm/cactus_mm/cactus_mm_tests_misc.c new file mode 100644 index 000000000..1d4d18a52 --- /dev/null +++ b/spm/cactus_mm/cactus_mm_tests_misc.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <errno.h> +#include <sp_helpers.h> +#include <spm_svc.h> +#include <stdint.h> + +#include "cactus_mm.h" +#include "cactus_mm_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); + svc_args svc_values = { SPM_VERSION_AARCH32 }; + ret = sp_svc(&svc_values); + 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/spm/cactus_mm/cactus_mm_tests_system_setup.c b/spm/cactus_mm/cactus_mm_tests_system_setup.c new file mode 100644 index 000000000..300d5f674 --- /dev/null +++ b/spm/cactus_mm/cactus_mm_tests_system_setup.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <debug.h> +#include <sp_helpers.h> +#include <stdint.h> + +#include "cactus_mm.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); + + /* + * Try accessing a floating point register. This should not trap to + * S-EL1. + */ + 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%llx\n", fp_reg); + __asm__ volatile( + "fmov d0, #1.0 \n\t" + "fmov %0, d0 \n\t" + : "=r" (fp_reg) + : + : "d0"); + INFO("D0 = 0x%llx\n", fp_reg); + announce_test_end(test_desc3); + + announce_test_section_end(test_sect_desc); +} |