From c877b414870bb3e421518caf9c7652a9807419b5 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Mon, 16 Jan 2017 16:52:35 +0000 Subject: [PATCH] Introduce locking primitives using CAS instruction The ARMv8v.1 architecture extension has introduced support for far atomics, which includes compare-and-swap. Compare and Swap instruction is only available for AArch64. Introduce build options to choose the architecture versions to target ARM Trusted Firmware: - ARM_ARCH_MAJOR: selects the major version of target ARM Architecture. Default value is 8. - ARM_ARCH_MINOR: selects the minor version of target ARM Architecture. Default value is 0. When: (ARM_ARCH_MAJOR > 8) || ((ARM_ARCH_MAJOR == 8) && (ARM_ARCH_MINOR >= 1)), for AArch64, Compare and Swap instruction is used to implement spin locks. Otherwise, the implementation falls back to using load-/store-exclusive instructions. Update user guide, and introduce a section in Firmware Design guide to summarize support for features introduced in ARMv8 Architecture Extensions. Change-Id: I73096a0039502f7aef9ec6ab3ae36680da033f16 Signed-off-by: Jeenu Viswambharan --- Makefile | 5 ++ docs/firmware-design.md | 41 +++++++++++++-- docs/user-guide.md | 8 +++ lib/locks/exclusive/aarch64/spinlock.S | 70 +++++++++++++++++++++++++- make_helpers/build_macros.mk | 12 ++++- make_helpers/defaults.mk | 6 ++- 6 files changed, 135 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9e148fbd..7b4e4f60 100644 --- a/Makefile +++ b/Makefile @@ -397,6 +397,9 @@ $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT)) $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT)) $(eval $(call assert_boolean,USE_COHERENT_MEM)) +$(eval $(call assert_numeric,ARM_ARCH_MAJOR)) +$(eval $(call assert_numeric,ARM_ARCH_MINOR)) + ################################################################################ # Add definitions to the cpp preprocessor based on the current build options. # This is done after including the platform specific makefile to allow the @@ -404,6 +407,8 @@ $(eval $(call assert_boolean,USE_COHERENT_MEM)) ################################################################################ $(eval $(call add_define,ARM_CCI_PRODUCT_ID)) +$(eval $(call add_define,ARM_ARCH_MAJOR)) +$(eval $(call add_define,ARM_ARCH_MINOR)) $(eval $(call add_define,ARM_GIC_ARCH)) $(eval $(call add_define,ASM_ASSERTION)) $(eval $(call add_define,COLD_BOOT_SINGLE_CPU)) diff --git a/docs/firmware-design.md b/docs/firmware-design.md index bd6e2f69..0fdc941c 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -16,8 +16,9 @@ Contents : 11. [Use of coherent memory in Trusted Firmware](#11--use-of-coherent-memory-in-trusted-firmware) 12. [Isolating code and read-only data on separate memory pages](#12--isolating-code-and-read-only-data-on-separate-memory-pages) 13. [Performance Measurement Framework](#13--performance-measurement-framework) -14. [Code Structure](#14--code-structure) -15. [References](#15--references) +14. [ARMv8 Architecture Extensions](#14--armv8-architecture-extensions) +15. [Code Structure](#15--code-structure) +16. [References](#16--references) 1. Introduction @@ -2208,7 +2209,39 @@ in this implementation. 5. `pmf_helpers.h` is an internal header used by `pmf.h`. -14. Code Structure +14. ARMv8 Architecture Extensions +---------------------------------- + +ARM Trusted Firmware makes use of ARMv8 Architecture Extensions where +applicable. This section lists the usage of Architecture Extensions, and build +flags controlling them. + +In general, and unless individually mentioned, the build options +`ARM_ARCH_MAJOR` and `ARM_ARCH_MINOR` selects the Architecture Extension to +target when building ARM Trusted Firmware. Subsequent ARM Architecture +Extensions are backward compatible with previous versions. + +The build system only requires that `ARM_ARCH_MAJOR` and `ARM_ARCH_MINOR` have a +valid numeric value. These build options only control whether or not +Architecture Extension-specific code is included in the build. Otherwise, ARM +Trusted Firmware targets the base ARMv8.0 architecture; i.e. as if +`ARM_ARCH_MAJOR` == 8 and `ARM_ARCH_MINOR` == 0, which are also their respective +default values. + +See also the _Summary of build options_ in [User Guide]. + +For details on the Architecture Extension and available features, please refer +to the respective Architecture Extension Supplement. + +### ARMv8.1 + +This Architecture Extension is targeted when `ARM_ARCH_MAJOR` >= 8, or when +`ARM_ARCH_MAJOR` == 8 and `ARM_ARCH_MINOR` >= 1. + +* The Compare and Swap instruction is used to implement spinlocks. Otherwise, + the load-/store-exclusive instruction pair is used. + +15. Code Structure ------------------- Trusted Firmware code is logically divided between the three boot loader @@ -2252,7 +2285,7 @@ FDTs provide a description of the hardware platform and are used by the Linux kernel at boot time. These can be found in the `fdts` directory. -15. References +16. References --------------- 1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available diff --git a/docs/user-guide.md b/docs/user-guide.md index c68565b7..7ae5b9ce 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -181,6 +181,14 @@ performed. is used to determine the number of valid slave interfaces available in the ARM CCI driver. Default is 400 (that is, CCI-400). +* `ARM_ARCH_MAJOR`: The major version of ARM Architecture to target when + compiling ARM Trusted Firmware. Its value must be numeric, and defaults to + 8. See also, _ARMv8 Architecture Extensions_ in [Firmware Design]. + +* `ARM_ARCH_MINOR`: The minor version of ARM Architecture to target when + compiling ARM Trusted Firmware. Its value must be a numeric, and defaults + to 0. See also, _ARMv8 Architecture Extensions_ in [Firmware Design]. + * `ARM_GIC_ARCH`: Choice of ARM GIC architecture version used by the ARM Legacy GIC driver for implementing the platform GIC API. This API is used by the interrupt management framework. Default is 2 (that is, version 2.0). diff --git a/lib/locks/exclusive/aarch64/spinlock.S b/lib/locks/exclusive/aarch64/spinlock.S index 1ca59123..bdc9ea0f 100644 --- a/lib/locks/exclusive/aarch64/spinlock.S +++ b/lib/locks/exclusive/aarch64/spinlock.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, 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: @@ -33,7 +33,66 @@ .globl spin_lock .globl spin_unlock +#if (ARM_ARCH_MAJOR > 8) || ((ARM_ARCH_MAJOR == 8) && (ARM_ARCH_MINOR >= 1)) +/* + * When compiled for ARMv8.1 or later, choose spin locks based on Compare and + * Swap instruction. + */ +# define USE_CAS 1 + +/* + * Lock contenders using CAS, upon failing to acquire the lock, wait with the + * monitor in open state. Therefore, a normal store upon unlocking won't + * generate an SEV. Use explicit SEV instruction with CAS unlock. + */ +# define COND_SEV() sev + +#else + +# define USE_CAS 0 + +/* + * Lock contenders using exclusive pairs, upon failing to acquire the lock, wait + * with the monitor in exclusive state. A normal store upon unlocking will + * implicitly generate an envent; so, no explicit SEV with unlock is required. + */ +# define COND_SEV() + +#endif + +#if USE_CAS + + .arch armv8.1-a + +/* + * Acquire lock using Compare and Swap instruction. + * + * Compare for 0 with acquire semantics, and swap 1. Wait until CAS returns + * 0. + * + * void spin_lock(spinlock_t *lock); + */ +func spin_lock + mov w2, #1 + sevl +1: + wfe + mov w1, wzr + casa w1, w2, [x0] + cbnz w1, 1b + ret +endfunc spin_lock + + .arch armv8-a + +#else /* !USE_CAS */ + +/* + * Acquire lock using load-/store-exclusive instruction pair. + * + * void spin_lock(spinlock_t *lock); + */ func spin_lock mov w2, #1 sevl @@ -45,8 +104,17 @@ l2: ldaxr w1, [x0] ret endfunc spin_lock +#endif /* USE_CAS */ +/* + * Release lock previously acquired by spin_lock. + * + * Unconditionally write 0, and conditionally generate an event. + * + * void spin_unlock(spinlock_t *lock); + */ func spin_unlock stlr wzr, [x0] + COND_SEV() ret endfunc spin_unlock diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index 2312d2c9..93db2d66 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2015-2017, 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: @@ -81,6 +81,16 @@ define assert_boolean $(and $(patsubst 0,,$(value $(1))),$(patsubst 1,,$(value $(1))),$(error $(1) must be boolean)) endef +0-9 := 0 1 2 3 4 5 6 7 8 9 + +# Function to verify that a given option $(1) contains a numeric value +define assert_numeric +$(if $($(1)),,$(error $(1) must not be empty)) +$(eval __numeric := $($(1))) +$(foreach d,$(0-9),$(eval __numeric := $(subst $(d),,$(__numeric)))) +$(if $(__numeric),$(error $(1) must be numeric)) +endef + # IMG_LINKERFILE defines the linker script corresponding to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_LINKERFILE diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 0b93dfca..b47ea46e 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2016-2017, 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: @@ -44,6 +44,10 @@ ARCH := aarch64 # port can change this value if needed. ARM_CCI_PRODUCT_ID := 400 +# ARM Architecture major and minor versions: 8.0 by default. +ARM_ARCH_MAJOR := 8 +ARM_ARCH_MINOR := 0 + # Determine the version of ARM GIC architecture to use for interrupt management # in EL3. The platform port can change this value if needed. ARM_GIC_ARCH := 2 -- 2.30.2