diff options
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | cactus/aarch64/cactus_arch_helpers.S | 14 | ||||
-rw-r--r-- | cactus/aarch64/cactus_entrypoint.S | 119 | ||||
-rw-r--r-- | cactus/cactus.h | 28 | ||||
-rw-r--r-- | cactus/cactus.ld.S | 52 | ||||
-rw-r--r-- | cactus/cactus.mk | 32 | ||||
-rw-r--r-- | cactus/cactus_helpers.c | 55 | ||||
-rw-r--r-- | cactus/cactus_helpers.h | 40 | ||||
-rw-r--r-- | cactus/cactus_main.c | 73 | ||||
-rw-r--r-- | cactus/cactus_tests.h | 46 | ||||
-rw-r--r-- | cactus/cactus_tests_memory_attributes.c | 238 | ||||
-rw-r--r-- | cactus/cactus_tests_misc.c | 38 | ||||
-rw-r--r-- | cactus/cactus_tests_system_setup.c | 77 | ||||
-rw-r--r-- | include/common/debug.h | 36 | ||||
-rw-r--r-- | include/common/param_header.h | 55 | ||||
-rw-r--r-- | include/lib/aarch64/arch_helpers.h | 1 | ||||
-rw-r--r-- | include/lib/utils_def.h | 95 | ||||
-rw-r--r-- | include/runtime_services/secure_el0_payloads/secure_partition.h | 81 | ||||
-rw-r--r-- | include/runtime_services/secure_el0_payloads/spm_svc.h | 72 |
19 files changed, 1144 insertions, 27 deletions
@@ -164,6 +164,7 @@ INCLUDES := -Iinclude \ -Iinclude/lib/utils \ -Iinclude/plat/common \ -Iinclude/runtime_services \ + -Iinclude/runtime_services/secure_el0_payloads \ -Iinclude/runtime_services/secure_el1_payloads \ -Iinclude/stdlib \ -Iinclude/stdlib/sys \ @@ -223,6 +224,10 @@ ifeq (${FIRMWARE_UPDATE},1) NS_BL2U_SOURCES += ${PLAT_SOURCES} endif +ifneq (${ARCH},aarch32) + include cactus/cactus.mk +endif + # Check that the file pointed by $TESTS_FILE exists ifeq (,$(wildcard ${TESTS_FILE})) $(error "The file TESTS_FILE points to cannot be found") @@ -316,6 +321,13 @@ ns_bl1u ns_bl2u: on this platform." @exit 1 endif +ifneq (${ARCH},aarch32) + BUILD_TARGETS += cactus +else +cactus: + @echo "ERROR: Can't build $@ for AArch32." + @exit 1 +endif # Does the list of goals specified on the command line include a build target? ifneq ($(call match_goals,${BUILD_TARGETS}),) @@ -466,13 +478,17 @@ ifeq ($(FIRMWARE_UPDATE), 1) $(eval $(call MAKE_IMG,ns_bl2u)) endif +ifneq (${ARCH},aarch32) + $(eval $(call MAKE_IMG,cactus)) +endif + cscope: @echo " CSCOPE" ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files ${Q}cscope -b -q -k help: - @echo "usage: ${MAKE} PLAT=<${PLATFORMS}> <all|tftf|ns_bl1u|ns_bl2u|distclean|clean|checkcodebase|checkpatch>" + @echo "usage: ${MAKE} PLAT=<${PLATFORMS}> <all|tftf|ns_bl1u|ns_bl2u|cactus|distclean|clean|checkcodebase|checkpatch>" @echo "" @echo "PLAT is used to specify which platform you wish to build." @echo "If no platform is specified, PLAT defaults to: ${DEFAULT_PLAT}" @@ -483,6 +499,7 @@ help: @echo " tftf Build the TFTF image" @echo " ns_bl1u Build the NS_BL1U image" @echo " ns_bl2u Build the NS_BL2U image" + @echo " cactus Build the Cactus image (Test S-EL0 payload)." @echo " checkcodebase Check the coding style of the entire source tree" @echo " checkpatch Check the coding style on changes in the current" @echo " branch against BASE_COMMIT (default origin/master)" 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); +} diff --git a/include/common/debug.h b/include/common/debug.h index 3b568c5..3c0ee42 100644 --- a/include/common/debug.h +++ b/include/common/debug.h @@ -1,31 +1,7 @@ /* - * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __DEBUG_H__ @@ -33,6 +9,13 @@ #include <stdio.h> +#ifdef IMAGE_CACTUS +/* + * The register MPIDR_EL1 can't be read from EL0, which means that mp_printf() + * can't be used. + */ +#define mp_printf printf +#else /* * Print a formatted string on the UART. * @@ -51,6 +34,7 @@ */ __attribute__((format(printf, 1, 2))) void mp_printf(const char *fmt, ...); +#endif /* * The log output macros print output to the console. These macros produce diff --git a/include/common/param_header.h b/include/common/param_header.h new file mode 100644 index 0000000..c982fc9 --- /dev/null +++ b/include/common/param_header.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __PARAM_HEADER_H__ +#define __PARAM_HEADER_H__ + +/* Param header types */ +#define PARAM_EP 0x01 +#define PARAM_IMAGE_BINARY 0x02 +#define PARAM_BL31 0x03 +#define PARAM_BL_LOAD_INFO 0x04 +#define PARAM_BL_PARAMS 0x05 +#define PARAM_PSCI_LIB_ARGS 0x06 +#define PARAM_SP_IMAGE_BOOT_INFO 0x07 + +/* Param header version */ +#define VERSION_1 0x01 +#define VERSION_2 0x02 + +#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \ + (_p)->h.type = (uint8_t)(_type); \ + (_p)->h.version = (uint8_t)(_ver); \ + (_p)->h.size = (uint16_t)sizeof(*_p); \ + (_p)->h.attr = (uint32_t)(_attr) ; \ + } while (0) + +/* Following is used for populating structure members statically. */ +#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr) \ + ._p.h.type = (uint8_t)(_type), \ + ._p.h.version = (uint8_t)(_ver), \ + ._p.h.size = (uint16_t)sizeof(_p_type), \ + ._p.h.attr = (uint32_t)(_attr) + +#ifndef __ASSEMBLY__ + +#include <types.h> + +/*************************************************************************** + * This structure provides version information and the size of the + * structure, attributes for the structure it represents + ***************************************************************************/ +typedef struct param_header { + uint8_t type; /* type of the structure */ + uint8_t version; /* version of this structure */ + uint16_t size; /* size of this structure in bytes */ + uint32_t attr; /* attributes: unused bits SBZ */ +} param_header_t; + +#endif /*__ASSEMBLY__*/ + +#endif /* __PARAM_HEADER_H__ */ + diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index 23e4bd9..3612b9d 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -204,6 +204,7 @@ static inline void disable_debug_exceptions(void) DEFINE_SYSREG_READ_FUNC(id_pfr1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1) DEFINE_SYSREG_READ_FUNC(CurrentEl) +DEFINE_SYSREG_READ_FUNC(ctr_el0) DEFINE_SYSREG_RW_FUNCS(daif) DEFINE_SYSREG_RW_FUNCS(spsr_el1) DEFINE_SYSREG_RW_FUNCS(spsr_el2) diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h new file mode 100644 index 0000000..185a1c1 --- /dev/null +++ b/include/lib/utils_def.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __UTILS_DEF_H__ +#define __UTILS_DEF_H__ + +/* Compute the number of elements in the given array */ +#define ARRAY_SIZE(a) \ + (sizeof(a) / sizeof((a)[0])) + +#define IS_POWER_OF_TWO(x) \ + (((x) & ((x) - 1)) == 0) + +#define SIZE_FROM_LOG2_WORDS(n) (4 << (n)) + +#define BIT(nr) (1ULL << (nr)) + +/* + * This variant of div_round_up can be used in macro definition but should not + * be used in C code as the `div` parameter is evaluated twice. + */ +#define DIV_ROUND_UP_2EVAL(n, d) (((n) + (d) - 1) / (d)) + +#define MIN(x, y) __extension__ ({ \ + __typeof__(x) _x = (x); \ + __typeof__(y) _y = (y); \ + (void)(&_x == &_y); \ + _x < _y ? _x : _y; \ +}) + +#define MAX(x, y) __extension__ ({ \ + __typeof__(x) _x = (x); \ + __typeof__(y) _y = (y); \ + (void)(&_x == &_y); \ + _x > _y ? _x : _y; \ +}) + +/* + * 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)) + +#define div_round_up(val, div) __extension__ ({ \ + __typeof__(div) _div = (div); \ + round_up((val), _div)/_div; \ +}) + +/* + * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise. + * Both arguments must be unsigned pointer values (i.e. uintptr_t). + */ +#define check_uptr_overflow(ptr, inc) \ + (((ptr) > UINTPTR_MAX - (inc)) ? 1 : 0) + +/* + * For those constants to be shared between C and other sources, apply a 'u' + * or 'ull' suffix to the argument only in C, to avoid undefined or unintended + * behaviour. + * + * The GNU assembler and linker do not support the 'u' and 'ull' suffix (it + * causes the build process to fail) therefore the suffix is omitted when used + * in linker scripts and assembler files. +*/ +#if defined(__LINKER__) || defined(__ASSEMBLY__) +# define U(_x) (_x) +# define ULL(_x) (_x) +#else +# define U(_x) (_x##u) +# define ULL(_x) (_x##ull) +#endif + +/* + * Test for the current architecture version to be at least the version + * expected. + */ +#define ARM_ARCH_AT_LEAST(_maj, _min) \ + ((ARM_ARCH_MAJOR > _maj) || \ + ((ARM_ARCH_MAJOR == _maj) && (ARM_ARCH_MINOR >= _min))) + +#endif /* __UTILS_DEF_H__ */ diff --git a/include/runtime_services/secure_el0_payloads/secure_partition.h b/include/runtime_services/secure_el0_payloads/secure_partition.h new file mode 100644 index 0000000..906fa2b --- /dev/null +++ b/include/runtime_services/secure_el0_payloads/secure_partition.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SECURE_PARTITION_H__ +#define __SECURE_PARTITION_H__ + +#include <utils_def.h> + +/* + * Definitions used to access the members of secure_partition_boot_info from + * assembly code. + */ +#define SP_BOOT_INFO_STACK_BASE_OFFSET U(32) +#define SP_BOOT_INFO_IMAGE_SIZE_OFFSET U(64) +#define SP_BOOT_INFO_PCPU_STACK_SIZE_OFFSET U(72) + +#ifndef __ASSEMBLY__ + +#include <cassert.h> +#include <param_header.h> +#include <types.h> + +/* + * Flags used by the secure_partition_mp_info structure to describe the + * characteristics of a cpu. Only a single flag is defined at the moment to + * indicate the primary cpu. + */ +#define MP_INFO_FLAG_PRIMARY_CPU U(0x00000001) + +/* + * This structure is used to provide information required to initialise a S-EL0 + * partition. + */ +typedef struct secure_partition_mp_info { + u_register_t mpidr; + unsigned int linear_id; + unsigned int flags; +} secure_partition_mp_info_t; + +typedef struct secure_partition_boot_info { + param_header_t h; + uintptr_t sp_mem_base; + uintptr_t sp_mem_limit; + uintptr_t sp_image_base; + uintptr_t sp_stack_base; + uintptr_t sp_heap_base; + uintptr_t sp_ns_comm_buf_base; + uintptr_t sp_shared_buf_base; + size_t sp_image_size; + size_t sp_pcpu_stack_size; + size_t sp_heap_size; + size_t sp_ns_comm_buf_size; + size_t sp_shared_buf_size; + unsigned int num_sp_mem_regions; + unsigned int num_cpus; + secure_partition_mp_info_t *mp_info; +} secure_partition_boot_info_t; + +/* + * Compile time assertions related to the 'secure_partition_boot_info' structure + * to ensure that the assembler and the compiler view of the offsets of the + * structure members is the same. + */ +CASSERT(SP_BOOT_INFO_STACK_BASE_OFFSET == + __builtin_offsetof(secure_partition_boot_info_t, sp_stack_base), \ + assert_secure_partition_boot_info_sp_stack_base_offset_mismatch); + +CASSERT(SP_BOOT_INFO_IMAGE_SIZE_OFFSET == + __builtin_offsetof(secure_partition_boot_info_t, sp_image_size), \ + assert_secure_partition_boot_info_sp_image_size_offset_mismatch); + +CASSERT(SP_BOOT_INFO_PCPU_STACK_SIZE_OFFSET == + __builtin_offsetof(secure_partition_boot_info_t, sp_pcpu_stack_size), \ + assert_secure_partition_boot_info_sp_pcpu_stack_size_offset_mismatch); + +#endif /* __ASSEMBLY__ */ + +#endif /* __SECURE_PARTITION_H__ */ diff --git a/include/runtime_services/secure_el0_payloads/spm_svc.h b/include/runtime_services/secure_el0_payloads/spm_svc.h new file mode 100644 index 0000000..48132fd --- /dev/null +++ b/include/runtime_services/secure_el0_payloads/spm_svc.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SPM_SVC_H__ +#define __SPM_SVC_H__ + +#include <utils_def.h> + +#define SPM_VERSION_MAJOR U(0) +#define SPM_VERSION_MINOR U(1) +#define SPM_VERSION_FORM(major, minor) ((major << 16) | (minor)) +#define SPM_VERSION_COMPILED SPM_VERSION_FORM(SPM_VERSION_MAJOR, SPM_VERSION_MINOR) + +#define SP_VERSION_MAJOR U(1) +#define SP_VERSION_MINOR U(0) +#define SP_VERSION_FORM(major, minor) ((major << 16) | (minor)) +#define SP_VERSION_COMPILED SP_VERSION_FORM(SP_VERSION_MAJOR, SP_VERSION_MINOR) + +/* The macros below are used to identify SPM calls from the SMC function ID */ +#define SPM_FID_MASK U(0xffff) +#define SPM_FID_MIN_VALUE U(0x40) +#define SPM_FID_MAX_VALUE U(0x7f) +#define is_spm_fid(_fid) \ + ((((_fid) & SPM_FID_MASK) >= SPM_FID_MIN_VALUE) && \ + (((_fid) & SPM_FID_MASK) <= SPM_FID_MAX_VALUE)) + +/* + * SVC IDs defined for accessing services implemented by the Secure Partition + * Manager from the Secure Partition(s). These services enable a partition to + * handle delegated events and request privileged operations from the manager. + */ +#define SPM_VERSION_AARCH32 U(0x84000060) +#define SP_EVENT_COMPLETE_AARCH64 U(0xC4000061) +#define SP_MEM_ATTRIBUTES_GET_AARCH64 U(0xC4000064) +#define SP_MEM_ATTRIBUTES_SET_AARCH64 U(0xC4000065) + +/* + * Macros used by SP_MEM_ATTRIBUTES_SET_AARCH64. + */ + +#define SP_MEM_ATTR_ACCESS_NOACCESS U(0) +#define SP_MEM_ATTR_ACCESS_RW U(1) +/* Value U(2) is reserved. */ +#define SP_MEM_ATTR_ACCESS_RO U(3) +#define SP_MEM_ATTR_ACCESS_MASK U(3) +#define SP_MEM_ATTR_ACCESS_SHIFT 0 + +#define SP_MEM_ATTR_EXEC (U(0) << 2) +#define SP_MEM_ATTR_NON_EXEC (U(1) << 2) + +/* + * SMC IDs defined in [1] for accessing secure partition services from the + * Non-secure world. These FIDs occupy the range 0x40 - 0x5f + * [1] DEN0060A_ARM_MM_Interface_Specification.pdf + */ +#define SP_VERSION_AARCH64 U(0xC4000040) +#define SP_VERSION_AARCH32 U(0x84000040) + +#define SP_COMMUNICATE_AARCH64 U(0xC4000041) +#define SP_COMMUNICATE_AARCH32 U(0x84000041) + +/* SPM error codes. */ +#define SPM_SUCCESS 0 +#define SPM_NOT_SUPPORTED -1 +#define SPM_INVALID_PARAMETER -2 +#define SPM_DENIED -3 +#define SPM_NO_MEMORY -5 + +#endif /* __SPM_SVC_H__ */ |