From dc60f9bbe50b4211a264363ee575eb3acc5ad8f5 Mon Sep 17 00:00:00 2001 From: isiora Date: Wed, 7 Mar 2018 11:50:05 +0000 Subject: [PATCH] New TSSI interface. git-svn-id: https://svn.code.sf.net/p/chibios/svn2/trunk@11612 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- os/common/ports/ARMCAx-TZ/chtssi.c | 321 +++++++++++++++++++++++++++++ os/common/ports/ARMCAx-TZ/chtssi.h | 209 +++++++++++++++++++ 2 files changed, 530 insertions(+) create mode 100644 os/common/ports/ARMCAx-TZ/chtssi.c create mode 100644 os/common/ports/ARMCAx-TZ/chtssi.h diff --git a/os/common/ports/ARMCAx-TZ/chtssi.c b/os/common/ports/ARMCAx-TZ/chtssi.c new file mode 100644 index 000000000..1d0c2db79 --- /dev/null +++ b/os/common/ports/ARMCAx-TZ/chtssi.c @@ -0,0 +1,321 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file chtssi.c + * @brief Trusted services related API and definition. + * + * @addtogroup TSSI + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "chtssi.h" +#include + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +#define LOWORD(in64) ((int64_t)in64 & 0x0FFFFFFFF) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/* The reference to the suspended nsec main thread.*/ +thread_reference_t _ns_thread = NULL; + +/* The services may broadcast and listen event flags via this object.*/ +EVENTSOURCE_DECL(tsEventSource); + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/* The ts module listen to the tsEventSource via this object.*/ +static event_listener_t tsEventListener; + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +static bool isAddrSpaceValid(uint8_t *addr, size_t size) +{ + //chEvtBroadcastFlags(); + return (bool)((addr - NSEC_MEMORY_START_ADDR) < + (NSEC_MEMORY_END_ADDR - NSEC_MEMORY_START_ADDR)) && + (bool)((addr + size - NSEC_MEMORY_START_ADDR) < + (NSEC_MEMORY_END_ADDR - NSEC_MEMORY_START_ADDR)); +} + +static bool isHndlValid(ts_state_t *handle) +{ + if ((handle < TS_STATE(0)) || (handle >= TS_STATE(TS_MAX_SVCS))) + return FALSE; + if (((char *)handle - (char *)TS_STATE(0)) % sizeof *TS_STATE(0)) + return FALSE; + return TRUE; +} + +static ts_state_t *findSvcsEntry(const char *name) +{ + int i; + for (i = 0; i < TS_MAX_SVCS; ++i) { + if (TS_CONF_TABLE(i)->name == NULL) + continue; + if (!strcmp(TS_CONF_TABLE(i)->name, name)) + return TS_CONF_TABLE(i)->arg; + } + return NULL; +} + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief The trusted service call entry point. + * @pre The foreign interrupts are disabled. + * @post A request is passed to the thread registered for the service. + * @post The service thread is resumed. + * + * @param[in] svc_handle the handle of the service to be invoked. + * @param[inout] svc_data service request data, often a reference to a more + * complex structure. + * @param[in] svc_datalen size of the svc_data memory area. + * @param[in] svc_timeout after this time interval, the service execution + * will be interrupted. Time is in microseconds. + * This interval represents the time slice granted + * to the services to continue their work. + * + * @return A 64bit value. It is the OR of the 32bit service + * status combined with a 32bit event mask (in the + * hi-word). + * The retval values are returned in the lower word + * as 32bit int. + * @retval SMC_SVC_OK generic success value. + * @retval SMC_SVC_INTR call interrupted. + * @retval SMC_SVC_BUSY the service has a pending request. + * @retval SMC_SVC_INVALID bad parameters. + * @retval SMC_SVC_NOENT no such service. + * @retval SMC_SVC_BADH bad handle. + * + * @notapi + */ +int64_t smcEntry(ts_state_t *svc_handle, ts_params_area_t svc_data, + size_t svc_datalen, sysinterval_t svc_timeout) { + ts_state_t *tssp = NULL; + msg_t r; + + /* Internal query service.*/ + if (svc_handle == TS_HND_STQRY) { + ts_state_t *tsqryd; + + /* svc_data is the handle of the service to whom 'query' the state.*/ + tsqryd = (ts_state_t *)svc_data; + + /* handle argument validation.*/ + if (!isHndlValid(tsqryd)) + return LOWORD(SMC_SVC_BADH); + + /* if the service has done, return its last status.*/ + if (tsqryd->ts_thdp != NULL) { + r = tsqryd->ts_status; + return LOWORD(r); + } + } + else if (svc_handle != TS_HND_IDLE) { + if (!isAddrSpaceValid(svc_data, svc_datalen)) + return LOWORD(SMC_SVC_INVALID); + + /* Internal discovery service.*/ + if (svc_handle == TS_HND_DISCOVERY) { + if (svc_datalen) { + *((char *)svc_data + svc_datalen - 1) = '\0'; + tssp = findSvcsEntry((char *)svc_data); + } + if (tssp == NULL) + return LOWORD(SMC_SVC_NOENT); + return LOWORD((int32_t)tssp); + } else { + if (!isHndlValid(svc_handle)) + return LOWORD(SMC_SVC_BADH); + tssp = svc_handle; + } + if (tssp->ts_thdp == NULL) + return LOWORD(SMC_SVC_BUSY); + tssp->ts_datap = svc_data; + tssp->ts_datalen = svc_datalen; + } + +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) + _dbg_check_lock(); +#endif + + /* limit the max timeout interval.*/ + if (svc_timeout > TS_MAX_TMO) + svc_timeout = TS_MAX_TMO; + + if (tssp) + chThdResumeS(&tssp->ts_thdp, MSG_OK); + r = chThdSuspendTimeoutS(&_ns_thread, TIME_US2I(svc_timeout)); + + /* Get and clear any pending event flags.*/ + eventflags_t f = chEvtGetAndClearFlagsI(&tsEventListener); + +#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) + _dbg_check_unlock(); +#endif + return LOWORD(r) | ((int64_t)f << 32); +} + +/** + * @brief The calling thread is a service and wait the arrival of + * a request. + * @post The service object state is filled with the parameters of + * the requester. + * + * @param[in] svcp the service object reference. + * + * @return The wakeup message. + * @retval MSG_OK a new request has to be processed. + * + * @api + */ +msg_t tssiWaitRequest(ts_state_t *svcp) +{ + msg_t r; + + chDbgCheck(svcp != NULL); + + chSysLock(); + if (_ns_thread) { + /* Ack a previous service invocation. Not schedule.*/ + chThdResumeI(&_ns_thread, svcp->ts_status); + } + r = chThdSuspendS(&svcp->ts_thdp); + chSysUnlock(); + return r; +} + +/** + * @brief Initializes the trusted services and jumps in the NSEC world. + * + * @init + */ +CC_NO_RETURN void tssiInit(void) +{ + int32_t i; + uint32_t d; + uint32_t *tt; + + + /* + * The DDR memory is divided in 4 region, each 32MB large. + * The last region is split in two areas, each 16MB large. + * The first 3 region and the lower area of this last region is non secure. + * All the rest of the regions space is secured. + * + * Those settings depend on the designed memory mapping. + */ + mtxSetSlaveRegionSize(MATRIX0, H64MX_SLAVE_DDR_PORT0, MATRIX_AREA_SIZE_32M, REGION_0_MSK); + mtxSetSlaveRegionSize(MATRIX0, H64MX_SLAVE_DDR_PORT1, MATRIX_AREA_SIZE_32M, REGION_0_MSK); + + mtxSetSlaveSplitAddr(MATRIX0, H64MX_SLAVE_DDR_PORT0, MATRIX_AREA_SIZE_32M, + REGION_0_MSK | REGION_1_MSK | REGION_2_MSK); + mtxSetSlaveSplitAddr(MATRIX0, H64MX_SLAVE_DDR_PORT1, MATRIX_AREA_SIZE_32M, + REGION_0_MSK | REGION_1_MSK | REGION_2_MSK); + + mtxSetSlaveSplitAddr(MATRIX0, H64MX_SLAVE_DDR_PORT0, MATRIX_AREA_SIZE_16M, REGION_3_MSK); + mtxSetSlaveSplitAddr(MATRIX0, H64MX_SLAVE_DDR_PORT1, MATRIX_AREA_SIZE_16M, REGION_3_MSK); + + mtxConfigSlaveSec(MATRIX0, H64MX_SLAVE_DDR_PORT0, + mtxRegionLansech(REGION_0, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_1, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_2, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_3, UPPER_AREA_SECURABLE), + mtxRegionRdnsech(REGION_0, NOT_SECURE_READ) | + mtxRegionRdnsech(REGION_1, NOT_SECURE_READ) | + mtxRegionRdnsech(REGION_2, NOT_SECURE_READ), + mtxRegionWrnsech(REGION_0, NOT_SECURE_WRITE) | + mtxRegionWrnsech(REGION_1, NOT_SECURE_WRITE) | + mtxRegionWrnsech(REGION_2, NOT_SECURE_WRITE)); + + mtxConfigSlaveSec(MATRIX0, H64MX_SLAVE_DDR_PORT1, + mtxRegionLansech(REGION_0, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_1, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_2, UPPER_AREA_SECURABLE) | + mtxRegionLansech(REGION_3, UPPER_AREA_SECURABLE), + mtxRegionRdnsech(REGION_0, NOT_SECURE_READ) | + mtxRegionRdnsech(REGION_1, NOT_SECURE_READ) | + mtxRegionRdnsech(REGION_2, NOT_SECURE_READ), + mtxRegionWrnsech(REGION_0, NOT_SECURE_WRITE) | + mtxRegionWrnsech(REGION_1, NOT_SECURE_WRITE) | + mtxRegionWrnsech(REGION_2, NOT_SECURE_WRITE)); + + /* Mark the whole non secure memory region as non executable + by the secure code.*/ + tt = (uint32_t *)(__get_TTBR0() & 0xFFFFC000); + for (d = ((uint32_t)NSEC_MEMORY_START_ADDR >> 20); + d < ((uint32_t)NSEC_MEMORY_END_ADDR >> 20); d += 1) { + MMU_XNSection(tt + d, NON_EXECUTE); + } + + /* Make sure that prio is NORMALPRIO.*/ + chThdSetPriority(NORMALPRIO); + + /* Initialize the services.*/ + for (i = 0; i < TS_MAX_SVCS; ++i) { + if (TS_CONF_TABLE(i)->arg == NULL) + continue; + + /* Check that the initialization of the TS_TABLE against TS_STATE_TABLE + was set right.*/ + if (TS_CONF_TABLE(i)->arg != TS_STATE(i)) { + chSysHalt("Bad TS_STATE setting in the services configuration table."); + } + + /* Check that the service priority was set right.*/ + if ((TS_CONF_TABLE(i)->prio <= NORMALPRIO) || + (TS_CONF_TABLE(i)->prio >= HIGHPRIO)) { + chSysHalt("Bad prio setting in the services configuration table."); + } + + /* Create the service thread.*/ + chThdCreate(TS_CONF_TABLE(i)); + } + + /* Register to the daemon services events. All flags.*/ + chEvtRegister(&tsEventSource, &tsEventListener, EVT_DAEMON_REQ_ATN); + + /* Now set the priority to the max.*/ + chThdSetPriority(HIGHPRIO); + + /* Jump in the NON SECURE world. + * This thread becomes the non secure environment as view by + * the secure world.*/ + _ns_trampoline(NSEC_MEMORY_START_ADDR); + + /* It never goes here.*/ +} + +/** @} */ diff --git a/os/common/ports/ARMCAx-TZ/chtssi.h b/os/common/ports/ARMCAx-TZ/chtssi.h new file mode 100644 index 000000000..3fbb1497b --- /dev/null +++ b/os/common/ports/ARMCAx-TZ/chtssi.h @@ -0,0 +1,209 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio. + + This file is part of ChibiOS. + + ChibiOS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file chtssi.h + * @brief tssi module macros and structures. + * + * @addtogroup TSSI + * @{ + */ + +#ifndef CHTSSI_H +#define CHTSSI_H + +#include "ch.h" +#include "ccportab.h" + +/*===========================================================================*/ +/* Module constants. */ +/*===========================================================================*/ + +/* Service registry errors as returned by smc.*/ +#define SMC_SVC_OK MSG_OK /* No error.*/ +#define SMC_SVC_INTR (msg_t)-1 /* Service interrupted ( == MSG_TIMEOUT).*/ +#define SMC_SVC_NOENT (msg_t)-2 /* No existent service.*/ +#define SMC_SVC_INVALID (msg_t)-3 /* Invalid service parameter(s).*/ +#define SMC_SVC_BADH (msg_t)-4 /* Invalid service handle.*/ +#define SMC_SVC_EXIST (msg_t)-5 /* Service already exists.*/ +#define SMC_SVC_NHND (msg_t)-6 /* No more services.*/ +#define SMC_SVC_BUSY (msg_t)-7 /* Service busy.*/ + +/* Special trusted service handles.*/ +#define TS_HND_TRAMP ((ts_state_t *)0) /* Trampoline service handle.*/ +#define TS_HND_DISCOVERY ((ts_state_t *)1) /* Discovery service handle.*/ +#define TS_HND_STQRY ((ts_state_t *)2) /* Query status service handle.*/ +#define TS_HND_IDLE ((ts_state_t *)3) /* Idle service handle.*/ + +/* Service states.*/ +#define TS_STATE_READY 0 +#define TS_STATE_PROCESSING 1 +#define TS_STATE_DONE 2 + +/* Services events event mask.*/ +#define EVT_DAEMON_REQ_ATN EVENT_MASK(0) + +/* Service events flags.*/ +#define EVT_DRA_SOCK_PROXY 1 + +/*===========================================================================*/ +/* Module pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name TSSI module settings. + * @{ + */ + +/* + * @brief Max number of services. + */ +#define TS_MAX_SVCS 64 + +/* + * @brief Max smc call timeout, in microseconds. + */ +#define TS_MAX_TMO 10000 + +/* + * @brief Secure and non secure memory address spaces. + */ +#define NSEC_MEMORY_START_ADDR ((uint8_t *)0x20000000) +#define NSEC_MEMORY_END_ADDR ((uint8_t *)0x27000000) +#define SEC_MEMORY_START_ADDR ((uint8_t *)0x27000000) +#define SEC_MEMORY_END_ADDR ((size_t)0x1000000) + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module data structures and types. */ +/*===========================================================================*/ +typedef uint8_t * ts_params_area_t; + +typedef struct tssi_service_state { + uint32_t ts_status; + thread_reference_t ts_thdp; + ts_params_area_t ts_datap; + uint32_t ts_datalen; +} ts_state_t; + +/*===========================================================================*/ +/* Module macros. */ +/*===========================================================================*/ + +/** + * @name Services tables definition macros. + * @{ + */ + +/** + * @brief Table of the runtime state of the services. + */ +#define TS_STATE_TABLE \ + ts_state_t ts_state[TS_MAX_SVCS] = {0}; + +/** + * @brief Accessor to the runtime state of service i. + */ +#define TS_STATE(i) (&ts_state[i]) + +/** + * @brief Start of user service table. + */ +#define TS_CONF_TABLE_BEGIN \ + const thread_descriptor_t ts_configs[TS_MAX_SVCS] = { + +/** + * @brief Entry of user services table. + */ +#define TS_CONF_TABLE_ENTRY(name, wap, prio, funcp, tsstatep) \ + {name, wap, ((stkalign_t *)(wap)) + (sizeof (wap) / sizeof(stkalign_t)), \ + prio, funcp, tsstatep}, + +/** + * @brief End of user services table. + */ +#define TS_CONF_TABLE_END \ +}; + +/* + * @brief Accessor to the service table entry i. + */ +#define TS_CONF_TABLE(i) (&ts_configs[i]) + +/* + * @brief Trusted services base prio. + */ +#define TS_BASE_PRIO (NORMALPRIO+1) + +/* + * @brief Check if service is busy. + */ +#define TS_IS_BUSY(state) (state != TS_STATE_READY) + +/* + * @brief Set the service status. + * @note The service sets the status at a value representing the status + * of the completion of the request. This value is + * service dependent. + */ +#define TS_SET_STATUS(svcp, newst) (((ts_state_t *)svcp)->ts_status = newst) + +/* + * @brief Get the client shared memory start address. + * @note The client sets the data field at the start address + * of a shared memory allocated from the non secure memory space. + */ +#define TS_GET_DATA(svcp) ((char *)((ts_state_t *)svcp)->ts_datap) + +/* + * @brief Get the client shared memory size. + * @note The client sets the datalen field to the size + * of a shared memory allocated from the non secure memory space. + */ +#define TS_GET_DATALEN(svcp) (((ts_state_t *)svcp)->ts_datalen) + +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + extern event_source_t tsEventSource; + extern ts_state_t ts_state[]; + extern const thread_descriptor_t ts_configs[]; + extern thread_reference_t _ns_thread; + CC_NO_RETURN void _ns_trampoline(uint8_t *addr); + CC_NO_RETURN void tssiInit(void); + msg_t tssiWaitRequest(ts_state_t *svcp); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Module inline functions. */ +/*===========================================================================*/ + +#endif /* CHTSSI_H */