Commit 874cd37f authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #280 from vwadekar/tlkd-fixed-v3

TLK dispatcher
parents 7e2d659e 0a34d1e6
......@@ -5,5 +5,7 @@ Companies
---------
Linaro Limited
NVIDIA Corporation
Individuals
-----------
Trusted Little Kernel (TLK) Dispatcher
=======================================
TLK dispatcher adds support for NVIDIA's Trusted Little Kernel (TLK) to work
with the Trusted Firmware. TLK-D can be compiled by including it in the
platform's makefile. TLK is primarily meant to work with Tegra SoCs, so until
Trusted Firmware starts supporting Tegra, the dispatcher code can only be
compiled for other platforms.
In order to compile TLK-D, we need a BL32 image to be present. Since, TLKD
just needs to compile, any BL32 image would do. To use TLK as the BL32, please
refer to the "Build TLK" section.
Once a BL32 is ready, TLKD can be compiled using the following command:
CROSS_COMPILE=<path_to_linaro_chain>/bin/aarch64-none-elf- make NEED_BL1=0
NEED_BL2=0 BL32=<path_to_BL32_image> PLAT=<platform> all
_
Trusted Little Kernel (TLK)
===========================
TLK is a Trusted OS running as Secure EL1. It is a Free Open Source Software
(FOSS) release of the NVIDIA® Trusted Little Kernel (TLK) technology, which
extends technology made available with the development of the Little Kernel (LK).
You can download the LK modular embedded preemptive kernel for use on ARM,
x86, and AVR32 systems from https://github.com/travisg/lk
NVIDIA implemented its Trusted Little Kernel (TLK) technology, designed as a
free and open-source trusted execution environment (OTE).
TLK features include:
• Small, pre-emptive kernel
• Supports multi-threading, IPCs, and thread scheduling
• Added TrustZone features
• Added Secure Storage
• Under MIT/FreeBSD license
NVIDIA extensions to Little Kernel (LK) include:
• User mode
• Address-space separation for TAs
• TLK Client Application (CA) library
• TLK TA library
• Crypto library (encrypt/decrypt, key handling) via OpenSSL
• Linux kernel driver
• Cortex A9/A15 support
• Power Management
• TrustZone memory carve-out (reconfigurable)
• Page table management
• Debugging support over UART (USB planned)
TLK is hosted by NVIDIA on http://nv-tegra.nvidia.com under the
3rdparty/ote_partner/tlk.git repository. Detailed information about
TLK and OTE can be found in the Tegra_BSP_for_Android_TLK_FOSS_Reference.pdf
manual located under the "documentation" directory_.
Build TLK
=========
To build and execute TLK, follow the instructions from "Building a TLK Device"
section from Tegra_BSP_for_Android_TLK_FOSS_Reference.pdf manual.
/*
* Copyright (c) 2015, 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 __TLK_H__
#define __TLK_H__
/*
* Generate function IDs for the Trusted OS/Apps
*/
#define TLK_TOS_STD_FID(fid) ((fid) | 0x72000000 | (0 << 31))
#define TLK_TA_STD_FID(fid) ((fid) | 0x70000000 | (0 << 31))
/*
* Trusted OS specific function IDs
*/
#define TLK_REGISTER_LOGBUF TLK_TOS_STD_FID(0x1)
#define TLK_REGISTER_REQBUF TLK_TOS_STD_FID(0x2)
#define TLK_RESUME_FID TLK_TOS_STD_FID(0x100)
/*
* SMC function IDs that TLK uses to signal various forms of completions
* to the secure payload dispatcher.
*/
#define TLK_REQUEST_DONE (0x32000001 | (1 << 31))
#define TLK_PREEMPTED (0x32000002 | (1 << 31))
#define TLK_ENTRY_DONE (0x32000003 | (1 << 31))
#define TLK_VA_TRANSLATE (0x32000004 | (1 << 31))
#define TLK_FID_SHARED_MEMBUF (0x32000005 | (1 << 31))
/*
* Trusted Application specific function IDs
*/
#define TLK_OPEN_TA_SESSION TLK_TA_STD_FID(0x1)
#define TLK_CLOSE_TA_SESSION TLK_TA_STD_FID(0x2)
#define TLK_TA_LAUNCH_OP TLK_TA_STD_FID(0x3)
#define TLK_TA_SEND_EVENT TLK_TA_STD_FID(0x4)
/*
* Total number of function IDs implemented for services offered to NS clients.
*/
#define TLK_NUM_FID 7
/* TLK implementation version numbers */
#define TLK_VERSION_MAJOR 0x0 /* Major version */
#define TLK_VERSION_MINOR 0x1 /* Minor version */
/*
* Standard Trusted OS Function IDs that fall under Trusted OS call range
* according to SMC calling convention
*/
#define TOS_CALL_COUNT 0xbf00ff00 /* Number of calls implemented */
#define TOS_UID 0xbf00ff01 /* Implementation UID */
#define TOS_CALL_VERSION 0xbf00ff03 /* Trusted OS Call Version */
#endif /* __TLK_H__ */
......@@ -136,6 +136,14 @@ DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, civac)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvau)
DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, zva)
/*******************************************************************************
* Address translation accessor prototypes
******************************************************************************/
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r)
DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w)
void flush_dcache_range(uint64_t, uint64_t);
void inv_dcache_range(uint64_t, uint64_t);
void dcsw_op_louis(uint32_t);
......@@ -160,6 +168,7 @@ DEFINE_SYSREG_WRITE_CONST_FUNC(daifclr)
#define disable_serror() write_daifset(DAIF_ABT_BIT)
#define disable_debug_exceptions() write_daifset(DAIF_DBG_BIT)
DEFINE_SYSREG_READ_FUNC(par_el1)
DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1)
DEFINE_SYSREG_READ_FUNC(CurrentEl)
......
#
# Copyright (c) 2015, 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.
#
SPD_INCLUDES := -Iinclude/bl32/payloads
SPD_SOURCES := services/spd/tlkd/tlkd_common.c \
services/spd/tlkd/tlkd_helpers.S \
services/spd/tlkd/tlkd_main.c \
services/spd/tlkd/tlkd_pm.c
NEED_BL32 := yes
/*
* Copyright (c) 2015, 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 <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <context_mgmt.h>
#include <string.h>
#include "tlkd_private.h"
#define AT_MASK 3
/*******************************************************************************
* This function helps the SP to translate NS/S virtual addresses.
******************************************************************************/
uint64_t tlkd_va_translate(uintptr_t va, int type)
{
uint64_t pa;
if (type & TLK_TRANSLATE_NS_VADDR) {
/* save secure context */
cm_el1_sysregs_context_save(SECURE);
/* restore non-secure context */
cm_el1_sysregs_context_restore(NON_SECURE);
/* switch NS bit to start using 64-bit, non-secure mappings */
write_scr(cm_get_scr_el3(NON_SECURE));
isb();
}
int at = type & AT_MASK;
switch (at) {
case 0:
ats12e1r(va);
break;
case 1:
ats12e1w(va);
break;
case 2:
ats12e0r(va);
break;
case 3:
ats12e0w(va);
break;
default:
assert(0);
}
/* get the (NS/S) physical address */
isb();
pa = read_par_el1();
/* Restore secure state */
if (type & TLK_TRANSLATE_NS_VADDR) {
/* restore secure context */
cm_el1_sysregs_context_restore(SECURE);
/* switch NS bit to start using 32-bit, secure mappings */
write_scr(cm_get_scr_el3(SECURE));
isb();
}
return pa;
}
/*******************************************************************************
* 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.
******************************************************************************/
void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point,
uint32_t rw,
uint64_t pc,
tlk_context_t *tlk_ctx)
{
uint32_t ep_attr, spsr;
/* Passing a NULL context is a critical programming error */
assert(tlk_ctx);
assert(tlk_entry_point);
assert(pc);
/* Associate this context with the cpu specified */
tlk_ctx->mpidr = read_mpidr_el1();
clr_std_smc_active_flag(tlk_ctx->state);
cm_set_context(&tlk_ctx->cpu_ctx, SECURE);
if (rw == SP_AARCH64)
spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
else
spsr = SPSR_MODE32(MODE32_svc,
SPSR_T_ARM,
read_sctlr_el3() & SCTLR_EE_BIT,
DISABLE_ALL_EXCEPTIONS);
/* initialise an entrypoint to set up the CPU context */
ep_attr = SECURE | EP_ST_ENABLE;
if (read_sctlr_el3() & SCTLR_EE_BIT)
ep_attr |= EP_EE_BIG;
SET_PARAM_HEAD(tlk_entry_point, PARAM_EP, VERSION_1, ep_attr);
tlk_entry_point->pc = pc;
tlk_entry_point->spsr = spsr;
}
/*******************************************************************************
* This function takes a TLK context pointer and:
* 1. Applies the S-EL1 system register context from tlk_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 tlk_ctx->cpu_ctx are used to enter the secure payload image.
******************************************************************************/
uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx)
{
uint64_t rc;
/* Passing a NULL context is a critical programming error */
assert(tlk_ctx);
assert(tlk_ctx->c_rt_ctx == 0);
/* Apply the Secure EL1 system register context and switch to it */
assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx);
cm_el1_sysregs_context_restore(SECURE);
cm_set_next_eret_context(SECURE);
rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx);
#if DEBUG
tlk_ctx->c_rt_ctx = 0;
#endif
return rc;
}
/*******************************************************************************
* This function takes a TLK context pointer and:
* 1. Saves the S-EL1 system register context to tlk_ctx->cpu_ctx.
* 2. Restores the current C runtime state (callee saved registers) from the
* stack frame using reference to this state saved in tlkd_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 tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx, uint64_t ret)
{
/* Passing a NULL context is a critical programming error */
assert(tlk_ctx);
/* Save the Secure EL1 system register context */
assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx);
cm_el1_sysregs_context_save(SECURE);
assert(tlk_ctx->c_rt_ctx != 0);
tlkd_exit_sp(tlk_ctx->c_rt_ctx, ret);
/* Should never reach here */
assert(0);
}
/*
* Copyright (c) 2015, 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 <asm_macros.S>
#include "tlkd_private.h"
.global tlkd_enter_sp
.global tlkd_exit_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.
* ---------------------------------------------
*/
func tlkd_enter_sp
/* Make space for the registers that we're going to save */
mov x3, sp
str x3, [x0, #0]
sub sp, sp, #TLKD_C_RT_CTX_SIZE
/* Save callee-saved registers on to the stack */
stp x19, x20, [sp, #TLKD_C_RT_CTX_X19]
stp x21, x22, [sp, #TLKD_C_RT_CTX_X21]
stp x23, x24, [sp, #TLKD_C_RT_CTX_X23]
stp x25, x26, [sp, #TLKD_C_RT_CTX_X25]
stp x27, x28, [sp, #TLKD_C_RT_CTX_X27]
stp x29, x30, [sp, #TLKD_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 with 'x0' pointing to
* a C runtime context saved in tlkd_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
* ----------------------------------------------
*/
func tlkd_exit_sp
/* Restore the previous stack */
mov sp, x0
/* Restore callee-saved registers on to the stack */
ldp x19, x20, [x0, #(TLKD_C_RT_CTX_X19 - TLKD_C_RT_CTX_SIZE)]
ldp x21, x22, [x0, #(TLKD_C_RT_CTX_X21 - TLKD_C_RT_CTX_SIZE)]
ldp x23, x24, [x0, #(TLKD_C_RT_CTX_X23 - TLKD_C_RT_CTX_SIZE)]
ldp x25, x26, [x0, #(TLKD_C_RT_CTX_X25 - TLKD_C_RT_CTX_SIZE)]
ldp x27, x28, [x0, #(TLKD_C_RT_CTX_X27 - TLKD_C_RT_CTX_SIZE)]
ldp x29, x30, [x0, #(TLKD_C_RT_CTX_X29 - TLKD_C_RT_CTX_SIZE)]
/* ------------------------------------------------
* This should take us back to the instruction
* after the call to the last tlkd_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
/*
* Copyright (c) 2015, 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 <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <bl31.h>
#include <context_mgmt.h>
#include <debug.h>
#include <errno.h>
#include <platform.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <tlk.h>
#include <uuid.h>
#include "tlkd_private.h"
extern const spd_pm_ops_t tlkd_pm_ops;
/*******************************************************************************
* Array to keep track of per-cpu Secure Payload state
******************************************************************************/
static tlk_context_t tlk_ctx;
/* TLK UID: RFC-4122 compliant UUID (version-5, sha-1) */
DEFINE_SVC_UUID(tlk_uuid,
0xbd11e9c9, 0x2bba, 0x52ee, 0xb1, 0x72,
0x46, 0x1f, 0xba, 0x97, 0x7f, 0x63);
int32_t tlkd_init(void);
/*
* The number of arguments/results to save during a SMC call for TLK.
*/
#define TLK_SHDBUF_SIZE 4
/*******************************************************************************
* Shared memory buffer for passing SMC args/results to TLK
******************************************************************************/
typedef struct tlk_args_results {
uint64_t args[TLK_SHDBUF_SIZE];
} tlk_args_results_t;
static tlk_args_results_t *tlk_args_results_buf;
/*
* Helper function to store args from TLK and pass results back
*/
static inline void store_tlk_args_results(uint64_t x0, uint64_t x1, uint64_t x2,
uint64_t x3)
{
/* store arguments sent by TLK */
tlk_args_results_buf->args[0] = x0;
tlk_args_results_buf->args[1] = x1;
tlk_args_results_buf->args[2] = x2;
tlk_args_results_buf->args[3] = x3;
flush_dcache_range((uint64_t)tlk_args_results_buf,
sizeof(tlk_args_results_t));
}
/*******************************************************************************
* 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 tlkd_setup(void)
{
entry_point_info_t *tlk_ep_info;
/*
* Get information about the Secure Payload (BL32) image. Its
* absence is a critical failure.
*/
tlk_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
if (!tlk_ep_info) {
WARN("No SP provided. Booting device without SP"
" initialization. SMC`s destined for SP"
" will return SMC_UNK\n");
return 1;
}
/*
* If there's no valid entry point for SP, we return a non-zero value
* signalling failure initializing the service. We bail out without
* registering any handlers
*/
if (!tlk_ep_info->pc)
return 1;
/*
* Inspect the SP image's SPSR and determine it's execution state
* i.e whether AArch32 or AArch64.
*/
tlkd_init_tlk_ep_state(tlk_ep_info,
(tlk_ep_info->spsr >> MODE_RW_SHIFT) & MODE_RW_MASK,
tlk_ep_info->pc,
&tlk_ctx);
/*
* All TLK SPD initialization done. Now register our init function
* with BL31 for deferred invocation
*/
bl31_register_bl32_init(&tlkd_init);
return 0;
}
/*******************************************************************************
* 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 tlkd_setup() which can be directly
* used. This function performs a synchronous entry into the Secure payload.
* The SP passes control back to this routine through a SMC.
******************************************************************************/
int32_t tlkd_init(void)
{
uint64_t mpidr = read_mpidr();
entry_point_info_t *tlk_entry_point;
/*
* Get information about the Secure Payload (BL32) image. Its
* absence is a critical failure.
*/
tlk_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
assert(tlk_entry_point);
cm_init_context(mpidr, tlk_entry_point);
/*
* Arrange for an entry into the test secure payload.
*/
return tlkd_synchronous_sp_entry(&tlk_ctx);
}
/*******************************************************************************
* 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 tlkd_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)
{
cpu_context_t *ns_cpu_context;
uint32_t ns;
uint64_t vaddr, type, par;
/* Passing a NULL context is a critical programming error */
assert(handle);
/* These SMCs are only supported by CPU0 */
if ((read_mpidr() & MPIDR_CPU_MASK) != 0)
SMC_RET1(handle, SMC_UNK);
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
switch (smc_fid) {
/*
* This function ID is used by SP to indicate that it was
* preempted by a non-secure world IRQ.
*/
case TLK_PREEMPTED:
if (ns)
SMC_RET1(handle, SMC_UNK);
assert(handle == cm_get_context(SECURE));
cm_el1_sysregs_context_save(SECURE);
/* Get a reference to the non-secure context */
ns_cpu_context = cm_get_context(NON_SECURE);
assert(ns_cpu_context);
/*
* Restore non-secure state. There is no need to save the
* secure system register context since the SP was supposed
* to preserve it during S-EL1 interrupt handling.
*/
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
SMC_RET1(ns_cpu_context, tlk_args_results_buf->args[0]);
/*
* Request from non secure world to resume the preempted
* Standard SMC call.
*/
case TLK_RESUME_FID:
/* RESUME should be invoked only by normal world */
if (!ns)
SMC_RET1(handle, SMC_UNK);
/*
* This is a resume request from the non-secure client.
* save the non-secure state and send the request to
* the secure payload.
*/
assert(handle == cm_get_context(NON_SECURE));
/* Check if we are already preempted before resume */
if (!get_std_smc_active_flag(tlk_ctx.state))
SMC_RET1(handle, SMC_UNK);
cm_el1_sysregs_context_save(NON_SECURE);
/*
* We are done stashing the non-secure context. Ask the
* secure payload to do the work now.
*/
/* We just need to return to the preempted point in
* SP and the execution will resume as normal.
*/
cm_el1_sysregs_context_restore(SECURE);
cm_set_next_eret_context(SECURE);
SMC_RET0(handle);
/*
* This is a request from the non-secure context to:
*
* a. register shared memory with the SP for storing it's
* activity logs.
* b. register shared memory with the SP for passing args
* required for maintaining sessions with the Trusted
* Applications.
* c. open/close sessions
* d. issue commands to the Trusted Apps
*/
case TLK_REGISTER_LOGBUF:
case TLK_REGISTER_REQBUF:
case TLK_OPEN_TA_SESSION:
case TLK_CLOSE_TA_SESSION:
case TLK_TA_LAUNCH_OP:
case TLK_TA_SEND_EVENT:
if (!ns || !tlk_args_results_buf)
SMC_RET1(handle, SMC_UNK);
/*
* This is a fresh request from the non-secure client.
* The parameters are in x1 and x2. Figure out which
* registers need to be preserved, save the non-secure
* state and send the request to the secure payload.
*/
assert(handle == cm_get_context(NON_SECURE));
/* Check if we are already preempted */
if (get_std_smc_active_flag(tlk_ctx.state))
SMC_RET1(handle, SMC_UNK);
cm_el1_sysregs_context_save(NON_SECURE);
/*
* Verify if there is a valid context to use.
*/
assert(&tlk_ctx.cpu_ctx == cm_get_context(SECURE));
/*
* Mark the SP state as active.
*/
set_std_smc_active_flag(tlk_ctx.state);
/* Save args for use by the SP on return */
store_tlk_args_results(smc_fid, x1, x2, x3);
/*
* We are done stashing the non-secure context. Ask the
* secure payload to do the work now.
*/
cm_el1_sysregs_context_restore(SECURE);
cm_set_next_eret_context(SECURE);
SMC_RET0(&tlk_ctx.cpu_ctx);
/*
* Translate NS/EL1-S virtual addresses
*/
case TLK_VA_TRANSLATE:
if (ns || !tlk_args_results_buf)
SMC_RET1(handle, SMC_UNK);
/* virtual address and type: ns/s */
vaddr = tlk_args_results_buf->args[0];
type = tlk_args_results_buf->args[1];
par = tlkd_va_translate(vaddr, type);
/* Save PA for use by the SP on return */
store_tlk_args_results(par, 0, 0, 0);
SMC_RET0(handle);
/*
* This is a request from the SP to mark completion of
* a standard function ID.
*/
case TLK_REQUEST_DONE:
if (ns || !tlk_args_results_buf)
SMC_RET1(handle, SMC_UNK);
/*
* Mark the SP state as inactive.
*/
clr_std_smc_active_flag(tlk_ctx.state);
/* Get a reference to the non-secure context */
ns_cpu_context = cm_get_context(NON_SECURE);
assert(ns_cpu_context);
/*
* This is a request completion SMC and we must switch to
* the non-secure world to pass the result.
*/
cm_el1_sysregs_context_save(SECURE);
/*
* We are done stashing the secure context. Switch to the
* non-secure context and return the result.
*/
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
SMC_RET1(ns_cpu_context, tlk_args_results_buf->args[0]);
/*
* This function ID is used only by the SP to indicate it has
* finished initialising itself after a cold boot
*/
case TLK_ENTRY_DONE:
if (ns || !tlk_args_results_buf)
SMC_RET1(handle, SMC_UNK);
/*
* SP has been successfully initialized. Register power
* managemnt hooks with PSCI
*/
psci_register_spd_pm_hook(&tlkd_pm_ops);
/*
* TLK 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.
*/
tlkd_synchronous_sp_exit(&tlk_ctx, tlk_args_results_buf->args[0]);
/*
* This is a request from the secure payload to register
* shared memory to pass SMC args/results between EL1, EL3.
*/
case TLK_FID_SHARED_MEMBUF:
if (ns || !x1)
SMC_RET1(handle, SMC_UNK);
/*
* TODO: Check if the passed memory pointer is valid. Might
* require a call into the platform code.
*/
tlk_args_results_buf = (tlk_args_results_t *)x1;
SMC_RET0(handle);
/*
* Return the number of service function IDs implemented to
* provide service to non-secure
*/
case TOS_CALL_COUNT:
SMC_RET1(handle, TLK_NUM_FID);
/*
* Return TLK's UID to the caller
*/
case TOS_UID:
SMC_UUID_RET(handle, tlk_uuid);
/*
* Return the version of current implementation
*/
case TOS_CALL_VERSION:
SMC_RET2(handle, TLK_VERSION_MAJOR, TLK_VERSION_MINOR);
default:
break;
}
SMC_RET1(handle, SMC_UNK);
}
/* Define a SPD runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
tlkd_tos_fast,
OEN_TOS_START,
OEN_TOS_END,
SMC_TYPE_FAST,
tlkd_setup,
tlkd_smc_handler
);
/* Define a SPD runtime service descriptor for standard SMC calls */
DECLARE_RT_SVC(
tlkd_tos_std,
OEN_TOS_START,
OEN_TOS_END,
SMC_TYPE_STD,
NULL,
tlkd_smc_handler
);
/* Define a SPD runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
tlkd_tap_fast,
OEN_TAP_START,
OEN_TAP_END,
SMC_TYPE_FAST,
NULL,
tlkd_smc_handler
);
/* Define a SPD runtime service descriptor for standard SMC calls */
DECLARE_RT_SVC(
tlkd_tap_std,
OEN_TAP_START,
OEN_TAP_END,
SMC_TYPE_STD,
NULL,
tlkd_smc_handler
);
/*
* Copyright (c) 2015, 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 <psci.h>
#define MPIDR_CPU0 0x80000000
/*******************************************************************************
* Return the type of payload TLKD is dealing with. Report the current
* resident cpu (mpidr format) if it is a UP/UP migratable payload.
******************************************************************************/
static int32_t cpu_migrate_info(uint64_t *resident_cpu)
{
/* the payload runs only on CPU0 */
*resident_cpu = MPIDR_CPU0;
/* Uniprocessor, not migrate capable payload */
return PSCI_TOS_NOT_UP_MIG_CAP;
}
/*******************************************************************************
* Structure populated by the Dispatcher to be given a chance to perform any
* bookkeeping before PSCI executes a power mgmt. operation.
******************************************************************************/
const spd_pm_ops_t tlkd_pm_ops = {
.svc_migrate_info = cpu_migrate_info,
};
/*
* Copyright (c) 2015, 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 __TLKD_PRIVATE_H__
#define __TLKD_PRIVATE_H__
#include <arch.h>
#include <context.h>
#include <interrupt_mgmt.h>
#include <platform_def.h>
#include <psci.h>
/*
* This flag is used by the TLKD to determine if the SP is servicing a standard
* SMC request prior to programming the next entry into the SP e.g. if SP
* execution is preempted by a non-secure interrupt and handed control to the
* normal world. If another request which is distinct from what the SP was
* previously doing arrives, then this flag will be help the TLKD to either
* reject the new request or service it while ensuring that the previous context
* is not corrupted.
*/
#define STD_SMC_ACTIVE_FLAG_SHIFT 2
#define STD_SMC_ACTIVE_FLAG_MASK 1
#define get_std_smc_active_flag(state) (((state) >> STD_SMC_ACTIVE_FLAG_SHIFT) \
& STD_SMC_ACTIVE_FLAG_MASK)
#define set_std_smc_active_flag(state) ((state) |= \
(1 << STD_SMC_ACTIVE_FLAG_SHIFT))
#define clr_std_smc_active_flag(state) ((state) &= \
~(STD_SMC_ACTIVE_FLAG_MASK \
<< STD_SMC_ACTIVE_FLAG_SHIFT))
/*******************************************************************************
* Translate virtual address received from the NS world
******************************************************************************/
#define TLK_TRANSLATE_NS_VADDR 4
/*******************************************************************************
* Secure Payload execution state information i.e. aarch32 or aarch64
******************************************************************************/
#define SP_AARCH32 MODE_RW_32
#define SP_AARCH64 MODE_RW_64
/*******************************************************************************
* 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 TLKD_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 TLKD_C_RT_CTX_X19 0x0
#define TLKD_C_RT_CTX_X20 0x8
#define TLKD_C_RT_CTX_X21 0x10
#define TLKD_C_RT_CTX_X22 0x18
#define TLKD_C_RT_CTX_X23 0x20
#define TLKD_C_RT_CTX_X24 0x28
#define TLKD_C_RT_CTX_X25 0x30
#define TLKD_C_RT_CTX_X26 0x38
#define TLKD_C_RT_CTX_X27 0x40
#define TLKD_C_RT_CTX_X28 0x48
#define TLKD_C_RT_CTX_X29 0x50
#define TLKD_C_RT_CTX_X30 0x58
#define TLKD_C_RT_CTX_SIZE 0x60
#define TLKD_C_RT_CTX_ENTRIES (TLKD_C_RT_CTX_SIZE >> DWORD_SHIFT)
#ifndef __ASSEMBLY__
#include <cassert.h>
#include <stdint.h>
/* AArch64 callee saved general purpose register context structure. */
DEFINE_REG_STRUCT(c_rt_regs, TLKD_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(TLKD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \
assert_tlkd_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
* 'saved_tsp_args' - space to store arguments for TSP arithmetic operations
* which will queried using the TSP_GET_ARGS SMC by TSP.
******************************************************************************/
typedef struct tlk_context {
uint32_t state;
uint64_t mpidr;
uint64_t c_rt_ctx;
cpu_context_t cpu_ctx;
} tlk_context_t;
/*******************************************************************************
* Function & Data prototypes
******************************************************************************/
uint64_t tlkd_va_translate(uintptr_t va, int type);
uint64_t tlkd_enter_sp(uint64_t *c_rt_ctx);
void __dead2 tlkd_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx);
void __dead2 tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx,
uint64_t ret);
void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point,
uint32_t rw,
uint64_t pc,
tlk_context_t *tlk_ctx);
#endif /*__ASSEMBLY__*/
#endif /* __TLKD_PRIVATE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment