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 <jeenu.viswambharan@arm.com>
This commit is contained in:
parent
4d07e7821e
commit
c877b41487
5
Makefile
5
Makefile
|
@ -397,6 +397,9 @@ $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT))
|
||||||
$(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
|
$(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
|
||||||
$(eval $(call assert_boolean,USE_COHERENT_MEM))
|
$(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.
|
# Add definitions to the cpp preprocessor based on the current build options.
|
||||||
# This is done after including the platform specific makefile to allow the
|
# 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_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,ARM_GIC_ARCH))
|
||||||
$(eval $(call add_define,ASM_ASSERTION))
|
$(eval $(call add_define,ASM_ASSERTION))
|
||||||
$(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
|
$(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
|
||||||
|
|
|
@ -16,8 +16,9 @@ Contents :
|
||||||
11. [Use of coherent memory in Trusted Firmware](#11--use-of-coherent-memory-in-trusted-firmware)
|
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)
|
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)
|
13. [Performance Measurement Framework](#13--performance-measurement-framework)
|
||||||
14. [Code Structure](#14--code-structure)
|
14. [ARMv8 Architecture Extensions](#14--armv8-architecture-extensions)
|
||||||
15. [References](#15--references)
|
15. [Code Structure](#15--code-structure)
|
||||||
|
16. [References](#16--references)
|
||||||
|
|
||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
|
@ -2208,7 +2209,39 @@ in this implementation.
|
||||||
5. `pmf_helpers.h` is an internal header used by `pmf.h`.
|
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
|
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.
|
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
|
1. Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
|
||||||
|
|
|
@ -181,6 +181,14 @@ performed.
|
||||||
is used to determine the number of valid slave interfaces available in the
|
is used to determine the number of valid slave interfaces available in the
|
||||||
ARM CCI driver. Default is 400 (that is, CCI-400).
|
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
|
* `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
|
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).
|
by the interrupt management framework. Default is 2 (that is, version 2.0).
|
||||||
|
|
|
@ -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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -33,7 +33,66 @@
|
||||||
.globl spin_lock
|
.globl spin_lock
|
||||||
.globl spin_unlock
|
.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
|
func spin_lock
|
||||||
mov w2, #1
|
mov w2, #1
|
||||||
sevl
|
sevl
|
||||||
|
@ -45,8 +104,17 @@ l2: ldaxr w1, [x0]
|
||||||
ret
|
ret
|
||||||
endfunc spin_lock
|
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
|
func spin_unlock
|
||||||
stlr wzr, [x0]
|
stlr wzr, [x0]
|
||||||
|
COND_SEV()
|
||||||
ret
|
ret
|
||||||
endfunc spin_unlock
|
endfunc spin_unlock
|
||||||
|
|
|
@ -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
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions are met:
|
# 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))
|
$(and $(patsubst 0,,$(value $(1))),$(patsubst 1,,$(value $(1))),$(error $(1) must be boolean))
|
||||||
endef
|
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
|
# IMG_LINKERFILE defines the linker script corresponding to a BL stage
|
||||||
# $(1) = BL stage (2, 30, 31, 32, 33)
|
# $(1) = BL stage (2, 30, 31, 32, 33)
|
||||||
define IMG_LINKERFILE
|
define IMG_LINKERFILE
|
||||||
|
|
|
@ -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
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions are met:
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -44,6 +44,10 @@ ARCH := aarch64
|
||||||
# port can change this value if needed.
|
# port can change this value if needed.
|
||||||
ARM_CCI_PRODUCT_ID := 400
|
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
|
# Determine the version of ARM GIC architecture to use for interrupt management
|
||||||
# in EL3. The platform port can change this value if needed.
|
# in EL3. The platform port can change this value if needed.
|
||||||
ARM_GIC_ARCH := 2
|
ARM_GIC_ARCH := 2
|
||||||
|
|
Loading…
Reference in New Issue