diff options
49 files changed, 2418 insertions, 634 deletions
@@ -11,6 +11,12 @@ build/ # Ignore build products from tools tools/**/*.o tools/fip_create/fip_create +tools/fip_create/fip_create.exe tools/cert_create/src/*.o tools/cert_create/src/**/*.o tools/cert_create/cert_create +tools/cert_create/cert_create.exe + +# Ignore header files copied. +tools/fip_create/firmware_image_package.h +tools/fip_create/uuid.h @@ -37,7 +37,9 @@ VERSION_MINOR := 2 # Default goal is build all images .DEFAULT_GOAL := all -include make_helpers/build_macros.mk +MAKE_HELPERS_DIRECTORY := make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk ################################################################################ # Default values for build configurations @@ -111,9 +113,10 @@ CHECK_IGNORE := --ignore COMPLEX_MACRO \ CHECKPATCH_ARGS := --no-tree --no-signoff ${CHECK_IGNORE} CHECKCODE_ARGS := --no-patch --no-tree --no-signoff ${CHECK_IGNORE} # Do not check the coding style on C library files -CHECK_PATHS := $(shell ls -I include -I lib) \ - $(addprefix include/,$(shell ls -I stdlib include)) \ - $(addprefix lib/,$(shell ls -I stdlib lib)) +INCLUDE_DIRS_TO_CHECK := $(sort $(filter-out include/stdlib, $(wildcard include/*))) +LIB_DIRS_TO_CHECK := $(sort $(filter-out lib/stdlib, $(wildcard lib/*))) +ROOT_DIRS_TO_CHECK := $(sort $(filter-out lib include, $(wildcard *)))) +CHECK_PATHS := ${ROOT_DIRS_TO_CHECK} ${INCLUDE_DIRS_TO_CHECK} ${LIB_DIRS_TO_CHECK} ################################################################################ @@ -122,10 +125,10 @@ CHECK_PATHS := $(shell ls -I include -I lib) \ # Verbose flag ifeq (${V},0) - Q=@ + Q:=@ CHECKCODE_ARGS += --no-summary --terse else - Q= + Q:= endif export Q @@ -234,17 +237,12 @@ INCLUDES += -Iinclude/bl1 \ # Generic definitions ################################################################################ +include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk + BUILD_BASE := ./build BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${BUILD_TYPE} -PLAT_MAKEFILE := platform.mk -# Generate the platforms list by recursively searching for all directories -# under /plat containing a PLAT_MAKEFILE. Append each platform with a `|` -# char and strip out the final '|'. -PLATFORMS := $(shell find plat/ -name '${PLAT_MAKEFILE}' -print0 | \ - sed -r 's%[^\x00]*\/([^/]*)\/${PLAT_MAKEFILE}\x00%\1|%g' | \ - sed -r 's/\|$$//') -SPDS := $(shell ls -I none services/spd) +SPDS := $(sort $(filter-out none, $(patsubst services/spd/%,%,$(wildcard services/spd/*)))) # Platforms providing their own TBB makefile may override this value INCLUDE_TBBR_MK := 1 @@ -260,7 +258,7 @@ ifdef EL3_PAYLOAD_BASE $(warning "The SPD and its BL32 companion will be present but ignored.") endif # We expect to locate an spd.mk under the specified SPD directory - SPD_MAKE := $(shell m="services/spd/${SPD}/${SPD}.mk"; [ -f "$$m" ] && echo "$$m") + SPD_MAKE := $(wildcard services/spd/${SPD}/${SPD}.mk) ifeq (${SPD_MAKE},) $(error Error: No services/spd/${SPD}/${SPD}.mk located) @@ -285,14 +283,6 @@ endif # makefile may use all previous definitions in this file) ################################################################################ -ifeq (${PLAT},) - $(error "Error: Unknown platform. Please use PLAT=<platform name> to specify the platform") -endif -PLAT_MAKEFILE_FULL := $(shell find plat/ -wholename '*/${PLAT}/${PLAT_MAKEFILE}') -ifeq ($(PLAT_MAKEFILE_FULL),) - $(error "Error: Invalid platform. The following platforms are available: ${PLATFORMS}") -endif - include ${PLAT_MAKEFILE_FULL} # If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default @@ -386,11 +376,11 @@ endif # Variables for use with Certificate Generation Tool CRTTOOLPATH ?= tools/cert_create -CRTTOOL ?= ${CRTTOOLPATH}/cert_create +CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT} # Variables for use with Firmware Image Package FIPTOOLPATH ?= tools/fip_create -FIPTOOL ?= ${FIPTOOLPATH}/fip_create +FIPTOOL ?= ${FIPTOOLPATH}/fip_create${BIN_EXT} ################################################################################ @@ -545,14 +535,14 @@ endif clean: @echo " CLEAN" - ${Q}rm -rf ${BUILD_PLAT} + $(call SHELL_REMOVE_DIR,${BUILD_PLAT}) ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean realclean distclean: @echo " REALCLEAN" - ${Q}rm -rf ${BUILD_BASE} - ${Q}rm -f ${CURDIR}/cscope.* + $(call SHELL_REMOVE_DIR,${BUILD_BASE}) + $(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*) ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean @@ -573,24 +563,24 @@ certtool: ${CRTTOOL} .PHONY: ${CRTTOOL} ${CRTTOOL}: ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} - @echo + @${ECHO_BLANK_LINE} @echo "Built $@ successfully" - @echo + @${ECHO_BLANK_LINE} ifneq (${GENERATE_COT},0) certificates: ${CRT_DEPS} ${CRTTOOL} ${Q}${CRTTOOL} ${CRT_ARGS} - @echo + @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @echo "Certificates can be found in ${BUILD_PLAT}" - @echo + @${ECHO_BLANK_LINE} endif ${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL} ${Q}${FIPTOOL} --dump ${FIP_ARGS} $@ - @echo + @${ECHO_BLANK_LINE} @echo "Built $@ successfully" - @echo + @${ECHO_BLANK_LINE} ifneq (${GENERATE_COT},0) fwu_certificates: ${FWU_CRT_DEPS} ${CRTTOOL} @@ -621,7 +611,7 @@ cscope: ${Q}cscope -b -q -k help: - @echo "usage: ${MAKE} PLAT=<${PLATFORMS}> [OPTIONS] [TARGET]" + @echo "usage: ${MAKE} PLAT=<${PLATFORM_LIST}> [OPTIONS] [TARGET]" @echo "" @echo "PLAT is used to specify which platform you wish to build." @echo "If no platform is specified, PLAT defaults to: ${DEFAULT_PLAT}" diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk index 9919fe4f..a5024284 100644 --- a/bl32/tsp/tsp.mk +++ b/bl32/tsp/tsp.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2013-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: @@ -52,8 +52,8 @@ $(eval $(call add_define,TSP_INIT_ASYNC)) # Include the platform-specific TSP Makefile # If no platform-specific TSP Makefile exists, it means TSP is not supported # on this platform. -TSP_PLAT_MAKEFILE := $(shell find plat/ -wholename '*/${PLAT}/tsp/tsp-${PLAT}.mk') -ifeq (,$(wildcard ${TSP_PLAT_MAKEFILE})) +TSP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/tsp/tsp-${PLAT}.mk) +ifeq (,${TSP_PLAT_MAKEFILE}) $(error TSP is not supported on platform ${PLAT}) else include ${TSP_PLAT_MAKEFILE} diff --git a/common/tf_printf.c b/common/tf_printf.c index c1d41889..9a7667a5 100644 --- a/common/tf_printf.c +++ b/common/tf_printf.c @@ -69,6 +69,7 @@ static void string_print(const char *str) * %ld and %lld - signed 64 bit decimal format * %lu and %llu - unsigned 64 bit decimal format * %p - pointer format + * %z - size_t format * Exits on all other formats. *******************************************************************/ @@ -124,6 +125,11 @@ loop: unsigned_num_print(unum, 16); break; + case 'z': + if (sizeof(size_t) == 8) + bit64 = 1; + fmt++; + goto loop; case 'l': bit64 = 1; fmt++; diff --git a/docs/porting-guide.md b/docs/porting-guide.md index f8d0ff38..3b6e242b 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -633,6 +633,35 @@ retrieved from the platform. The function also reports extra information related to the ROTPK in the flags parameter. +### Function: plat_get_nv_ctr() + + Argument : void *, unsigned int * + Return : int + +This function is mandatory when Trusted Board Boot is enabled. It returns the +non-volatile counter value stored in the platform in the second argument. The +cookie in the first argument may be used to select the counter in case the +platform provides more than one (for example, on platforms that use the default +TBBR CoT, the cookie will correspond to the OID values defined in +TRUSTED_FW_NVCOUNTER_OID or NON_TRUSTED_FW_NVCOUNTER_OID). + +The function returns 0 on success. Any other value means the counter value could +not be retrieved from the platform. + + +### Function: plat_set_nv_ctr() + + Argument : void *, unsigned int + Return : int + +This function is mandatory when Trusted Board Boot is enabled. It sets a new +counter value in the platform. The cookie in the first argument may be used to +select the counter (as explained in plat_get_nv_ctr()). + +The function returns 0 on success. Any other value means the counter value could +not be updated. + + 2.3 Common mandatory modifications --------------------------------- diff --git a/docs/user-guide.md b/docs/user-guide.md index 37e20346..8d7376d4 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -42,6 +42,9 @@ The software has been tested on Ubuntu 14.04 LTS (64-bit). Packages used for building the software were installed from that distribution unless otherwise specified. +The software has also been built on Windows 7 Enterprise SP1, using CMD.EXE, +Cygwin, and Msys (MinGW) shells, using version 4.9.1 of the GNU toolchain. + 3. Tools --------- 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 <assert.h> +#include <debug.h> +#include <mmio.h> +#include <stddef.h> +#include <tzc400.h> +#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 <mmio.h> +#include <tzc_common.h> + +#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/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 <assert.h> +#include <debug.h> +#include <mmio.h> +#include <tzc_dmc500.h> +#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/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 <assert.h> -#include <debug.h> -#include <mmio.h> -#include <stddef.h> -#include <tzc400.h> - -/* - * 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/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c index bdd3c5a1..41845561 100644 --- a/drivers/auth/auth_mod.c +++ b/drivers/auth/auth_mod.c @@ -40,6 +40,9 @@ #include <stdint.h> #include <string.h> +/* ASN.1 tags */ +#define ASN1_INTEGER 0x02 + #define return_if_error(rc) \ do { \ if (rc != 0) { \ @@ -227,6 +230,83 @@ static int auth_signature(const auth_method_param_sig_t *param, } /* + * Authenticate by Non-Volatile counter + * + * To protect the system against rollback, the platform includes a non-volatile + * counter whose value can only be increased. All certificates include a counter + * value that should not be lower than the value stored in the platform. If the + * value is larger, the counter in the platform must be updated to the new + * value. + * + * Return: 0 = success, Otherwise = error + */ +static int auth_nvctr(const auth_method_param_nv_ctr_t *param, + const auth_img_desc_t *img_desc, + void *img, unsigned int img_len) +{ + char *p; + void *data_ptr = NULL; + unsigned int data_len, len, i; + unsigned int cert_nv_ctr, plat_nv_ctr; + int rc = 0; + + /* Get the counter value from current image. The AM expects the IPM + * to return the counter value as a DER encoded integer */ + rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr, + img, img_len, &data_ptr, &data_len); + return_if_error(rc); + + /* Parse the DER encoded integer */ + assert(data_ptr); + p = (char *)data_ptr; + if (*p != ASN1_INTEGER) { + /* Invalid ASN.1 integer */ + return 1; + } + p++; + + /* NV-counters are unsigned integers up to 32-bit */ + len = (unsigned int)(*p & 0x7f); + if ((*p & 0x80) || (len > 4)) { + return 1; + } + p++; + + /* Check the number is not negative */ + if (*p & 0x80) { + return 1; + } + + /* Convert to unsigned int. This code is for a little-endian CPU */ + cert_nv_ctr = 0; + for (i = 0; i < len; i++) { + cert_nv_ctr = (cert_nv_ctr << 8) | *p++; + } + + /* Get the counter from the platform */ + rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr); + return_if_error(rc); + + if (cert_nv_ctr < plat_nv_ctr) { + /* Invalid NV-counter */ + return 1; + } else if (cert_nv_ctr > plat_nv_ctr) { + if (img_desc->parent == NULL) { + /* This certificate has been signed with the ROT key. + * Update the platform counter value */ + rc = plat_set_nv_ctr(param->plat_nv_ctr->cookie, + cert_nv_ctr); + return_if_error(rc); + } else { + /* Secondary certificates cannot modify the counter */ + return 1; + } + } + + return 0; +} + +/* * Return the parent id in the output parameter '*parent_id' * * Return value: @@ -310,6 +390,10 @@ int auth_mod_verify_img(unsigned int img_id, rc = auth_signature(&auth_method->param.sig, img_desc, img_ptr, img_len); break; + case AUTH_METHOD_NV_CTR: + rc = auth_nvctr(&auth_method->param.nv_ctr, + img_desc, img_ptr, img_len); + break; default: /* Unknown authentication method */ rc = 1; diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c index 52e69719..1a6a9a75 100644 --- a/drivers/auth/mbedtls/mbedtls_x509_parser.c +++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c @@ -405,6 +405,13 @@ static int check_integrity(void *img, unsigned int img_len) /* * Extract an authentication parameter from an X509v3 certificate + * + * This function returns a pointer to the extracted data and its length. + * Depending on the type of parameter, a pointer to the data stored in the + * certificate may be returned (i.e. an octet string containing a hash). Other + * data may need to be copied and formatted (i.e. integers). In the later case, + * a buffer of the correct type needs to be statically allocated, filled and + * returned. */ static int get_auth_param(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, @@ -422,6 +429,7 @@ static int get_auth_param(const auth_param_type_desc_t *type_desc, *param_len = (unsigned int)tbs.len; break; case AUTH_PARAM_HASH: + case AUTH_PARAM_NV_CTR: /* All these parameters are included as X509v3 extensions */ rc = get_ext(type_desc->cookie, param, param_len); break; diff --git a/drivers/auth/tbbr/tbbr_cot.c b/drivers/auth/tbbr/tbbr_cot.c index 6023c784..dae35d13 100644 --- a/drivers/auth/tbbr/tbbr_cot.c +++ b/drivers/auth/tbbr/tbbr_cot.c @@ -56,6 +56,11 @@ static unsigned char content_pk_buf[PK_DER_LEN]; /* * Parameter type descriptors */ +static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID); +static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID); + static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, 0); static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC( @@ -116,6 +121,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -158,6 +170,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -193,6 +212,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -218,6 +244,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -260,6 +293,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -285,6 +325,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -327,6 +374,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -352,6 +406,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -394,6 +455,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &non_trusted_nv_ctr, + .plat_nv_ctr = &non_trusted_nv_ctr + } } }, .authenticated_data = { @@ -419,6 +487,13 @@ static const auth_img_desc_t cot_desc[] = { .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &non_trusted_nv_ctr, + .plat_nv_ctr = &non_trusted_nv_ctr + } } }, .authenticated_data = { 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 <tzc_common.h> -#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 <cdefs.h> #include <stdint.h> /******************************************************************************* * 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__ */ 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 <tzc_common.h> + +#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 <stdint.h> + +/* + * 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__ */ + diff --git a/include/drivers/auth/auth_common.h b/include/drivers/auth/auth_common.h index 52a895e4..456f69f2 100644 --- a/include/drivers/auth/auth_common.h +++ b/include/drivers/auth/auth_common.h @@ -46,6 +46,7 @@ typedef enum auth_param_type_enum { AUTH_PARAM_SIG_ALG, /* The image signature algorithm */ AUTH_PARAM_HASH, /* A hash (including the algorithm) */ AUTH_PARAM_PUB_KEY, /* A public key */ + AUTH_PARAM_NV_CTR, /* A non-volatile counter */ } auth_param_type_t; /* @@ -80,6 +81,7 @@ typedef enum auth_method_type_enum { AUTH_METHOD_NONE = 0, AUTH_METHOD_HASH, /* Authenticate by hash matching */ AUTH_METHOD_SIG, /* Authenticate by PK operation */ + AUTH_METHOD_NV_CTR, /* Authenticate by Non-Volatile Counter */ AUTH_METHOD_NUM /* Number of methods */ } auth_method_type_t; @@ -105,7 +107,8 @@ typedef struct auth_method_param_sig_s { * Parameters for authentication by NV counter */ typedef struct auth_method_param_nv_ctr_s { - auth_param_type_desc_t *nv_ctr; /* NV counter value */ + auth_param_type_desc_t *cert_nv_ctr; /* NV counter in certificate */ + auth_param_type_desc_t *plat_nv_ctr; /* NV counter in platform */ } auth_method_param_nv_ctr_t; /* diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index e9eebaa0..2fe0a690 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -130,7 +130,9 @@ 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); +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/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/include/plat/arm/soc/common/soc_css_def.h b/include/plat/arm/soc/common/soc_css_def.h index 428df4d2..f1396a6c 100644 --- a/include/plat/arm/soc/common/soc_css_def.h +++ b/include/plat/arm/soc/common/soc_css_def.h @@ -65,6 +65,13 @@ */ #define SOC_CSS_NIC400_APB4_BRIDGE 4 +/* Non-volatile counters */ +#define SOC_TRUSTED_NVCTR_BASE 0x7fe70000 +#define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0000) +#define TFW_NVCTR_SIZE 4 +#define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0004) +#define NTFW_CTR_SIZE 4 + /* Keys */ #define SOC_KEYS_BASE 0x7fe80000 #define TZ_PUB_KEY_HASH_BASE (SOC_KEYS_BASE + 0x0000) diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 6f0a8a0f..58575012 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -249,6 +249,8 @@ void bl32_plat_enable_mmu(uint32_t flags); ******************************************************************************/ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags); +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr); +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr); #if ENABLE_PLAT_COMPAT /* diff --git a/make_helpers/build_env.mk b/make_helpers/build_env.mk new file mode 100644 index 00000000..62c7f681 --- /dev/null +++ b/make_helpers/build_env.mk @@ -0,0 +1,96 @@ +# +# 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. +# + +# This file contains the logic to identify and include any relevant +# build environment specific make include files. + +ifndef BUILD_ENV_MK + BUILD_ENV_MK := $(lastword $(MAKEFILE_LIST)) + + # Block possible built-in command definitions that are not fully portable. + # This traps occurences that need replacing with our OS portable macros + COPY := $$(error "Replace COPY with call to SHELL_COPY or SHELL_COPY_TREE.") + CP := $$(error "Replace CP with call to SHELL_COPY or SHELL_COPY_TREE.") + DEL := $$(error "Replace DEL with call to SHELL_DELETE.") + MD := $$(error "Replace MD with call to MAKE_PREREQ_DIR.") + MKDIR := $$(error "Replace MKDIR with call to MAKE_PREREQ_DIR.") + RD := $$(error "Replace RD with call to SHELL_REMOVE_DIR.") + RM := $$(error "Replace RM with call to SHELL_DELETE.") + RMDIR := $$(error "Replace RMDIR with call to SHELL_REMOVE_DIR.") + + ENV_FILE_TO_INCLUDE := unix.mk + ifdef OSTYPE + ifneq ($(findstring ${OSTYPE}, cygwin),) + ENV_FILE_TO_INCLUDE := cygwin.mk + else + ifneq ($(findstring ${OSTYPE}, MINGW32 mingw msys),) + ENV_FILE_TO_INCLUDE := msys.mk + endif + endif + else + ifdef MSYSTEM + # Although the MINGW MSYS shell sets OSTYPE as msys in its environment, + # it does not appear in the GNU make view of environment variables. + # We use MSYSTEM as an alternative, as that is seen by make + ifneq ($(findstring ${MSYSTEM}, MINGW32 mingw msys),) + OSTYPE ?= msys + ENV_FILE_TO_INCLUDE := msys.mk + endif + else + ifdef OS + ifneq ($(findstring ${OS}, Windows_NT),) + ENV_FILE_TO_INCLUDE := windows.mk + endif + endif + endif + endif + include ${MAKE_HELPERS_DIRECTORY}${ENV_FILE_TO_INCLUDE} + ENV_FILE_TO_INCLUDE := + + ifndef SHELL_COPY + $(error "SHELL_COPY not defined for build environment.") + endif + ifndef SHELL_COPY_TREE + $(error "SHELL_COPY_TREE not defined for build environment.") + endif + ifndef SHELL_DELETE_ALL + $(error "SHELL_DELETE_ALL not defined for build environment.") + endif + ifndef SHELL_DELETE + $(error "SHELL_DELETE not defined for build environment.") + endif + ifndef MAKE_PREREQ_DIR + $(error "MAKE_PREREQ_DIR not defined for build environment.") + endif + ifndef SHELL_REMOVE_DIR + $(error "SHELL_REMOVE_DIR not defined for build environment.") + endif + +endif diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index b22eaf90..5171ff00 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2015-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,6 +28,23 @@ # POSSIBILITY OF SUCH DAMAGE. # +# Report an error if the eval make function is not available. +$(eval eval_available := T) +ifneq (${eval_available},T) + $(error This makefile only works with a Make program that supports $$(eval)) +endif + +# Some utility macros for manipulating awkward (whitespace) characters. +blank := +space :=${blank} ${blank} + +# A user defined function to recursively search for a filename below a directory +# $1 is the directory root of the recursive search (blank for current directory). +# $2 is the file name to search for. +define rwildcard +$(strip $(foreach d,$(wildcard ${1}*),$(call rwildcard,${d}/,${2}) $(filter $(subst *,%,%${2}),${d}))) +endef + # This table is used in converting lower case to upper case. uppercase_table:=a,A b,B c,C d,D e,E f,F g,G h,H i,I j,J k,K l,L m,M n,N o,O p,P q,Q r,R s,S t,T u,U v,V w,W x,X y,Y z,Z @@ -193,10 +210,8 @@ $(OBJ): $(2) @echo " CC $$<" $$(Q)$$(CC) $$(CFLAGS) -D$(IMAGE) -c $$< -o $$@ - -$(PREREQUISITES): $(2) +$(PREREQUISITES): $(2) | bl$(3)_dirs @echo " DEPS $$@" - @mkdir -p $(1) $$(Q)$$(CC) $$(CFLAGS) -M -MT $(OBJ) -MF $$@ $$< ifdef IS_ANYTHING_TO_BUILD @@ -220,9 +235,8 @@ $(OBJ): $(2) @echo " AS $$<" $$(Q)$$(AS) $$(ASFLAGS) -D$(IMAGE) -c $$< -o $$@ -$(PREREQUISITES): $(2) +$(PREREQUISITES): $(2) | bl$(3)_dirs @echo " DEPS $$@" - @mkdir -p $(1) $$(Q)$$(AS) $$(ASFLAGS) -M -MT $(OBJ) -MF $$@ $$< ifdef IS_ANYTHING_TO_BUILD @@ -243,9 +257,8 @@ $(1): $(2) @echo " PP $$<" $$(Q)$$(AS) $$(ASFLAGS) -P -E -D__LINKER__ -o $$@ $$< -$(PREREQUISITES): $(2) +$(PREREQUISITES): $(2) | $(dir ${1}) @echo " DEPS $$@" - @mkdir -p $$(dir $$@) $$(Q)$$(AS) $$(ASFLAGS) -M -MT $(1) -MF $$@ $$< ifdef IS_ANYTHING_TO_BUILD @@ -274,7 +287,7 @@ endef # NOTE: The line continuation '\' is required in the next define otherwise we # end up with a line-feed characer at the end of the last c filename. -# Also bare this issue in mind if extending the list of supported filetypes. +# Also bear this issue in mind if extending the list of supported filetypes. define SOURCES_TO_OBJS $(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \ $(notdir $(patsubst %.S,%.o,$(filter %.S,$(1)))) @@ -310,18 +323,36 @@ define MAKE_BL $(eval DUMP := $(call IMG_DUMP,$(1))) $(eval BIN := $(call IMG_BIN,$(1))) $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE)) + # We use sort only to get a list of unique object directory names. + # ordering is not relevant but sort removes duplicates. + $(eval TEMP_OBJ_DIRS := $(sort $(BUILD_DIR)/ $(dir ${OBJS}))) + # The $(dir ) function leaves a trailing / on the directory names + # We append a . then strip /. from each, to remove the trailing / characters + # This gives names suitable for use as make rule targets. + $(eval OBJ_DIRS := $(subst /.,,$(addsuffix .,$(TEMP_OBJ_DIRS)))) + +# Create generators for object directory structure + +$(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},))) - $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) - $(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE))) +.PHONY : bl${1}_dirs -$(BUILD_DIR): - $$(Q)mkdir -p "$$@" +# We use order-only prerequisites to ensure that directories are created, +# but do not cause re-builds every time a file is written. +bl${1}_dirs: | ${OBJ_DIRS} -$(ELF): $(OBJS) $(LINKERFILE) +$(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) +$(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE))) + +$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs @echo " LD $$@" +ifdef MAKE_BUILD_STRINGS + $(call MAKE_BUILD_STRINGS, $(BUILD_DIR)/build_message.o) +else @echo 'const char build_message[] = "Built : "$(BUILD_MESSAGE_TIMESTAMP); \ const char version_string[] = "${VERSION_STRING}";' | \ $$(CC) $$(CFLAGS) -xc - -o $(BUILD_DIR)/build_message.o +endif $$(Q)$$(LD) -o $$@ $$(LDFLAGS) -Map=$(MAPFILE) --script $(LINKERFILE) \ $(BUILD_DIR)/build_message.o $(OBJS) @@ -337,7 +368,7 @@ $(BIN): $(ELF) @echo .PHONY: bl$(1) -bl$(1): $(BUILD_DIR) $(BIN) $(DUMP) +bl$(1): $(BIN) $(DUMP) all: bl$(1) diff --git a/make_helpers/cygwin.mk b/make_helpers/cygwin.mk new file mode 100644 index 00000000..e69c0b1b --- /dev/null +++ b/make_helpers/cygwin.mk @@ -0,0 +1,43 @@ +# +# 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. +# +# + +# OS specific definitions for builds in a Cygwin environment. +# Cygwin allows us to use unix style commands on a windows platform. + +ifndef CYGWIN_MK + CYGWIN_MK := $(lastword $(MAKEFILE_LIST)) + + include ${MAKE_HELPERS_DIRECTORY}unix.mk + + # In cygwin executable files have the Windows .exe extension type. + BIN_EXT := .exe + +endif diff --git a/make_helpers/msys.mk b/make_helpers/msys.mk new file mode 100644 index 00000000..188dc6ca --- /dev/null +++ b/make_helpers/msys.mk @@ -0,0 +1,44 @@ +# +# 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. +# +# + +# OS specific definitions for builds in a Mingw32 MSYS environment. +# Mingw32 allows us to use some unix style commands on a windows platform. + +ifndef MSYS_MK + MSYS_MK := $(lastword $(MAKEFILE_LIST)) + + include ${MAKE_HELPERS_DIRECTORY}unix.mk + + # In MSYS executable files have the Windows .exe extension type. + BIN_EXT := .exe + +endif + diff --git a/make_helpers/plat_helpers.mk b/make_helpers/plat_helpers.mk new file mode 100644 index 00000000..85ba84fe --- /dev/null +++ b/make_helpers/plat_helpers.mk @@ -0,0 +1,62 @@ +# +# 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. +# + +################################################################################ +# Helpers for finding and referencing platform directories +################################################################################ + +ifndef PLAT_HELPERS_MK + PLAT_HELPERS_MK := $(lastword $(MAKEFILE_LIST)) + + ifeq (${PLAT},) + $(error "Error: Unknown platform. Please use PLAT=<platform name> to specify the platform") + endif + + # PLATFORM_ROOT can be overridden for when building tools directly + PLATFORM_ROOT ?= plat/ + PLAT_MAKEFILE := platform.mk + + # Generate the platforms list by recursively searching for all directories + # under /plat containing a PLAT_MAKEFILE. Append each platform with a `|` + # char and strip out the final '|'. + ALL_PLATFORM_MK_FILES := $(call rwildcard,${PLATFORM_ROOT},${PLAT_MAKEFILE}) + ALL_PLATFORM_DIRS := $(patsubst %/,%,$(dir ${ALL_PLATFORM_MK_FILES})) + ALL_PLATFORMS := $(sort $(notdir ${ALL_PLATFORM_DIRS})) + + PLAT_MAKEFILE_FULL := $(filter %/${PLAT}/${PLAT_MAKEFILE},${ALL_PLATFORM_MK_FILES}) + PLATFORM_LIST := $(subst ${space},|,${ALL_PLATFORMS}) + ifeq ($(PLAT_MAKEFILE_FULL),) + $(error "Error: Invalid platform. The following platforms are available: ${PLATFORM_LIST}") + endif + + # Record the directory where the platform make file was found. + PLAT_DIR := $(dir ${PLAT_MAKEFILE_FULL}) + +endif diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk index e934d720..71d97473 100644 --- a/make_helpers/tbbr/tbbr_tools.mk +++ b/make_helpers/tbbr/tbbr_tools.mk @@ -58,6 +58,14 @@ TRUSTED_KEY_CERT := ${BUILD_PLAT}/trusted_key.crt FWU_CERT := ${BUILD_PLAT}/fwu_cert.crt +# Default non-volatile counter values (overridable by the platform) +TFW_NVCTR_VAL ?= 0 +NTFW_NVCTR_VAL ?= 0 + +# Pass the non-volatile counters to the cert_create tool +$(eval $(call CERT_ADD_CMD_OPT,${TFW_NVCTR_VAL},--tfw-nvctr)) +$(eval $(call CERT_ADD_CMD_OPT,${NTFW_NVCTR_VAL},--ntfw-nvctr)) + # Add Trusted Key certificate to the fip_create and cert_create command line options $(eval $(call FIP_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert)) $(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_KEY_CERT},--trusted-key-cert)) diff --git a/make_helpers/unix.mk b/make_helpers/unix.mk new file mode 100644 index 00000000..ab604357 --- /dev/null +++ b/make_helpers/unix.mk @@ -0,0 +1,81 @@ +# +# 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. +# +# + +# Trusted Firmware shell command definitions for a Unix style environment. + +ifndef UNIX_MK + UNIX_MK := $(lastword $(MAKEFILE_LIST)) + + ECHO_BLANK_LINE := echo + + DIR_DELIM := / + PATH_SEP := : + + # These defines provide Unix style equivalents of the shell commands + # required by the Trusted Firmware build environment. + + # ${1} is the file to be copied. + # ${2} is the destination file name. + define SHELL_COPY + ${Q}cp -f "${1}" "${2}" + endef + + # ${1} is the directory to be copied. + # ${2} is the destination directory path. + define SHELL_COPY_TREE + ${Q}cp -rf "${1}" "${2}" + endef + + # ${1} is the file to be deleted. + define SHELL_DELETE + -${Q}rm -f "${1}" + endef + + # ${1} is a space delimited list of files to be deleted. + # Note that we do not quote ${1}, as multiple parameters may be passed. + define SHELL_DELETE_ALL + -${Q}rm -rf ${1} + endef + + # ${1} is the directory to be generated. + # ${2} is optional, and allows a prerequisite to be specified. + define MAKE_PREREQ_DIR + +${1} : ${2} + ${Q}mkdir -p "${1}" + + endef + + define SHELL_REMOVE_DIR + -${Q}rm -rf "${1}" + endef + +endif diff --git a/make_helpers/windows.mk b/make_helpers/windows.mk new file mode 100644 index 00000000..8ac82460 --- /dev/null +++ b/make_helpers/windows.mk @@ -0,0 +1,109 @@ +# +# 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. +# +# + +# OS specific parts for builds in a Windows_NT environment. The +# environment variable OS is set to Windows_NT on all modern Windows platforms + +# Include generic windows command definitions. + +ifndef WINDOWS_MK + WINDOWS_MK := $(lastword $(MAKEFILE_LIST)) + + ECHO_BLANK_LINE := @cmd /c echo. + DIR_DELIM := $(strip \) + BIN_EXT := .exe + PATH_SEP := ; + + # For some Windows native commands there is a problem with the directory delimiter. + # Make uses / (slash) and the commands expect \ (backslash) + # We have to provide a means of translating these, so we define local functions. + + # ${1} is the file to be copied. + # ${2} is the destination file name. + define SHELL_COPY + $(eval tmp_from_file:=$(subst /,\,${1})) + $(eval tmp_to_file:=$(subst /,\,${2})) + copy "${tmp_from_file}" "${tmp_to_file}" + endef + + # ${1} is the directory to be copied. + # ${2} is the destination directory path. + define SHELL_COPY_TREE + $(eval tmp_from_dir:=$(subst /,\,${1})) + $(eval tmp_to_dir:=$(subst /,\,${2})) + xcopy /HIVE "${tmp_from_dir}" "${tmp_to_dir}" + endef + + # ${1} is the file to be deleted. + define SHELL_DELETE + $(eval tmp_del_file:=$(subst /,\,${*})) + -@if exist $(tmp_del_file) del /Q $(tmp_del_file) + endef + + # ${1} is a space delimited list of files to be deleted. + define SHELL_DELETE_ALL + $(eval $(foreach filename,$(wildcard ${1}),$(call DELETE_IF_THERE,${filename}))) + endef + + # ${1} is the directory to be generated. + # ${2} is optional, and allows prerequisites to be specified. + define MAKE_PREREQ_DIR + +${1} : ${2} + $(eval tmp_dir:=$(subst /,\,${1})) + -@if not exist "$(tmp_dir)" mkdir "${tmp_dir}" + + endef + + # ${1} is the directory to be removed. + define SHELL_REMOVE_DIR + $(eval tmp_dir:=$(subst /,\,${1})) + -@if exist "$(tmp_dir)" rd /Q /S "$(tmp_dir)" + endef + +endif + +# Because git is not available from CMD.EXE, we need to avoid +# the BUILD_STRING generation which uses git. +# For now we use "development build". +# This can be overridden from the command line or environment. +BUILD_STRING ?= development build + +# The DOS echo shell command does not strip ' characters from the command +# parameters before printing. We therefore use an alternative method invoked +# by defining the MAKE_BUILD_STRINGS macro. +BUILT_TIME_DATE_STRING = const char build_message[] = "Built : "${BUILD_MESSAGE_TIMESTAMP}; +VERSION_STRING_MESSAGE = const char version_string[] = "${VERSION_STRING}"; +define MAKE_BUILD_STRINGS + @echo $$(BUILT_TIME_DATE_STRING) $$(VERSION_STRING_MESSAGE) | \ + $$(CC) $$(CFLAGS) -x c - -o $1 +endef + diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c index 103aafbf..7ae00cce 100644 --- a/plat/arm/board/common/board_arm_trusted_boot.c +++ b/plat/arm/board/common/board_arm_trusted_boot.c @@ -31,11 +31,14 @@ #include <arm_def.h> #include <assert.h> #include <platform.h> +#include <platform_oid.h> #include <stdint.h> #include <string.h> /* Weak definition may be overridden in specific platform */ #pragma weak plat_match_rotpk +#pragma weak plat_get_nv_ctr +#pragma weak plat_set_nv_ctr /* SHA256 algorithm */ #define SHA256_BYTES 32 @@ -148,3 +151,43 @@ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, return 0; } +/* + * Return the non-volatile counter value stored in the platform. The cookie + * will contain the OID of the counter in the certificate. + * + * Return: 0 = success, Otherwise = error + */ +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) +{ + const char *oid; + uint32_t *nv_ctr_addr; + + assert(cookie != NULL); + assert(nv_ctr != NULL); + + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) { + nv_ctr_addr = (uint32_t *)TFW_NVCTR_BASE; + } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { + nv_ctr_addr = (uint32_t *)NTFW_CTR_BASE; + } else { + return 1; + } + + *nv_ctr = (unsigned int)(*nv_ctr_addr); + + return 0; +} + +/* + * Store a new non-volatile counter value. On Juno and FVP, the non-volatile + * counters are RO and cannot be modified. We expect the values in the + * certificates to always match the RO values so that this function is never + * called. + * + * Return: 0 = success, Otherwise = error + */ +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) +{ + return 1; +} diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk index da6beec6..6ddc0c92 100644 --- a/plat/arm/board/common/board_common.mk +++ b/plat/arm/board/common/board_common.mk @@ -51,6 +51,11 @@ ifneq (${TRUSTED_BOARD_BOOT},0) endif $(eval $(call add_define,ARM_ROTPK_LOCATION_ID)) + # Certificate NV-Counters. Use values corresponding to tied off values in + # ARM development platforms + TFW_NVCTR_VAL ?= 31 + NTFW_NVCTR_VAL ?= 223 + BL1_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c BL2_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c endif diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index dbca280c..b0f07ef5 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -69,7 +69,13 @@ #define PCIE_EXP_BASE 0x40000000 #define TZRNG_BASE 0x7fe60000 -#define TZNVCTR_BASE 0x7fe70000 + +/* Non-volatile counters */ +#define TRUSTED_NVCTR_BASE 0x7fe70000 +#define TFW_NVCTR_BASE (TRUSTED_NVCTR_BASE + 0x0000) +#define TFW_NVCTR_SIZE 4 +#define NTFW_CTR_BASE (TRUSTED_NVCTR_BASE + 0x0004) +#define NTFW_CTR_SIZE 4 /* Keys */ #define SOC_KEYS_BASE 0x7fe80000 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 3428cb51..ca8e35e3 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(); } 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 <arm_def.h> +#include <assert.h> +#include <debug.h> +#include <platform_def.h> +#include <tzc_dmc500.h> + +/******************************************************************************* + * 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()) + ; +} diff --git a/plat/mediatek/mt8173/drivers/spm/spm.c b/plat/mediatek/mt8173/drivers/spm/spm.c index f28b2640..75eb61a0 100644 --- a/plat/mediatek/mt8173/drivers/spm/spm.c +++ b/plat/mediatek/mt8173/drivers/spm/spm.c @@ -49,10 +49,6 @@ #define SPM_SYSCLK_SETTLE 128 /* 3.9ms */ -#if DEBUG -static int spm_dormant_sta = CPU_DORMANT_RESET; -#endif - DEFINE_BAKERY_LOCK(spm_lock); static int spm_hotplug_ready __section("tzfw_coherent_mem"); @@ -378,7 +374,6 @@ enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta) wakesta->raw_sta, wakesta->idle_sta, wakesta->event_reg, wakesta->isr); - INFO("dormant state = %d\n", spm_dormant_sta); return wr; } diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile index 8d7b8a52..27545bae 100644 --- a/tools/cert_create/Makefile +++ b/tools/cert_create/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2015-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: @@ -32,7 +32,7 @@ PROJECT := cert_create PLAT := none V := 0 DEBUG := 0 -BINARY := ${PROJECT} +BINARY := ${PROJECT}${BIN_EXT} OPENSSL_DIR := /usr OBJECTS := src/cert.o \ @@ -47,15 +47,17 @@ OBJECTS := src/cert.o \ CFLAGS := -Wall -std=c99 -# Check the platform -ifeq (${PLAT},none) - $(error "Error: Unknown platform. Please use PLAT=<platform name> to specify the platform") -endif -PLAT_MAKEFILE := platform.mk -PLAT_INCLUDE := $(shell find ../../plat/ -wholename '*/${PLAT}/${PLAT_MAKEFILE}' | \ - sed 's/${PLAT_MAKEFILE}/include/') +MAKE_HELPERS_DIRECTORY := ../../make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk + +PLATFORM_ROOT := ../../plat/ +include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk + +PLAT_INCLUDE := $(wildcard ${PLAT_DIR}include) + ifeq ($(PLAT_INCLUDE),) - $(error "Error: Invalid platform '${PLAT}'") + $(error "Error: Invalid platform '${PLAT}' has no include directory.") endif ifeq (${DEBUG},1) @@ -76,9 +78,8 @@ LIB_DIR := -L ${OPENSSL_DIR}/lib LIB := -lssl -lcrypto CC := gcc -RM := rm -rf -.PHONY: all clean +.PHONY: all clean realclean all: clean ${BINARY} @@ -94,7 +95,8 @@ ${BINARY}: ${OBJECTS} Makefile ${Q}${CC} -c ${CFLAGS} ${INC_DIR} $< -o $@ clean: - ${Q}${RM} -f src/build_msg.o ${OBJECTS} + $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS}) realclean: clean - ${Q}${RM} -f ${BINARY} + $(call SHELL_DELETE, ${BINARY}) + diff --git a/tools/cert_create/include/ext.h b/tools/cert_create/include/ext.h index 82a4bcb9..95bde6ce 100644 --- a/tools/cert_create/include/ext.h +++ b/tools/cert_create/include/ext.h @@ -35,12 +35,18 @@ #include <openssl/x509v3.h> /* Extension types supported */ -enum { +enum ext_type_e { EXT_TYPE_NVCOUNTER, EXT_TYPE_PKEY, EXT_TYPE_HASH }; +/* NV-Counter types */ +enum nvctr_type_e { + NVCTR_TYPE_TFW, + NVCTR_TYPE_NTFW +}; + /* * This structure contains the relevant information to create the extensions * to be included in the certificates. This extensions will be used to @@ -50,20 +56,21 @@ typedef struct ext_s { const char *oid; /* OID of the extension */ const char *sn; /* Short name */ const char *ln; /* Long description */ + const char *opt; /* Command line option to specify data */ const char *help_msg; /* Help message */ + const char *arg; /* Argument passed from command line */ int asn1_type; /* OpenSSL ASN1 type of the extension data. * Supported types are: * - V_ASN1_INTEGER * - V_ASN1_OCTET_STRING */ - int type; - const char *opt; /* Command line option to specify data */ - /* Extension data (depends on extension type) */ + int type; /* See ext_type_e */ + + /* Extension attributes (depends on extension type) */ union { - const char *fn; /* File with extension data */ - int nvcounter; /* Non volatile counter */ - int key; /* Public key */ - } data; + int nvctr_type; /* See nvctr_type_e */ + int key; /* Index into array of registered public keys */ + } attr; int alias; /* In case OpenSSL provides an standard * extension of the same type, add the new diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c index 3d2b4ba2..c87d9888 100644 --- a/tools/cert_create/src/main.c +++ b/tools/cert_create/src/main.c @@ -196,9 +196,17 @@ static void check_cmd_params(void) for (j = 0; j < cert->num_ext; j++) { ext = &extensions[cert->ext[j]]; switch (ext->type) { + case EXT_TYPE_NVCOUNTER: + /* Counter value must be specified */ + if ((!ext->optional) && (ext->arg == NULL)) { + ERROR("Value for '%s' not specified\n", + ext->ln); + exit(1); + } + break; case EXT_TYPE_PKEY: /* Key filename must be specified */ - key = &keys[ext->data.key]; + key = &keys[ext->attr.key]; if (!new_keys && key->fn == NULL) { ERROR("Key '%s' required by '%s' not " "specified\n", key->desc, @@ -211,15 +219,15 @@ static void check_cmd_params(void) * Binary image must be specified * unless it is explicitly made optional. */ - if ((!ext->optional) && (ext->data.fn == NULL)) { + if ((!ext->optional) && (ext->arg == NULL)) { ERROR("Image for '%s' not specified\n", ext->ln); exit(1); } break; default: - ERROR("Unknown extension type in '%s'\n", - ext->ln); + ERROR("Unknown extension type '%d' in '%s'\n", + ext->type, ext->ln); exit(1); break; } @@ -259,7 +267,7 @@ int main(int argc, char *argv[]) key_t *key = NULL; cert_t *cert = NULL; FILE *file = NULL; - int i, j, ext_nid; + int i, j, ext_nid, nvctr; int c, opt_idx = 0; const struct option *cmd_opt; const char *cur_opt; @@ -331,7 +339,7 @@ int main(int argc, char *argv[]) case CMD_OPT_EXT: cur_opt = cmd_opt_get_name(opt_idx); ext = ext_get_by_opt(cur_opt); - ext->data.fn = strdup(optarg); + ext->arg = strdup(optarg); break; case CMD_OPT_KEY: cur_opt = cmd_opt_get_name(opt_idx); @@ -420,11 +428,12 @@ int main(int argc, char *argv[]) */ switch (ext->type) { case EXT_TYPE_NVCOUNTER: + nvctr = atoi(ext->arg); CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, - EXT_CRIT, ext->data.nvcounter)); + EXT_CRIT, nvctr)); break; case EXT_TYPE_HASH: - if (ext->data.fn == NULL) { + if (ext->arg == NULL) { if (ext->optional) { /* Include a hash filled with zeros */ memset(md, 0x0, SHA256_DIGEST_LENGTH); @@ -434,9 +443,9 @@ int main(int argc, char *argv[]) } } else { /* Calculate the hash of the file */ - if (!sha_file(ext->data.fn, md)) { + if (!sha_file(ext->arg, md)) { ERROR("Cannot calculate hash of %s\n", - ext->data.fn); + ext->arg); exit(1); } } @@ -446,11 +455,11 @@ int main(int argc, char *argv[]) break; case EXT_TYPE_PKEY: CHECK_NULL(cert_ext, ext_new_key(ext_nid, - EXT_CRIT, keys[ext->data.key].key)); + EXT_CRIT, keys[ext->attr.key].key)); break; default: - ERROR("Unknown extension type in %s\n", - cert->cn); + ERROR("Unknown extension type '%d' in %s\n", + ext->type, cert->cn); exit(1); } diff --git a/tools/cert_create/src/tbbr/tbb_cert.c b/tools/cert_create/src/tbbr/tbb_cert.c index 7a50ab35..8f7feb51 100644 --- a/tools/cert_create/src/tbbr/tbb_cert.c +++ b/tools/cert_create/src/tbbr/tbb_cert.c @@ -49,9 +49,10 @@ static cert_t tbb_certs[] = { .key = ROT_KEY, .issuer = TRUSTED_BOOT_FW_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_BOOT_FW_HASH_EXT }, - .num_ext = 1 + .num_ext = 2 }, [TRUSTED_KEY_CERT] = { .id = TRUSTED_KEY_CERT, @@ -62,10 +63,11 @@ static cert_t tbb_certs[] = { .key = ROT_KEY, .issuer = TRUSTED_KEY_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_WORLD_PK_EXT, NON_TRUSTED_WORLD_PK_EXT }, - .num_ext = 2 + .num_ext = 3 }, [SCP_FW_KEY_CERT] = { .id = SCP_FW_KEY_CERT, @@ -76,9 +78,10 @@ static cert_t tbb_certs[] = { .key = TRUSTED_WORLD_KEY, .issuer = SCP_FW_KEY_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, SCP_FW_CONTENT_CERT_PK_EXT }, - .num_ext = 1 + .num_ext = 2 }, [SCP_FW_CONTENT_CERT] = { .id = SCP_FW_CONTENT_CERT, @@ -89,9 +92,10 @@ static cert_t tbb_certs[] = { .key = SCP_FW_CONTENT_CERT_KEY, .issuer = SCP_FW_CONTENT_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, SCP_FW_HASH_EXT }, - .num_ext = 1 + .num_ext = 2 }, [SOC_FW_KEY_CERT] = { .id = SOC_FW_KEY_CERT, @@ -102,9 +106,10 @@ static cert_t tbb_certs[] = { .key = TRUSTED_WORLD_KEY, .issuer = SOC_FW_KEY_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, SOC_FW_CONTENT_CERT_PK_EXT }, - .num_ext = 1 + .num_ext = 2 }, [SOC_FW_CONTENT_CERT] = { .id = SOC_FW_CONTENT_CERT, @@ -115,9 +120,10 @@ static cert_t tbb_certs[] = { .key = SOC_FW_CONTENT_CERT_KEY, .issuer = SOC_FW_CONTENT_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, SOC_AP_FW_HASH_EXT }, - .num_ext = 1 + .num_ext = 2 }, [TRUSTED_OS_FW_KEY_CERT] = { .id = TRUSTED_OS_FW_KEY_CERT, @@ -128,9 +134,10 @@ static cert_t tbb_certs[] = { .key = TRUSTED_WORLD_KEY, .issuer = TRUSTED_OS_FW_KEY_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_OS_FW_CONTENT_CERT_PK_EXT }, - .num_ext = 1 + .num_ext = 2 }, [TRUSTED_OS_FW_CONTENT_CERT] = { .id = TRUSTED_OS_FW_CONTENT_CERT, @@ -141,9 +148,10 @@ static cert_t tbb_certs[] = { .key = TRUSTED_OS_FW_CONTENT_CERT_KEY, .issuer = TRUSTED_OS_FW_CONTENT_CERT, .ext = { + TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_OS_FW_HASH_EXT }, - .num_ext = 1 + .num_ext = 2 }, [NON_TRUSTED_FW_KEY_CERT] = { .id = NON_TRUSTED_FW_KEY_CERT, @@ -154,9 +162,10 @@ static cert_t tbb_certs[] = { .key = NON_TRUSTED_WORLD_KEY, .issuer = NON_TRUSTED_FW_KEY_CERT, .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, NON_TRUSTED_FW_CONTENT_CERT_PK_EXT }, - .num_ext = 1 + .num_ext = 2 }, [NON_TRUSTED_FW_CONTENT_CERT] = { .id = NON_TRUSTED_FW_CONTENT_CERT, @@ -167,9 +176,10 @@ static cert_t tbb_certs[] = { .key = NON_TRUSTED_FW_CONTENT_CERT_KEY, .issuer = NON_TRUSTED_FW_CONTENT_CERT, .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT }, - .num_ext = 1 + .num_ext = 2 }, [FWU_CERT] = { .id = FWU_CERT, diff --git a/tools/cert_create/src/tbbr/tbb_ext.c b/tools/cert_create/src/tbbr/tbb_ext.c index 8bcb0704..5304bd5e 100644 --- a/tools/cert_create/src/tbbr/tbb_ext.c +++ b/tools/cert_create/src/tbbr/tbb_ext.c @@ -44,19 +44,23 @@ static ext_t tbb_ext[] = { [TRUSTED_FW_NVCOUNTER_EXT] = { .oid = TRUSTED_FW_NVCOUNTER_OID, + .opt = "tfw-nvctr", + .help_msg = "Trusted Firmware Non-Volatile counter value", .sn = "TrustedWorldNVCounter", .ln = "Trusted World Non-Volatile counter", .asn1_type = V_ASN1_INTEGER, .type = EXT_TYPE_NVCOUNTER, - .data.nvcounter = TRUSTED_WORLD_NVCTR_VALUE + .attr.nvctr_type = NVCTR_TYPE_TFW }, [NON_TRUSTED_FW_NVCOUNTER_EXT] = { .oid = NON_TRUSTED_FW_NVCOUNTER_OID, + .opt = "ntfw-nvctr", + .help_msg = "Non-Trusted Firmware Non-Volatile counter value", .sn = "NormalWorldNVCounter", - .ln = "Normal World Non-Volatile counter", + .ln = "Non-Trusted Firmware Non-Volatile counter", .asn1_type = V_ASN1_INTEGER, .type = EXT_TYPE_NVCOUNTER, - .data.nvcounter = NORMAL_WORLD_NVCTR_VALUE + .attr.nvctr_type = NVCTR_TYPE_NTFW }, [TRUSTED_BOOT_FW_HASH_EXT] = { .oid = TRUSTED_BOOT_FW_HASH_OID, @@ -73,7 +77,7 @@ static ext_t tbb_ext[] = { .ln = "Trusted World Public Key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = TRUSTED_WORLD_KEY + .attr.key = TRUSTED_WORLD_KEY }, [NON_TRUSTED_WORLD_PK_EXT] = { .oid = NON_TRUSTED_WORLD_PK_OID, @@ -81,7 +85,7 @@ static ext_t tbb_ext[] = { .ln = "Non-Trusted World Public Key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = NON_TRUSTED_WORLD_KEY + .attr.key = NON_TRUSTED_WORLD_KEY }, [SCP_FW_CONTENT_CERT_PK_EXT] = { .oid = SCP_FW_CONTENT_CERT_PK_OID, @@ -89,7 +93,7 @@ static ext_t tbb_ext[] = { .ln = "SCP Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = SCP_FW_CONTENT_CERT_KEY + .attr.key = SCP_FW_CONTENT_CERT_KEY }, [SCP_FW_HASH_EXT] = { .oid = SCP_FW_HASH_OID, @@ -106,7 +110,7 @@ static ext_t tbb_ext[] = { .ln = "SoC Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = SOC_FW_CONTENT_CERT_KEY + .attr.key = SOC_FW_CONTENT_CERT_KEY }, [SOC_AP_FW_HASH_EXT] = { .oid = SOC_AP_FW_HASH_OID, @@ -123,7 +127,7 @@ static ext_t tbb_ext[] = { .ln = "Trusted OS Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = TRUSTED_OS_FW_CONTENT_CERT_KEY + .attr.key = TRUSTED_OS_FW_CONTENT_CERT_KEY }, [TRUSTED_OS_FW_HASH_EXT] = { .oid = TRUSTED_OS_FW_HASH_OID, @@ -140,7 +144,7 @@ static ext_t tbb_ext[] = { .ln = "Non-Trusted Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, - .data.key = NON_TRUSTED_FW_CONTENT_CERT_KEY + .attr.key = NON_TRUSTED_FW_CONTENT_CERT_KEY }, [NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = { .oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID, diff --git a/tools/fip_create/Makefile b/tools/fip_create/Makefile index c72bae53..2e367c2f 100644 --- a/tools/fip_create/Makefile +++ b/tools/fip_create/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 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,38 +28,56 @@ # POSSIBILITY OF SUCH DAMAGE. # -PROJECT = fip_create -OBJECTS = fip_create.o +MAKE_HELPERS_DIRECTORY := ../../make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk -CFLAGS = -Wall -Werror -pedantic -std=c99 +PROJECT := fip_create${BIN_EXT} +OBJECTS := fip_create.o +COPIED_H_FILES := uuid.h firmware_image_package.h + +CFLAGS := -Wall -Werror -pedantic -std=c99 ifeq (${DEBUG},1) CFLAGS += -g -O0 -DDEBUG else CFLAGS += -O2 endif -# Make soft links and include from local directory otherwise wrong headers -# could get pulled in from firmware tree. -INCLUDE_PATHS = -I. +# Only include from local directory (see comment below). +INCLUDE_PATHS := -I. CC := gcc -RM := rm -rf -.PHONY: all clean +.PHONY: all clean distclean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " LD $@" ${Q}${CC} ${OBJECTS} -o $@ - @echo + @${ECHO_BLANK_LINE} @echo "Built $@ successfully" - @echo + @${ECHO_BLANK_LINE} -%.o: %.c %.h Makefile +%.o: %.c %.h ${COPIED_H_FILES} Makefile @echo " CC $<" ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ +# +# Copy required library headers to a local directory so they can be included +# by this project without adding the library directories to the system include +# path. This avoids conflicts with definitions in the compiler standard +# include path. +# +uuid.h : ../../include/stdlib/sys/uuid.h + $(call SHELL_COPY,$<,$@) + +firmware_image_package.h : ../../include/common/firmware_image_package.h + $(call SHELL_COPY,$<,$@) + clean: - ${Q}${RM} ${PROJECT} - ${Q}${RM} ${OBJECTS} + $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) + +distclean: clean + $(call SHELL_DELETE_ALL, ${COPIED_H_FILES}) + diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c index 19afc748..7bce348a 100644 --- a/tools/fip_create/fip_create.c +++ b/tools/fip_create/fip_create.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: @@ -40,12 +40,19 @@ /* Values returned by getopt() as part of the command line parsing */ #define OPT_TOC_ENTRY 0 -#define OPT_DUMP 1 -#define OPT_HELP 2 - -file_info_t files[MAX_FILES]; -unsigned file_info_count = 0; -uuid_t uuid_null = {0}; +#define OPT_DUMP 'd' +#define OPT_HELP 'h' +#define OPT_UNPACK 'u' +#define OPT_FORCE 'f' +#define OPT_STR "dfhu" + +static file_info_t files[MAX_FILES]; +static unsigned file_info_count; +static uuid_t uuid_null = {0}; +static int do_dump; +static int do_pack; +static int do_unpack; +static int do_force; /* * TODO: Add ability to specify and flag different file types. @@ -118,12 +125,15 @@ static void print_usage(void) { entry_lookup_list_t *entry = toc_entry_lookup_list; - printf("Usage: fip_create [options] FIP_FILENAME\n\n"); - printf("\tThis tool is used to create a Firmware Image Package.\n\n"); + printf("\nThis tool is used to create a Firmware Image Package.\n\n"); + printf("Usage:\n"); + printf("\tfip_create [options] FIP_FILENAME\n\n"); printf("Options:\n"); - printf("\t--help: Print this help message and exit\n"); - printf("\t--dump: Print contents of FIP\n\n"); - printf("\tComponents that can be added/updated:\n"); + printf("\t-h,--help: Print this help message and exit\n"); + printf("\t-d,--dump: Print contents of FIP after update\n"); + printf("\t-u,--unpack: Unpack images from an existing FIP\n"); + printf("\t-f,--force: Overwrite existing files when unpacking images\n\n"); + printf("Components that can be added/updated:\n"); for (; entry->command_line_name != NULL; entry++) { printf("\t--%s%s\t\t%s", entry->command_line_name, @@ -131,6 +141,7 @@ static void print_usage(void) entry->name); printf("\n"); } + printf("\n"); } @@ -371,6 +382,109 @@ static int pack_images(const char *fip_filename) } +/* + * Unpack all images from an existing FIP + * + * Images will be unpacked into the working directory using filenames as + * specified by the corresponding command line option plus the 'bin' extension. + * For example, the image specified by the --soc-fw option will be unpacked as + * 'soc-fw.bin' + */ +static int unpack_images(void) +{ + FILE *stream; + size_t bytes_written; + file_info_t *file_info; + char *filename[MAX_FILES]; + int status, ret = 0; + unsigned int i, idx, num_img; + struct stat st; + size_t len; + + /* Make the output filenames */ + for (idx = 0; idx < file_info_count; idx++) { + filename[idx] = NULL; + file_info = &files[idx]; + if (file_info->image_buffer == NULL) { + continue; + } + len = strlen(file_info->entry->command_line_name); + filename[idx] = malloc(len + 5); /* ".bin" + '\0' */ + if (filename[idx] == NULL) { + printf("ERROR: out of memory\n"); + for (i = 0; i < idx; i++) { + free(filename[i]); + } + return ENOMEM; + } + strcpy(filename[idx], file_info->entry->command_line_name); + strcat(filename[idx], ".bin"); + } + + + /* Check if output files already exist in the filesystem. We perform + * this check before any other action, so if any of the files + * exists, nothing is unpacked. If force overwrite is enabled, we skip + * this check */ + if (!do_force) { + for (idx = 0; idx < file_info_count; idx++) { + file_info = &files[idx]; + if (file_info->image_buffer == NULL) { + continue; + } + status = stat(filename[idx], &st); + if (!status) { + printf("File '%s' exists. Use --force to overwrite.\n", + filename[idx]); + printf("Process aborted.\n"); + ret = EEXIST; + goto unpack_images_free; + } + } + } + + printf("Unpacking images...\n"); + + /* Write the images to files */ + num_img = 0; + for (idx = 0; idx < file_info_count; idx++) { + file_info = &files[idx]; + if (file_info->image_buffer == NULL) { + continue; + } + /* Unpack the image to a file */ + stream = fopen(filename[idx], "w"); + if (!stream) { + printf("ERROR: cannot open '%s' for writing\n", + filename[idx]); + ret = EIO; + goto unpack_images_free; + } + bytes_written = fwrite(file_info->image_buffer, sizeof(uint8_t), + file_info->size, stream); + fclose(stream); + + if (bytes_written != file_info->size) { + printf("ERROR: Incorrect write for file \"%s\": Size=%u," + "Written=%lu bytes.\n", filename[idx], file_info->size, + bytes_written); + ret = EIO; + goto unpack_images_free; + } + num_img++; + } + + printf("Done. %u images unpacked\n", num_img); + +unpack_images_free: + for (idx = 0; idx < file_info_count; idx++) { + free(filename[idx]); + } + + return ret; +} + + static void dump_toc(void) { unsigned int index = 0; @@ -528,7 +642,7 @@ static char *get_filename(int argc, char **argv, struct option *options) */ optind = 1; while (1) { - c = getopt_long(argc, argv, "", options, NULL); + c = getopt_long(argc, argv, OPT_STR, options, NULL); if (c == -1) break; @@ -549,19 +663,17 @@ static char *get_filename(int argc, char **argv, struct option *options) /* Work through command-line options */ -static int parse_cmdline(int argc, char **argv, struct option *options, - int *do_pack) +static int parse_cmdline(int argc, char **argv, struct option *options) { int c; int status = 0; int option_index = 0; entry_lookup_list_t *lookup_entry; - int do_dump = 0; /* restart parse to process all options. starts at 1. */ optind = 1; while (1) { - c = getopt_long(argc, argv, "", options, &option_index); + c = getopt_long(argc, argv, OPT_STR, options, &option_index); if (c == -1) break; @@ -578,7 +690,7 @@ static int parse_cmdline(int argc, char **argv, struct option *options, return status; } else { /* Update package */ - *do_pack = 1; + do_pack = 1; } } } @@ -586,24 +698,26 @@ static int parse_cmdline(int argc, char **argv, struct option *options, case OPT_DUMP: do_dump = 1; - continue; + break; case OPT_HELP: print_usage(); exit(0); + case OPT_UNPACK: + do_unpack = 1; + break; + + case OPT_FORCE: + do_force = 1; + break; + default: /* Unrecognised options are caught in get_filename() */ break; } } - - /* Do not dump toc if we have an error as it could hide the error */ - if ((status == 0) && (do_dump)) { - dump_toc(); - } - return status; } @@ -613,17 +727,17 @@ int main(int argc, char **argv) int i; int status; char *fip_filename; - int do_pack = 0; + struct stat st; /* Clear file list table. */ memset(files, 0, sizeof(files)); /* Initialise for getopt_long(). * Use image table as defined at top of file to get options. - * Add 'dump' option, 'help' option and end marker. + * Add common options and end marker. */ static struct option long_options[(sizeof(toc_entry_lookup_list)/ - sizeof(entry_lookup_list_t)) + 2]; + sizeof(entry_lookup_list_t)) + 4]; for (i = 0; /* -1 because we dont want to process end marker in toc table */ @@ -648,6 +762,18 @@ int main(int argc, char **argv) long_options[i].flag = 0; long_options[i].val = OPT_HELP; + /* Add '--unpack' option */ + long_options[++i].name = "unpack"; + long_options[i].has_arg = 0; + long_options[i].flag = 0; + long_options[i].val = OPT_UNPACK; + + /* Add '--force' option */ + long_options[++i].name = "force"; + long_options[i].has_arg = 0; + long_options[i].flag = 0; + long_options[i].val = OPT_FORCE; + /* Zero the last entry (required) */ long_options[++i].name = 0; long_options[i].has_arg = 0; @@ -677,7 +803,7 @@ int main(int argc, char **argv) } /* Work through provided program arguments and perform actions */ - status = parse_cmdline(argc, argv, long_options, &do_pack); + status = parse_cmdline(argc, argv, long_options); if (status != 0) { return status; }; @@ -688,10 +814,28 @@ int main(int argc, char **argv) return 0; } - /* Processed all command line options. Create/update the package if - * required. - */ - if (do_pack) { + /* Unpack images from FIP always takes precedence over packaging. In + * the future, there will be different commands for each action and + * only one will be specified in the command line */ + if (do_unpack) { + status = stat(fip_filename, &st); + if (status != 0) { + printf("ERROR: cannot open %s\n", fip_filename); + return status; + } + /* Warning if user has specified images */ + if (do_pack) { + printf("WARNING: Unpack option specified. Input images " + "will be ignored.\n"); + } + status = unpack_images(); + if (status != 0) { + printf("ERROR: failed to unpack package (status = %d).\n", + status); + return status; + } + } else if (do_pack) { + /* Create/update FIP */ status = pack_images(fip_filename); if (status != 0) { printf("Failed to create package (status = %d).\n", @@ -699,5 +843,10 @@ int main(int argc, char **argv) } } + /* Do not dump toc if we have an error as it could hide the error */ + if ((status == 0) && (do_dump)) { + dump_toc(); + } + return status; } diff --git a/tools/fip_create/firmware_image_package.h b/tools/fip_create/firmware_image_package.h deleted file mode 120000 index cc61903e..00000000 --- a/tools/fip_create/firmware_image_package.h +++ /dev/null @@ -1 +0,0 @@ -../../include/common/firmware_image_package.h
\ No newline at end of file diff --git a/tools/fip_create/uuid.h b/tools/fip_create/uuid.h deleted file mode 120000 index c77762f4..00000000 --- a/tools/fip_create/uuid.h +++ /dev/null @@ -1 +0,0 @@ -../../include/stdlib/sys/uuid.h
\ No newline at end of file |