From 6b4770637593f79aa6cfd1f062c1e5d0b1d587bc Mon Sep 17 00:00:00 2001 From: Vikram Kanigiri Date: Thu, 28 Jan 2016 17:22:16 +0000 Subject: Refactor the ARM CoreLink TZC-400 driver TrustZone protection can be programmed by both memory and TrustZone address space controllers like DMC-500 and TZC-400. These peripherals share a similar programmer's view. Furthermore, it is possible to have multiple instances of each type of peripheral in a system resulting in multiple programmer's views. For example, on the TZC-400 each of the 4 filter units can be enabled or disabled for each region. There is a single set of registers to program the region attributes. On the DMC-500, each filter unit has its own programmer's view resulting in multiple sets of registers to program the region attributes. The layout of the registers is almost the same across all these variations. Hence the existing driver in `tzc400\tzc400.c` is refactored into the new driver in `tzc\tzc400.c`. The previous driver file is still maintained for compatibility and it is now deprecated. Change-Id: Ieabd0528e244582875bc7e65029a00517671216d --- drivers/arm/tzc/tzc400.c | 259 ++++++++++++++++++++++++++++ drivers/arm/tzc/tzc_common_private.c | 202 ++++++++++++++++++++++ drivers/arm/tzc400/tzc400.c | 317 +---------------------------------- include/drivers/arm/tzc400.h | 285 +++++++++++++++---------------- include/drivers/arm/tzc_common.h | 119 +++++++++++++ 5 files changed, 729 insertions(+), 453 deletions(-) create mode 100644 drivers/arm/tzc/tzc400.c create mode 100644 drivers/arm/tzc/tzc_common_private.c create mode 100644 include/drivers/arm/tzc_common.h diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c new file mode 100644 index 00000000..ee6bf8db --- /dev/null +++ b/drivers/arm/tzc/tzc400.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016, 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 "tzc_common_private.c" + +/* + * Macros which will be used by common core functions. + */ +#define TZC_400_REGION_BASE_LOW_0_OFFSET 0x100 +#define TZC_400_REGION_BASE_HIGH_0_OFFSET 0x104 +#define TZC_400_REGION_TOP_LOW_0_OFFSET 0x108 +#define TZC_400_REGION_TOP_HIGH_0_OFFSET 0x10c +#define TZC_400_REGION_ATTR_0_OFFSET 0x110 +#define TZC_400_REGION_ID_ACCESS_0_OFFSET 0x114 + +/* + * Implementation defined values used to validate inputs later. + * Filters : max of 4 ; 0 to 3 + * Regions : max of 9 ; 0 to 8 + * Address width : Values between 32 to 64 + */ +typedef struct tzc400_instance { + uintptr_t base; + uint8_t addr_width; + uint8_t num_filters; + uint8_t num_regions; +} tzc400_instance_t; + +tzc400_instance_t tzc400; + +static inline unsigned int _tzc400_read_build_config(uintptr_t base) +{ + return mmio_read_32(base + BUILD_CONFIG_OFF); +} + +static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base) +{ + return mmio_read_32(base + GATE_KEEPER_OFF); +} + +static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GATE_KEEPER_OFF, val); +} + +/* + * Get the open status information for all filter units. + */ +#define get_gate_keeper_os(base) ((_tzc400_read_gate_keeper(base) >> \ + GATE_KEEPER_OS_SHIFT) & \ + GATE_KEEPER_OS_MASK) + + +/* Define common core functions used across different TZC peripherals. */ +DEFINE_TZC_COMMON_WRITE_ACTION(400, 400) +DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400) +DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400) +DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400) +DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400) +DEFINE_TZC_COMMON_CONFIGURE_REGION0(400) +DEFINE_TZC_COMMON_CONFIGURE_REGION(400) + +static unsigned int _tzc400_get_gate_keeper(uintptr_t base, + unsigned int filter) +{ + unsigned int open_status; + + open_status = get_gate_keeper_os(base); + + return (open_status >> filter) & GATE_KEEPER_FILTER_MASK; +} + +/* This function is not MP safe. */ +static void _tzc400_set_gate_keeper(uintptr_t base, + unsigned int filter, + int val) +{ + unsigned int open_status; + + /* Upper half is current state. Lower half is requested state. */ + open_status = get_gate_keeper_os(base); + + if (val) + open_status |= (1 << filter); + else + open_status &= ~(1 << filter); + + _tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) << + GATE_KEEPER_OR_SHIFT); + + /* Wait here until we see the change reflected in the TZC status. */ + while ((get_gate_keeper_os(base)) != open_status) + ; +} + +void tzc400_set_action(tzc_action_t action) +{ + assert(tzc400.base); + assert(action <= TZC_ACTION_ERR_INT); + + /* + * - Currently no handler is provided to trap an error via interrupt + * or exception. + * - The interrupt action has not been tested. + */ + _tzc400_write_action(tzc400.base, action); +} + +void tzc400_init(uintptr_t base) +{ +#if DEBUG + unsigned int tzc400_id; +#endif + unsigned int tzc400_build; + + assert(base); + tzc400.base = base; + +#if DEBUG + tzc400_id = _tzc_read_peripheral_id(base); + if (tzc400_id != TZC_400_PERIPHERAL_ID) { + ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id); + panic(); + } +#endif + + /* Save values we will use later. */ + tzc400_build = _tzc400_read_build_config(tzc400.base); + tzc400.num_filters = ((tzc400_build >> BUILD_CONFIG_NF_SHIFT) & + BUILD_CONFIG_NF_MASK) + 1; + tzc400.addr_width = ((tzc400_build >> BUILD_CONFIG_AW_SHIFT) & + BUILD_CONFIG_AW_MASK) + 1; + tzc400.num_regions = ((tzc400_build >> BUILD_CONFIG_NR_SHIFT) & + BUILD_CONFIG_NR_MASK) + 1; +} + +/* + * `tzc400_configure_region0` is used to program region 0 into the TrustZone + * controller. Region 0 covers the whole address space that is not mapped + * to any other region, and is enabled on all filters; this cannot be + * changed. This function only changes the access permissions. + */ +void tzc400_configure_region0(tzc_region_attributes_t sec_attr, + unsigned int ns_device_access) +{ + assert(tzc400.base); + assert(sec_attr <= TZC_REGION_S_RDWR); + + _tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access); +} + +/* + * `tzc400_configure_region` is used to program regions into the TrustZone + * controller. A region can be associated with more than one filter. The + * associated filters are passed in as a bitmap (bit0 = filter0). + * NOTE: + * Region 0 is special; it is preferable to use tzc400_configure_region0 + * for this region (see comment for that function). + */ +void tzc400_configure_region(unsigned int filters, + int region, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int nsaid_permissions) +{ + assert(tzc400.base); + + /* Do range checks on filters and regions. */ + assert(((filters >> tzc400.num_filters) == 0) && + (region >= 0) && (region < tzc400.num_regions)); + + /* + * Do address range check based on TZC configuration. A 64bit address is + * the max and expected case. + */ + assert(((region_top <= (UINT64_MAX >> (64 - tzc400.addr_width))) && + (region_base < region_top))); + + /* region_base and (region_top + 1) must be 4KB aligned */ + assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0); + + assert(sec_attr <= TZC_REGION_S_RDWR); + + _tzc400_configure_region(tzc400.base, filters, region, region_base, + region_top, + sec_attr, nsaid_permissions); +} + +void tzc400_enable_filters(void) +{ + unsigned int state; + unsigned int filter; + + assert(tzc400.base); + + for (filter = 0; filter < tzc400.num_filters; filter++) { + state = _tzc400_get_gate_keeper(tzc400.base, filter); + if (state) { + /* The TZC filter is already configured. Changing the + * programmer's view in an active system can cause + * unpredictable behavior therefore panic for now rather + * than try to determine whether this is safe in this + * instance. See: + * http://infocenter.arm.com/help/index.jsp?\ + * topic=/com.arm.doc.ddi0504c/CJHHECBF.html */ + ERROR("TZC-400 : Filter %d Gatekeeper already" + " enabled.\n", filter); + panic(); + } + _tzc400_set_gate_keeper(tzc400.base, filter, 1); + } +} + +void tzc400_disable_filters(void) +{ + unsigned int filter; + + assert(tzc400.base); + + /* + * We don't do the same state check as above as the Gatekeepers are + * disabled after reset. + */ + for (filter = 0; filter < tzc400.num_filters; filter++) + _tzc400_set_gate_keeper(tzc400.base, filter, 0); +} diff --git a/drivers/arm/tzc/tzc_common_private.c b/drivers/arm/tzc/tzc_common_private.c new file mode 100644 index 00000000..f570daf3 --- /dev/null +++ b/drivers/arm/tzc/tzc_common_private.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, 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 + +#define DEFINE_TZC_COMMON_WRITE_ACTION(fn_name, macro_name) \ + static inline void _tzc##fn_name##_write_action( \ + uintptr_t base, \ + tzc_action_t action) \ + { \ + mmio_write_32(base + TZC_##macro_name##_ACTION_OFF, \ + action); \ + } + +#define DEFINE_TZC_COMMON_WRITE_REGION_BASE(fn_name, macro_name) \ + static inline void _tzc##fn_name##_write_region_base( \ + uintptr_t base, \ + int region_no, \ + uintptr_t region_base) \ + { \ + mmio_write_32(base + \ + TZC_REGION_OFFSET( \ + TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_BASE_LOW_0_OFFSET, \ + (unsigned int)region_base); \ + mmio_write_32(base + \ + TZC_REGION_OFFSET( \ + TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_BASE_HIGH_0_OFFSET, \ + (unsigned int)(region_base >> 32)); \ + } + +#define DEFINE_TZC_COMMON_WRITE_REGION_TOP(fn_name, macro_name) \ + static inline void _tzc##fn_name##_write_region_top( \ + uintptr_t base, \ + int region_no, \ + uintptr_t region_top) \ + { \ + mmio_write_32(base + \ + TZC_REGION_OFFSET \ + (TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_TOP_LOW_0_OFFSET, \ + (unsigned int)region_top); \ + mmio_write_32(base + \ + TZC_REGION_OFFSET( \ + TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_TOP_HIGH_0_OFFSET, \ + (unsigned int)(region_top >> 32)); \ + } + +#define DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(fn_name, macro_name) \ + static inline void _tzc##fn_name##_write_region_attributes( \ + uintptr_t base, \ + int region_no, \ + unsigned int attr) \ + { \ + mmio_write_32(base + \ + TZC_REGION_OFFSET( \ + TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_ATTR_0_OFFSET, \ + attr); \ + } + +#define DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(fn_name, macro_name) \ + static inline void _tzc##fn_name##_write_region_id_access( \ + uintptr_t base, \ + int region_no, \ + unsigned int val) \ + { \ + mmio_write_32(base + \ + TZC_REGION_OFFSET( \ + TZC_##macro_name##_REGION_SIZE, \ + region_no) + \ + TZC_##macro_name##_REGION_ID_ACCESS_0_OFFSET, \ + val); \ + } + +/* + * It is used to program region 0 ATTRIBUTES and ACCESS register. + */ +#define DEFINE_TZC_COMMON_CONFIGURE_REGION0(fn_name) \ + void _tzc##fn_name##_configure_region0(uintptr_t base, \ + tzc_region_attributes_t sec_attr, \ + unsigned int ns_device_access) \ + { \ + assert(base); \ + VERBOSE("TrustZone : Configuring region 0 " \ + "(TZC Interface Base=%p sec_attr=0x%x," \ + " ns_devs=0x%x)\n", (void *)base, \ + sec_attr, ns_device_access); \ + \ + /* Set secure attributes on region 0 */ \ + _tzc##fn_name##_write_region_attributes(base, 0, \ + sec_attr << TZC_REGION_ATTR_SEC_SHIFT); \ + \ + /***************************************************/ \ + /* Specify which non-secure devices have permission*/ \ + /* to access region 0. */ \ + /***************************************************/ \ + _tzc##fn_name##_write_region_id_access(base, \ + 0, \ + ns_device_access); \ + } + +/* + * It is used to program a region from 1 to 8 in the TrustZone controller. + * NOTE: + * Region 0 is special; it is preferable to use + * ##fn_name##_configure_region0 for this region (see comment for + * that function). + */ +#define DEFINE_TZC_COMMON_CONFIGURE_REGION(fn_name) \ + void _tzc##fn_name##_configure_region(uintptr_t base, \ + unsigned int filters, \ + int region_no, \ + uintptr_t region_base, \ + uintptr_t region_top, \ + tzc_region_attributes_t sec_attr, \ + unsigned int nsaid_permissions) \ + { \ + assert(base); \ + VERBOSE("TrustZone : Configuring region " \ + "(TZC Interface Base: %p, region_no = %d)" \ + "...\n", (void *)base, region_no); \ + VERBOSE("TrustZone : ... base = %p, top = %p," \ + "\n", (void *)region_base, (void *)region_top);\ + VERBOSE("TrustZone : ... sec_attr = 0x%x," \ + " ns_devs = 0x%x)\n", \ + sec_attr, nsaid_permissions); \ + \ + /***************************************************/ \ + /* Inputs look ok, start programming registers. */ \ + /* All the address registers are 32 bits wide and */ \ + /* have a LOW and HIGH */ \ + /* component used to construct an address up to a */ \ + /* 64bit. */ \ + /***************************************************/ \ + _tzc##fn_name##_write_region_base(base, \ + region_no, region_base); \ + _tzc##fn_name##_write_region_top(base, \ + region_no, region_top); \ + \ + /* Enable filter to the region and set secure attributes */\ + _tzc##fn_name##_write_region_attributes(base, \ + region_no, \ + (sec_attr << TZC_REGION_ATTR_SEC_SHIFT) |\ + (filters << TZC_REGION_ATTR_F_EN_SHIFT));\ + \ + /***************************************************/ \ + /* Specify which non-secure devices have permission*/ \ + /* to access this region. */ \ + /***************************************************/ \ + _tzc##fn_name##_write_region_id_access(base, \ + region_no, \ + nsaid_permissions); \ + } + +#if DEBUG +static unsigned int _tzc_read_peripheral_id(uintptr_t base) +{ + unsigned int id; + + id = mmio_read_32(base + PID0_OFF); + /* Masks DESC part in PID1 */ + id |= ((mmio_read_32(base + PID1_OFF) & 0xF) << 8); + + return id; +} +#endif diff --git a/drivers/arm/tzc400/tzc400.c b/drivers/arm/tzc400/tzc400.c index 7194443e..97adf81f 100644 --- a/drivers/arm/tzc400/tzc400.c +++ b/drivers/arm/tzc400/tzc400.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2016, 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: @@ -28,313 +28,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include - -/* - * Implementation defined values used to validate inputs later. - * Filters : max of 4 ; 0 to 3 - * Regions : max of 9 ; 0 to 8 - * Address width : Values between 32 to 64 - */ -typedef struct tzc_instance { - uintptr_t base; - uint8_t addr_width; - uint8_t num_filters; - uint8_t num_regions; -} tzc_instance_t; - -tzc_instance_t tzc; - - -static inline uint32_t tzc_read_build_config(uintptr_t base) -{ - return mmio_read_32(base + BUILD_CONFIG_OFF); -} - -static inline uint32_t tzc_read_gate_keeper(uintptr_t base) -{ - return mmio_read_32(base + GATE_KEEPER_OFF); -} - -static inline void tzc_write_gate_keeper(uintptr_t base, uint32_t val) -{ - mmio_write_32(base + GATE_KEEPER_OFF, val); -} - -static inline void tzc_write_action(uintptr_t base, tzc_action_t action) -{ - mmio_write_32(base + ACTION_OFF, action); -} - -static inline void tzc_write_region_base_low(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_BASE_LOW_OFF + - REGION_NUM_OFF(region), val); -} - -static inline void tzc_write_region_base_high(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_BASE_HIGH_OFF + - REGION_NUM_OFF(region), val); -} - -static inline void tzc_write_region_top_low(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_TOP_LOW_OFF + - REGION_NUM_OFF(region), val); -} - -static inline void tzc_write_region_top_high(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_TOP_HIGH_OFF + - REGION_NUM_OFF(region), val); -} - -static inline void tzc_write_region_attributes(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_ATTRIBUTES_OFF + - REGION_NUM_OFF(region), val); -} - -static inline void tzc_write_region_id_access(uintptr_t base, - uint32_t region, - uint32_t val) -{ - mmio_write_32(base + REGION_ID_ACCESS_OFF + - REGION_NUM_OFF(region), val); -} - -static unsigned int tzc_read_peripheral_id(uintptr_t base) -{ - unsigned int id; - - id = mmio_read_8(base + PID0_OFF); - /* Masks jep106_id_3_0 part in PID1 */ - id |= ((mmio_read_8(base + PID1_OFF) & 0xF) << 8); - - return id; -} - -static uint32_t tzc_get_gate_keeper(uintptr_t base, uint8_t filter) -{ - uint32_t tmp; - - tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & - GATE_KEEPER_OS_MASK; - - return (tmp >> filter) & GATE_KEEPER_FILTER_MASK; -} - -/* This function is not MP safe. */ -static void tzc_set_gate_keeper(uintptr_t base, uint8_t filter, uint32_t val) -{ - uint32_t tmp; - - /* Upper half is current state. Lower half is requested state. */ - tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & - GATE_KEEPER_OS_MASK; - - if (val) - tmp |= (1 << filter); - else - tmp &= ~(1 << filter); - - tzc_write_gate_keeper(base, (tmp & GATE_KEEPER_OR_MASK) << - GATE_KEEPER_OR_SHIFT); - - /* Wait here until we see the change reflected in the TZC status. */ - while (((tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & - GATE_KEEPER_OS_MASK) != tmp) - ; -} - - -void tzc_init(uintptr_t base) -{ - unsigned int tzc_id; - unsigned int tzc_build; - - assert(base); - - tzc.base = base; - - /* - * We expect to see a tzc400. Check peripheral ID. - */ - tzc_id = tzc_read_peripheral_id(tzc.base); - if (tzc_id != TZC400_PERIPHERAL_ID) { - ERROR("TZC : Wrong device ID (0x%x).\n", tzc_id); - panic(); - } - - /* Save values we will use later. */ - tzc_build = tzc_read_build_config(tzc.base); - tzc.num_filters = ((tzc_build >> BUILD_CONFIG_NF_SHIFT) & - BUILD_CONFIG_NF_MASK) + 1; - tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & - BUILD_CONFIG_AW_MASK) + 1; - tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & - BUILD_CONFIG_NR_MASK) + 1; -} - -/* - * `tzc_configure_region0` is used to program region 0 into the TrustZone - * controller. Region 0 covers the whole address space that is not mapped - * to any other region, and is enabled on all filters; this cannot be - * changed. This function only changes the access permissions. - */ -void tzc_configure_region0(tzc_region_attributes_t sec_attr, - uint32_t ns_device_access) -{ - assert(tzc.base); - - VERBOSE("TZC : Configuring region 0 (sec_attr=0x%x, ns_devs=0x%x)\n", - sec_attr, ns_device_access); - - assert(sec_attr <= TZC_REGION_S_RDWR); - - /* Set secure attributes on region 0 */ - tzc_write_region_attributes(tzc.base, 0, - sec_attr << REG_ATTR_SEC_SHIFT); - - /* - * Specify which non-secure devices have permission to access - * region 0. - */ - tzc_write_region_id_access(tzc.base, 0, ns_device_access); -} - - -/* - * `tzc_configure_region` is used to program regions into the TrustZone - * controller. A region can be associated with more than one filter. The - * associated filters are passed in as a bitmap (bit0 = filter0). - * NOTE: - * Region 0 is special; it is preferable to use tzc_configure_region0 - * for this region (see comment for that function). - */ -void tzc_configure_region(uint32_t filters, - uint8_t region, - uint64_t region_base, - uint64_t region_top, - tzc_region_attributes_t sec_attr, - uint32_t ns_device_access) -{ - assert(tzc.base); - - VERBOSE("TZC : Configuring region (filters=0x%x, region=%d, ...\n", - filters, region); - VERBOSE("TZC : ... base=0x%lx, top=0x%lx, ...\n", - region_base, region_top); - VERBOSE("TZC : ... sec_attr=0x%x, ns_devs=0x%x)\n", - sec_attr, ns_device_access); - - /* Do range checks on filters and regions. */ - assert(((filters >> tzc.num_filters) == 0) && - (region < tzc.num_regions)); - - /* - * Do address range check based on TZC configuration. A 64bit address is - * the max and expected case. - */ - assert(((region_top <= (UINT64_MAX >> (64 - tzc.addr_width))) && - (region_base < region_top))); - - /* region_base and (region_top + 1) must be 4KB aligned */ - assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0); - - assert(sec_attr <= TZC_REGION_S_RDWR); - - /* - * Inputs look ok, start programming registers. - * All the address registers are 32 bits wide and have a LOW and HIGH - * component used to construct a up to a 64bit address. - */ - tzc_write_region_base_low(tzc.base, region, - (uint32_t)(region_base)); - tzc_write_region_base_high(tzc.base, region, - (uint32_t)(region_base >> 32)); - - tzc_write_region_top_low(tzc.base, region, - (uint32_t)(region_top)); - tzc_write_region_top_high(tzc.base, region, - (uint32_t)(region_top >> 32)); - - /* Assign the region to a filter and set secure attributes */ - tzc_write_region_attributes(tzc.base, region, - (sec_attr << REG_ATTR_SEC_SHIFT) | filters); - - /* - * Specify which non-secure devices have permission to access this - * region. - */ - tzc_write_region_id_access(tzc.base, region, ns_device_access); -} - - -void tzc_set_action(tzc_action_t action) -{ - assert(tzc.base); - - /* - * - Currently no handler is provided to trap an error via interrupt - * or exception. - * - The interrupt action has not been tested. - */ - tzc_write_action(tzc.base, action); -} - - -void tzc_enable_filters(void) -{ - uint32_t state; - uint32_t filter; - - assert(tzc.base); - - for (filter = 0; filter < tzc.num_filters; filter++) { - state = tzc_get_gate_keeper(tzc.base, filter); - if (state) { - /* The TZC filter is already configured. Changing the - * programmer's view in an active system can cause - * unpredictable behavior therefore panic for now rather - * than try to determine whether this is safe in this - * instance. See: - * http://infocenter.arm.com/help/index.jsp?\ - * topic=/com.arm.doc.ddi0504c/CJHHECBF.html */ - ERROR("TZC : Filter %d Gatekeeper already enabled.\n", - filter); - panic(); - } - tzc_set_gate_keeper(tzc.base, filter, 1); - } -} - - -void tzc_disable_filters(void) -{ - uint32_t filter; - - assert(tzc.base); - - /* - * We don't do the same state check as above as the Gatekeepers are - * disabled after reset. - */ - for (filter = 0; filter < tzc.num_filters; filter++) - tzc_set_gate_keeper(tzc.base, filter, 0); -} +#if ERROR_DEPRECATED +#error "Using deprecated TZC-400 source file" +#else +#include "../tzc/tzc400.c" +#endif /* ERROR_DEPRECATED */ diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h index f8e1664e..30856889 100644 --- a/include/drivers/arm/tzc400.h +++ b/include/drivers/arm/tzc400.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2016, 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: @@ -31,178 +31,179 @@ #ifndef __TZC400_H__ #define __TZC400_H__ +#include -#define BUILD_CONFIG_OFF 0x000 -#define ACTION_OFF 0x004 -#define GATE_KEEPER_OFF 0x008 -#define SPECULATION_CTRL_OFF 0x00c -#define INT_STATUS 0x010 -#define INT_CLEAR 0x014 - -#define FAIL_ADDRESS_LOW_OFF 0x020 -#define FAIL_ADDRESS_HIGH_OFF 0x024 -#define FAIL_CONTROL_OFF 0x028 -#define FAIL_ID 0x02c - -#define REGION_BASE_LOW_OFF 0x100 -#define REGION_BASE_HIGH_OFF 0x104 -#define REGION_TOP_LOW_OFF 0x108 -#define REGION_TOP_HIGH_OFF 0x10c -#define REGION_ATTRIBUTES_OFF 0x110 -#define REGION_ID_ACCESS_OFF 0x114 -#define REGION_NUM_OFF(region) (0x20 * region) - -/* ID Registers */ -#define PID0_OFF 0xfe0 -#define PID1_OFF 0xfe4 -#define PID2_OFF 0xfe8 -#define PID3_OFF 0xfec -#define PID4_OFF 0xfd0 -#define PID5_OFF 0xfd4 -#define PID6_OFF 0xfd8 -#define PID7_OFF 0xfdc -#define CID0_OFF 0xff0 -#define CID1_OFF 0xff4 -#define CID2_OFF 0xff8 -#define CID3_OFF 0xffc - -#define BUILD_CONFIG_NF_SHIFT 24 -#define BUILD_CONFIG_NF_MASK 0x3 -#define BUILD_CONFIG_AW_SHIFT 8 -#define BUILD_CONFIG_AW_MASK 0x3f -#define BUILD_CONFIG_NR_SHIFT 0 -#define BUILD_CONFIG_NR_MASK 0x1f - -/* Not describing the case where regions 1 to 8 overlap */ -#define ACTION_RV_SHIFT 0 -#define ACTION_RV_MASK 0x3 -#define ACTION_RV_LOWOK 0x0 -#define ACTION_RV_LOWERR 0x1 -#define ACTION_RV_HIGHOK 0x2 -#define ACTION_RV_HIGHERR 0x3 +#define BUILD_CONFIG_OFF 0x000 +#define GATE_KEEPER_OFF 0x008 +#define SPECULATION_CTRL_OFF 0x00c +#define INT_STATUS 0x010 +#define INT_CLEAR 0x014 + +#define FAIL_ADDRESS_LOW_OFF 0x020 +#define FAIL_ADDRESS_HIGH_OFF 0x024 +#define FAIL_CONTROL_OFF 0x028 +#define FAIL_ID 0x02c + +/* ID registers not common across different varieties of TZC */ +#define PID5 0xFD4 +#define PID6 0xFD8 +#define PID7 0xFDC + +#define BUILD_CONFIG_NF_SHIFT 24 +#define BUILD_CONFIG_NF_MASK 0x3 +#define BUILD_CONFIG_AW_SHIFT 8 +#define BUILD_CONFIG_AW_MASK 0x3f +#define BUILD_CONFIG_NR_SHIFT 0 +#define BUILD_CONFIG_NR_MASK 0x1f /* * Number of gate keepers is implementation defined. But we know the max for * this device is 4. Get implementation details from BUILD_CONFIG. */ -#define GATE_KEEPER_OS_SHIFT 16 -#define GATE_KEEPER_OS_MASK 0xf -#define GATE_KEEPER_OR_SHIFT 0 -#define GATE_KEEPER_OR_MASK 0xf -#define GATE_KEEPER_FILTER_MASK 0x1 +#define GATE_KEEPER_OS_SHIFT 16 +#define GATE_KEEPER_OS_MASK 0xf +#define GATE_KEEPER_OR_SHIFT 0 +#define GATE_KEEPER_OR_MASK 0xf +#define GATE_KEEPER_FILTER_MASK 0x1 /* Speculation is enabled by default. */ -#define SPECULATION_CTRL_WRITE_DISABLE (1 << 1) -#define SPECULATION_CTRL_READ_DISABLE (1 << 0) +#define SPECULATION_CTRL_WRITE_DISABLE (1 << 1) +#define SPECULATION_CTRL_READ_DISABLE (1 << 0) /* Max number of filters allowed is 4. */ -#define INT_STATUS_OVERLAP_SHIFT 16 -#define INT_STATUS_OVERLAP_MASK 0xf -#define INT_STATUS_OVERRUN_SHIFT 8 -#define INT_STATUS_OVERRUN_MASK 0xf -#define INT_STATUS_STATUS_SHIFT 0 -#define INT_STATUS_STATUS_MASK 0xf - -#define INT_CLEAR_CLEAR_SHIFT 0 -#define INT_CLEAR_CLEAR_MASK 0xf - -#define FAIL_CONTROL_DIR_SHIFT (1 << 24) -#define FAIL_CONTROL_DIR_READ 0x0 -#define FAIL_CONTROL_DIR_WRITE 0x1 -#define FAIL_CONTROL_NS_SHIFT (1 << 21) -#define FAIL_CONTROL_NS_SECURE 0x0 -#define FAIL_CONTROL_NS_NONSECURE 0x1 -#define FAIL_CONTROL_PRIV_SHIFT (1 << 20) -#define FAIL_CONTROL_PRIV_PRIV 0x0 -#define FAIL_CONTROL_PRIV_UNPRIV 0x1 +#define INT_STATUS_OVERLAP_SHIFT 16 +#define INT_STATUS_OVERLAP_MASK 0xf +#define INT_STATUS_OVERRUN_SHIFT 8 +#define INT_STATUS_OVERRUN_MASK 0xf +#define INT_STATUS_STATUS_SHIFT 0 +#define INT_STATUS_STATUS_MASK 0xf + +#define INT_CLEAR_CLEAR_SHIFT 0 +#define INT_CLEAR_CLEAR_MASK 0xf + +#define FAIL_CONTROL_DIR_SHIFT (1 << 24) +#define FAIL_CONTROL_DIR_READ 0x0 +#define FAIL_CONTROL_DIR_WRITE 0x1 +#define FAIL_CONTROL_NS_SHIFT (1 << 21) +#define FAIL_CONTROL_NS_SECURE 0x0 +#define FAIL_CONTROL_NS_NONSECURE 0x1 +#define FAIL_CONTROL_PRIV_SHIFT (1 << 20) +#define FAIL_CONTROL_PRIV_PRIV 0x0 +#define FAIL_CONTROL_PRIV_UNPRIV 0x1 /* * FAIL_ID_ID_MASK depends on AID_WIDTH which is platform specific. * Platform should provide the value on initialisation. */ -#define FAIL_ID_VNET_SHIFT 24 -#define FAIL_ID_VNET_MASK 0xf -#define FAIL_ID_ID_SHIFT 0 - -/* Used along with 'tzc_region_attributes_t' below */ -#define REG_ATTR_SEC_SHIFT 30 -#define REG_ATTR_F_EN_SHIFT 0 -#define REG_ATTR_F_EN_MASK 0xf -#define REG_ATTR_FILTER_BIT(x) ((1 << x) << REG_ATTR_F_EN_SHIFT) -#define REG_ATTR_FILTER_BIT_ALL (REG_ATTR_F_EN_MASK << \ - REG_ATTR_F_EN_SHIFT) +#define FAIL_ID_VNET_SHIFT 24 +#define FAIL_ID_VNET_MASK 0xf +#define FAIL_ID_ID_SHIFT 0 -#define REGION_ID_ACCESS_NSAID_WR_EN_SHIFT 16 -#define REGION_ID_ACCESS_NSAID_RD_EN_SHIFT 0 -#define REGION_ID_ACCESS_NSAID_ID_MASK 0xf +#define TZC_400_PERIPHERAL_ID 0x460 +/* Filter enable bits in a TZC */ +#define TZC_400_REGION_ATTR_F_EN_MASK 0xf +#define TZC_400_REGION_ATTR_FILTER_BIT(x) ((1 << x) \ + << TZC_REGION_ATTR_F_EN_SHIFT) +#define TZC_400_REGION_ATTR_FILTER_BIT_ALL \ + (TZC_400_REGION_ATTR_F_EN_MASK << \ + TZC_REGION_ATTR_F_EN_SHIFT) -/* Macros for setting Region ID access permissions based on NSAID */ -#define TZC_REGION_ACCESS_RD(id) \ - ((1 << (id & REGION_ID_ACCESS_NSAID_ID_MASK)) << \ - REGION_ID_ACCESS_NSAID_RD_EN_SHIFT) -#define TZC_REGION_ACCESS_WR(id) \ - ((1 << (id & REGION_ID_ACCESS_NSAID_ID_MASK)) << \ - REGION_ID_ACCESS_NSAID_WR_EN_SHIFT) -#define TZC_REGION_ACCESS_RDWR(id) \ - (TZC_REGION_ACCESS_RD(id) | TZC_REGION_ACCESS_WR(id)) - -/* Consist of part_number_1 and part_number_0 */ -#define TZC400_PERIPHERAL_ID 0x0460 - +/* + * Define some macros for backward compatibility with existing tzc400 clients. + */ +#if !ERROR_DEPRECATED +#define REG_ATTR_FILTER_BIT(x) ((1 << x) \ + << TZC_REGION_ATTR_F_EN_SHIFT) +#define REG_ATTR_FILTER_BIT_ALL (TZC_400_REGION_ATTR_F_EN_MASK << \ + TZC_REGION_ATTR_F_EN_SHIFT) +#endif /* __ERROR_DEPRECATED__ */ +/* + * All TZC region configuration registers are placed one after another. It + * depicts size of block of registers for programming each region. + */ +#define TZC_400_REGION_SIZE 0x20 +#define TZC_400_ACTION_OFF 0x4 #ifndef __ASSEMBLY__ +#include #include /******************************************************************************* * Function & variable prototypes ******************************************************************************/ +void tzc400_init(uintptr_t base); +void tzc400_configure_region0(tzc_region_attributes_t sec_attr, + unsigned int ns_device_access); +void tzc400_configure_region(unsigned int filters, + int region, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int ns_device_access); +void tzc400_set_action(tzc_action_t action); +void tzc400_enable_filters(void); +void tzc400_disable_filters(void); /* - * What type of action is expected when an access violation occurs. - * The memory requested is zeroed. But we can also raise and event to - * let the system know it happened. - * We can raise an interrupt(INT) and/or cause an exception(ERR). - * TZC_ACTION_NONE - No interrupt, no Exception - * TZC_ACTION_ERR - No interrupt, raise exception -> sync external - * data abort - * TZC_ACTION_INT - Raise interrupt, no exception - * TZC_ACTION_ERR_INT - Raise interrupt, raise exception -> sync - * external data abort + * Deprecated APIs */ -typedef enum { - TZC_ACTION_NONE = 0, - TZC_ACTION_ERR = 1, - TZC_ACTION_INT = 2, - TZC_ACTION_ERR_INT = (TZC_ACTION_ERR | TZC_ACTION_INT) -} tzc_action_t; - -/* - * Controls secure access to a region. If not enabled secure access is not - * allowed to region. - */ -typedef enum { - TZC_REGION_S_NONE = 0, - TZC_REGION_S_RD = 1, - TZC_REGION_S_WR = 2, - TZC_REGION_S_RDWR = (TZC_REGION_S_RD | TZC_REGION_S_WR) -} tzc_region_attributes_t; - - -void tzc_init(uintptr_t base); -void tzc_configure_region0(tzc_region_attributes_t sec_attr, - uint32_t ns_device_access); -void tzc_configure_region(uint32_t filters, - uint8_t region, - uint64_t region_base, - uint64_t region_top, +static inline void tzc_init(uintptr_t base) __deprecated; +static inline void tzc_configure_region0( + tzc_region_attributes_t sec_attr, + unsigned int ns_device_access) __deprecated; +static inline void tzc_configure_region( + unsigned int filters, + int region, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int ns_device_access) __deprecated; +static inline void tzc_set_action(tzc_action_t action) __deprecated; +static inline void tzc_enable_filters(void) __deprecated; +static inline void tzc_disable_filters(void) __deprecated; + +static inline void tzc_init(uintptr_t base) +{ + tzc400_init(base); +} + +static inline void tzc_configure_region0( tzc_region_attributes_t sec_attr, - uint32_t ns_device_access); -void tzc_enable_filters(void); -void tzc_disable_filters(void); -void tzc_set_action(tzc_action_t action); + unsigned int ns_device_access) +{ + tzc400_configure_region0(sec_attr, ns_device_access); +} + +static inline void tzc_configure_region( + unsigned int filters, + int region, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int ns_device_access) +{ + tzc400_configure_region(filters, region, region_base, + region_top, sec_attr, ns_device_access); +} + +static inline void tzc_set_action(tzc_action_t action) +{ + tzc400_set_action(action); +} + + +static inline void tzc_enable_filters(void) +{ + tzc400_enable_filters(); +} + +static inline void tzc_disable_filters(void) +{ + tzc400_disable_filters(); +} #endif /* __ASSEMBLY__ */ diff --git a/include/drivers/arm/tzc_common.h b/include/drivers/arm/tzc_common.h new file mode 100644 index 00000000..9b73c3f8 --- /dev/null +++ b/include/drivers/arm/tzc_common.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016, 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 __TZC_COMMON_H__ +#define __TZC_COMMON_H__ + +/* + * Offset of core registers from the start of the base of configuration + * registers for each region. + */ + +/* ID Registers */ +#define PID0_OFF 0xfe0 +#define PID1_OFF 0xfe4 +#define PID2_OFF 0xfe8 +#define PID3_OFF 0xfec +#define PID4_OFF 0xfd0 +#define CID0_OFF 0xff0 +#define CID1_OFF 0xff4 +#define CID2_OFF 0xff8 +#define CID3_OFF 0xffc + +/* Bit positions of TZC_ACTION registers */ +#define TZC_ACTION_RV_SHIFT 0 +#define TZC_ACTION_RV_MASK 0x3 +#define TZC_ACTION_RV_LOWOK 0x0 +#define TZC_ACTION_RV_LOWERR 0x1 +#define TZC_ACTION_RV_HIGHOK 0x2 +#define TZC_ACTION_RV_HIGHERR 0x3 + +/* Used along with 'tzc_region_attributes_t' below */ +#define TZC_REGION_ATTR_S_RD_SHIFT 30 +#define TZC_REGION_ATTR_S_WR_SHIFT 31 +#define TZC_REGION_ATTR_F_EN_SHIFT 0 +#define TZC_REGION_ATTR_SEC_SHIFT 30 +#define TZC_REGION_ATTR_S_RD_MASK 0x1 +#define TZC_REGION_ATTR_S_WR_MASK 0x1 +#define TZC_REGION_ATTR_SEC_MASK 0x3 + +#define TZC_REGION_ACCESS_WR_EN_SHIFT 16 +#define TZC_REGION_ACCESS_RD_EN_SHIFT 0 +#define TZC_REGION_ACCESS_ID_MASK 0xf + +/* Macros for allowing Non-Secure access to a region based on NSAID */ +#define TZC_REGION_ACCESS_RD(nsaid) \ + ((1 << (nsaid & TZC_REGION_ACCESS_ID_MASK)) << \ + TZC_REGION_ACCESS_RD_EN_SHIFT) +#define TZC_REGION_ACCESS_WR(nsaid) \ + ((1 << (nsaid & TZC_REGION_ACCESS_ID_MASK)) << \ + TZC_REGION_ACCESS_WR_EN_SHIFT) +#define TZC_REGION_ACCESS_RDWR(nsaid) \ + (TZC_REGION_ACCESS_RD(nsaid) | \ + TZC_REGION_ACCESS_WR(nsaid)) + +#ifndef __ASSEMBLY__ + +/* Returns offset of registers to program for a given region no */ +#define TZC_REGION_OFFSET(region_size, region_no) \ + ((region_size) * (region_no)) + +/* + * What type of action is expected when an access violation occurs. + * The memory requested is returned as zero. But we can also raise an event to + * let the system know it happened. + * We can raise an interrupt(INT) and/or cause an exception(ERR). + * TZC_ACTION_NONE - No interrupt, no Exception + * TZC_ACTION_ERR - No interrupt, raise exception -> sync external + * data abort + * TZC_ACTION_INT - Raise interrupt, no exception + * TZC_ACTION_ERR_INT - Raise interrupt, raise exception -> sync + * external data abort + */ +typedef enum { + TZC_ACTION_NONE = 0, + TZC_ACTION_ERR = 1, + TZC_ACTION_INT = 2, + TZC_ACTION_ERR_INT = (TZC_ACTION_ERR | TZC_ACTION_INT) +} tzc_action_t; + +/* + * Controls secure access to a region. If not enabled secure access is not + * allowed to region. + */ +typedef enum { + TZC_REGION_S_NONE = 0, + TZC_REGION_S_RD = 1, + TZC_REGION_S_WR = 2, + TZC_REGION_S_RDWR = (TZC_REGION_S_RD | TZC_REGION_S_WR) +} tzc_region_attributes_t; + +#endif /* __ASSEMBLY__ */ +#endif /* __TZC_COMMON_H__ */ -- cgit From 57f782019a0007670625414517cb94c4ab2aaa58 Mon Sep 17 00:00:00 2001 From: Soby Mathew Date: Fri, 26 Feb 2016 14:23:19 +0000 Subject: Migrate ARM standard platforms to the refactored TZC driver This patch migrates ARM Standard platforms to the refactored TZC driver. Change-Id: I2a2f60b645f73e14d8f416740c4551cec87cb1fb --- include/plat/arm/common/plat_arm.h | 2 +- include/plat/arm/css/common/css_def.h | 2 +- plat/arm/board/fvp/fvp_security.c | 2 +- plat/arm/board/fvp/include/platform_def.h | 2 +- plat/arm/board/fvp/platform.mk | 2 +- plat/arm/board/juno/juno_security.c | 2 +- plat/arm/board/juno/platform.mk | 2 +- plat/arm/common/arm_tzc400.c | 22 +++++++++++----------- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index e9eebaa0..45b50771 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -130,7 +130,7 @@ void arm_configure_mmu_el3(unsigned long total_base, void arm_io_setup(void); /* Security utility functions */ -void arm_tzc_setup(void); +void arm_tzc400_setup(void); /* Systimer utility function */ void arm_configure_sys_timer(void); diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h index f92126ba..636daf29 100644 --- a/include/plat/arm/css/common/css_def.h +++ b/include/plat/arm/css/common/css_def.h @@ -143,7 +143,7 @@ #define PLAT_ARM_NS_IMAGE_OFFSET 0xE0000000 /* TZC related constants */ -#define PLAT_ARM_TZC_FILTERS REG_ATTR_FILTER_BIT_ALL +#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT_ALL /* Trusted mailbox base address common to all CSS */ #define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE diff --git a/plat/arm/board/fvp/fvp_security.c b/plat/arm/board/fvp/fvp_security.c index 0cf8450c..b1de9776 100644 --- a/plat/arm/board/fvp/fvp_security.c +++ b/plat/arm/board/fvp/fvp_security.c @@ -46,5 +46,5 @@ void plat_arm_security_setup(void) */ if (get_arm_config()->flags & ARM_CONFIG_HAS_TZC) - arm_tzc_setup(); + arm_tzc400_setup(); } diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index a8267dec..85fead6c 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -113,7 +113,7 @@ * would normally use the default ID so allow that too. */ #define PLAT_ARM_TZC_BASE 0x2a4a0000 -#define PLAT_ARM_TZC_FILTERS REG_ATTR_FILTER_BIT(0) +#define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0) #define PLAT_ARM_TZC_NS_DEV_ACCESS ( \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_DEFAULT) | \ diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index aad2e2ef..afd939d1 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -65,7 +65,7 @@ endif FVP_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c \ plat/arm/common/arm_cci.c -FVP_SECURITY_SOURCES := drivers/arm/tzc400/tzc400.c \ +FVP_SECURITY_SOURCES := drivers/arm/tzc/tzc400.c \ plat/arm/board/fvp/fvp_security.c \ plat/arm/common/arm_tzc400.c diff --git a/plat/arm/board/juno/juno_security.c b/plat/arm/board/juno/juno_security.c index f9386cad..202342af 100644 --- a/plat/arm/board/juno/juno_security.c +++ b/plat/arm/board/juno/juno_security.c @@ -65,7 +65,7 @@ static void css_init_nic400(void) void plat_arm_security_setup(void) { /* Initialize the TrustZone Controller */ - arm_tzc_setup(); + arm_tzc400_setup(); /* Do ARM CSS internal NIC setup */ css_init_nic400(); /* Do ARM CSS SoC security setup */ diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk index 0a2244d5..4fda4ca1 100644 --- a/plat/arm/board/juno/platform.mk +++ b/plat/arm/board/juno/platform.mk @@ -37,7 +37,7 @@ JUNO_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ JUNO_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c \ plat/arm/common/arm_cci.c -JUNO_SECURITY_SOURCES := drivers/arm/tzc400/tzc400.c \ +JUNO_SECURITY_SOURCES := drivers/arm/tzc/tzc400.c \ plat/arm/board/juno/juno_security.c \ plat/arm/common/arm_tzc400.c diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c index 8b46aaed..3962940b 100644 --- a/plat/arm/common/arm_tzc400.c +++ b/plat/arm/common/arm_tzc400.c @@ -48,53 +48,53 @@ * When booting an EL3 payload, this is simplified: we configure region 0 with * secure access only and do not enable any other region. ******************************************************************************/ -void arm_tzc_setup(void) +void arm_tzc400_setup(void) { INFO("Configuring TrustZone Controller\n"); - tzc_init(PLAT_ARM_TZC_BASE); + tzc400_init(PLAT_ARM_TZC_BASE); /* Disable filters. */ - tzc_disable_filters(); + tzc400_disable_filters(); #ifndef EL3_PAYLOAD_BASE /* Region 0 set to no access by default */ - tzc_configure_region0(TZC_REGION_S_NONE, 0); + tzc400_configure_region0(TZC_REGION_S_NONE, 0); /* Region 1 set to cover Secure part of DRAM */ - tzc_configure_region(PLAT_ARM_TZC_FILTERS, 1, + tzc400_configure_region(PLAT_ARM_TZC_FILTERS, 1, ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END, TZC_REGION_S_RDWR, 0); /* Region 2 set to cover Non-Secure access to 1st DRAM address range. * Apply the same configuration to given filters in the TZC. */ - tzc_configure_region(PLAT_ARM_TZC_FILTERS, 2, + tzc400_configure_region(PLAT_ARM_TZC_FILTERS, 2, ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, TZC_REGION_S_NONE, PLAT_ARM_TZC_NS_DEV_ACCESS); /* Region 3 set to cover Non-Secure access to 2nd DRAM address range */ - tzc_configure_region(PLAT_ARM_TZC_FILTERS, 3, + tzc400_configure_region(PLAT_ARM_TZC_FILTERS, 3, ARM_DRAM2_BASE, ARM_DRAM2_END, TZC_REGION_S_NONE, PLAT_ARM_TZC_NS_DEV_ACCESS); #else /* Allow secure access only to DRAM for EL3 payloads. */ - tzc_configure_region0(TZC_REGION_S_RDWR, 0); + tzc400_configure_region0(TZC_REGION_S_RDWR, 0); #endif /* EL3_PAYLOAD_BASE */ /* * Raise an exception if a NS device tries to access secure memory * TODO: Add interrupt handling support. */ - tzc_set_action(TZC_ACTION_ERR); + tzc400_set_action(TZC_ACTION_ERR); /* Enable filters. */ - tzc_enable_filters(); + tzc400_enable_filters(); } void plat_arm_security_setup(void) { - arm_tzc_setup(); + arm_tzc400_setup(); } -- cgit From f568604b067cfd450e6fb39121b1c510dd3c1fd1 Mon Sep 17 00:00:00 2001 From: Vikram Kanigiri Date: Fri, 29 Jan 2016 11:37:04 +0000 Subject: Add ARM CoreLink DMC-500 driver to program TrustZone protection The ARM CoreLink DMC-500 Dynamic Memory Controller provides the programmable address region control of a TrustZone Address Space Controller. The access permissions can be defined for eight separate address regions plus a background or default region. This patch adds a DMC-500 driver to define address regions and program their access permissions as per ARM 100131_0000_02_en (r0p0) document. Change-Id: I9d33120f9480d742bcf7937e4b876f9d40c727e6 --- drivers/arm/tzc/tzc_dmc500.c | 299 +++++++++++++++++++++++++++++++++++++++ include/drivers/arm/tzc_dmc500.h | 174 +++++++++++++++++++++++ 2 files changed, 473 insertions(+) create mode 100644 drivers/arm/tzc/tzc_dmc500.c create mode 100644 include/drivers/arm/tzc_dmc500.h diff --git a/drivers/arm/tzc/tzc_dmc500.c b/drivers/arm/tzc/tzc_dmc500.c new file mode 100644 index 00000000..16a53a4f --- /dev/null +++ b/drivers/arm/tzc/tzc_dmc500.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2016, 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 "tzc_common.h" +#include "tzc_common_private.c" + +/* + * Macros which will be used by common core functions. + */ +#define TZC_DMC500_REGION_BASE_LOW_0_OFFSET 0x054 +#define TZC_DMC500_REGION_BASE_HIGH_0_OFFSET 0x058 +#define TZC_DMC500_REGION_TOP_LOW_0_OFFSET 0x05C +#define TZC_DMC500_REGION_TOP_HIGH_0_OFFSET 0x060 +#define TZC_DMC500_REGION_ATTR_0_OFFSET 0x064 +#define TZC_DMC500_REGION_ID_ACCESS_0_OFFSET 0x068 + +#define TZC_DMC500_ACTION_OFF 0x50 + +/* Pointer to the tzc_dmc500_driver_data structure populated by the platform */ +static const tzc_dmc500_driver_data_t *g_driver_data; + +#define verify_region_attr(region, attr) \ + ((g_conf_regions[(region)].sec_attr == \ + ((attr) >> TZC_REGION_ATTR_SEC_SHIFT)) \ + && ((attr) & (0x1 << TZC_REGION_ATTR_F_EN_SHIFT))) + +/* + * Structure for configured regions attributes in DMC500. + */ +typedef struct tzc_dmc500_regions { + tzc_region_attributes_t sec_attr; + int is_enabled; +} tzc_dmc500_regions_t; + +/* + * Array storing the attributes of the configured regions. This array + * will be used by the `tzc_dmc500_verify_complete` to verify the flush + * completion. + */ +static tzc_dmc500_regions_t g_conf_regions[MAX_REGION_VAL + 1]; + +/* Helper Macros for making the code readable */ +#define DMC_INST_BASE_ADDR(instance) (g_driver_data->dmc_base[instance]) +#define DMC_INST_SI_BASE(instance, interface) \ + (DMC_INST_BASE_ADDR(instance) + IFACE_OFFSET(interface)) + +DEFINE_TZC_COMMON_WRITE_ACTION(_dmc500, DMC500) +DEFINE_TZC_COMMON_WRITE_REGION_BASE(_dmc500, DMC500) +DEFINE_TZC_COMMON_WRITE_REGION_TOP(_dmc500, DMC500) +DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(_dmc500, DMC500) +DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(_dmc500, DMC500) + +DEFINE_TZC_COMMON_CONFIGURE_REGION0(_dmc500) +DEFINE_TZC_COMMON_CONFIGURE_REGION(_dmc500) + +static inline unsigned int _tzc_dmc500_read_region_attr_0( + uintptr_t dmc_si_base, + int region_no) +{ + return mmio_read_32(dmc_si_base + + TZC_REGION_OFFSET(TZC_DMC500_REGION_SIZE, region_no) + + TZC_DMC500_REGION_ATTR_0_OFFSET); +} + +static inline void _tzc_dmc500_write_flush_control(uintptr_t dmc_si_base) +{ + mmio_write_32(dmc_si_base + SI_FLUSH_CTRL_OFFSET, 1); +} + +/* + * Sets the Flush controls for all the DMC Instances and System Interfaces. + * This initiates the flush of configuration settings from the shadow + * registers to the actual configuration register. The caller should poll + * changed register to confirm update. + */ +void tzc_dmc500_config_complete(void) +{ + int dmc_inst, sys_if; + + assert(g_driver_data); + + for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { + assert(DMC_INST_BASE_ADDR(dmc_inst)); + for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++) + _tzc_dmc500_write_flush_control( + DMC_INST_SI_BASE(dmc_inst, sys_if)); + } +} + +/* + * This function reads back the secure attributes from the configuration + * register for each DMC Instance and System Interface and compares it with + * the configured value. The successful verification of the region attributes + * confirms that the flush operation has completed. + * If the verification fails, the caller is expected to invoke this API again + * till it succeeds. + * Returns 0 on success and 1 on failure. + */ +int tzc_dmc500_verify_complete(void) +{ + int dmc_inst, sys_if, region_no; + unsigned int attr; + + assert(g_driver_data); + /* Region 0 must be configured */ + assert(g_conf_regions[0].is_enabled); + + /* Iterate over all configured regions */ + for (region_no = 0; region_no <= MAX_REGION_VAL; region_no++) { + if (!g_conf_regions[region_no].is_enabled) + continue; + for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; + dmc_inst++) { + assert(DMC_INST_BASE_ADDR(dmc_inst)); + for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; + sys_if++) { + attr = _tzc_dmc500_read_region_attr_0( + DMC_INST_SI_BASE(dmc_inst, sys_if), + region_no); + VERBOSE("Verifying DMC500 region:%d" + " dmc_inst:%d sys_if:%d attr:%x\n", + region_no, dmc_inst, sys_if, attr); + if (!verify_region_attr(region_no, attr)) + return 1; + } + } + } + + return 0; +} + +/* + * `tzc_dmc500_configure_region0` is used to program region 0 in both the + * system interfaces of all the DMC-500 instances. Region 0 covers the whole + * address space that is not mapped to any other region for a system interface, + * and is always enabled; this cannot be changed. This function only changes + * the access permissions. + */ +void tzc_dmc500_configure_region0(tzc_region_attributes_t sec_attr, + unsigned int nsaid_permissions) +{ + int dmc_inst, sys_if; + + /* Assert if DMC-500 is not initialized */ + assert(g_driver_data); + + /* Configure region_0 in all DMC instances */ + for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { + assert(DMC_INST_BASE_ADDR(dmc_inst)); + for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++) + _tzc_dmc500_configure_region0( + DMC_INST_SI_BASE(dmc_inst, sys_if), + sec_attr, nsaid_permissions); + } + + g_conf_regions[0].sec_attr = sec_attr; + g_conf_regions[0].is_enabled = 1; +} + +/* + * `tzc_dmc500_configure_region` is used to program a region into all system + * interfaces of all the DMC instances. + * NOTE: + * Region 0 is special; it is preferable to use tzc_dmc500_configure_region0 + * for this region (see comment for that function). + */ +void tzc_dmc500_configure_region(int region_no, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int nsaid_permissions) +{ + int dmc_inst, sys_if; + + assert(g_driver_data); + /* Do range checks on regions. */ + assert(region_no >= 0 && region_no <= MAX_REGION_VAL); + + /* + * Do address range check based on DMC-TZ configuration. A 43bit address + * is the max and expected case. + */ + assert(((region_top <= (UINT64_MAX >> (64 - 43))) && + (region_base < region_top))); + + /* region_base and (region_top + 1) must be 4KB aligned */ + assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0); + + for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { + assert(DMC_INST_BASE_ADDR(dmc_inst)); + for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++) + _tzc_dmc500_configure_region( + DMC_INST_SI_BASE(dmc_inst, sys_if), + TZC_DMC500_REGION_ATTR_F_EN_MASK, + region_no, region_base, region_top, + sec_attr, nsaid_permissions); + } + + g_conf_regions[region_no].sec_attr = sec_attr; + g_conf_regions[region_no].is_enabled = 1; +} + +/* Sets the action value for all the DMC instances */ +void tzc_dmc500_set_action(tzc_action_t action) +{ + int dmc_inst; + + assert(g_driver_data); + + for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { + assert(DMC_INST_BASE_ADDR(dmc_inst)); + /* + * - Currently no handler is provided to trap an error via + * interrupt or exception. + * - The interrupt action has not been tested. + */ + _tzc_dmc500_write_action(DMC_INST_BASE_ADDR(dmc_inst), action); + } +} + +/* + * A DMC-500 instance must be present at each base address provided by the + * platform. It also expects platform to pass at least one instance of + * DMC-500. + */ +static void validate_plat_driver_data( + const tzc_dmc500_driver_data_t *plat_driver_data) +{ +#if DEBUG + int i; + unsigned int dmc_id; + uintptr_t dmc_base; + + assert(plat_driver_data); + assert(plat_driver_data->dmc_count > 0 && + (plat_driver_data->dmc_count <= MAX_DMC_COUNT)); + + for (i = 0; i < plat_driver_data->dmc_count; i++) { + dmc_base = plat_driver_data->dmc_base[i]; + assert(dmc_base); + + dmc_id = _tzc_read_peripheral_id(dmc_base); + assert(dmc_id == DMC500_PERIPHERAL_ID); + } +#endif /* DEBUG */ +} + + +/* + * Initializes the base address and count of DMC instances. + * + * Note : Only pointer to plat_driver_data is saved, so it is caller's + * responsibility to keep it valid until the driver is used. + */ +void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data) +{ + /* Check valid pointer is passed */ + assert(plat_driver_data); + + /* + * NOTE: This driver expects the DMC-500 controller is already in + * READY state. Hence, it uses the reconfiguration method for + * programming TrustZone regions + */ + /* Validates the information passed by platform */ + validate_plat_driver_data(plat_driver_data); + g_driver_data = plat_driver_data; +} diff --git a/include/drivers/arm/tzc_dmc500.h b/include/drivers/arm/tzc_dmc500.h new file mode 100644 index 00000000..70f8ad2d --- /dev/null +++ b/include/drivers/arm/tzc_dmc500.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2016, 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 __TZC_DMC500_H__ +#define __TZC_DMC500_H__ + +#include + +#define SI_STATUS_OFFSET 0x000 +#define SI_STATE_CTRL_OFFSET 0x030 +#define SI_FLUSH_CTRL_OFFSET 0x034 +#define SI_INT_CONTROL_OFFSET 0x048 + +#define SI_INT_STATUS_OFFSET 0x004 +#define SI_TZ_FAIL_ADDRESS_LOW_OFFSET 0x008 +#define SI_TZ_FAIL_ADDRESS_HIGH_OFFSET 0x00c +#define SI_FAIL_CONTROL_OFFSET 0x010 +#define SI_FAIL_ID_OFFSET 0x014 +#define SI_INT_CLR_OFFSET 0x04c + +/* + * DMC-500 has 2 system interfaces each having a similar set of regs + * to configure each interface. + */ +#define SI0_BASE 0x0000 +#define SI1_BASE 0x0200 + +/* Bit positions of SIx_SI_STATUS */ +#define SI_EMPTY_SHIFT 0x01 +#define SI_STALL_ACK_SHIFT 0x00 +#define SI_EMPTY_MASK 0x01 +#define SI_STALL_ACK_MASK 0x01 + +/* Bit positions of SIx_SI_INT_STATUS */ +#define PMU_REQ_INT_OVERFLOW_STATUS_SHIFT 18 +#define FAILED_ACCESS_INT_OVERFLOW_STATUS_SHIFT 16 +#define PMU_REQ_INT_STATUS_SHIFT 2 +#define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_SHIFT 1 +#define FAILED_ACCESS_INT_STATUS_SHIFT 0 +#define PMU_REQ_INT_OVERFLOW_STATUS_MASK 0x1 +#define FAILED_ACCESS_INT_OVERFLOW_STATUS_MASK 0x1 +#define PMU_REQ_INT_STATUS_MASK 0x1 +#define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_MASK 0x1 +#define FAILED_ACCESS_INT_STATUS_MASK 0x1 + +/* Bit positions of SIx_TZ_FAIL_CONTROL */ +#define DIRECTION_SHIFT 24 +#define NON_SECURE_SHIFT 21 +#define PRIVILEGED_SHIFT 20 +#define FAILED_ACCESS_INT_INFO_RANK_MASKED_SHIFT 3 +#define FAILED_ACCESS_INT_INFO_UNMAPPED_SHIFT 2 +#define FAILED_ACCESS_INT_TZ_FAIL_SHIFT 0x1 +#define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_SHIFT 0 +#define DIRECTION_MASK 0x1 +#define NON_SECURE_MASK 0x1 +#define PRIVILEGED_MASK 0x1 +#define FAILED_ACCESS_INT_INFO_RANK_MASKED_MASK 0x1 +#define FAILED_ACCESS_INT_INFO_UNMAPPED_MASK 0x1 +#define FAILED_ACCESS_INT_TZ_FAIL_MASK 1 +#define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_MASK 0x1 + +/* Bit positions of SIx_FAIL_STATUS */ +#define FAIL_ID_VNET_SHIFT 24 +#define FAIL_ID_ID_SHIFT 0 +#define FAIL_ID_VNET_MASK 0xf +#define FAIL_ID_ID_MASK 0xffffff + +/* Bit positions of SIx_SI_STATE_CONTRL */ +#define SI_STALL_REQ_GO 0x0 +#define SI_STALL_REQ_STALL 0x1 + +/* Bit positions of SIx_SI_FLUSH_CONTROL */ +#define SI_FLUSH_REQ_INACTIVE 0x0 +#define SI_FLUSH_REQ_ACTIVE 0x1 +#define SI_FLUSH_REQ_MASK 0x1 + +/* Bit positions of SIx_SI_INT_CONTROL */ +#define PMU_REQ_INT_EN_SHIFT 2 +#define OVERLAP_DETECT_INT_EN_SHIFT 1 +#define FAILED_ACCESS_INT_EN_SHIFT 0 +#define PMU_REQ_INT_EN_MASK 0x1 +#define OVERLAP_DETECT_INT_EN_MASK 0x1 +#define FAILED_ACCESS_INT_EN_MASK 0x1 +#define PMU_REQ_INT_EN 0x1 +#define OVERLAP_DETECT_INT_EN 0x1 +#define FAILED_ACCESS_INT_EN 0x1 + +/* Bit positions of SIx_SI_INT_CLR */ +#define PMU_REQ_OFLOW_CLR_SHIFT 18 +#define FAILED_ACCESS_OFLOW_CLR_SHIFT 16 +#define PMU_REQ_INT_CLR_SHIFT 2 +#define FAILED_ACCESS_INT_CLR_SHIFT 0 +#define PMU_REQ_OFLOW_CLR_MASK 0x1 +#define FAILED_ACCESS_OFLOW_CLR_MASK 0x1 +#define PMU_REQ_INT_CLR_MASK 0x1 +#define FAILED_ACCESS_INT_CLR_MASK 0x1 +#define PMU_REQ_OFLOW_CLR 0x1 +#define FAILED_ACCESS_OFLOW_CLR 0x1 +#define PMU_REQ_INT_CLR 0x1 +#define FAILED_ACCESS_INT_CLR 0x1 + +/* Macro to get the correct base register for a system interface */ +#define IFACE_OFFSET(sys_if) ((sys_if) ? SI1_BASE : SI0_BASE) + +#define MAX_SYS_IF_COUNT 2 +#define MAX_REGION_VAL 8 + +/* DMC-500 supports striping across a max of 4 DMC instances */ +#define MAX_DMC_COUNT 4 + +/* Consist of part_number_1 and part_number_0 */ +#define DMC500_PERIPHERAL_ID 0x0450 + +/* Filter enable bits in a TZC */ +#define TZC_DMC500_REGION_ATTR_F_EN_MASK 0x1 + +/* Length of registers for configuring each region */ +#define TZC_DMC500_REGION_SIZE 0x018 + +#ifndef __ASSEMBLY__ + +#include + +/* + * Contains the base addresses of all the DMC instances. + */ +typedef struct tzc_dmc500_driver_data { + uintptr_t dmc_base[MAX_DMC_COUNT]; + int dmc_count; +} tzc_dmc500_driver_data_t; + +void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data); +void tzc_dmc500_configure_region0(tzc_region_attributes_t sec_attr, + unsigned int nsaid_permissions); +void tzc_dmc500_configure_region(int region_no, + uintptr_t region_base, + uintptr_t region_top, + tzc_region_attributes_t sec_attr, + unsigned int nsaid_permissions); +void tzc_dmc500_set_action(tzc_action_t action); +void tzc_dmc500_config_complete(void); +int tzc_dmc500_verify_complete(void); + + +#endif /* __ASSEMBLY__ */ +#endif /* __TZC_DMC500_H__ */ + -- cgit From 618f0feeed78db24974b1d761dd161f63d03fa11 Mon Sep 17 00:00:00 2001 From: Vikram Kanigiri Date: Fri, 29 Jan 2016 12:32:58 +0000 Subject: Add support to program a DMC-500 TZC on ARM platforms This patch adds support to program TrustZone protection on ARM platforms that implement a DMC-500. arm_dmc_500.c has been added which implements the arm_dmc_tzc_setup() function. This function relies on constants related to TZC programming that are exported by each platform to program TrustZone protection using the DMC-500 TrustZone controller driver. This function should be called from plat_arm_security_setup() which is implemented by each platform. Change-Id: I5400bdee9e4b29155fd11296a40693d512312f29 --- include/plat/arm/common/plat_arm.h | 2 + plat/arm/common/arm_tzc_dmc500.c | 100 +++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 plat/arm/common/arm_tzc_dmc500.c diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index 45b50771..2fe0a690 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -131,6 +131,8 @@ void arm_io_setup(void); /* Security utility functions */ void arm_tzc400_setup(void); +struct tzc_dmc500_driver_data; +void arm_tzc_dmc500_setup(struct tzc_dmc500_driver_data *plat_driver_data); /* Systimer utility function */ void arm_configure_sys_timer(void); diff --git a/plat/arm/common/arm_tzc_dmc500.c b/plat/arm/common/arm_tzc_dmc500.c new file mode 100644 index 00000000..f0ed9a60 --- /dev/null +++ b/plat/arm/common/arm_tzc_dmc500.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, 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 + +/******************************************************************************* + * Initialize the DMC500-TrustZone Controller for ARM standard platforms. + * Configure both the interfaces on Region 0 with no access, Region 1 with + * secure access only, and the remaining DRAM regions access from the + * given Non-Secure masters. + * + * When booting an EL3 payload, this is simplified: we configure region 0 with + * secure access only and do not enable any other region. + ******************************************************************************/ +void arm_tzc_dmc500_setup(tzc_dmc500_driver_data_t *plat_driver_data) +{ + assert(plat_driver_data); + + INFO("Configuring DMC-500 TZ Settings\n"); + + tzc_dmc500_driver_init(plat_driver_data); + +#ifndef EL3_PAYLOAD_BASE + /* Region 0 set to no access by default */ + tzc_dmc500_configure_region0(TZC_REGION_S_NONE, 0); + + /* Region 1 set to cover Secure part of DRAM */ + tzc_dmc500_configure_region(1, ARM_AP_TZC_DRAM1_BASE, + ARM_AP_TZC_DRAM1_END, + TZC_REGION_S_RDWR, + 0); + + /* Region 2 set to cover Non-Secure access to 1st DRAM address range.*/ + tzc_dmc500_configure_region(2, + ARM_NS_DRAM1_BASE, + ARM_NS_DRAM1_END, + TZC_REGION_S_NONE, + PLAT_ARM_TZC_NS_DEV_ACCESS); + + /* Region 3 set to cover Non-Secure access to 2nd DRAM address range */ + tzc_dmc500_configure_region(3, + ARM_DRAM2_BASE, + ARM_DRAM2_END, + TZC_REGION_S_NONE, + PLAT_ARM_TZC_NS_DEV_ACCESS); +#else + /* Allow secure access only to DRAM for EL3 payloads */ + tzc_dmc500_configure_region0(TZC_REGION_S_RDWR, 0); +#endif + /* + * Raise an exception if a NS device tries to access secure memory + * TODO: Add interrupt handling support. + */ + tzc_dmc500_set_action(TZC_ACTION_RV_LOWERR); + + /* + * Flush the configuration settings to have an affect. Validate + * flush by checking FILTER_EN is set on region 1 attributes + * register. + */ + tzc_dmc500_config_complete(); + + /* + * Wait for the flush to complete. + * TODO: Have a timeout for this loop + */ + while (tzc_dmc500_verify_complete()) + ; +} -- cgit