diff options
55 files changed, 3623 insertions, 166 deletions
@@ -87,8 +87,14 @@ TRUSTED_BOARD_BOOT := 0 # By default, consider that the platform's reset address is not programmable. # The platform Makefile is free to override this value. PROGRAMMABLE_RESET_ADDRESS := 0 -# Build flag to warn about usage of deprecated platform and framework APIs -WARN_DEPRECATED := 0 +# Build flag to treat usage of deprecated platform and framework APIs as error. +ERROR_DEPRECATED := 0 +# By default, consider that the platform may release several CPUs out of reset. +# The platform Makefile is free to override this value. +COLD_BOOT_SINGLE_CPU := 0 +# Flag to introduce an infinite loop in BL1 just before it exits into the next +# image. This is meant to help debugging the post-BL2 phase. +SPIN_ON_BL1_EXIT := 0 ################################################################################ @@ -232,6 +238,10 @@ INCLUDE_TBBR_MK := 1 ################################################################################ ifneq (${SPD},none) +ifdef EL3_PAYLOAD_BASE + $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.") + $(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") @@ -297,7 +307,12 @@ endif # supplied for the FIP and Certificate generation tools. This flag can be # overridden by the platform. ifdef BL2_SOURCES +ifndef EL3_PAYLOAD_BASE NEED_BL33 ?= yes +else +# The BL33 image is not needed when booting an EL3 payload. +NEED_BL33 := no +endif endif # Process TBB related flags @@ -345,9 +360,11 @@ $(eval $(call assert_boolean,CREATE_KEYS)) $(eval $(call assert_boolean,SAVE_KEYS)) $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT)) $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS)) +$(eval $(call assert_boolean,COLD_BOOT_SINGLE_CPU)) $(eval $(call assert_boolean,PSCI_EXTENDED_STATE_ID)) -$(eval $(call assert_boolean,WARN_DEPRECATED)) +$(eval $(call assert_boolean,ERROR_DEPRECATED)) $(eval $(call assert_boolean,ENABLE_PLAT_COMPAT)) +$(eval $(call assert_boolean,SPIN_ON_BL1_EXIT)) ################################################################################ @@ -367,9 +384,15 @@ $(eval $(call add_define,LOG_LEVEL)) $(eval $(call add_define,USE_COHERENT_MEM)) $(eval $(call add_define,TRUSTED_BOARD_BOOT)) $(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS)) +$(eval $(call add_define,COLD_BOOT_SINGLE_CPU)) $(eval $(call add_define,PSCI_EXTENDED_STATE_ID)) -$(eval $(call add_define,WARN_DEPRECATED)) +$(eval $(call add_define,ERROR_DEPRECATED)) $(eval $(call add_define,ENABLE_PLAT_COMPAT)) +$(eval $(call add_define,SPIN_ON_BL1_EXIT)) +# Define the EL3_PAYLOAD_BASE flag only if it is provided. +ifdef EL3_PAYLOAD_BASE +$(eval $(call add_define,EL3_PAYLOAD_BASE)) +endif ################################################################################ @@ -387,9 +410,13 @@ include bl2/bl2.mk endif ifdef BL31_SOURCES +# When booting an EL3 payload, there is no need to compile the BL31 image nor +# put it in the FIP. +ifndef EL3_PAYLOAD_BASE NEED_BL31 := yes include bl31/bl31.mk endif +endif ################################################################################ @@ -404,6 +431,11 @@ all: msg_start msg_start: @echo "Building ${PLAT}" +# Check if deprecated declarations should be treated as error or not. +ifeq (${ERROR_DEPRECATED},0) + CFLAGS += -Wno-error=deprecated-declarations +endif + # Expand build macros for the different images ifeq (${NEED_BL1},yes) $(eval $(call MAKE_BL,1)) diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S index 4fc52918..83594f21 100644 --- a/bl1/aarch64/bl1_entrypoint.S +++ b/bl1/aarch64/bl1_entrypoint.S @@ -51,7 +51,7 @@ func bl1_entrypoint el3_entrypoint_common \ _set_endian=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ - _secondary_cold_boot=1 \ + _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=bl1_exceptions diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S index 0bd04857..5415d395 100644 --- a/bl1/aarch64/bl1_exceptions.S +++ b/bl1/aarch64/bl1_exceptions.S @@ -207,6 +207,13 @@ func smc_handler64 bl disable_mmu_icache_el3 tlbi alle3 +#if SPIN_ON_BL1_EXIT + bl print_debug_loop_message +debug_loop: + b debug_loop +#endif + + mov x0, x20 bl bl1_plat_prepare_exit ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)] diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c index f62f31d5..73f023ab 100644 --- a/bl1/bl1_main.c +++ b/bl1/bl1_main.c @@ -208,3 +208,11 @@ void bl1_print_bl31_ep_info(const entry_point_info_t *bl31_ep_info) NOTICE("BL1: Booting BL3-1\n"); print_entry_point_info(bl31_ep_info); } + +#if SPIN_ON_BL1_EXIT +void print_debug_loop_message(void) +{ + NOTICE("BL1: Debug loop, spinning forever\n"); + NOTICE("BL1: Please connect the debugger to continue\n"); +} +#endif diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index f8a2372f..a3f016f9 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -83,6 +83,7 @@ static int load_bl30(void) return e; } +#ifndef EL3_PAYLOAD_BASE /******************************************************************************* * Load the BL3-1 image. * The bl2_to_bl31_params and bl31_ep_info params will be updated with the @@ -190,6 +191,7 @@ static int load_bl33(bl31_params_t *bl2_to_bl31_params) return e; } +#endif /* EL3_PAYLOAD_BASE */ /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to @@ -232,6 +234,22 @@ void bl2_main(void) bl2_to_bl31_params = bl2_plat_get_bl31_params(); bl31_ep_info = bl2_plat_get_bl31_ep_info(); +#ifdef EL3_PAYLOAD_BASE + /* + * In the case of an EL3 payload, we don't need to load any further + * images. Just update the BL31 entrypoint info structure to make BL1 + * jump to the EL3 payload. + * The pointer to the memory the platform has set aside to pass + * information to BL3-1 in the normal boot flow is reused here, even + * though only a fraction of the information contained in the + * bl31_params_t structure makes sense in the context of EL3 payloads. + * This will be refined in the future. + */ + VERBOSE("BL2: Populating the entrypoint info for the EL3 payload\n"); + bl31_ep_info->pc = EL3_PAYLOAD_BASE; + bl31_ep_info->args.arg0 = (unsigned long) bl2_to_bl31_params; + bl2_plat_set_bl31_ep_info(NULL, bl31_ep_info); +#else e = load_bl31(bl2_to_bl31_params, bl31_ep_info); if (e) { ERROR("Failed to load BL3-1 (%i)\n", e); @@ -253,6 +271,7 @@ void bl2_main(void) ERROR("Failed to load BL3-3 (%i)\n", e); plat_error_handler(e); } +#endif /* EL3_PAYLOAD_BASE */ /* Flush the params to be passed to memory */ bl2_plat_flush_bl31_params(); diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index 636b1d28..45aa85dc 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -85,7 +85,7 @@ func bl31_entrypoint el3_entrypoint_common \ _set_endian=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ - _secondary_cold_boot=1 \ + _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=runtime_exceptions diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index bbc7f1b4..28353202 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -130,16 +130,6 @@ mov x21, x0 mov x0, #INTR_ID_UNAVAILABLE -#if IMF_READ_INTERRUPT_ID - /* - * Read the id of the highest priority pending interrupt. If - * no interrupt is asserted then return to where we came from. - */ - mov x19, #INTR_ID_UNAVAILABLE - bl plat_ic_get_pending_interrupt_id - cmp x19, x0 - b.eq interrupt_exit_\label -#endif /* Set the current security state in the 'flags' parameter */ mrs x2, scr_el3 diff --git a/bl31/bl31.mk b/bl31/bl31.mk index 04e15420..a31c1f47 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -60,13 +60,6 @@ endif BL31_LINKERFILE := bl31/bl31.ld.S -# Flag used by the generic interrupt management framework to determine if -# upon the assertion of an interrupt, it should pass the interrupt id or not -IMF_READ_INTERRUPT_ID := 0 - -$(eval $(call assert_boolean,IMF_READ_INTERRUPT_ID)) -$(eval $(call add_define,IMF_READ_INTERRUPT_ID)) - # Flag used to inidicate if Crash reporting via console should be included # in BL3-1. This defaults to being present in DEBUG builds only ifndef CRASH_REPORTING diff --git a/bl31/context_mgmt.c b/bl31/context_mgmt.c index a0fd1b65..6d405343 100644 --- a/bl31/context_mgmt.c +++ b/bl31/context_mgmt.c @@ -90,6 +90,14 @@ void cm_set_context_by_index(unsigned int cpu_idx, void *context, set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context); } +#if !ERROR_DEPRECATED +/* + * These context management helpers are deprecated but are maintained for use + * by SPDs which have not migrated to the new API. If ERROR_DEPRECATED + * is enabled, these are excluded from the build so as to force users to + * migrate to the new API. + */ + /******************************************************************************* * This function returns a pointer to the most recent 'cpu_context' structure * for the CPU identified by MPIDR that was set as the context for the specified @@ -115,6 +123,21 @@ void cm_set_context_by_mpidr(uint64_t mpidr, void *context, uint32_t security_st } /******************************************************************************* + * The following function provides a compatibility function for SPDs using the + * existing cm library routines. This function is expected to be invoked for + * initializing the cpu_context for the CPU specified by MPIDR for first use. + ******************************************************************************/ +void cm_init_context(unsigned long mpidr, const entry_point_info_t *ep) +{ + if ((mpidr & MPIDR_AFFINITY_MASK) == + (read_mpidr_el1() & MPIDR_AFFINITY_MASK)) + cm_init_my_context(ep); + else + cm_init_context_by_index(platform_get_core_pos(mpidr), ep); +} +#endif + +/******************************************************************************* * This function is used to program the context that's used for exception * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for * the required security state @@ -261,20 +284,6 @@ void cm_init_my_context(const entry_point_info_t *ep) } /******************************************************************************* - * The following function provides a compatibility function for SPDs using the - * existing cm library routines. This function is expected to be invoked for - * initializing the cpu_context for the CPU specified by MPIDR for first use. - ******************************************************************************/ -void cm_init_context(unsigned long mpidr, const entry_point_info_t *ep) -{ - if ((mpidr & MPIDR_AFFINITY_MASK) == - (read_mpidr_el1() & MPIDR_AFFINITY_MASK)) - cm_init_my_context(ep); - else - cm_init_context_by_index(platform_get_core_pos(mpidr), ep); -} - -/******************************************************************************* * Prepare the CPU system registers for first entry into secure or normal world * * If execution is requested to EL2 or hyp mode, SCTLR_EL2 is initialized diff --git a/docs/interrupt-framework-design.md b/docs/interrupt-framework-design.md index cee29a31..53707ae9 100644 --- a/docs/interrupt-framework-design.md +++ b/docs/interrupt-framework-design.md @@ -293,11 +293,9 @@ This component declares the following prototype for a handler of an interrupt ty void *handle, void *cookie); -The value of the `id` parameter depends upon the definition of the -`IMF_READ_INTERRUPT_ID` build time flag. When the flag is defined, `id` contains -the number of the highest priority pending interrupt of the type that this -handler was registered for. When the flag is not defined `id` contains -`INTR_ID_UNAVAILABLE`. +The `id` is parameter is reserved and could be used in the future for passing +the interrupt id of the highest pending interrupt only if there is a foolproof +way of determining the id. Currently it contains `INTR_ID_UNAVAILABLE`. The `flags` parameter contains miscellaneous information as follows. @@ -583,11 +581,10 @@ responsible for: irrecoverable error condition. 6. Calling the registered handler function for the interrupt type generated. - The firmware also determines the interrupt id if the IMF_READ_INTERRUPT_ID - build time flag is set. The id is set to `INTR_ID_UNAVAILABLE` if the flag - is not set. The id along with the current security state and a reference to - the `cpu_context_t` structure for the current security state are passed to - the handler function as its arguments. + The `id` parameter is set to `INTR_ID_UNAVAILABLE` currently. The id along + with the current security state and a reference to the `cpu_context_t` + structure for the current security state are passed to the handler function + as its arguments. The handler function returns a reference to the per-cpu `cpu_context_t` structure for the target security state. diff --git a/docs/porting-guide.md b/docs/porting-guide.md index 6e71025c..e5b4a9c7 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -459,7 +459,7 @@ type of reset nor to query the warm reset entrypoint. Therefore, implementing this function is not required on such platforms. -### Function : plat_secondary_cold_boot_setup() [mandatory] +### Function : plat_secondary_cold_boot_setup() [mandatory when COLD_BOOT_SINGLE_CPU == 0] Argument : void @@ -468,14 +468,20 @@ for placing the executing secondary CPU in a platform-specific state until the primary CPU performs the necessary actions to bring it out of that state and allow entry into the OS. This function must not return. -In the ARM FVP port, each secondary CPU powers itself off. The primary CPU is -responsible for powering up the secondary CPU when normal world software -requires them. +In the ARM FVP port, when using the normal boot flow, each secondary CPU powers +itself off. The primary CPU is responsible for powering up the secondary CPUs +when normal world software requires them. When booting an EL3 payload instead, +they stay powered on and are put in a holding pen until their mailbox gets +populated. This function fulfills requirement 2 above. +Note that for platforms that can't release secondary CPUs out of reset, only the +primary CPU will execute the cold boot code. Therefore, implementing this +function is not required on such platforms. -### Function : plat_is_my_cpu_primary() [mandatory] + +### Function : plat_is_my_cpu_primary() [mandatory when COLD_BOOT_SINGLE_CPU == 0] Argument : void Return : unsigned int @@ -485,6 +491,11 @@ secondary CPU. A return value of zero indicates that the CPU is not the primary CPU, while a non-zero return value indicates that the CPU is the primary CPU. +Note that for platforms that can't release secondary CPUs out of reset, only the +primary CPU will execute the cold boot code. Therefore, there is no need to +distinguish between primary and secondary CPUs and implementing this function is +not required. + ### Function : platform_mem_init() [mandatory] @@ -810,13 +821,14 @@ represents the entry point system state for BL2. ### Function : bl1_plat_prepare_exit() [optional] - Argument : void + Argument : entry_point_info_t * Return : void -This function is called prior to exiting BL1 in response to the `RUN_IMAGE_SMC` +This function is called prior to exiting BL1 in response to the `RUN_IMAGE` SMC request raised by BL2. It should be used to perform platform specific clean up -or bookkeeping operations before transferring control to the next image. This -function runs with MMU disabled. +or bookkeeping operations before transferring control to the next image. It +receives the address of the `entry_point_info_t` structure passed from BL2. +This function runs with MMU disabled. 3.2 Boot Loader Stage 2 (BL2) @@ -1000,10 +1012,13 @@ structure in BL2 memory. Argument : image_info *, entry_point_info * Return : void -This function is called after loading BL3-1 image and it can be used to -overwrite the entry point set by loader and also set the security state -and SPSR which represents the entry point system state for BL3-1. +In the normal boot flow, this function is called after loading BL3-1 image and +it can be used to overwrite the entry point set by loader and also set the +security state and SPSR which represents the entry point system state for BL3-1. +When booting an EL3 payload instead, this function is called after populating +its entry point address and can be used for the same purpose for the payload +image. It receives a null pointer as its first argument in this case. ### Function : bl2_plat_set_bl32_ep_info() [mandatory] @@ -1473,9 +1488,8 @@ of interrupt depends upon the id value as follows. Return : uint32_t This API returns the id of the highest priority pending interrupt at the -platform IC. The IMF passes the id returned by this API to the registered -handler for the pending interrupt if the `IMF_READ_INTERRUPT_ID` build time flag -is set. INTR_ID_UNAVAILABLE is returned when there is no interrupt pending. +platform IC. INTR_ID_UNAVAILABLE is returned when there is no interrupt +pending. ARM standard platforms read the _Highest Priority Pending Interrupt Register_ (`GICC_HPPIR`) to determine the id of the pending interrupt. The id diff --git a/docs/user-guide.md b/docs/user-guide.md index 7987d10e..bcdc645d 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -9,9 +9,10 @@ Contents : 4. [Getting the Trusted Firmware source code](#4--getting-the-trusted-firmware-source-code) 5. [Building the Trusted Firmware](#5--building-the-trusted-firmware) 6. [Building the rest of the software stack](#6--building-the-rest-of-the-software-stack) -7. [Preparing the images to run on FVP](#7--preparing-the-images-to-run-on-fvp) -8. [Running the software on FVP](#8--running-the-software-on-fvp) -9. [Running the software on Juno](#9--running-the-software-on-juno) +7. [EL3 payloads alternative boot flow](#7--el3-payloads-alternative-boot-flow) +8. [Preparing the images to run on FVP](#8--preparing-the-images-to-run-on-fvp) +9. [Running the software on FVP](#9--running-the-software-on-fvp) +10. [Running the software on Juno](#10--running-the-software-on-juno) 1. Introduction @@ -250,11 +251,6 @@ performed. is used to determine the number of valid slave interfaces available in the ARM CCI driver. Default is 400 (that is, CCI-400). -* `IMF_READ_INTERRUPT_ID`: Boolean flag used by the interrupt management - framework to enable passing of the interrupt id to its handler. The id is - read using a platform GIC API. `INTR_ID_UNAVAILABLE` is passed instead if - this option set to 0. Default is 0. - * `RESET_TO_BL31`: Enable BL3-1 entrypoint as the CPU reset vector instead of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1 entrypoint) or 1 (CPU reset to BL3-1 entrypoint). @@ -354,9 +350,18 @@ performed. either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a programmable reset address, it is expected that a CPU will start executing code directly at the right address, both on a cold and warm reset. In this - case, there is no need to identify the entrypoint on boot and this has - implication for `plat_get_my_entrypoint()` platform porting interface. - (see the [Porting Guide] for details) + case, there is no need to identify the entrypoint on boot and the boot path + can be optimised. The `plat_get_my_entrypoint()` platform porting interface + does not need to be implemented in this case. + +* `COLD_BOOT_SINGLE_CPU`: This option indicates whether the platform may + release several CPUs out of reset. It can take either 0 (several CPUs may be + brought up) or 1 (only one CPU will ever be brought up during cold reset). + Default is 0. If the platform always brings up a single CPU, there is no + need to distinguish between primary and secondary CPUs and the boot path can + be optimised. The `plat_is_my_cpu_primary()` and + `plat_secondary_cold_boot_setup()` platform porting interfaces do not need + to be implemented in this case. * `PSCI_EXTENDED_STATE_ID`: As per PSCI1.0 Specification, there are 2 formats possible for the PSCI power-state parameter viz original and extended @@ -367,10 +372,21 @@ performed. and it governs the return value of PSCI_FEATURES API for CPU_SUSPEND smc function id. -* `WARN_DEPRECATED`: This option decides whether to warn the usage of - deprecated platform APIs and context management helpers within Trusted - Firmware. It can take the value 1 (warn the use of deprecated APIs) or - 0. The default is 0. +* `ERROR_DEPRECATED`: This option decides whether to treat the usage of + deprecated platform APIs, helper functions or drivers within Trusted + Firmware as error. It can take the value 1 (flag the use of deprecated + APIs as error) or 0. The default is 0. + +* `SPIN_ON_BL1_EXIT`: This option introduces an infinite loop in BL1. It can + take either 0 (no loop) or 1 (add a loop). 0 is the default. This loop stops + execution in BL1 just before handing over to BL31. At this point, all + firmware images have been loaded in memory and the MMU as well as the caches + are turned off. Refer to the "Debugging options" section for more details. + +* `EL3_PAYLOAD_BASE`: This option enables booting an EL3 payload instead of + the normal boot flow. It must specify the entry point address of the EL3 + payload. Please refer to the "Booting an EL3 payload" section for more + details. #### ARM development platform specific build options @@ -407,6 +423,14 @@ map is explained in the [Firmware Design]. in which case the platform is configured to expect NULL in the State-ID field of power-state parameter. +* `ARM_DISABLE_TRUSTED_WDOG`: boolean option to disable the Trusted Watchdog. + By default, ARM platforms use a watchdog to trigger a system reset in case + an error is encountered during the boot process (for example, when an image + could not be loaded or authenticated). The watchdog is enabled in the early + platform setup hook at BL1 and disabled in the BL1 prepare exit hook. The + Trusted Watchdog may be disabled at build time for testing or development + purposes. + #### ARM CSS platform specific build options * `CSS_DETECT_PRE_1_7_0_SCP`: Boolean flag to detect SCP version @@ -500,6 +524,25 @@ Extra debug options can be passed to the build system by setting `CFLAGS`: BL33=<path-to>/<bl33_image> \ make PLAT=<platform> DEBUG=1 V=1 all fip +It is also possible to introduce an infinite loop to help in debugging the +post-BL2 phase of the Trusted Firmware. This can be done by rebuilding BL1 with +the `SPIN_ON_BL1_EXIT=1` build flag. Refer to the "Summary of build options" +section. In this case, the developer may take control of the target using a +debugger when indicated by the console output. When using DS-5, the following +commands can be used: + + # Stop target execution + interrupt + + # + # Prepare your debugging environment, e.g. set breakpoints + # + + # Jump over the debug loop + set var $AARCH64::$Core::$PC = $AARCH64::$Core::$PC + 4 + + # Resume execution + continue ### Building the Test Secure Payload @@ -699,9 +742,49 @@ above. The EDK2 binary for use with the ARM Trusted Firmware can be found here: instructions in the "Building the Trusted Firmware" section. -7. Preparing the images to run on FVP +7. EL3 payloads alternative boot flow +-------------------------------------- + +On a pre-production system, the ability to execute arbitrary, bare-metal code at +the highest exception level is required. It allows full, direct access to the +hardware, for example to run silicon soak tests. + +Although it is possible to implement some baremetal secure firmware from +scratch, this is a complex task on some platforms, depending on the level of +configuration required to put the system in the expected state. + +Rather than booting a baremetal application, a possible compromise is to boot +`EL3 payloads` through the Trusted Firmware instead. This is implemented as an +alternative boot flow, where a modified BL2 boots an EL3 payload, instead of +loading the other BL images and passing control to BL31. It reduces the +complexity of developing EL3 baremetal code by: + +* putting the system into a known architectural state; +* taking care of platform secure world initialization; +* loading the BL30 image if required by the platform. + +When booting an EL3 payload on ARM standard platforms, the configuration of the +TrustZone controller is simplified such that only region 0 is enabled and is +configured to permit secure access only. This gives full access to the whole +DRAM to the EL3 payload. + +The system is left in the same state as when entering BL31 in the default boot +flow. In particular: + +* Running in EL3; +* Current state is AArch64; +* Little-endian data access; +* All exceptions disabled; +* MMU disabled; +* Caches disabled. + + +8. Preparing the images to run on FVP -------------------------------------- +Note: This section can be ignored when booting an EL3 payload, as no Flattened +Device Tree or kernel image is needed in this case. + ### Obtaining the Flattened Device Trees Depending on the FVP configuration and Linux configuration used, different @@ -749,7 +832,7 @@ Copy the kernel image file `linux/arch/arm64/boot/Image` to the directory from which the FVP is launched. Alternatively a symbolic link may be used. -8. Running the software on FVP +9. Running the software on FVP ------------------------------- This version of the ARM Trusted Firmware has been tested on the following ARM @@ -1048,9 +1131,41 @@ The `bp.variant` parameter corresponds to the build variant field of the `SYS_ID` register. Setting this to `0x0` allows the ARM Trusted Firmware to detect the legacy VE memory map while configuring the GIC. +### Booting an EL3 payload on FVP + +Booting an EL3 payload on FVP requires a couple of changes to the way the +model is normally invoked. + +First of all, the EL3 payload image is not part of the FIP and is not loaded by +the Trusted Firmware. Therefore, it must be loaded in memory some other way. +There are 2 ways of doing that: + +1. It can be loaded over JTAG at the appropriate time. The infinite loop + introduced in BL1 when compiling the Trusted Firmware with + `SPIN_ON_BL1_EXIT=1` stops execution at the right moment for a debugger to + take control of the target and load the payload. + +2. It can be pre-loaded in the FVP memory using the following model parameter: -9. Running the software on Juno --------------------------------- + --data="<path-to-binary>"@<base-address-of-binary> + + The base address provided to the FVP must match the `EL3_PAYLOAD_BASE` + address used when building the Trusted Firmware. + +Secondly, the EL3 payloads boot flow requires the CPUs mailbox to be cleared +at reset for the secondary CPUs holding pen to work properly. Unfortunately, +its reset value is undefined on FVP. One way to clear it is to create an +8-byte file containing all zero bytes and pre-load it into the FVP memory at the +mailbox address (i.e. `0x04000000`) using the same `--data` FVP parameter as +described above. + +The following command creates such a file called `mailbox.dat`: + + dd if=/dev/zero of=mailbox.dat bs=1 count=8 + + +10. Running the software on Juno +--------------------------------- This version of the ARM Trusted Firmware has been tested on Juno r0 and Juno r1. @@ -1143,6 +1258,5 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._ [Juno Software Guide]: http://community.arm.com/docs/DOC-8396 [DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php [mbedTLS Repository]: https://github.com/ARMmbed/mbedtls.git -[Porting Guide]: ./porting-guide.md [PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)" [Trusted Board Boot]: trusted-board-boot.md diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c new file mode 100644 index 00000000..17be61d5 --- /dev/null +++ b/drivers/arm/gic/common/gic_common.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <gic_common.h> +#include <mmio.h> + +/******************************************************************************* + * GIC Distributor interface accessors for reading entire registers + ******************************************************************************/ +/* + * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt + * `id`, 32 interrupt ids at a time. + */ +unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> IGROUPR_SHIFT; + return mmio_read_32(base + GICD_IGROUPR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISENABLER corresponding to the + * interrupt `id`, 32 interrupt ids at a time. + */ +unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ISENABLER_SHIFT; + return mmio_read_32(base + GICD_ISENABLER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ICENABLER_SHIFT; + return mmio_read_32(base + GICD_ICENABLER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ISPENDR_SHIFT; + return mmio_read_32(base + GICD_ISPENDR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ICPENDR_SHIFT; + return mmio_read_32(base + GICD_ICPENDR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ISACTIVER_SHIFT; + return mmio_read_32(base + GICD_ISACTIVER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ICACTIVER_SHIFT; + return mmio_read_32(base + GICD_ICACTIVER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> IPRIORITYR_SHIFT; + return mmio_read_32(base + GICD_IPRIORITYR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICGFR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ICFGR_SHIFT; + return mmio_read_32(base + GICD_ICFGR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor NSACR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> NSACR_SHIFT; + return mmio_read_32(base + GICD_NSACR + (n << 2)); +} + +/******************************************************************************* + * GIC Distributor interface accessors for writing entire registers + ******************************************************************************/ +/* + * Accessor to write the GIC Distributor IGROUPR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> IGROUPR_SHIFT; + mmio_write_32(base + GICD_IGROUPR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ISENABLER_SHIFT; + mmio_write_32(base + GICD_ISENABLER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ICENABLER_SHIFT; + mmio_write_32(base + GICD_ICENABLER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ISPENDR_SHIFT; + mmio_write_32(base + GICD_ISPENDR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ICPENDR_SHIFT; + mmio_write_32(base + GICD_ICPENDR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ISACTIVER_SHIFT; + mmio_write_32(base + GICD_ISACTIVER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ICACTIVER_SHIFT; + mmio_write_32(base + GICD_ICACTIVER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> IPRIORITYR_SHIFT; + mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICFGR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ICFGR_SHIFT; + mmio_write_32(base + GICD_ICFGR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor NSACR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> NSACR_SHIFT; + mmio_write_32(base + GICD_NSACR + (n << 2), val); +} + +/******************************************************************************* + * GIC Distributor interface accessors for individual interrupt manipulation + ******************************************************************************/ +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + return (reg_val >> bit_num) & 0x1; +} + +void gicd_set_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val | (1 << bit_num)); +} + +void gicd_clr_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val & ~(1 << bit_num)); +} + +void gicd_set_isenabler(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1); + + gicd_write_isenabler(base, id, (1 << bit_num)); +} + +void gicd_set_icenabler(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1); + + gicd_write_icenabler(base, id, (1 << bit_num)); +} + +void gicd_set_ispendr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1); + + gicd_write_ispendr(base, id, (1 << bit_num)); +} + +void gicd_set_icpendr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1); + + gicd_write_icpendr(base, id, (1 << bit_num)); +} + +void gicd_set_isactiver(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1); + + gicd_write_isactiver(base, id, (1 << bit_num)); +} + +void gicd_set_icactiver(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1); + + gicd_write_icactiver(base, id, (1 << bit_num)); +} diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c new file mode 100644 index 00000000..1f904c51 --- /dev/null +++ b/drivers/arm/gic/v2/gicv2_helpers.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <gic_common.h> +#include "gicv2_private.h" + +/* + * Accessor to read the GIC Distributor ITARGETSR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ITARGETSR_SHIFT; + return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor CPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) +{ + unsigned n = id >> CPENDSGIR_SHIFT; + return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor SPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) +{ + unsigned n = id >> SPENDSGIR_SHIFT; + return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); +} + +/* + * Accessor to write the GIC Distributor ITARGETSR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ITARGETSR_SHIFT; + mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor CPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> CPENDSGIR_SHIFT; + mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor SPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> SPENDSGIR_SHIFT; + mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ITARGETSR corresponding to the + * interrupt `id`. + */ +void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) +{ + unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1); + unsigned int reg_val = gicd_read_itargetsr(base, id); + + gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3))); +} + +/******************************************************************************* + * Get the current CPU bit mask from GICD_ITARGETSR0 + ******************************************************************************/ +unsigned int gicv2_get_cpuif_id(uintptr_t base) +{ + unsigned int val; + + val = gicd_read_itargetsr(base, 0); + return val & GIC_TARGET_CPU_MASK; +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv2_spis_configure_defaults(uintptr_t gicd_base) +{ + unsigned int index, num_ints; + + num_ints = gicd_read_typer(gicd_base); + num_ints &= TYPER_IT_LINES_NO_MASK; + num_ints = (num_ints + 1) << 5; + + /* + * Treat all SPIs as G1NS by default. The number of interrupts is + * calculated as 32 * (IT_LINES + 1). We do 32 at a time. + */ + for (index = MIN_SPI_ID; index < num_ints; index += 32) + gicd_write_igroupr(gicd_base, index, ~0U); + + /* Setup the default SPI priorities doing four at a time */ + for (index = MIN_SPI_ID; index < num_ints; index += 4) + gicd_write_ipriorityr(gicd_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + /* Treat all SPIs as level triggered by default, 16 at a time */ + for (index = MIN_SPI_ID; index < num_ints; index += 16) + gicd_write_icfgr(gicd_base, index, 0); +} + +/******************************************************************************* + * Helper function to configure secure G0 SPIs. + ******************************************************************************/ +void gicv2_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list) +{ + unsigned int index, irq_num; + + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num >= MIN_SPI_ID) { + /* Configure this interrupt as a secure interrupt */ + gicd_clr_igroupr(gicd_base, irq_num); + + /* Set the priority of this interrupt */ + gicd_write_ipriorityr(gicd_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + + /* Target the secure interrupts to primary CPU */ + gicd_set_itargetsr(gicd_base, irq_num, + gicv2_get_cpuif_id(gicd_base)); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, irq_num); + } + } + +} + +/******************************************************************************* + * Helper function to configure secure G0 SGIs and PPIs. + ******************************************************************************/ +void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list) +{ + unsigned int index, irq_num, sec_ppi_sgi_mask = 0; + + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + /* + * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a + * more scalable approach as it avoids clearing the enable bits in the + * GICD_CTLR. + */ + gicd_write_icenabler(gicd_base, 0, ~0); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (index = 0; index < MIN_SPI_ID; index += 4) + gicd_write_ipriorityr(gicd_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num < MIN_SPI_ID) { + /* We have an SGI or a PPI. They are Group0 at reset */ + sec_ppi_sgi_mask |= 1U << irq_num; + + /* Set the priority of this interrupt */ + gicd_write_ipriorityr(gicd_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + } + } + + /* + * Invert the bitmask to create a mask for non-secure PPIs and + * SGIs. Program the GICD_IGROUPR0 with this bit mask. + */ + gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); + + /* Enable the Group 0 SGIs and PPIs */ + gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); +} diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c new file mode 100644 index 00000000..cf939261 --- /dev/null +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <gic_common.h> +#include <gicv2.h> +#include "gicv2_private.h" + +static const gicv2_driver_data_t *driver_data; + +/******************************************************************************* + * Enable secure interrupts and use FIQs to route them. Disable legacy bypass + * and set the priority mask register to allow all interrupts to trickle in. + ******************************************************************************/ +void gicv2_cpuif_enable(void) +{ + unsigned int val; + + assert(driver_data); + assert(driver_data->gicc_base); + + /* + * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 + * bypass. + */ + val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; + val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; + + /* Program the idle priority in the PMR */ + gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); + gicc_write_ctlr(driver_data->gicc_base, val); +} + +/******************************************************************************* + * Place the cpu interface in a state where it can never make a cpu exit wfi as + * as result of an asserted interrupt. This is critical for powering down a cpu + ******************************************************************************/ +void gicv2_cpuif_disable(void) +{ + unsigned int val; + + assert(driver_data); + assert(driver_data->gicc_base); + + /* Disable secure, non-secure interrupts and disable their bypass */ + val = gicc_read_ctlr(driver_data->gicc_base); + val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); + val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; + val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; + gicc_write_ctlr(driver_data->gicc_base, val); +} + +/******************************************************************************* + * Per cpu gic distributor setup which will be done by all cpus after a cold + * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. + ******************************************************************************/ +void gicv2_pcpu_distif_init(void) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(driver_data->g0_interrupt_array); + + gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); +} + +/******************************************************************************* + * Global gic distributor init which will be done by the primary cpu after a + * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It + * then enables the secure GIC distributor interface. + ******************************************************************************/ +void gicv2_distif_init(void) +{ + unsigned int ctlr; + + assert(driver_data); + assert(driver_data->gicd_base); + assert(driver_data->g0_interrupt_array); + + /* Disable the distributor before going further */ + ctlr = gicd_read_ctlr(driver_data->gicd_base); + gicd_write_ctlr(driver_data->gicd_base, + ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); + + /* Set the default attribute of all SPIs */ + gicv2_spis_configure_defaults(driver_data->gicd_base); + + /* Configure the G0 SPIs */ + gicv2_secure_spis_configure(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); + + /* Re-enable the secure SPIs now that they have been configured */ + gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); +} + +/******************************************************************************* + * Initialize the ARM GICv2 driver with the provided platform inputs + ******************************************************************************/ +void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) +{ + unsigned int gic_version; + assert(plat_driver_data); + assert(plat_driver_data->gicd_base); + assert(plat_driver_data->gicc_base); + + /* + * The platform should provide a list of atleast one type of + * interrupts + */ + assert(plat_driver_data->g0_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the number of + * interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + + /* Ensure that this is a GICv2 system */ + gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); + gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) + & PIDR2_ARCH_REV_MASK; + assert(gic_version == ARCH_REV_GICV2); + + driver_data = plat_driver_data; + + INFO("ARM GICv2 driver initialized\n"); +} + +/****************************************************************************** + * This function returns whether FIQ is enabled in the GIC CPU interface. + *****************************************************************************/ +unsigned int gicv2_is_fiq_enabled(void) +{ + unsigned int gicc_ctlr; + + assert(driver_data); + assert(driver_data->gicc_base); + + gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); + return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1; +} + +/******************************************************************************* + * This function returns the type of the highest priority pending interrupt at + * the GIC cpu interface. The return values can be one of the following : + * PENDING_G1_INTID : The interrupt type is non secure Group 1. + * 0 - 1019 : The interrupt type is secure Group 0. + * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with + * sufficient priority to be signaled + ******************************************************************************/ +unsigned int gicv2_get_pending_interrupt_type(void) +{ + assert(driver_data); + assert(driver_data->gicc_base); + + return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; +} + +/******************************************************************************* + * This function returns the id of the highest priority pending interrupt at + * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no + * interrupt pending. + ******************************************************************************/ +unsigned int gicv2_get_pending_interrupt_id(void) +{ + unsigned int id; + + assert(driver_data); + assert(driver_data->gicc_base); + + id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; + + /* + * Find out which non-secure interrupt it is under the assumption that + * the GICC_CTLR.AckCtl bit is 0. + */ + if (id == PENDING_G1_INTID) + id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; + + return id; +} + +/******************************************************************************* + * This functions reads the GIC cpu interface Interrupt Acknowledge register + * to start handling the pending secure 0 interrupt. It returns the + * contents of the IAR. + ******************************************************************************/ +unsigned int gicv2_acknowledge_interrupt(void) +{ + assert(driver_data); + assert(driver_data->gicc_base); + + return gicc_read_IAR(driver_data->gicc_base); +} + +/******************************************************************************* + * This functions writes the GIC cpu interface End Of Interrupt register with + * the passed value to finish handling the active secure group 0 interrupt. + ******************************************************************************/ +void gicv2_end_of_interrupt(unsigned int id) +{ + assert(driver_data); + assert(driver_data->gicc_base); + + gicc_write_EOIR(driver_data->gicc_base, id); +} + +/******************************************************************************* + * This function returns the type of the interrupt id depending upon the group + * this interrupt has been configured under by the interrupt controller i.e. + * group0 secure or group1 non secure. It returns zero for Group 0 secure and + * one for Group 1 non secure interrupt. + ******************************************************************************/ +unsigned int gicv2_get_interrupt_group(unsigned int id) +{ + assert(driver_data); + assert(driver_data->gicd_base); + + return gicd_get_igroupr(driver_data->gicd_base, id); +} diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h new file mode 100644 index 00000000..6a1ec82b --- /dev/null +++ b/drivers/arm/gic/v2/gicv2_private.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV2_PRIVATE_H__ +#define __GICV2_PRIVATE_H__ + +#include <gicv2.h> +#include <mmio.h> +#include <stdint.h> + +/******************************************************************************* + * Private function prototypes + ******************************************************************************/ +void gicv2_spis_configure_defaults(uintptr_t gicd_base); +void gicv2_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list); +void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list); +unsigned int gicv2_get_cpuif_id(uintptr_t base); + +/******************************************************************************* + * GIC Distributor interface accessors for reading entire registers + ******************************************************************************/ +static inline unsigned int gicd_read_pidr2(uintptr_t base) +{ + return mmio_read_32(base + GICD_PIDR2_GICV2); +} + +/******************************************************************************* + * GIC CPU interface accessors for reading entire registers + ******************************************************************************/ + +static inline unsigned int gicc_read_ctlr(uintptr_t base) +{ + return mmio_read_32(base + GICC_CTLR); +} + +static inline unsigned int gicc_read_pmr(uintptr_t base) +{ + return mmio_read_32(base + GICC_PMR); +} + +static inline unsigned int gicc_read_BPR(uintptr_t base) +{ + return mmio_read_32(base + GICC_BPR); +} + +static inline unsigned int gicc_read_IAR(uintptr_t base) +{ + return mmio_read_32(base + GICC_IAR); +} + +static inline unsigned int gicc_read_EOIR(uintptr_t base) +{ + return mmio_read_32(base + GICC_EOIR); +} + +static inline unsigned int gicc_read_hppir(uintptr_t base) +{ + return mmio_read_32(base + GICC_HPPIR); +} + +static inline unsigned int gicc_read_ahppir(uintptr_t base) +{ + return mmio_read_32(base + GICC_AHPPIR); +} + +static inline unsigned int gicc_read_dir(uintptr_t base) +{ + return mmio_read_32(base + GICC_DIR); +} + +static inline unsigned int gicc_read_iidr(uintptr_t base) +{ + return mmio_read_32(base + GICC_IIDR); +} + +/******************************************************************************* + * GIC CPU interface accessors for writing entire registers + ******************************************************************************/ + +static inline void gicc_write_ctlr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_CTLR, val); +} + +static inline void gicc_write_pmr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_PMR, val); +} + +static inline void gicc_write_BPR(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_BPR, val); +} + + +static inline void gicc_write_IAR(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_IAR, val); +} + +static inline void gicc_write_EOIR(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_EOIR, val); +} + +static inline void gicc_write_hppir(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_HPPIR, val); +} + +static inline void gicc_write_dir(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICC_DIR, val); +} + +#endif /* __GICV2_PRIVATE_H__ */ diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c new file mode 100644 index 00000000..6e8251d5 --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <gic_common.h> +#include "gicv3_private.h" + +/* + * Accessor to read the GIC Distributor IGRPMODR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> IGRPMODR_SHIFT; + return mmio_read_32(base + GICD_IGRPMODR + (n << 2)); +} + +/* + * Accessor to write the GIC Distributor IGRPMODR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> IGRPMODR_SHIFT; + mmio_write_32(base + GICD_IGRPMODR + (n << 2), val); +} + +/* + * Accessor to get the bit corresponding to interrupt ID + * in GIC Distributor IGRPMODR. + */ +unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * Accessor to set the bit corresponding to interrupt ID + * in GIC Distributor IGRPMODR. + */ +void gicd_set_igrpmodr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + gicd_write_igrpmodr(base, id, reg_val | (1 << bit_num)); +} + +/* + * Accessor to clear the bit corresponding to interrupt ID + * in GIC Distributor IGRPMODR. + */ +void gicd_clr_igrpmodr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + gicd_write_igrpmodr(base, id, reg_val & ~(1 << bit_num)); +} + +/* + * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupts IDs at a time. + */ +unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> IPRIORITYR_SHIFT; + return mmio_read_32(base + GICR_IPRIORITYR + (n << 2)); +} + +/* + * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupts IDs at a time. + */ +void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> IPRIORITYR_SHIFT; + mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val); +} + +/* + * Accessor to get the bit corresponding to interrupt ID + * from GIC Re-distributor IGROUPR0. + */ +unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * Accessor to set the bit corresponding to interrupt ID + * in GIC Re-distributor IGROUPR0. + */ +void gicr_set_igroupr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + gicr_write_igroupr0(base, reg_val | (1 << bit_num)); +} + +/* + * Accessor to clear the bit corresponding to interrupt ID + * in GIC Re-distributor IGROUPR0. + */ +void gicr_clr_igroupr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + gicr_write_igroupr0(base, reg_val & ~(1 << bit_num)); +} + +/* + * Accessor to get the bit corresponding to interrupt ID + * from GIC Re-distributor IGRPMODR0. + */ +unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * Accessor to set the bit corresponding to interrupt ID + * in GIC Re-distributor IGRPMODR0. + */ +void gicr_set_igrpmodr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + gicr_write_igrpmodr0(base, reg_val | (1 << bit_num)); +} + +/* + * Accessor to clear the bit corresponding to interrupt ID + * in GIC Re-distributor IGRPMODR0. + */ +void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + gicr_write_igrpmodr0(base, reg_val & ~(1 << bit_num)); +} + +/* + * Accessor to set the bit corresponding to interrupt ID + * in GIC Re-distributor ISENABLER0. + */ +void gicr_set_isenabler0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1); + + gicr_write_isenabler0(base, (1 << bit_num)); +} + +/****************************************************************************** + * This function marks the core as awake in the re-distributor and + * ensures that the interface is active. + *****************************************************************************/ +void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) +{ + /* + * The WAKER_PS_BIT should be changed to 0 + * only when WAKER_CA_BIT is 1. + */ + assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT); + + /* Mark the connected core as awake */ + gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT); + + /* Wait till the WAKER_CA_BIT changes to 0 */ + while (gicr_read_waker(gicr_base) & WAKER_CA_BIT) + ; +} + + +/****************************************************************************** + * This function marks the core as asleep in the re-distributor and ensures + * that the interface is quiescent. + *****************************************************************************/ +void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base) +{ + /* Mark the connected core as asleep */ + gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT); + + /* Wait till the WAKER_CA_BIT changes to 1 */ + while (!(gicr_read_waker(gicr_base) & WAKER_CA_BIT)) + ; +} + + +/******************************************************************************* + * This function probes the Redistributor frames when the driver is initialised + * and saves their base addresses. These base addresses are used later to + * initialise each Redistributor interface. + ******************************************************************************/ +void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, + unsigned int rdistif_num, + uintptr_t gicr_base, + mpidr_hash_fn mpidr_to_core_pos) +{ + unsigned long mpidr; + unsigned int proc_num; + unsigned long long typer_val; + uintptr_t rdistif_base = gicr_base; + + assert(rdistif_base_addrs); + + /* + * Iterate over the Redistributor frames. Store the base address of each + * frame in the platform provided array. Use the "Processor Number" + * field to index into the array if the platform has not provided a hash + * function to convert an MPIDR (obtained from the "Affinity Value" + * field into a linear index. + */ + do { + typer_val = gicr_read_typer(rdistif_base); + if (mpidr_to_core_pos) { + mpidr = mpidr_from_gicr_typer(typer_val); + proc_num = mpidr_to_core_pos(mpidr); + } else { + proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) & + TYPER_PROC_NUM_MASK; + } + assert(proc_num < rdistif_num); + rdistif_base_addrs[proc_num] = rdistif_base; + rdistif_base += (1 << GICR_PCPUBASE_SHIFT); + } while (!(typer_val & TYPER_LAST_BIT)); +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv3_spis_configure_defaults(uintptr_t gicd_base) +{ + unsigned int index, num_ints; + + num_ints = gicd_read_typer(gicd_base); + num_ints &= TYPER_IT_LINES_NO_MASK; + num_ints = (num_ints + 1) << 5; + + /* + * Treat all SPIs as G1NS by default. The number of interrupts is + * calculated as 32 * (IT_LINES + 1). We do 32 at a time. + */ + for (index = MIN_SPI_ID; index < num_ints; index += 32) + gicd_write_igroupr(gicd_base, index, ~0U); + + /* Setup the default SPI priorities doing four at a time */ + for (index = MIN_SPI_ID; index < num_ints; index += 4) + gicd_write_ipriorityr(gicd_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + /* + * Treat all SPIs as level triggered by default, write 16 at + * a time + */ + for (index = MIN_SPI_ID; index < num_ints; index += 16) + gicd_write_icfgr(gicd_base, index, 0); +} + +/******************************************************************************* + * Helper function to configure secure G0 and G1S SPIs. + ******************************************************************************/ +void gicv3_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp) +{ + unsigned int index, irq_num; + uint64_t gic_affinity_val; + + assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num >= MIN_SPI_ID) { + + /* Configure this interrupt as a secure interrupt */ + gicd_clr_igroupr(gicd_base, irq_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + if (int_grp == INT_TYPE_G1S) + gicd_set_igrpmodr(gicd_base, irq_num); + else + gicd_clr_igrpmodr(gicd_base, irq_num); + + /* Set the priority of this interrupt */ + gicd_write_ipriorityr(gicd_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + + /* Target SPIs to the primary CPU */ + gic_affinity_val = + gicd_irouter_val_from_mpidr(read_mpidr(), 0); + gicd_write_irouter(gicd_base, + irq_num, + gic_affinity_val); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, irq_num); + } + } + +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base) +{ + unsigned int index; + + /* + * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a + * more scalable approach as it avoids clearing the enable bits in the + * GICD_CTLR + */ + gicr_write_icenabler0(gicr_base, ~0); + gicr_wait_for_pending_write(gicr_base); + + /* Treat all SGIs/PPIs as G1NS by default. */ + gicr_write_igroupr0(gicr_base, ~0U); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (index = 0; index < MIN_SPI_ID; index += 4) + gicr_write_ipriorityr(gicr_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + /* Configure all PPIs as level triggered by default */ + gicr_write_icfgr1(gicr_base, 0); +} + +/******************************************************************************* + * Helper function to configure secure G0 and G1S SPIs. + ******************************************************************************/ +void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp) +{ + unsigned int index, irq_num; + + assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num < MIN_SPI_ID) { + + /* Configure this interrupt as a secure interrupt */ + gicr_clr_igroupr0(gicr_base, irq_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + if (int_grp == INT_TYPE_G1S) + gicr_set_igrpmodr0(gicr_base, irq_num); + else + gicr_clr_igrpmodr0(gicr_base, irq_num); + + /* Set the priority of this interrupt */ + gicr_write_ipriorityr(gicr_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + + /* Enable this interrupt */ + gicr_set_isenabler0(gicr_base, irq_num); + } + } +} diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c new file mode 100644 index 00000000..06311e3a --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <debug.h> +#include <gic_common.h> +#include <gicv3.h> +#include "gicv3_private.h" + +static const gicv3_driver_data_t *driver_data; +static unsigned int gicv2_compat; + +/******************************************************************************* + * This function initialises the ARM GICv3 driver in EL3 with provided platform + * inputs. + ******************************************************************************/ +void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) +{ + unsigned int gic_version; + + assert(plat_driver_data); + assert(plat_driver_data->gicd_base); + assert(plat_driver_data->gicr_base); + assert(plat_driver_data->rdistif_num); + assert(plat_driver_data->rdistif_base_addrs); + + assert(IS_IN_EL3()); + + /* + * The platform should provide a list of at least one type of + * interrupts + */ + assert(plat_driver_data->g0_interrupt_array || + plat_driver_data->g1s_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the number of + * interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + assert(plat_driver_data->g1s_interrupt_array ? + plat_driver_data->g1s_interrupt_num : + plat_driver_data->g1s_interrupt_num == 0); + + /* Check for system register support */ + assert(read_id_aa64pfr0_el1() & + (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)); + + /* The GIC version should be 3.0 */ + gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); + gic_version >>= PIDR2_ARCH_REV_SHIFT; + gic_version &= PIDR2_ARCH_REV_MASK; + assert(gic_version == ARCH_REV_GICV3); + + /* + * Find out whether the GIC supports the GICv2 compatibility mode. The + * ARE_S bit resets to 0 if supported + */ + gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base); + gicv2_compat >>= CTLR_ARE_S_SHIFT; + gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK); + + /* + * Find the base address of each implemented Redistributor interface. + * The number of interfaces should be equal to the number of CPUs in the + * system. The memory for saving these addresses has to be allocated by + * the platform port + */ + gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs, + plat_driver_data->rdistif_num, + plat_driver_data->gicr_base, + plat_driver_data->mpidr_to_core_pos); + + driver_data = plat_driver_data; + + INFO("GICv3 %s legacy support detected." + " ARM GICV3 driver initialized in EL3\n", + gicv2_compat ? "with" : "without"); +} + +/******************************************************************************* + * This function initialises the GIC distributor interface based upon the data + * provided by the platform while initialising the driver. + ******************************************************************************/ +void gicv3_distif_init(void) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(driver_data->g1s_interrupt_array); + assert(driver_data->g0_interrupt_array); + + assert(IS_IN_EL3()); + + /* + * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring + * the ARE_S bit. The Distributor might generate a system error + * otherwise. + */ + gicd_clr_ctlr(driver_data->gicd_base, + CTLR_ENABLE_G0_BIT | + CTLR_ENABLE_G1S_BIT | + CTLR_ENABLE_G1NS_BIT, + RWP_TRUE); + + /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ + gicd_set_ctlr(driver_data->gicd_base, + CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); + + /* Set the default attribute of all SPIs */ + gicv3_spis_configure_defaults(driver_data->gicd_base); + + /* Configure the G1S SPIs */ + gicv3_secure_spis_configure(driver_data->gicd_base, + driver_data->g1s_interrupt_num, + driver_data->g1s_interrupt_array, + INT_TYPE_G1S); + + /* Configure the G0 SPIs */ + gicv3_secure_spis_configure(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array, + INT_TYPE_G0); + + /* Enable the secure SPIs now that they have been configured */ + gicd_set_ctlr(driver_data->gicd_base, + CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT, + RWP_TRUE); +} + +/******************************************************************************* + * This function initialises the GIC Redistributor interface of the calling CPU + * (identified by the 'proc_num' parameter) based upon the data provided by the + * platform while initialising the driver. + ******************************************************************************/ +void gicv3_rdistif_init(unsigned int proc_num) +{ + uintptr_t gicr_base; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + assert(driver_data->gicd_base); + assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT); + assert(driver_data->g1s_interrupt_array); + assert(driver_data->g0_interrupt_array); + + assert(IS_IN_EL3()); + + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + + /* Set the default attribute of all SGIs and PPIs */ + gicv3_ppi_sgi_configure_defaults(gicr_base); + + /* Configure the G1S SGIs/PPIs */ + gicv3_secure_ppi_sgi_configure(gicr_base, + driver_data->g1s_interrupt_num, + driver_data->g1s_interrupt_array, + INT_TYPE_G1S); + + /* Configure the G0 SGIs/PPIs */ + gicv3_secure_ppi_sgi_configure(gicr_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array, + INT_TYPE_G0); +} + +/******************************************************************************* + * This function enables the GIC CPU interface of the calling CPU using only + * system register accesses. + ******************************************************************************/ +void gicv3_cpuif_enable(unsigned int proc_num) +{ + uintptr_t gicr_base; + unsigned int scr_el3; + unsigned int icc_sre_el3; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + assert(IS_IN_EL3()); + + /* Mark the connected core as awake */ + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + gicv3_rdistif_mark_core_awake(gicr_base); + + /* Disable the legacy interrupt bypass */ + icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT; + + /* + * Enable system register access for EL3 and allow lower exception + * levels to configure the same for themselves. If the legacy mode is + * not supported, the SRE bit is RAO/WI + */ + icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT); + write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3); + + scr_el3 = read_scr_el3(); + + /* + * Switch to NS state to write Non secure ICC_SRE_EL1 and + * ICC_SRE_EL2 registers. + */ + write_scr_el3(scr_el3 | SCR_NS_BIT); + isb(); + + write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3); + write_icc_sre_el1(ICC_SRE_SRE_BIT); + isb(); + + /* Switch to secure state. */ + write_scr_el3(scr_el3 & (~SCR_NS_BIT)); + isb(); + + /* Program the idle priority in the PMR */ + write_icc_pmr_el1(GIC_PRI_MASK); + + /* Enable Group0 interrupts */ + write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT); + + /* Enable Group1 Secure interrupts */ + write_icc_igrpen1_el3(read_icc_igrpen1_el3() | + IGRPEN1_EL3_ENABLE_G1S_BIT); + + /* Write the secure ICC_SRE_EL1 register */ + write_icc_sre_el1(ICC_SRE_SRE_BIT); + isb(); +} + +/******************************************************************************* + * This function disables the GIC CPU interface of the calling CPU using + * only system register accesses. + ******************************************************************************/ +void gicv3_cpuif_disable(unsigned int proc_num) +{ + uintptr_t gicr_base; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + + assert(IS_IN_EL3()); + + /* Disable legacy interrupt bypass */ + write_icc_sre_el3(read_icc_sre_el3() | + (ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)); + + /* Disable Group0 interrupts */ + write_icc_igrpen0_el1(read_icc_igrpen0_el1() & + ~IGRPEN1_EL1_ENABLE_G0_BIT); + + /* Disable Group1 Secure interrupts */ + write_icc_igrpen1_el3(read_icc_igrpen1_el3() & + ~IGRPEN1_EL3_ENABLE_G1S_BIT); + + /* Synchronise accesses to group enable registers */ + isb(); + + /* Mark the connected core as asleep */ + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + gicv3_rdistif_mark_core_asleep(gicr_base); +} + +/******************************************************************************* + * This function returns the id of the highest priority pending interrupt at + * the GIC cpu interface. + ******************************************************************************/ +unsigned int gicv3_get_pending_interrupt_id(void) +{ + unsigned int id; + + assert(IS_IN_EL3()); + id = read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; + + /* + * If the ID is special identifier corresponding to G1S or G1NS + * interrupt, then read the highest pending group 1 interrupt. + */ + if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID)) + return read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK; + + return id; +} + +/******************************************************************************* + * This function returns the type of the highest priority pending interrupt at + * the GIC cpu interface. The return values can be one of the following : + * PENDING_G1S_INTID : The interrupt type is secure Group 1. + * PENDING_G1NS_INTID : The interrupt type is non secure Group 1. + * 0 - 1019 : The interrupt type is secure Group 0. + * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with + * sufficient priority to be signaled + ******************************************************************************/ +unsigned int gicv3_get_pending_interrupt_type(void) +{ + assert(IS_IN_EL3()); + return read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; +} + +/******************************************************************************* + * This function returns the type of the interrupt id depending upon the group + * this interrupt has been configured under by the interrupt controller i.e. + * group0 or group1 Secure / Non Secure. The return value can be one of the + * following : + * INT_TYPE_G0 : The interrupt type is a Secure Group 0 interrupt + * INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt + * INT_TYPE_G1NS: The interrupt type is a Secure Group 1 non secure + * interrupt. + ******************************************************************************/ +unsigned int gicv3_get_interrupt_type(unsigned int id, + unsigned int proc_num) +{ + unsigned int igroup, grpmodr; + uintptr_t gicr_base; + + assert(IS_IN_EL3()); + assert(driver_data); + + /* Ensure the parameters are valid */ + assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID); + assert(proc_num < driver_data->rdistif_num); + + /* All LPI interrupts are Group 1 non secure */ + if (id >= MIN_LPI_ID) + return INT_TYPE_G1NS; + + if (id < MIN_SPI_ID) { + assert(driver_data->rdistif_base_addrs); + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + igroup = gicr_get_igroupr0(gicr_base, id); + grpmodr = gicr_get_igrpmodr0(gicr_base, id); + } else { + assert(driver_data->gicd_base); + igroup = gicd_get_igroupr(driver_data->gicd_base, id); + grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id); + } + + /* + * If the IGROUP bit is set, then it is a Group 1 Non secure + * interrupt + */ + if (igroup) + return INT_TYPE_G1NS; + + /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */ + if (grpmodr) + return INT_TYPE_G1S; + + /* Else it is a Group 0 Secure interrupt */ + return INT_TYPE_G0; +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h new file mode 100644 index 00000000..c8b311a1 --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV3_PRIVATE_H__ +#define __GICV3_PRIVATE_H__ + +#include <gicv3.h> +#include <mmio.h> +#include <stdint.h> + +/******************************************************************************* + * GICv3 private macro definitions + ******************************************************************************/ + +/* Constants to indicate the status of the RWP bit */ +#define RWP_TRUE 1 +#define RWP_FALSE 0 + +/* + * Macro to wait for updates to : + * GICD_CTLR[2:0] - the Group Enables + * GICD_CTLR[5:4] - the ARE bits + * GICD_ICENABLERn - the clearing of enable state for SPIs + */ +#define gicd_wait_for_pending_write(gicd_base) \ + do { \ + ; \ + } while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) + +/* + * Macro to convert an mpidr to a value suitable for programming into a + * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant + * to GICv3. + */ +#define gicd_irouter_val_from_mpidr(mpidr, irm) \ + ((mpidr & ~(0xff << 24)) | \ + (irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT) + +/* + * Macro to wait for updates to : + * GICR_ICENABLER0 + * GICR_CTLR.DPG1S + * GICR_CTLR.DPG1NS + * GICR_CTLR.DPG0 + */ +#define gicr_wait_for_pending_write(gicr_base) \ + do { \ + ; \ + } while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) + +/* + * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24] + * are zeroes. + */ +#define mpidr_from_gicr_typer(typer_val) \ + ((((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) | \ + ((typer_val >> 32) & 0xffffff)) + +/******************************************************************************* + * Private function prototypes + ******************************************************************************/ +unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id); +unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id); +unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id); +unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id); +unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id); +unsigned int gicv3_get_pending_grp1_interrupt_id(unsigned int pending_grp); +void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val); +void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_set_igrpmodr(uintptr_t base, unsigned int id); +void gicr_set_igrpmodr0(uintptr_t base, unsigned int id); +void gicr_set_isenabler0(uintptr_t base, unsigned int id); +void gicr_set_igroupr0(uintptr_t base, unsigned int id); +void gicd_clr_igrpmodr(uintptr_t base, unsigned int id); +void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id); +void gicr_clr_igroupr0(uintptr_t base, unsigned int id); +void gicv3_spis_configure_defaults(uintptr_t gicd_base); +void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base); +void gicv3_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp); +void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp); +void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, + unsigned int rdistif_num, + uintptr_t gicr_base, + mpidr_hash_fn mpidr_to_core_pos); +void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base); +void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base); + +/******************************************************************************* + * GIC Distributor interface accessors + ******************************************************************************/ +static inline unsigned int gicd_read_pidr2(uintptr_t base) +{ + return mmio_read_32(base + GICD_PIDR2_GICV3); +} + +static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id) +{ + return mmio_read_64(base + GICD_IROUTER + (id << 3)); +} + +static inline void gicd_write_irouter(uintptr_t base, + unsigned int id, + unsigned long long affinity) +{ + mmio_write_64(base + GICD_IROUTER + (id << 3), affinity); +} + +static inline void gicd_clr_ctlr(uintptr_t base, + unsigned int bitmap, + unsigned int rwp) +{ + gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap); + if (rwp) + gicd_wait_for_pending_write(base); +} + +static inline void gicd_set_ctlr(uintptr_t base, + unsigned int bitmap, + unsigned int rwp) +{ + gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap); + if (rwp) + gicd_wait_for_pending_write(base); +} + +/******************************************************************************* + * GIC Redistributor interface accessors + ******************************************************************************/ +static inline unsigned long long gicr_read_ctlr(uintptr_t base) +{ + return mmio_read_64(base + GICR_CTLR); +} + +static inline unsigned long long gicr_read_typer(uintptr_t base) +{ + return mmio_read_64(base + GICR_TYPER); +} + +static inline unsigned int gicr_read_waker(uintptr_t base) +{ + return mmio_read_32(base + GICR_WAKER); +} + +static inline void gicr_write_waker(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_WAKER, val); +} + +static inline unsigned int gicr_read_icenabler0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICENABLER0); +} + +static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ICENABLER0, val); +} + +static inline unsigned int gicr_read_isenabler0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ISENABLER0); +} + +static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ISENABLER0, val); +} + +static inline unsigned int gicr_read_igroupr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_IGROUPR0); +} + +static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_IGROUPR0, val); +} + +static inline unsigned int gicr_read_igrpmodr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_IGRPMODR0); +} + +static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_IGRPMODR0, val); +} + +static inline unsigned int gicr_read_icfgr1(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICFGR1); +} + +static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ICFGR1, val); +} + +#endif /* __GICV3_PRIVATE_H__ */ diff --git a/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c new file mode 100644 index 00000000..4886e01f --- /dev/null +++ b/drivers/arm/sp805/sp805.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <mmio.h> +#include <sp805.h> +#include <stdint.h> + +/* Inline register access functions */ + +static inline void sp805_write_wdog_load(uintptr_t base, unsigned long value) +{ + mmio_write_32(base + SP805_WDOG_LOAD_OFF, value); +} + +static inline void sp805_write_wdog_ctrl(uintptr_t base, unsigned long value) +{ + mmio_write_32(base + SP805_WDOG_CTR_OFF, value); +} + +static inline void sp805_write_wdog_lock(uintptr_t base, unsigned long value) +{ + mmio_write_32(base + SP805_WDOG_LOCK_OFF, value); +} + + +/* Public API implementation */ + +void sp805_start(uintptr_t base, unsigned long ticks) +{ + sp805_write_wdog_load(base, ticks); + sp805_write_wdog_ctrl(base, SP805_CTR_RESEN | SP805_CTR_INTEN); + /* Lock registers access */ + sp805_write_wdog_lock(base, 0); +} + +void sp805_stop(uintptr_t base) +{ + sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY); + sp805_write_wdog_ctrl(base, 0); +} + +void sp805_refresh(uintptr_t base, unsigned long ticks) +{ + sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY); + sp805_write_wdog_load(base, ticks); + sp805_write_wdog_lock(base, 0); +} diff --git a/include/common/asm_macros.S b/include/common/asm_macros.S index 128259f1..a331c051 100644 --- a/include/common/asm_macros.S +++ b/include/common/asm_macros.S @@ -101,10 +101,10 @@ /* * Theses macros are used to create function labels for deprecated - * APIs. If WARN_DEPRECATED is non zero, the callers of these APIs + * APIs. If ERROR_DEPRECATED is non zero, the callers of these APIs * will fail to link and cause build failure. */ -#if WARN_DEPRECATED +#if ERROR_DEPRECATED .macro func_deprecated _name func deprecated\_name .endm diff --git a/include/drivers/arm/arm_gic.h b/include/drivers/arm/arm_gic.h index 5752d8f9..8c1f03fb 100644 --- a/include/drivers/arm/arm_gic.h +++ b/include/drivers/arm/arm_gic.h @@ -31,6 +31,7 @@ #ifndef __ARM_GIC_H__ #define __ARM_GIC_H__ +#include <common_def.h> #include <stdint.h> /******************************************************************************* @@ -40,18 +41,18 @@ void arm_gic_init(uintptr_t gicc_base, uintptr_t gicd_base, uintptr_t gicr_base, const unsigned int *irq_sec_ptr, - unsigned int num_irqs); -void arm_gic_setup(void); -void arm_gic_cpuif_deactivate(void); -void arm_gic_cpuif_setup(void); -void arm_gic_pcpu_distif_setup(void); + unsigned int num_irqs) __warn_deprecated; +void arm_gic_setup(void) __warn_deprecated; +void arm_gic_cpuif_deactivate(void) __warn_deprecated; +void arm_gic_cpuif_setup(void) __warn_deprecated; +void arm_gic_pcpu_distif_setup(void) __warn_deprecated; uint32_t arm_gic_interrupt_type_to_line(uint32_t type, - uint32_t security_state); -uint32_t arm_gic_get_pending_interrupt_type(void); -uint32_t arm_gic_get_pending_interrupt_id(void); -uint32_t arm_gic_acknowledge_interrupt(void); -void arm_gic_end_of_interrupt(uint32_t id); -uint32_t arm_gic_get_interrupt_type(uint32_t id); + uint32_t security_state) __warn_deprecated; +uint32_t arm_gic_get_pending_interrupt_type(void) __warn_deprecated; +uint32_t arm_gic_get_pending_interrupt_id(void) __warn_deprecated; +uint32_t arm_gic_acknowledge_interrupt(void) __warn_deprecated; +void arm_gic_end_of_interrupt(uint32_t id) __warn_deprecated; +uint32_t arm_gic_get_interrupt_type(uint32_t id) __warn_deprecated; #endif /* __GIC_H__ */ diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h new file mode 100644 index 00000000..6a322a22 --- /dev/null +++ b/include/drivers/arm/gic_common.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GIC_COMMON_H__ +#define __GIC_COMMON_H__ + +/******************************************************************************* + * GIC Distributor interface general definitions + ******************************************************************************/ +/* Constants to categorise interrupts */ +#define MIN_SGI_ID 0 +#define MIN_PPI_ID 16 +#define MIN_SPI_ID 32 + +/* Mask for the priority field common to all GIC interfaces */ +#define GIC_PRI_MASK 0xff + +/* Constant to indicate a spurious interrupt in all GIC versions */ +#define GIC_SPURIOUS_INTERRUPT 1023 + +/* Constants to categorise priorities */ +#define GIC_HIGHEST_SEC_PRIORITY 0 +#define GIC_LOWEST_SEC_PRIORITY 127 +#define GIC_HIGHEST_NS_PRIORITY 128 +#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */ + +/******************************************************************************* + * GIC Distributor interface register offsets that are common to GICv3 & GICv2 + ******************************************************************************/ +#define GICD_CTLR 0x0 +#define GICD_TYPER 0x4 +#define GICD_IIDR 0x8 +#define GICD_IGROUPR 0x80 +#define GICD_ISENABLER 0x100 +#define GICD_ICENABLER 0x180 +#define GICD_ISPENDR 0x200 +#define GICD_ICPENDR 0x280 +#define GICD_ISACTIVER 0x300 +#define GICD_ICACTIVER 0x380 +#define GICD_IPRIORITYR 0x400 +#define GICD_ICFGR 0xc00 +#define GICD_NSACR 0xe00 + +/* GICD_CTLR bit definitions */ +#define CTLR_ENABLE_G0_SHIFT 0 +#define CTLR_ENABLE_G0_MASK 0x1 +#define CTLR_ENABLE_G0_BIT (1 << CTLR_ENABLE_G0_SHIFT) + + +/******************************************************************************* + * GIC Distributor interface register constants that are common to GICv3 & GICv2 + ******************************************************************************/ +#define PIDR2_ARCH_REV_SHIFT 4 +#define PIDR2_ARCH_REV_MASK 0xf + +/* GICv3 revision as reported by the PIDR2 register */ +#define ARCH_REV_GICV3 0x3 +/* GICv2 revision as reported by the PIDR2 register */ +#define ARCH_REV_GICV2 0x2 + +#define IGROUPR_SHIFT 5 +#define ISENABLER_SHIFT 5 +#define ICENABLER_SHIFT ISENABLER_SHIFT +#define ISPENDR_SHIFT 5 +#define ICPENDR_SHIFT ISPENDR_SHIFT +#define ISACTIVER_SHIFT 5 +#define ICACTIVER_SHIFT ISACTIVER_SHIFT +#define IPRIORITYR_SHIFT 2 +#define ICFGR_SHIFT 4 +#define NSACR_SHIFT 4 + +/* GICD_TYPER shifts and masks */ +#define TYPER_IT_LINES_NO_SHIFT 0 +#define TYPER_IT_LINES_NO_MASK 0x1f + +/* Value used to initialize Normal world interrupt priorities four at a time */ +#define GICD_IPRIORITYR_DEF_VAL \ + (GIC_HIGHEST_NS_PRIORITY | \ + (GIC_HIGHEST_NS_PRIORITY << 8) | \ + (GIC_HIGHEST_NS_PRIORITY << 16) | \ + (GIC_HIGHEST_NS_PRIORITY << 24)) + +#ifndef __ASSEMBLY__ + +#include <mmio.h> +#include <stdint.h> + +/******************************************************************************* + * GIC Distributor interface register accessors that are common to GICv3 & GICv2 + ******************************************************************************/ +static inline unsigned int gicd_read_ctlr(uintptr_t base) +{ + return mmio_read_32(base + GICD_CTLR); +} + +static inline unsigned int gicd_read_typer(uintptr_t base) +{ + return mmio_read_32(base + GICD_TYPER); +} + +static inline unsigned int gicd_read_iidr(uintptr_t base) +{ + return mmio_read_32(base + GICD_IIDR); +} + +static inline void gicd_write_ctlr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICD_CTLR, val); +} + +/******************************************************************************* + * GIC Distributor function prototypes + ******************************************************************************/ +unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id); +unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id); +unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id); +unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id); +unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id); +unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id); +unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id); +unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id); +unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id); +unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id); +void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val); +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id); +void gicd_set_igroupr(uintptr_t base, unsigned int id); +void gicd_clr_igroupr(uintptr_t base, unsigned int id); +void gicd_set_isenabler(uintptr_t base, unsigned int id); +void gicd_set_icenabler(uintptr_t base, unsigned int id); +void gicd_set_ispendr(uintptr_t base, unsigned int id); +void gicd_set_icpendr(uintptr_t base, unsigned int id); +void gicd_set_isactiver(uintptr_t base, unsigned int id); +void gicd_set_icactiver(uintptr_t base, unsigned int id); + + +#endif /* __ASSEMBLY__ */ +#endif /* __GIC_COMMON_H__ */ diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h index ce9311e8..594ce499 100644 --- a/include/drivers/arm/gic_v2.h +++ b/include/drivers/arm/gic_v2.h @@ -31,6 +31,13 @@ #ifndef __GIC_V2_H__ #define __GIC_V2_H__ +/****************************************************************************** + * THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h + * and for GICv3 systems, use the driver in gicv3.h. + *****************************************************************************/ +#if ERROR_DEPRECATED +#error " The legacy ARM GIC driver is deprecated." +#endif #define GIC400_NUM_SPIS 480 #define MAX_PPIS 14 diff --git a/include/drivers/arm/gic_v3.h b/include/drivers/arm/gic_v3.h index c4106266..a1b6f1b3 100644 --- a/include/drivers/arm/gic_v3.h +++ b/include/drivers/arm/gic_v3.h @@ -31,6 +31,14 @@ #ifndef __GIC_V3_H__ #define __GIC_V3_H__ +/****************************************************************************** + * THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h + * and for GICv3 systems, use the driver in gicv3.h. + *****************************************************************************/ +#if ERROR_DEPRECATED +#error " The legacy ARM GIC driver is deprecated." +#endif + #include <mmio.h> #include <stdint.h> diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h new file mode 100644 index 00000000..88dc0153 --- /dev/null +++ b/include/drivers/arm/gicv2.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV2_H__ +#define __GICV2_H__ + +/******************************************************************************* + * GICv2 miscellaneous definitions + ******************************************************************************/ +/* Interrupt IDs reported by the HPPIR and IAR registers */ +#define PENDING_G1_INTID 1022 + +/******************************************************************************* + * GICv2 specific Distributor interface register offsets and constants. + ******************************************************************************/ +#define GICD_ITARGETSR 0x800 +#define GICD_SGIR 0xF00 +#define GICD_CPENDSGIR 0xF10 +#define GICD_SPENDSGIR 0xF20 +#define GICD_PIDR2_GICV2 0xFE8 + +#define ITARGETSR_SHIFT 2 +#define GIC_TARGET_CPU_MASK 0xff + +#define CPENDSGIR_SHIFT 2 +#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT + +/******************************************************************************* + * GICv2 specific CPU interface register offsets and constants. + ******************************************************************************/ +/* Physical CPU Interface registers */ +#define GICC_CTLR 0x0 +#define GICC_PMR 0x4 +#define GICC_BPR 0x8 +#define GICC_IAR 0xC +#define GICC_EOIR 0x10 +#define GICC_RPR 0x14 +#define GICC_HPPIR 0x18 +#define GICC_AHPPIR 0x28 +#define GICC_IIDR 0xFC +#define GICC_DIR 0x1000 +#define GICC_PRIODROP GICC_EOIR + +/* GICC_CTLR bit definitions */ +#define EOI_MODE_NS (1 << 10) +#define EOI_MODE_S (1 << 9) +#define IRQ_BYP_DIS_GRP1 (1 << 8) +#define FIQ_BYP_DIS_GRP1 (1 << 7) +#define IRQ_BYP_DIS_GRP0 (1 << 6) +#define FIQ_BYP_DIS_GRP0 (1 << 5) +#define CBPR (1 << 4) +#define FIQ_EN_SHIFT 3 +#define FIQ_EN_BIT (1 << FIQ_EN_SHIFT) +#define ACK_CTL (1 << 2) + +/* GICC_IIDR bit masks and shifts */ +#define GICC_IIDR_PID_SHIFT 20 +#define GICC_IIDR_ARCH_SHIFT 16 +#define GICC_IIDR_REV_SHIFT 12 +#define GICC_IIDR_IMP_SHIFT 0 + +#define GICC_IIDR_PID_MASK 0xfff +#define GICC_IIDR_ARCH_MASK 0xf +#define GICC_IIDR_REV_MASK 0xf +#define GICC_IIDR_IMP_MASK 0xfff + +/* HYP view virtual CPU Interface registers */ +#define GICH_CTL 0x0 +#define GICH_VTR 0x4 +#define GICH_ELRSR0 0x30 +#define GICH_ELRSR1 0x34 +#define GICH_APR0 0xF0 +#define GICH_LR_BASE 0x100 + +/* Virtual CPU Interface registers */ +#define GICV_CTL 0x0 +#define GICV_PRIMASK 0x4 +#define GICV_BP 0x8 +#define GICV_INTACK 0xC +#define GICV_EOI 0x10 +#define GICV_RUNNINGPRI 0x14 +#define GICV_HIGHESTPEND 0x18 +#define GICV_DEACTIVATE 0x1000 + +/* GICD_CTLR bit definitions */ +#define CTLR_ENABLE_G1_SHIFT 1 +#define CTLR_ENABLE_G1_MASK 0x1 +#define CTLR_ENABLE_G1_BIT (1 << CTLR_ENABLE_G1_SHIFT) + +/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */ +#define INT_ID_MASK 0x3ff + +#ifndef __ASSEMBLY__ + +#include <stdint.h> + +/******************************************************************************* + * This structure describes some of the implementation defined attributes of + * the GICv2 IP. It is used by the platform port to specify these attributes + * in order to initialize the GICv2 driver. The attributes are described + * below. + * + * 1. The 'gicd_base' field contains the base address of the Distributor + * interface programmer's view. + * + * 2. The 'gicc_base' field contains the base address of the CPU Interface + * programmer's view. + * + * 3. The 'g0_interrupt_array' field is a pointer to an array in which each + * entry corresponds to an ID of a Group 0 interrupt. + * + * 4. The 'g0_interrupt_num' field contains the number of entries in the + * 'g0_interrupt_array'. + ******************************************************************************/ +typedef struct gicv2_driver_data { + uintptr_t gicd_base; + uintptr_t gicc_base; + unsigned int g0_interrupt_num; + const unsigned int *g0_interrupt_array; +} gicv2_driver_data_t; + +/******************************************************************************* + * Function prototypes + ******************************************************************************/ +void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data); +void gicv2_distif_init(void); +void gicv2_pcpu_distif_init(void); +void gicv2_cpuif_enable(void); +void gicv2_cpuif_disable(void); +unsigned int gicv2_is_fiq_enabled(void); +unsigned int gicv2_get_pending_interrupt_type(void); +unsigned int gicv2_get_pending_interrupt_id(void); +unsigned int gicv2_acknowledge_interrupt(void); +void gicv2_end_of_interrupt(unsigned int id); +unsigned int gicv2_get_interrupt_group(unsigned int id); + +#endif /* __ASSEMBLY__ */ +#endif /* __GICV2_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h new file mode 100644 index 00000000..e874f5cd --- /dev/null +++ b/include/drivers/arm/gicv3.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV3_H__ +#define __GICV3_H__ + +/******************************************************************************* + * GICv3 miscellaneous definitions + ******************************************************************************/ +/* Interrupt group definitions */ +#define INT_TYPE_G1S 0 +#define INT_TYPE_G0 1 +#define INT_TYPE_G1NS 2 + +/* Interrupt IDs reported by the HPPIR and IAR registers */ +#define PENDING_G1S_INTID 1020 +#define PENDING_G1NS_INTID 1021 + +/* Constant to categorize LPI interrupt */ +#define MIN_LPI_ID 8192 + +/******************************************************************************* + * GICv3 specific Distributor interface register offsets and constants. + ******************************************************************************/ +#define GICD_STATUSR 0x10 +#define GICD_SETSPI_NSR 0x40 +#define GICD_CLRSPI_NSR 0x48 +#define GICD_SETSPI_SR 0x50 +#define GICD_CLRSPI_SR 0x50 +#define GICD_IGRPMODR 0xd00 +#define GICD_IROUTER 0x6100 +#define GICD_PIDR2_GICV3 0xffe8 + +#define IGRPMODR_SHIFT 5 + +/* GICD_CTLR bit definitions */ +#define CTLR_ENABLE_G1NS_SHIFT 1 +#define CTLR_ENABLE_G1S_SHIFT 2 +#define CTLR_ARE_S_SHIFT 4 +#define CTLR_ARE_NS_SHIFT 5 +#define CTLR_DS_SHIFT 6 +#define CTLR_E1NWF_SHIFT 7 +#define GICD_CTLR_RWP_SHIFT 31 + +#define CTLR_ENABLE_G1NS_MASK 0x1 +#define CTLR_ENABLE_G1S_MASK 0x1 +#define CTLR_ARE_S_MASK 0x1 +#define CTLR_ARE_NS_MASK 0x1 +#define CTLR_DS_MASK 0x1 +#define CTLR_E1NWF_MASK 0x1 +#define GICD_CTLR_RWP_MASK 0x1 + +#define CTLR_ENABLE_G1NS_BIT (1 << CTLR_ENABLE_G1NS_SHIFT) +#define CTLR_ENABLE_G1S_BIT (1 << CTLR_ENABLE_G1S_SHIFT) +#define CTLR_ARE_S_BIT (1 << CTLR_ARE_S_SHIFT) +#define CTLR_ARE_NS_BIT (1 << CTLR_ARE_NS_SHIFT) +#define CTLR_DS_BIT (1 << CTLR_DS_SHIFT) +#define CTLR_E1NWF_BIT (1 << CTLR_E1NWF_SHIFT) +#define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT) + +/* GICD_IROUTER shifts and masks */ +#define IROUTER_IRM_SHIFT 31 +#define IROUTER_IRM_MASK 0x1 + +/******************************************************************************* + * GICv3 Re-distributor interface registers & constants + ******************************************************************************/ +#define GICR_PCPUBASE_SHIFT 0x11 +#define GICR_SGIBASE_OFFSET (1 << 0x10) /* 64 KB */ +#define GICR_CTLR 0x0 +#define GICR_TYPER 0x08 +#define GICR_WAKER 0x14 +#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80) +#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100) +#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180) +#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + 0x400) +#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + 0xc00) +#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + 0xc04) +#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + 0xd00) + +/* GICR_CTLR bit definitions */ +#define GICR_CTLR_RWP_SHIFT 3 +#define GICR_CTLR_RWP_MASK 0x1 +#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT) + +/* GICR_WAKER bit definitions */ +#define WAKER_CA_SHIFT 2 +#define WAKER_PS_SHIFT 1 + +#define WAKER_CA_MASK 0x1 +#define WAKER_PS_MASK 0x1 + +#define WAKER_CA_BIT (1 << WAKER_CA_SHIFT) +#define WAKER_PS_BIT (1 << WAKER_PS_SHIFT) + +/* GICR_TYPER bit definitions */ +#define TYPER_AFF_VAL_SHIFT 32 +#define TYPER_PROC_NUM_SHIFT 8 +#define TYPER_LAST_SHIFT 4 + +#define TYPER_AFF_VAL_MASK 0xffffffff +#define TYPER_PROC_NUM_MASK 0xffff +#define TYPER_LAST_MASK 0x1 + +#define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT) + +/******************************************************************************* + * GICv3 CPU interface registers & constants + ******************************************************************************/ +/* ICC_SRE bit definitions*/ +#define ICC_SRE_EN_BIT (1 << 3) +#define ICC_SRE_DIB_BIT (1 << 2) +#define ICC_SRE_DFB_BIT (1 << 1) +#define ICC_SRE_SRE_BIT (1 << 0) + +/* ICC_IGRPEN1_EL3 bit definitions */ +#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0 +#define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1 + +#define IGRPEN1_EL3_ENABLE_G1NS_BIT (1 << IGRPEN1_EL3_ENABLE_G1NS_SHIFT) +#define IGRPEN1_EL3_ENABLE_G1S_BIT (1 << IGRPEN1_EL3_ENABLE_G1S_SHIFT) + +/* ICC_IGRPEN0_EL1 bit definitions */ +#define IGRPEN1_EL1_ENABLE_G0_SHIFT 0 +#define IGRPEN1_EL1_ENABLE_G0_BIT (1 << IGRPEN1_EL1_ENABLE_G0_SHIFT) + +/* ICC_HPPIR0_EL1 bit definitions */ +#define HPPIR0_EL1_INTID_SHIFT 0 +#define HPPIR0_EL1_INTID_MASK 0xffffff + +/* ICC_HPPIR1_EL1 bit definitions */ +#define HPPIR1_EL1_INTID_SHIFT 0 +#define HPPIR1_EL1_INTID_MASK 0xffffff + +/* ICC_IAR0_EL1 bit definitions */ +#define IAR0_EL1_INTID_SHIFT 0 +#define IAR0_EL1_INTID_MASK 0xffffff + +/* ICC_IAR1_EL1 bit definitions */ +#define IAR1_EL1_INTID_SHIFT 0 +#define IAR1_EL1_INTID_MASK 0xffffff + +#ifndef __ASSEMBLY__ + +#include <stdint.h> + +#define gicv3_is_intr_id_special_identifier(id) \ + (((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT)) + +/******************************************************************************* + * Helper GICv3 macros for SEL1 + ******************************************************************************/ +#define gicv3_acknowledge_interrupt_sel1() read_icc_iar1_el1() &\ + IAR1_EL1_INTID_MASK +#define gicv3_get_pending_interrupt_id_sel1() read_icc_hppir1_el1() &\ + HPPIR1_EL1_INTID_MASK +#define gicv3_end_of_interrupt_sel1(id) write_icc_eoir1_el1(id) + + +/******************************************************************************* + * Helper GICv3 macros for EL3 + ******************************************************************************/ +#define gicv3_acknowledge_interrupt() read_icc_iar0_el1() &\ + IAR0_EL1_INTID_MASK +#define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id) + +/******************************************************************************* + * This structure describes some of the implementation defined attributes of the + * GICv3 IP. It is used by the platform port to specify these attributes in order + * to initialise the GICV3 driver. The attributes are described below. + * + * 1. The 'gicd_base' field contains the base address of the Distributor + * interface programmer's view. + * + * 2. The 'gicr_base' field contains the base address of the Re-distributor + * interface programmer's view. + * + * 3. The 'g0_interrupt_array' field is a ponter to an array in which each + * entry corresponds to an ID of a Group 0 interrupt. + * + * 4. The 'g0_interrupt_num' field contains the number of entries in the + * 'g0_interrupt_array'. + * + * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each + * entry corresponds to an ID of a Group 1 interrupt. + * + * 6. The 'g1s_interrupt_num' field contains the number of entries in the + * 'g1s_interrupt_array'. + * + * 7. The 'rdistif_num' field contains the number of Redistributor interfaces + * the GIC implements. This is equal to the number of CPUs or CPU interfaces + * instantiated in the GIC. + * + * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry + * for storing the base address of the Redistributor interface frame of each + * CPU in the system. The size of the array = 'rdistif_num'. The base + * addresses are detected during driver initialisation. + * + * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the + * driver will use to convert an MPIDR value to a linear core index. This + * index will be used for accessing the 'rdistif_base_addrs' array. This is + * an optional field. A GICv3 implementation maps each MPIDR to a linear core + * index as well. This mapping can be found by reading the "Affinity Value" + * and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the + * "Processor Numbers" are suitable to index into an array to access core + * specific information. If this not the case, the platform port must provide + * a hash function. Otherwise, the "Processor Number" field will be used to + * access the array elements. + ******************************************************************************/ +typedef unsigned int (*mpidr_hash_fn)(unsigned long mpidr); + +typedef struct gicv3_driver_data { + uintptr_t gicd_base; + uintptr_t gicr_base; + unsigned int g0_interrupt_num; + unsigned int g1s_interrupt_num; + const unsigned int *g0_interrupt_array; + const unsigned int *g1s_interrupt_array; + unsigned int rdistif_num; + uintptr_t *rdistif_base_addrs; + mpidr_hash_fn mpidr_to_core_pos; +} gicv3_driver_data_t; + +/******************************************************************************* + * GICv3 EL3 driver API + ******************************************************************************/ +void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data); +void gicv3_distif_init(void); +void gicv3_rdistif_init(unsigned int proc_num); +void gicv3_cpuif_enable(unsigned int proc_num); +void gicv3_cpuif_disable(unsigned int proc_num); +unsigned int gicv3_get_pending_interrupt_type(void); +unsigned int gicv3_get_pending_interrupt_id(void); +unsigned int gicv3_get_interrupt_type(unsigned int id, + unsigned int proc_num); + + +#endif /* __ASSEMBLY__ */ +#endif /* __GICV3_H__ */ diff --git a/include/drivers/arm/sp805.h b/include/drivers/arm/sp805.h new file mode 100644 index 00000000..6bd81587 --- /dev/null +++ b/include/drivers/arm/sp805.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SP805_H__ +#define __SP805_H__ + +/* SP805 register offset */ +#define SP805_WDOG_LOAD_OFF 0x000 +#define SP805_WDOG_CTR_OFF 0x008 +#define SP805_WDOG_LOCK_OFF 0xc00 + +/* Magic word to unlock the wd registers */ +#define WDOG_UNLOCK_KEY 0x1ACCE551 + +/* Register field definitions */ +#define SP805_CTR_RESEN (1 << 1) +#define SP805_CTR_INTEN (1 << 0) + +#ifndef __ASSEMBLY__ + +#include <stdint.h> + +/* Public high level API */ + +void sp805_start(uintptr_t base, unsigned long ticks); +void sp805_stop(uintptr_t base); +void sp805_refresh(uintptr_t base, unsigned long ticks); + +#endif /* __ASSEMBLY__ */ + +#endif /* __SP805_H__ */ diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index 9aea2c9d..49efafc5 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -88,6 +88,14 @@ #define ICC_CTLR_EL1 S3_0_C12_C12_4 #define ICC_CTLR_EL3 S3_6_C12_C12_4 #define ICC_PMR_EL1 S3_0_C4_C6_0 +#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7 +#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6 +#define ICC_HPPIR0_EL1 S3_0_c12_c8_2 +#define ICC_HPPIR1_EL1 S3_0_c12_c12_2 +#define ICC_IAR0_EL1 S3_0_c12_c8_0 +#define ICC_IAR1_EL1 S3_0_c12_c12_0 +#define ICC_EOIR0_EL1 S3_0_c12_c8_1 +#define ICC_EOIR1_EL1 S3_0_c12_c12_1 /******************************************************************************* * Generic timer memory mapped registers & offsets @@ -122,6 +130,10 @@ #define ID_AA64PFR0_EL3_SHIFT 12 #define ID_AA64PFR0_ELX_MASK 0xf +#define ID_AA64PFR0_GIC_SHIFT 24 +#define ID_AA64PFR0_GIC_WIDTH 4 +#define ID_AA64PFR0_GIC_MASK ((1 << ID_AA64PFR0_GIC_WIDTH) - 1) + /* ID_PFR1_EL1 definitions */ #define ID_PFR1_VIRTEXT_SHIFT 12 #define ID_PFR1_VIRTEXT_MASK 0xf diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index d01ea315..43c6917e 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -74,6 +74,14 @@ static inline void write_ ## _name(const uint64_t v) \ _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) +/* Define read function for renamed system register */ +#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \ + _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) + +/* Define write function for renamed system register */ +#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \ + _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) + /* Define write function for special system registers */ #define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \ _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name) @@ -284,12 +292,18 @@ DEFINE_SYSREG_READ_FUNC(isr_el1) DEFINE_SYSREG_READ_FUNC(ctr_el0) -/* GICv3 System Registers */ - DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1) +DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1) +DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1) #define IS_IN_EL(x) \ diff --git a/include/plat/arm/board/common/board_arm_oid.h b/include/plat/arm/board/common/board_arm_oid.h index 92a9bd1e..b29212e4 100644 --- a/include/plat/arm/board/common/board_arm_oid.h +++ b/include/plat/arm/board/common/board_arm_oid.h @@ -32,39 +32,136 @@ #define __BOARD_ARM_OID_H__ /* - * This is the list of the different extensions containing relevant information - * to establish the chain of trust. + * The following is a list of OID values defined and reserved by ARM, which + * are used to define the extension fields of the certificate structure, as + * defined in the Trusted Board Boot Requirements (TBBR) specification, + * ARM DEN0006C-1. * - * The OIDs shown here are just an example. Real OIDs should be obtained from - * the ITU-T. + * Non-ARM platform owners that wish to align with the TBBR should define + * constants with the same name in their own platform port(s), using their + * own OIDs obtained from the ITU-T. */ -/* Non-volatile counter extensions */ -#define TZ_FW_NVCOUNTER_OID "1.2.3.1" -#define NTZ_FW_NVCOUNTER_OID "1.2.3.2" -/* BL2 extensions */ -#define BL2_HASH_OID "1.2.3.3" +/* TrustedFirmwareNVCounter - Non-volatile counter extension */ +#define TZ_FW_NVCOUNTER_OID "1.3.6.1.4.1.4128.2100.1" +/* NonTrustedFirmwareNVCounter - Non-volatile counter extension */ +#define NTZ_FW_NVCOUNTER_OID "1.3.6.1.4.1.4128.2100.2" -/* Trusted Key extensions */ -#define TZ_WORLD_PK_OID "1.2.3.4" -#define NTZ_WORLD_PK_OID "1.2.3.5" -/* BL3-1 extensions */ -#define BL31_CONTENT_CERT_PK_OID "1.2.3.6" -#define BL31_HASH_OID "1.2.3.7" +/* + * Non-Trusted Firmware Updater Certificate + */ + +/* APFirmwareUpdaterConfigHash - BL2U */ +#define BL2U_HASH_OID "1.3.6.1.4.1.4128.2100.101" +/* SCPFirmwareUpdaterConfigHash - SCP_BL2U */ +#define SCP_BL2U_HASH_OID "1.3.6.1.4.1.4128.2100.102" +/* FirmwareUpdaterHash - NS_BL2U */ +#define NS_BL2U_HASH_OID "1.3.6.1.4.1.4128.2100.103" +/* TrustedWatchdogRefreshTime */ +#define TRUSTED_WATCHDOG_TIME_OID "1.3.6.1.4.1.4128.2100.104" + + +/* + * Trusted Boot Firmware Certificate + */ + +/* TrustedBootFirmwareHash - BL2 */ +#define BL2_HASH_OID "1.3.6.1.4.1.4128.2100.201" + + +/* + * Trusted Key Certificate + */ + +/* PrimaryDebugCertificatePK */ +#define PRIMARY_DEBUG_PK_OID "1.3.6.1.4.1.4128.2100.301" +/* TrustedWorldPK */ +#define TZ_WORLD_PK_OID "1.3.6.1.4.1.4128.2100.302" +/* NonTrustedWorldPK */ +#define NTZ_WORLD_PK_OID "1.3.6.1.4.1.4128.2100.303" + + +/* + * Trusted Debug Certificate + */ + +/* DebugScenario */ +#define TRUSTED_DEBUG_SCENARIO_OID "1.3.6.1.4.1.4128.2100.401" +/* SoC Specific */ +#define TRUSTED_DEBUG_SOC_SPEC_OID "1.3.6.1.4.1.4128.2100.402" +/* SecondaryDebugCertPK */ +#define SECONDARY_DEBUG_PK_OID "1.3.6.1.4.1.4128.2100.403" + + +/* + * SoC Firmware Key Certificate + */ + +/* SoCFirmwareContentCertPK */ +#define BL31_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.501" + + +/* + * SoC Firmware Content Certificate + */ -/* BL3-0 extensions */ -#define BL30_CONTENT_CERT_PK_OID "1.2.3.8" -#define BL30_HASH_OID "1.2.3.9" +/* APRomPatchHash - BL1_PATCH */ +#define APROM_PATCH_HASH_OID "1.3.6.1.4.1.4128.2100.601" +/* SoCConfigHash */ +#define SOC_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.602" +/* SoCAPFirmwareHash - BL31 */ +#define BL31_HASH_OID "1.3.6.1.4.1.4128.2100.603" -/* BL3-2 extensions */ -#define BL32_CONTENT_CERT_PK_OID "1.2.3.10" -#define BL32_HASH_OID "1.2.3.11" -/* BL3-3 extensions */ -#define BL33_CONTENT_CERT_PK_OID "1.2.3.12" -#define BL33_HASH_OID "1.2.3.13" +/* + * SCP Firmware Key Certificate + */ + +/* SCPFirmwareContentCertPK */ +#define BL30_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.701" + + +/* + * SCP Firmware Content Certificate + */ + +/* SCPFirmwareHash - BL30 */ +#define BL30_HASH_OID "1.3.6.1.4.1.4128.2100.801" +/* SCPRomPatchHash - BL0_PATCH */ +#define SCP_ROM_PATCH_HASH_OID "1.3.6.1.4.1.4128.2100.802" + + +/* + * Trusted OS Firmware Key Certificate + */ + +/* TrustedOSFirmwareContentCertPK */ +#define BL32_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.901" + + +/* + * Trusted OS Firmware Content Certificate + */ + +/* TrustedOSFirmwareHash - BL32 */ +#define BL32_HASH_OID "1.3.6.1.4.1.4128.2100.1001" + + +/* + * Non-Trusted Firmware Key Certificate + */ + +/* NonTrustedFirmwareContentCertPK */ +#define BL33_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.1101" + + +/* + * Non-Trusted Firmware Content Certificate + */ +/* NonTrustedWorldBootloaderHash - BL33 */ +#define BL33_HASH_OID "1.3.6.1.4.1.4128.2100.1201" #endif /* __BOARD_ARM_OID_H__ */ diff --git a/include/plat/arm/board/common/drivers/norflash.h b/include/plat/arm/board/common/drivers/norflash.h new file mode 100644 index 00000000..0bf35a50 --- /dev/null +++ b/include/plat/arm/board/common/drivers/norflash.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NORFLASH_H_ +#define __NORFLASH_H_ + +#include <stdint.h> + +/* First bus cycle */ +#define NOR_CMD_READ_ARRAY 0xFF +#define NOR_CMD_READ_ID_CODE 0x90 +#define NOR_CMD_READ_QUERY 0x98 +#define NOR_CMD_READ_STATUS_REG 0x70 +#define NOR_CMD_CLEAR_STATUS_REG 0x50 +#define NOR_CMD_WRITE_TO_BUFFER 0xE8 +#define NOR_CMD_WORD_PROGRAM 0x40 +#define NOR_CMD_BLOCK_ERASE 0x20 +#define NOR_CMD_LOCK_UNLOCK 0x60 + +/* Second bus cycle */ +#define NOR_LOCK_BLOCK 0x01 +#define NOR_UNLOCK_BLOCK 0xD0 + +/* Status register bits */ +#define NOR_DWS (1 << 7) +#define NOR_ESS (1 << 6) +#define NOR_ES (1 << 5) +#define NOR_PS (1 << 4) +#define NOR_VPPS (1 << 3) +#define NOR_PSS (1 << 2) +#define NOR_BLS (1 << 1) +#define NOR_BWS (1 << 0) + +/* Public API */ +void nor_send_cmd(uintptr_t base_addr, unsigned long cmd); +int nor_word_program(uintptr_t base_addr, unsigned long data); +void nor_lock(uintptr_t base_addr); +void nor_unlock(uintptr_t base_addr); + +#endif /* __NORFLASH_H_ */ + diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h index 7a4ef5ad..7ed0af6c 100644 --- a/include/plat/arm/board/common/v2m_def.h +++ b/include/plat/arm/board/common/v2m_def.h @@ -38,6 +38,9 @@ #define V2M_SYS_ID 0x0 #define V2M_SYS_SWITCH 0x4 #define V2M_SYS_LED 0x8 +#define V2M_SYS_NVFLAGS 0x38 +#define V2M_SYS_NVFLAGSSET 0x38 +#define V2M_SYS_NVFLAGSCLR 0x3c #define V2M_SYS_CFGDATA 0xa0 #define V2M_SYS_CFGCTRL 0xa4 #define V2M_SYS_CFGSTATUS 0xa8 @@ -109,7 +112,11 @@ #define V2M_SP804_TIMER0_BASE 0x1C110000 #define V2M_SP804_TIMER1_BASE 0x1C120000 -#define V2M_MAP_FLASH0 MAP_REGION_FLAT(V2M_FLASH0_BASE,\ +#define V2M_MAP_FLASH0_RW MAP_REGION_FLAT(V2M_FLASH0_BASE,\ + V2M_FLASH0_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define V2M_MAP_FLASH0_RO MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h index 452c3856..4726d5e5 100644 --- a/include/plat/arm/common/arm_def.h +++ b/include/plat/arm/common/arm_def.h @@ -175,6 +175,15 @@ #define ARM_CONSOLE_BAUDRATE 115200 +/* Trusted Watchdog constants */ +#define ARM_SP805_TWDG_BASE 0x2a490000 +#define ARM_SP805_TWDG_CLK_HZ 32768 +/* The TBBR document specifies a watchdog timeout of 256 seconds. SP805 + * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) */ +#define ARM_TWDG_TIMEOUT_SEC 128 +#define ARM_TWDG_LOAD_VAL (ARM_SP805_TWDG_CLK_HZ * \ + ARM_TWDG_TIMEOUT_SEC) + /****************************************************************************** * Required platform porting definitions common to all ARM standard platforms *****************************************************************************/ diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index 044e18ef..aadf58d8 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -149,6 +149,7 @@ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); int arm_validate_ns_entrypoint(uintptr_t entrypoint); void arm_system_pwr_domain_resume(void); +void arm_program_trusted_mailbox(uintptr_t address); /* Topology utility function */ int arm_check_mpidr(u_register_t mpidr); diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h index 077080df..43c69cc8 100644 --- a/include/plat/common/common_def.h +++ b/include/plat/common/common_def.h @@ -69,15 +69,10 @@ /* * Macros to wrap declarations of deprecated APIs within Trusted Firmware. - * The callers of these APIs will continue to compile as long as the build - * flag WARN_DEPRECATED is zero. Else the compiler will emit a warning - * when the callers of these APIs are compiled. + * The callers of these APIs will continue to compile with a warning as long + * as the build flag ERROR_DEPRECATED is zero. */ -#if WARN_DEPRECATED #define __warn_deprecated __attribute__ ((deprecated)) -#else -#define __warn_deprecated -#endif #endif /* __COMMON_DEF_H__ */ diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk index bec49ed2..9e0c8484 100644 --- a/plat/arm/board/common/board_common.mk +++ b/plat/arm/board/common/board_common.mk @@ -28,14 +28,15 @@ # POSSIBILITY OF SUCH DAMAGE. # -PLAT_INCLUDES += -Iinclude/plat/arm/board/common/ +PLAT_INCLUDES += -Iinclude/plat/arm/board/common/ \ + -Iinclude/plat/arm/board/common/drivers PLAT_BL_COMMON_SOURCES += drivers/arm/pl011/pl011_console.S \ plat/arm/board/common/aarch64/board_arm_helpers.S -#BL1_SOURCES += +BL1_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c -#BL2_SOURCES += +BL2_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c #BL31_SOURCES += diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c index 3bb3dd6f..7bf0273d 100644 --- a/plat/arm/board/common/board_css_common.c +++ b/plat/arm/board/common/board_css_common.c @@ -38,7 +38,7 @@ #if IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, - V2M_MAP_FLASH0, + V2M_MAP_FLASH0_RO, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, @@ -48,7 +48,7 @@ const mmap_region_t plat_arm_mmap[] = { #if IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, - V2M_MAP_FLASH0, + V2M_MAP_FLASH0_RO, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, diff --git a/plat/arm/board/common/drivers/norflash/norflash.c b/plat/arm/board/common/drivers/norflash/norflash.c new file mode 100644 index 00000000..88954614 --- /dev/null +++ b/plat/arm/board/common/drivers/norflash/norflash.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <errno.h> +#include <mmio.h> +#include <norflash.h> + +/* Helper macros to access two flash banks in parallel */ +#define NOR_2X16(d) ((d << 16) | (d & 0xffff)) + +/* + * DWS ready poll retries. The number of retries in this driver have been + * obtained empirically from Juno. FVP implements a zero wait state NOR flash + * model + */ +#define DWS_WORD_PROGRAM_RETRIES 1000 + +/* + * Poll Write State Machine. Return values: + * 0 = WSM ready + * -EBUSY = WSM busy after the number of retries + */ +static int nor_poll_dws(uintptr_t base_addr, unsigned int retries) +{ + uint32_t status; + int ret; + + for (;;) { + nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); + status = mmio_read_32(base_addr); + if ((status & NOR_DWS) && + (status & (NOR_DWS << 16))) { + ret = 0; + break; + } + if (retries-- == 0) { + ret = -EBUSY; + break; + } + } + + return ret; +} + +void nor_send_cmd(uintptr_t base_addr, unsigned long cmd) +{ + mmio_write_32(base_addr, NOR_2X16(cmd)); +} + +/* + * Return values: + * 0 = success + * -EBUSY = WSM not ready + * -EPERM = Device protected or Block locked + */ +int nor_word_program(uintptr_t base_addr, unsigned long data) +{ + uint32_t status; + int ret; + + /* Set the device in write word mode */ + nor_send_cmd(base_addr, NOR_CMD_WORD_PROGRAM); + mmio_write_32(base_addr, data); + + ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES); + if (ret != 0) { + goto word_program_end; + } + + /* Full status check */ + nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); + status = mmio_read_32(base_addr); + + if (status & (NOR_PS | NOR_BLS)) { + nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); + ret = -EPERM; + } + +word_program_end: + nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); + return ret; +} + +void nor_lock(uintptr_t base_addr) +{ + nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); + mmio_write_32(base_addr, NOR_2X16(NOR_LOCK_BLOCK)); + nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); +} + +void nor_unlock(uintptr_t base_addr) +{ + nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); + mmio_write_32(base_addr, NOR_2X16(NOR_UNLOCK_BLOCK)); + nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); +} + diff --git a/plat/arm/board/fvp/aarch64/fvp_common.c b/plat/arm/board/fvp/aarch64/fvp_common.c index 58b646a4..8771e5b4 100644 --- a/plat/arm/board/fvp/aarch64/fvp_common.c +++ b/plat/arm/board/fvp/aarch64/fvp_common.c @@ -68,7 +68,7 @@ arm_config_t arm_config; #if IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, - V2M_MAP_FLASH0, + V2M_MAP_FLASH0_RW, V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, @@ -79,7 +79,7 @@ const mmap_region_t plat_arm_mmap[] = { #if IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, - V2M_MAP_FLASH0, + V2M_MAP_FLASH0_RW, V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S index 865c615a..2c24e61f 100644 --- a/plat/arm/board/fvp/aarch64/fvp_helpers.S +++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S @@ -60,6 +60,7 @@ * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup +#ifndef EL3_PAYLOAD_BASE /* --------------------------------------------- * Power down this cpu. * TODO: Do we need to worry about powering the @@ -93,6 +94,18 @@ func plat_secondary_cold_boot_setup wfi cb_panic: b cb_panic +#else + mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE + + /* Wait until the entrypoint gets populated */ +poll_mailbox: + ldr x1, [x0] + cbz x1, 1f + br x1 +1: + wfe + b poll_mailbox +#endif /* EL3_PAYLOAD_BASE */ endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- diff --git a/plat/arm/board/fvp/fvp_err.c b/plat/arm/board/fvp/fvp_err.c new file mode 100644 index 00000000..7867e49c --- /dev/null +++ b/plat/arm/board/fvp/fvp_err.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <board_arm_def.h> +#include <debug.h> +#include <errno.h> +#include <norflash.h> +#include <stdint.h> + +/* + * FVP error handler + */ +void plat_error_handler(int err) +{ + int ret; + + switch (err) { + case -ENOENT: + case -EAUTH: + /* Image load or authentication error. Erase the ToC */ + INFO("Erasing FIP ToC from flash...\n"); + nor_unlock(PLAT_ARM_FIP_BASE); + ret = nor_word_program(PLAT_ARM_FIP_BASE, 0); + if (ret) { + ERROR("Cannot erase ToC\n"); + } else { + INFO("Done\n"); + } + break; + default: + /* Unexpected error */ + break; + } + + /* Loop until the watchdog resets the system */ + for (;;) + ; +} diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 51b718ee..c46d3b71 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -41,6 +41,7 @@ BL1_SOURCES += drivers/io/io_semihosting.c \ lib/semihosting/aarch64/semihosting_call.S \ plat/arm/board/fvp/aarch64/fvp_helpers.S \ plat/arm/board/fvp/fvp_bl1_setup.c \ + plat/arm/board/fvp/fvp_err.c \ plat/arm/board/fvp/fvp_io_storage.c BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c \ @@ -49,6 +50,7 @@ BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c \ lib/semihosting/semihosting.c \ lib/semihosting/aarch64/semihosting_call.S \ plat/arm/board/fvp/fvp_bl2_setup.c \ + plat/arm/board/fvp/fvp_err.c \ plat/arm/board/fvp/fvp_io_storage.c \ plat/arm/board/fvp/fvp_security.c diff --git a/plat/arm/board/juno/juno_err.c b/plat/arm/board/juno/juno_err.c new file mode 100644 index 00000000..497cc7fa --- /dev/null +++ b/plat/arm/board/juno/juno_err.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <errno.h> +#include <v2m_def.h> + +#define V2M_SYS_NVFLAGS_ADDR (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS) + +/* + * Juno error handler + */ +void plat_error_handler(int err) +{ + uint32_t *flags_ptr = (uint32_t *)V2M_SYS_NVFLAGS_ADDR; + + /* Propagate the err code in the NV-flags register */ + *flags_ptr = err; + + /* Loop until the watchdog resets the system */ + for (;;) + ; +} diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk index b711f3d5..127dcbea 100644 --- a/plat/arm/board/juno/platform.mk +++ b/plat/arm/board/juno/platform.mk @@ -34,9 +34,11 @@ PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/aarch64/juno_helpers.S BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ - lib/cpus/aarch64/cortex_a72.S + lib/cpus/aarch64/cortex_a72.S \ + plat/arm/board/juno/juno_err.c BL2_SOURCES += plat/arm/board/juno/juno_security.c \ + plat/arm/board/juno/juno_err.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c index ddf383fe..79c7d944 100644 --- a/plat/arm/common/arm_bl1_setup.c +++ b/plat/arm/common/arm_bl1_setup.c @@ -35,6 +35,7 @@ #include <console.h> #include <platform_def.h> #include <plat_arm.h> +#include <sp805.h> #include "../../../bl1/bl1_private.h" @@ -74,6 +75,11 @@ void arm_bl1_early_platform_setup(void) { const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; +#if !ARM_DISABLE_TRUSTED_WDOG + /* Enable watchdog */ + sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); +#endif + /* Initialize the console to provide early debug support */ console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE); @@ -145,6 +151,25 @@ void bl1_platform_setup(void) arm_bl1_platform_setup(); } +void bl1_plat_prepare_exit(entry_point_info_t *ep_info) +{ +#if !ARM_DISABLE_TRUSTED_WDOG + /* Disable watchdog before leaving BL1 */ + sp805_stop(ARM_SP805_TWDG_BASE); +#endif + +#ifdef EL3_PAYLOAD_BASE + /* + * Program the EL3 payload's entry point address into the CPUs mailbox + * in order to release secondary CPUs from their holding pen and make + * them jump there. + */ + arm_program_trusted_mailbox(ep_info->pc); + dsbsy(); + sev(); +#endif +} + /******************************************************************************* * Before calling this function BL2 is loaded in memory and its entrypoint * is set by load_image. This is a placeholder for the platform to change diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c index 923c333c..8682fd19 100644 --- a/plat/arm/common/arm_bl31_setup.c +++ b/plat/arm/common/arm_bl31_setup.c @@ -124,7 +124,8 @@ void arm_bl31_early_platform_setup(bl31_params_t *from_bl2, assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); - /* Populate entry point information for BL3-2 and BL3-3 */ +#ifdef BL32_BASE + /* Populate entry point information for BL3-2 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, @@ -132,7 +133,9 @@ void arm_bl31_early_platform_setup(bl31_params_t *from_bl2, SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); +#endif /* BL32_BASE */ + /* Populate entry point information for BL3-3 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, @@ -161,10 +164,11 @@ void arm_bl31_early_platform_setup(bl31_params_t *from_bl2, ARM_BL31_PLAT_PARAM_VAL); /* - * Copy BL3-2 and BL3-3 entry point information. + * Copy BL3-2 (if populated by BL2) and BL3-3 entry point information. * They are stored in Secure RAM, in BL2's address space. */ - bl32_image_ep_info = *from_bl2->bl32_ep_info; + if (from_bl2->bl32_ep_info) + bl32_image_ep_info = *from_bl2->bl32_ep_info; bl33_image_ep_info = *from_bl2->bl33_ep_info; #endif } diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index eb5ae111..1290cef3 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -63,6 +63,15 @@ endif $(eval $(call assert_boolean,ARM_RECOM_STATE_ID_ENC)) $(eval $(call add_define,ARM_RECOM_STATE_ID_ENC)) +# Process ARM_DISABLE_TRUSTED_WDOG flag +# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set +ARM_DISABLE_TRUSTED_WDOG := 0 +ifeq (${SPIN_ON_BL1_EXIT}, 1) +ARM_DISABLE_TRUSTED_WDOG := 1 +endif +$(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG)) +$(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG)) + PLAT_INCLUDES += -Iinclude/common/tbbr \ -Iinclude/plat/arm/common \ -Iinclude/plat/arm/common/aarch64 @@ -75,12 +84,18 @@ PLAT_BL_COMMON_SOURCES += lib/aarch64/xlat_tables.c \ BL1_SOURCES += drivers/arm/cci/cci.c \ drivers/arm/ccn/ccn.c \ + drivers/arm/sp805/sp805.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl1_setup.c \ plat/arm/common/arm_io_storage.c \ plat/common/aarch64/platform_up_stack.S +ifdef EL3_PAYLOAD_BASE +# Need the arm_program_trusted_mailbox() function to release secondary CPUs from +# their holding pen +BL1_SOURCES += plat/arm/common/arm_pm.c +endif BL2_SOURCES += drivers/arm/tzc400/tzc400.c \ drivers/io/io_fip.c \ diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c index d13d2683..cae65970 100644 --- a/plat/arm/common/arm_pm.c +++ b/plat/arm/common/arm_pm.c @@ -175,7 +175,7 @@ void arm_system_pwr_domain_resume(void) * from reset. This function assumes that the Trusted mail box base is within * the ARM_SHARED_RAM region ******************************************************************************/ -static void arm_program_trusted_mailbox(uintptr_t address) +void arm_program_trusted_mailbox(uintptr_t address) { uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; diff --git a/plat/arm/common/arm_security.c b/plat/arm/common/arm_security.c index 990d8d4a..8b46aaed 100644 --- a/plat/arm/common/arm_security.c +++ b/plat/arm/common/arm_security.c @@ -40,8 +40,13 @@ /******************************************************************************* * Initialize the TrustZone Controller for ARM standard platforms. - * Configure Region 0 with no access, Region 1 with secure access only, and - * the remaining DRAM regions access from the given Non-Secure masters. + * Configure: + * - Region 0 with no access; + * - Region 1 with secure access only; + * - 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_setup(void) { @@ -52,6 +57,7 @@ void arm_tzc_setup(void) /* Disable filters. */ tzc_disable_filters(); +#ifndef EL3_PAYLOAD_BASE /* Region 0 set to no access by default */ tzc_configure_region0(TZC_REGION_S_NONE, 0); @@ -73,6 +79,10 @@ void arm_tzc_setup(void) 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); +#endif /* EL3_PAYLOAD_BASE */ /* * Raise an exception if a NS device tries to access secure memory diff --git a/plat/arm/css/common/aarch64/css_helpers.S b/plat/arm/css/common/aarch64/css_helpers.S index d1702708..27476186 100644 --- a/plat/arm/css/common/aarch64/css_helpers.S +++ b/plat/arm/css/common/aarch64/css_helpers.S @@ -37,19 +37,36 @@ .globl css_calc_core_pos_swap_cluster .weak plat_is_my_cpu_primary - /* ----------------------------------------------------- - * void plat_secondary_cold_boot_setup (void); + /* --------------------------------------------------------------------- + * void plat_secondary_cold_boot_setup(void); * - * This function performs any platform specific actions - * needed for a secondary cpu after a cold reset e.g - * mark the cpu's presence, mechanism to place it in a - * holding pen etc. - * ----------------------------------------------------- + * In the normal boot flow, cold-booting secondary CPUs is not yet + * implemented and they panic. + * + * When booting an EL3 payload, secondary CPUs are placed in a holding + * pen, waiting for their mailbox to be populated. Note that all CPUs + * share the same mailbox ; therefore, populating it will release all + * CPUs from their holding pen. If finer-grained control is needed then + * this should be handled in the code that secondary CPUs jump to. + * --------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup - /* todo: Implement secondary CPU cold boot setup on CSS platforms */ +#ifndef EL3_PAYLOAD_BASE + /* TODO: Implement secondary CPU cold boot setup on CSS platforms */ cb_panic: b cb_panic +#else + mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE + + /* Wait until the mailbox gets populated */ +poll_mailbox: + ldr x1, [x0] + cbz x1, 1f + br x1 +1: + wfe + b poll_mailbox +#endif /* EL3_PAYLOAD_BASE */ endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c index 2e423d96..6054f7a5 100644 --- a/plat/arm/css/common/css_bl2_setup.c +++ b/plat/arm/css/common/css_bl2_setup.c @@ -29,7 +29,11 @@ */ #include <bl_common.h> +#include <css_def.h> #include <debug.h> +#include <mmio.h> +#include <plat_arm.h> +#include <string.h> #include "css_scp_bootloader.h" /* Weak definition may be overridden in specific CSS based platform */ @@ -55,3 +59,38 @@ int bl2_plat_handle_bl30(image_info_t *bl30_image_info) return ret; } + +#ifdef EL3_PAYLOAD_BASE +/* + * We need to override some of the platform functions when booting an EL3 + * payload. + */ + +static unsigned int scp_boot_config; + +void bl2_early_platform_setup(meminfo_t *mem_layout) +{ + arm_bl2_early_platform_setup(mem_layout); + + /* Save SCP Boot config before it gets overwritten by BL30 loading */ + scp_boot_config = mmio_read_32(SCP_BOOT_CFG_ADDR); + VERBOSE("BL2: Saved SCP Boot config = 0x%x\n", scp_boot_config); +} + +void bl2_platform_setup(void) +{ + arm_bl2_platform_setup(); + + /* + * Before releasing the AP cores out of reset, the SCP writes some data + * at the beginning of the Trusted SRAM. It is is overwritten before + * reaching this function. We need to restore this data, as if the + * target had just come out of reset. This implies: + * - zeroing the first 128 bytes of Trusted SRAM; + * - restoring the SCP boot configuration. + */ + VERBOSE("BL2: Restoring SCP reset data in Trusted SRAM\n"); + memset((void *) ARM_TRUSTED_SRAM_BASE, 0, 128); + mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config); +} +#endif /* EL3_PAYLOAD_BASE */ diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S index 56b88bc0..29f01ce9 100644 --- a/plat/common/aarch64/platform_helpers.S +++ b/plat/common/aarch64/platform_helpers.S @@ -115,7 +115,7 @@ func plat_disable_acp endfunc plat_disable_acp /* ----------------------------------------------------- - * void bl1_plat_prepare_exit(void); + * void bl1_plat_prepare_exit(entry_point_info_t *ep_info); * Called before exiting BL1. Default: do nothing * ----------------------------------------------------- */ diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c index fefc8a75..7796fc4a 100644 --- a/services/spd/opteed/opteed_main.c +++ b/services/spd/opteed/opteed_main.c @@ -85,11 +85,6 @@ static uint64_t opteed_sel1_interrupt_handler(uint32_t id, /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); -#if IMF_READ_INTERRUPT_ID - /* Check the security status of the interrupt */ - assert(plat_ic_get_interrupt_type(id) == INTR_TYPE_S_EL1); -#endif - /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index b8b67fad..62231601 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -106,11 +106,6 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); -#if IMF_READ_INTERRUPT_ID - /* Check the security status of the interrupt */ - assert(plat_ic_get_interrupt_type(id) == INTR_TYPE_S_EL1); -#endif - /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); @@ -173,10 +168,6 @@ static uint64_t tspd_ns_interrupt_handler(uint32_t id, /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == SECURE); -#if IMF_READ_INTERRUPT_ID - /* Check the security status of the interrupt */ - assert(plat_ic_get_interrupt_type(id) == INTR_TYPE_NS); -#endif /* * Disable the routing of NS interrupts from secure world to EL3 while * interrupted on this core. |