diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c new file mode 100644 index 0000000..ee6bf8d --- /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 0000000..f570daf --- /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 7194443..97adf81 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 f8e1664..3085688 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 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 +#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 not common across different varieties of TZC */ +#define PID5 0xFD4 +#define PID6 0xFD8 +#define PID7 0xFDC -/* 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_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_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 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 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 +#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 TZC_400_PERIPHERAL_ID 0x460 -#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 +/* 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) +/* + * 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__ */ -/* 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 - - +/* + * 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, - 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) __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, + 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 0000000..9b73c3f --- /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__ */