diff --git a/Makefile b/Makefile index a5a3a78..7b0f78b 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,8 @@ # By default, build all platforms available PLAT ?= all +# By default, build no SPD component +SPD ?= none BUILD_BASE := ./build BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${BUILD_TYPE} @@ -79,6 +81,7 @@ BUILD_DIRS := ${BUILD_BL1} ${BUILD_BL2} ${BUILD_BL31} PLATFORMS := $(shell ls -I common plat/) +SPDS := $(shell ls -I none services/spd) HELP_PLATFORMS := $(shell echo ${PLATFORMS} | sed 's/ /|/g') ifeq (${PLAT},) @@ -111,13 +114,29 @@ include bl31/bl31.mk endif +# Include SPD Makefile if one has been specified +ifneq (${SPD},none) + # We expect to locate an spd.mk under the specified SPD directory + SPD_MAKE := $(shell m="services/spd/${SPD}/${SPD}.mk"; [ -f "$$m" ] && echo "$$m") + + ifeq (${SPD_MAKE},) + $(error Error: No services/spd/${SPD}/${SPD}.mk located) + endif + $(info Including ${SPD_MAKE}) + include ${SPD_MAKE} + + # If there's BL32 companion for the chosen SPD, and the SPD wants to build the + # BL2 from source, we expect that the SPD's Makefile would set NEED_BL32 + # variable to "yes" +endif + .PHONY: all msg_start ${PLATFORMS} dump clean realclean distclean bl1 bl2 bl31 cscope locate-checkpatch checkcodebase checkpatch fiptool fip locate-bl33 .SUFFIXES: BL1_OBJS := $(addprefix ${BUILD_BL1}/,${BL1_OBJS} ${BL_COMMON_OBJS} ${PLAT_BL_COMMON_OBJS}) BL2_OBJS := $(addprefix ${BUILD_BL2}/,${BL2_OBJS} ${BL_COMMON_OBJS} ${PLAT_BL_COMMON_OBJS}) -BL31_OBJS := $(addprefix ${BUILD_BL31}/,${BL31_OBJS} ${BL_COMMON_OBJS} ${PLAT_BL_COMMON_OBJS}) +BL31_OBJS := $(addprefix ${BUILD_BL31}/,${BL31_OBJS} ${BL_COMMON_OBJS} ${PLAT_BL_COMMON_OBJS} ${SPD_OBJS}) BL1_MAPFILE := $(addprefix ${BUILD_BL1}/,${BL1_MAPFILE}) BL2_MAPFILE := $(addprefix ${BUILD_BL2}/,${BL2_MAPFILE}) BL31_MAPFILE := $(addprefix ${BUILD_BL31}/,${BL31_MAPFILE}) @@ -125,7 +144,6 @@ BL2_LINKERFILE := $(addprefix ${BUILD_BL2}/,${BL2_LINKERFILE}) BL31_LINKERFILE := $(addprefix ${BUILD_BL31}/,${BL31_LINKERFILE}) - INCLUDES += -Ilib/include/ \ -Idrivers/io \ -Iinclude/${ARCH}/ \ @@ -135,7 +153,8 @@ -Iinclude/stdlib \ -Iinclude/stdlib/sys \ -Iplat/${PLAT} \ - ${PLAT_INCLUDES} + ${PLAT_INCLUDES} \ + ${SPD_INCLUDES} ASFLAGS += -nostdinc -ffreestanding -Wa,--fatal-warnings \ -mgeneral-regs-only -D__ASSEMBLY__ ${INCLUDES} \ @@ -185,7 +204,7 @@ # Variables for use with Firmware Image Package FIPTOOLPATH ?= tools/fip_create -FIPTOOL ?= ${FIPTOOLPATH}/fip_create +FIPTOOL ?= ${FIPTOOLPATH}/fip_create fiptool: ${FIPTOOL} fip: ${BUILD_PLAT}/fip.bin @@ -214,6 +233,53 @@ endif +# If BL32 needs to be built, provide necessary build rules and targets +ifeq (${NEED_BL32},yes) +BUILD_BL32 := ${BUILD_PLAT}/bl32 +BUILD_DIRS += ${BUILD_BL32} + +BL32_OBJS := $(addprefix ${BUILD_BL32}/,${BL32_OBJS}) +BL32_MAPFILE := $(addprefix ${BUILD_BL32}/,${BL32_MAPFILE}) +BL32_LINKERFILE := $(addprefix ${BUILD_BL32}/,${BL32_LINKERFILE}) +BL32_LDFLAGS := -Map=${BL32_MAPFILE} --script ${BL32_LINKERFILE} --entry=${BL32_ENTRY_POINT} + +bl32: ${BUILD_BL32} ${BUILD_PLAT}/bl32.bin +all: bl32 +dump: bl32_dump +.PHONY: bl32 + +# Add BL32 image to FIP's input image list +FIP_DEPS := bl32 +FIP_ARGS := --bl32 ${BUILD_PLAT}/bl32.bin + +${BUILD_BL32}/%.o: %.S + @echo " AS $<" + ${Q}${AS} ${ASFLAGS} -c $< -o $@ + +${BUILD_BL32}/%.o: %.c + @echo " CC $<" + ${Q}${CC} ${CFLAGS} -c $< -o $@ + +${BUILD_BL32}/%.ld: %.ld.S + @echo " PP $<" + ${Q}${AS} ${ASFLAGS} -P -E $< -o $@ + +${BUILD_BL32}/bl32.elf: ${BL32_OBJS} ${BL32_LINKERFILE} + @echo " LD $@" + ${Q}${LD} -o $@ ${LDFLAGS} ${BL32_LDFLAGS} ${BL32_OBJS} + +${BUILD_PLAT}/bl32.bin: ${BUILD_BL32}/bl32.elf + @echo " BIN $@" + ${Q}${OC} -O binary $< $@ + @echo + @echo "Built $@ successfully" + @echo + +bl32_dump: + ${Q}${OD} -d ${BUILD_BL32}/bl32.elf > ${BUILD_BL32}/bl32.dump +endif + + clean: @echo " CLEAN" ${Q}rm -rf ${BUILD_PLAT} @@ -323,13 +389,14 @@ @echo "Built $@ successfully" @echo -${BUILD_PLAT}/fip.bin: bl2 bl31 locate-bl33 ${FIPTOOL} +${BUILD_PLAT}/fip.bin: bl2 bl31 ${FIP_DEPS} locate-bl33 ${FIPTOOL} @echo " CREATE FIRMWARE IMAGE PACKAGE $@" @echo ${Q}${FIPTOOL} --dump \ --bl2 ${BUILD_PLAT}/bl2.bin \ --bl31 ${BUILD_PLAT}/bl31.bin \ --bl33 ${BL33} \ + ${FIP_ARGS} \ $@ @echo @@ -345,9 +412,8 @@ @echo "PLAT is used to specify which platform you wish to build." @echo "" @echo "Supported Targets:" - @echo " all Build the BL1, BL2 and BL31 binaries" + @echo " all Build the BL1, BL31 binaries" @echo " bl1 Build the BL1 binary" - @echo " bl2 Build the BL2 binary" @echo " bl31 Build the BL31 binary" @echo " checkcodebase Check the coding style of the entire source tree" @echo " checkpatch Check the coding style on changes in the current" diff --git a/bl32/tsp/tsp-fvp.mk b/bl32/tsp/tsp-fvp.mk index c5bbd7f..2bf748e 100644 --- a/bl32/tsp/tsp-fvp.mk +++ b/bl32/tsp/tsp-fvp.mk @@ -36,5 +36,4 @@ BL32_OBJS += bl32_plat_setup.o \ bl32_setup_xlat.o \ plat_common.o \ - ${BL_COMMON_OBJS} \ ${PLAT_BL_COMMON_OBJS} diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk index 923af5c..bc23315 100644 --- a/bl32/tsp/tsp.mk +++ b/bl32/tsp/tsp.mk @@ -42,7 +42,8 @@ tsp_main.o \ tsp_request.o \ spinlock.o \ - early_exceptions.o + early_exceptions.o \ + ${BL_COMMON_OBJS} BL32_ENTRY_POINT := tsp_entrypoint BL32_MAPFILE := tsp.map diff --git a/plat/fvp/plat_io_storage.c b/plat/fvp/plat_io_storage.c index fd2d2b2..768c3c5 100644 --- a/plat/fvp/plat_io_storage.c +++ b/plat/fvp/plat_io_storage.c @@ -62,6 +62,7 @@ static int fvp_bl2_policy(io_dev_handle *dev_handle, void **image_spec); static int fvp_bl31_policy(io_dev_handle *dev_handle, void **image_spec); +static int fvp_bl32_policy(io_dev_handle *dev_handle, void **image_spec); static int fvp_bl33_policy(io_dev_handle *dev_handle, void **image_spec); static int fvp_fip_policy(io_dev_handle *dev_handle, void **image_spec); @@ -81,6 +82,11 @@ .mode = FOPEN_MODE_R }; +static io_file_spec bl32_file_spec = { + .path = BL32_IMAGE_NAME, + .mode = FOPEN_MODE_R +}; + static io_file_spec bl33_file_spec = { .path = BL33_IMAGE_NAME, .mode = FOPEN_MODE_R @@ -89,6 +95,7 @@ static plat_io_policy fvp_policy[] = { {BL2_IMAGE_NAME, fvp_bl2_policy}, {BL31_IMAGE_NAME, fvp_bl31_policy}, + {BL32_IMAGE_NAME, fvp_bl32_policy}, {BL33_IMAGE_NAME, fvp_bl33_policy}, {FIP_IMAGE_NAME, fvp_fip_policy}, {NULL, NULL} @@ -194,6 +201,31 @@ } +/* Try to load BL32 from Firmware Image Package in FLASH first. If there is no + * FIP in FLASH or it is broken, try to load the file from semi-hosting. + */ +static int fvp_bl32_policy(io_dev_handle *dev_handle, void **image_spec) +{ + int result = IO_FAIL; + void *local_image_spec = &bl32_file_spec; + + INFO("Loading BL32\n"); + /* FIP first then fall back to semi-hosting */ + result = open_fip(local_image_spec); + if (result == IO_SUCCESS) { + *dev_handle = fip_dev_handle; + *(io_file_spec **)image_spec = local_image_spec; + } else { + result = open_semihosting(local_image_spec); + if (result == IO_SUCCESS) { + *dev_handle = sh_dev_handle; + *(io_file_spec **)image_spec = local_image_spec; + } + } + return result; +} + + /* Try to load BL33 from Firmware Image Package in FLASH first. If there is no * FIP in FLASH or it is broken, try to load the file from semi-hosting. */ diff --git a/services/spd/tspd/tspd.mk b/services/spd/tspd/tspd.mk new file mode 100644 index 0000000..60a51a6 --- /dev/null +++ b/services/spd/tspd/tspd.mk @@ -0,0 +1,57 @@ +# +# Copyright (c) 2013-2014, 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. +# + +TSPD_DIR := services/spd/tspd +SPD_INCLUDES := -Iinclude/spd/tspd \ + -I${TSPD_DIR} + +SPD_OBJS := tspd_common.o \ + tspd_main.o \ + tspd_helpers.o + +vpath %.c ${TSPD_DIR} +vpath %.S ${TSPD_DIR} + +# This dispatcher is paired with a Test Secure Payload source and we intend to +# build the Test Secure Payload along with this dispatcher. +# +# In cases where an associated Secure Payload lies outside this build +# system/source tree, the the dispatcher Makefile can either invoke an external +# build command or assume it pre-built + +BL32_ROOT := bl32/tsp + +# Include SP's Makefile. The assumption is that the TSP's build system is +# compatible with that of Trusted Firmware, and it'll add and populate necessary +# build targets and variables +include ${BL32_ROOT}/tsp.mk + +# Let the top-level Makefile know that we intend to build the SP from source +NEED_BL32 := yes diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c new file mode 100644 index 0000000..1bfe696 --- /dev/null +++ b/services/spd/tspd/tspd_common.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2013-2014, 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + * Given a secure payload entrypoint, register width, cpu id & pointer to a + * context data structure, this function will create a secure context ready for + * programming an entry into the secure payload. + ******************************************************************************/ +int32_t tspd_init_secure_context(uint64_t entrypoint, + uint32_t rw, + uint64_t mpidr, + tsp_context *tsp_ctx) +{ + uint32_t scr = read_scr(), sctlr = read_sctlr(); + el1_sys_regs *el1_state; + uint32_t spsr; + + /* Passing a NULL context is a critical programming error */ + assert(tsp_ctx); + + /* + * We support AArch64 TSP for now. + * TODO: Add support for AArch32 TSP + */ + assert(rw == TSP_AARCH64); + + /* + * This might look redundant if the context was statically + * allocated but this function cannot make that assumption. + */ + memset(tsp_ctx, 0, sizeof(*tsp_ctx)); + + /* Set the right security state and register width for the SP */ + scr &= ~SCR_NS_BIT; + scr &= ~SCR_RW_BIT; + if (rw == TSP_AARCH64) + scr |= SCR_RW_BIT; + + /* Get a pointer to the S-EL1 context memory */ + el1_state = get_sysregs_ctx(&tsp_ctx->cpu_ctx); + + /* + * Program the sctlr to allow execution in S-EL1 with caches + * and mmu off + */ + sctlr &= SCTLR_EE_BIT; + sctlr |= SCTLR_EL1_RES1; + write_ctx_reg(el1_state, CTX_SCTLR_EL1, sctlr); + + /* Set this context as ready to be initialised i.e OFF */ + tsp_ctx->state = TSP_STATE_OFF; + + /* Associate this context with the cpu specified */ + tsp_ctx->mpidr = mpidr; + + cm_set_context(mpidr, &tsp_ctx->cpu_ctx, SECURE); + spsr = make_spsr(MODE_EL1, MODE_SP_ELX, rw); + cm_set_el3_eret_context(SECURE, entrypoint, spsr, scr); + + cm_init_exception_stack(mpidr, SECURE); + + return 0; +} + +/******************************************************************************* + * This function takes an SP context pointer and: + * 1. Applies the S-EL1 system register context from tsp_ctx->cpu_ctx. + * 2. Saves the current C runtime state (callee saved registers) on the stack + * frame and saves a reference to this state. + * 3. Calls el3_exit() so that the EL3 system and general purpose registers + * from the tsp_ctx->cpu_ctx are used to enter the secure payload image. + ******************************************************************************/ +uint64_t tspd_synchronous_sp_entry(tsp_context *tsp_ctx) +{ + uint64_t rc; + + assert(tsp_ctx->c_rt_ctx == 0); + + /* Apply the Secure EL1 system register context and switch to it */ + assert(cm_get_context(read_mpidr(), SECURE) == &tsp_ctx->cpu_ctx); + cm_el1_sysregs_context_restore(SECURE); + cm_set_next_eret_context(SECURE); + + rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx); +#if DEBUG + tsp_ctx->c_rt_ctx = 0; +#endif + + return rc; +} + + +/******************************************************************************* + * This function takes an SP context pointer and: + * 1. Saves the S-EL1 system register context tp tsp_ctx->cpu_ctx. + * 2. Restores the current C runtime state (callee saved registers) from the + * stack frame using the reference to this state saved in tspd_enter_sp(). + * 3. It does not need to save any general purpose or EL3 system register state + * as the generic smc entry routine should have saved those. + ******************************************************************************/ +void tspd_synchronous_sp_exit(tsp_context *tsp_ctx, uint64_t ret) +{ + /* Save the Secure EL1 system register context */ + assert(cm_get_context(read_mpidr(), SECURE) == &tsp_ctx->cpu_ctx); + cm_el1_sysregs_context_save(SECURE); + + assert(tsp_ctx->c_rt_ctx != 0); + tspd_exit_sp(tsp_ctx->c_rt_ctx, ret); + + /* Should never reach here */ + assert(0); +} diff --git a/services/spd/tspd/tspd_helpers.S b/services/spd/tspd/tspd_helpers.S new file mode 100644 index 0000000..b56b2aa --- /dev/null +++ b/services/spd/tspd/tspd_helpers.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013-2014, 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. + */ + +#include +#include +#include +#include + + .global tspd_enter_sp + /* --------------------------------------------- + * This function is called with SP_EL0 as stack. + * Here we stash our EL3 callee-saved registers + * on to the stack as a part of saving the C + * runtime and enter the secure payload. + * 'x0' contains a pointer to the memory where + * the address of the C runtime context is to be + * saved. + * --------------------------------------------- + */ +tspd_enter_sp: + /* Make space for the registers that we're going to save */ + mov x3, sp + str x3, [x0, #0] + sub sp, sp, #TSPD_C_RT_CTX_SIZE + + /* Save callee-saved registers on to the stack */ + stp x19, x20, [sp, #TSPD_C_RT_CTX_X19] + stp x21, x22, [sp, #TSPD_C_RT_CTX_X21] + stp x23, x24, [sp, #TSPD_C_RT_CTX_X23] + stp x25, x26, [sp, #TSPD_C_RT_CTX_X25] + stp x27, x28, [sp, #TSPD_C_RT_CTX_X27] + stp x29, x30, [sp, #TSPD_C_RT_CTX_X29] + + /* --------------------------------------------- + * Everything is setup now. el3_exit() will + * use the secure context to restore to the + * general purpose and EL3 system registers to + * ERET into the secure payload. + * --------------------------------------------- + */ + b el3_exit + + /* --------------------------------------------- + * This function is called 'x0' pointing to a C + * runtime context saved in tspd_enter_sp(). It + * restores the saved registers and jumps to + * that runtime with 'x0' as the new sp. This + * destroys the C runtime context that had been + * built on the stack below the saved context by + * the caller. Later the second parameter 'x1' + * is passed as return value to the caller + * --------------------------------------------- + */ + .global tspd_exit_sp +tspd_exit_sp: + /* Restore the previous stack */ + mov sp, x0 + + /* Restore callee-saved registers on to the stack */ + ldp x19, x20, [x0, #(TSPD_C_RT_CTX_X19 - TSPD_C_RT_CTX_SIZE)] + ldp x21, x22, [x0, #(TSPD_C_RT_CTX_X21 - TSPD_C_RT_CTX_SIZE)] + ldp x23, x24, [x0, #(TSPD_C_RT_CTX_X23 - TSPD_C_RT_CTX_SIZE)] + ldp x25, x26, [x0, #(TSPD_C_RT_CTX_X25 - TSPD_C_RT_CTX_SIZE)] + ldp x27, x28, [x0, #(TSPD_C_RT_CTX_X27 - TSPD_C_RT_CTX_SIZE)] + ldp x29, x30, [x0, #(TSPD_C_RT_CTX_X29 - TSPD_C_RT_CTX_SIZE)] + + /* --------------------------------------------- + * This should take us back to the instruction + * after the call to the last tspd_enter_sp(). + * Place the second parameter to x0 so that the + * caller will see it as a return value from the + * original entry call + * --------------------------------------------- + */ + mov x0, x1 + ret diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c new file mode 100644 index 0000000..6896379 --- /dev/null +++ b/services/spd/tspd/tspd_main.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013-2014, 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. + */ + + +/******************************************************************************* + * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a + * plug-in component to the Secure Monitor, registered as a runtime service. The + * SPD is expected to be a functional extension of the Secure Payload (SP) that + * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting + * the Trusted OS/Applications range to the dispatcher. The SPD will either + * handle the request locally or delegate it to the Secure Payload. It is also + * responsible for initialising and maintaining communication with the SP. + ******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + * Single structure to hold information about the various entry points into the + * Secure Payload. It is initialised once on the primary core after a cold boot. + ******************************************************************************/ +entry_info *tsp_entry_info; + +/******************************************************************************* + * Array to keep track of per-cpu Secure Payload state + ******************************************************************************/ +tsp_context tspd_sp_context[TSPD_CORE_COUNT]; + +/******************************************************************************* + * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type + * (aarch32/aarch64) if not already known and initialises the context for entry + * into the SP for its initialisation. + ******************************************************************************/ +int32_t tspd_setup(void) +{ + el_change_info *image_info; + int32_t rc; + uint64_t mpidr = read_mpidr(); + uint32_t linear_id; + + linear_id = platform_get_core_pos(mpidr); + + /* + * Get information about the Secure Payload (BL32) image. Its + * absence is a critical failure. TODO: Add support to + * conditionally include the SPD service + */ + image_info = bl31_get_next_image_info(SECURE); + assert(image_info); + + /* + * We could inspect the SP image and determine it's execution + * state i.e whether AArch32 or AArch64. Assuming it's AArch64 + * for the time being. + */ + rc = tspd_init_secure_context(image_info->entrypoint, + TSP_AARCH64, + mpidr, + &tspd_sp_context[linear_id]); + assert(rc == 0); + + return rc; +} + +/******************************************************************************* + * This function passes control to the Secure Payload image (BL32) for the first + * time on the primary cpu after a cold boot. It assumes that a valid secure + * context has already been created by tspd_setup() which can be directly used. + * It also assumes that a valid non-secure context has been initialised by PSCI + * so it does not need to save and restore any non-secure state. This function + * performs a synchronous entry into the Secure payload. The SP passes control + * back to this routine through a SMC. It also passes the extents of memory made + * available to BL32 by BL31. + ******************************************************************************/ +int32_t bl32_init(meminfo *bl32_meminfo) +{ + uint64_t mpidr = read_mpidr(); + uint32_t linear_id = platform_get_core_pos(mpidr); + uint64_t rc; + tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; + + /* + * Arrange for passing a pointer to the meminfo structure + * describing the memory extents available to the secure + * payload. + * TODO: We are passing a pointer to BL31 internal memory + * whereas this structure should be copied to a communication + * buffer between the SP and SPD. + */ + write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), + CTX_GPREG_X0, + (uint64_t) bl32_meminfo); + + /* Arrange for an entry into the secure payload */ + rc = tspd_synchronous_sp_entry(tsp_ctx); + assert(rc != 0); + if (rc) + tsp_ctx->state = TSP_STATE_ON; + + return rc; +} + +/******************************************************************************* + * This function is responsible for handling all SMCs in the Trusted OS/App + * range from the non-secure state as defined in the SMC Calling Convention + * Document. It is also responsible for communicating with the Secure payload + * to delegate work and return results back to the non-secure state. Lastly it + * will also return any information that the secure payload needs to do the + * work assigned to it. + ******************************************************************************/ +uint64_t tspd_smc_handler(uint32_t smc_fid, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + unsigned long mpidr = read_mpidr(); + uint32_t linear_id = platform_get_core_pos(mpidr), ns; + + /* Determine which security state this SMC originated from */ + ns = is_caller_non_secure(flags); + + switch (smc_fid) { + + /* + * This function ID is used only by the SP to indicate it has + * finished initialising itself after a cold boot + */ + case TSP_ENTRY_DONE: + if (ns) + SMC_RET1(handle, SMC_UNK); + + /* + * Stash the SP entry points information. This is done + * only once on the primary cpu + */ + assert(tsp_entry_info == NULL); + tsp_entry_info = (entry_info *) x1; + + /* + * SP reports completion. The SPD must have initiated + * the original request through a synchronous entry + * into the SP. Jump back to the original C runtime + * context. + */ + tspd_synchronous_sp_exit(&tspd_sp_context[linear_id], x1); + + /* Should never reach here */ + assert(0); + + default: + panic(); + } + + SMC_RET1(handle, 0); +} + +/* Define a SPD runtime service descriptor */ +DECLARE_RT_SVC( + spd, + + OEN_TOS_START, + OEN_TOS_END, + SMC_TYPE_FAST, + tspd_setup, + tspd_smc_handler +); diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h new file mode 100644 index 0000000..2bc35c1 --- /dev/null +++ b/services/spd/tspd/tspd_private.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013-2014, 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. + */ + +#ifndef __SPD_PRIVATE_H__ +#define __SPD_PRIVATE_H__ + +#include +#include +#include +#include + +/******************************************************************************* + * Secure Payload PM state information e.g. SP is suspended, uninitialised etc + ******************************************************************************/ +#define TSP_STATE_OFF 0 +#define TSP_STATE_ON 1 +#define TSP_STATE_SUSPEND 2 + +/******************************************************************************* + * Secure Payload execution state information i.e. aarch32 or aarch64 + ******************************************************************************/ +#define TSP_AARCH32 MODE_RW_32 +#define TSP_AARCH64 MODE_RW_64 + +/******************************************************************************* + * The SPD should know the type of Secure Payload. + ******************************************************************************/ +#define TSP_TYPE_UP PSCI_TOS_NOT_UP_MIG_CAP +#define TSP_TYPE_UPM PSCI_TOS_UP_MIG_CAP +#define TSP_TYPE_MP PSCI_TOS_NOT_PRESENT_MP + +/******************************************************************************* + * Secure Payload migrate type information as known to the SPD. We assume that + * the SPD is dealing with an MP Secure Payload. + ******************************************************************************/ +#define TSP_MIGRATE_INFO TSP_TYPE_MP + +/******************************************************************************* + * Number of cpus that the present on this platform. TODO: Rely on a topology + * tree to determine this in the future to avoid assumptions about mpidr + * allocation + ******************************************************************************/ +#define TSPD_CORE_COUNT PLATFORM_CORE_COUNT + +/******************************************************************************* + * Constants that allow assembler code to preserve callee-saved registers of the + * C runtime context while performing a security state switch. + ******************************************************************************/ +#define TSPD_C_RT_CTX_X19 0x0 +#define TSPD_C_RT_CTX_X20 0x8 +#define TSPD_C_RT_CTX_X21 0x10 +#define TSPD_C_RT_CTX_X22 0x18 +#define TSPD_C_RT_CTX_X23 0x20 +#define TSPD_C_RT_CTX_X24 0x28 +#define TSPD_C_RT_CTX_X25 0x30 +#define TSPD_C_RT_CTX_X26 0x38 +#define TSPD_C_RT_CTX_X27 0x40 +#define TSPD_C_RT_CTX_X28 0x48 +#define TSPD_C_RT_CTX_X29 0x50 +#define TSPD_C_RT_CTX_X30 0x58 +#define TSPD_C_RT_CTX_SIZE 0x60 +#define TSPD_C_RT_CTX_ENTRIES (TSPD_C_RT_CTX_SIZE >> DWORD_SHIFT) + +#ifndef __ASSEMBLY__ + +/* AArch64 callee saved general purpose register context structure. */ +DEFINE_REG_STRUCT(c_rt_regs, TSPD_C_RT_CTX_ENTRIES); + +/* + * Compile time assertion to ensure that both the compiler and linker + * have the same double word aligned view of the size of the C runtime + * register context. + */ +CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs), \ + assert_spd_c_rt_regs_size_mismatch); + +/******************************************************************************* + * Structure which helps the SPD to maintain the per-cpu state of the SP. + * 'state' - collection of flags to track SP state e.g. on/off + * 'mpidr' - mpidr to associate a context with a cpu + * 'c_rt_ctx' - stack address to restore C runtime context from after returning + * from a synchronous entry into the SP. + * 'cpu_ctx' - space to maintain SP architectural state + ******************************************************************************/ +typedef struct { + uint32_t state; + uint64_t mpidr; + uint64_t c_rt_ctx; + cpu_context cpu_ctx; +} tsp_context; + +/******************************************************************************* + * Function & Data prototypes + ******************************************************************************/ +extern uint64_t tspd_enter_sp(uint64_t *c_rt_ctx); +extern void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret); +extern uint64_t tspd_synchronous_sp_entry(tsp_context *tsp_ctx); +extern void __dead2 tspd_synchronous_sp_exit(tsp_context *tsp_ctx, uint64_t ret); +extern int32_t tspd_init_secure_context(uint64_t entrypoint, + uint32_t rw, + uint64_t mpidr, + tsp_context *tsp_ctx); +extern tsp_context tspd_sp_context[TSPD_CORE_COUNT]; +extern entry_info *tsp_entry_info; +#endif /*__ASSEMBLY__*/ + +#endif /* __SPD_PRIVATE_H__ */