diff options
-rw-r--r-- | include/lib/aarch32/arch.h | 5 | ||||
-rw-r--r-- | include/lib/aarch64/arch.h | 55 | ||||
-rw-r--r-- | include/lib/aarch64/arch_helpers.h | 5 | ||||
-rw-r--r-- | include/lib/extensions/amu.h | 76 | ||||
-rw-r--r-- | include/lib/extensions/amu_private.h | 20 | ||||
-rw-r--r-- | lib/extensions/amu/aarch32/amu.c | 29 | ||||
-rw-r--r-- | lib/extensions/amu/aarch64/amu.c | 99 | ||||
-rw-r--r-- | lib/extensions/amu/aarch64/amu_helpers.S | 174 | ||||
-rw-r--r-- | tftf/tests/extensions/amu/test_amu.c | 82 |
9 files changed, 483 insertions, 62 deletions
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h index dcc4243b5..640457b51 100644 --- a/include/lib/aarch32/arch.h +++ b/include/lib/aarch32/arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -103,6 +103,9 @@ #define ID_PFR0_AMU_SHIFT U(20) #define ID_PFR0_AMU_LENGTH U(4) #define ID_PFR0_AMU_MASK U(0xf) +#define ID_PFR0_AMU_NOT_SUPPORTED U(0x0) +#define ID_PFR0_AMU_V1 U(0x1) +#define ID_PFR0_AMU_V1P1 U(0x2) #define ID_PFR0_DIT_SHIFT U(24) #define ID_PFR0_DIT_LENGTH U(4) diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index 2d2a892a8..f2681676a 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -129,6 +129,9 @@ #define ID_AA64PFR0_AMU_SHIFT U(44) #define ID_AA64PFR0_AMU_LENGTH U(4) #define ID_AA64PFR0_AMU_MASK ULL(0xf) +#define ID_AA64PFR0_AMU_NOT_SUPPORTED U(0x0) +#define ID_AA64PFR0_AMU_V1 U(0x1) +#define ID_AA64PFR0_AMU_V1P1 U(0x2) #define ID_AA64PFR0_ELX_MASK ULL(0xf) #define ID_AA64PFR0_SVE_SHIFT U(32) #define ID_AA64PFR0_SVE_MASK ULL(0xf) @@ -303,6 +306,7 @@ /* SCR definitions */ #define SCR_RES1_BITS ((U(1) << 4) | (U(1) << 5)) +#define SCR_AMVOFFEN_BIT (UL(1) << 35) #define SCR_ATA_BIT (U(1) << 26) #define SCR_FIEN_BIT (U(1) << 21) #define SCR_API_BIT (U(1) << 17) @@ -364,6 +368,7 @@ #define VTTBR_BADDR_SHIFT U(0) /* HCR definitions */ +#define HCR_AMVOFFEN_BIT (ULL(1) << 51) #define HCR_API_BIT (ULL(1) << 41) #define HCR_APK_BIT (ULL(1) << 40) #define HCR_TGE_BIT (ULL(1) << 27) @@ -861,10 +866,14 @@ #define AMEVTYPER1E_EL0 S3_3_C13_C15_6 #define AMEVTYPER1F_EL0 S3_3_C13_C15_7 +/* AMCFGR_EL0 definitions */ +#define AMCFGR_EL0_NCG_SHIFT U(28) +#define AMCFGR_EL0_NCG_MASK U(0xf) + /* AMCGCR_EL0 definitions */ -#define AMCGCR_EL0_CG1NC_SHIFT U(8) -#define AMCGCR_EL0_CG1NC_LENGTH U(8) -#define AMCGCR_EL0_CG1NC_MASK U(0xff) +#define AMCGCR_EL0_CG1NC_SHIFT U(8) +#define AMCGCR_EL0_CG1NC_LENGTH U(8) +#define AMCGCR_EL0_CG1NC_MASK U(0xff) /* MPAM register definitions */ #define MPAM3_EL3_MPAMEN_BIT (ULL(1) << 63) @@ -876,6 +885,44 @@ #define MPAMIDR_HAS_HCR_BIT (ULL(1) << 17) /******************************************************************************* + * Definitions for system register interface to AMU for ARMv8.6 enhancements + ******************************************************************************/ + +/* Definition for register defining which virtual offsets are implemented. */ +#define AMCG1IDR_EL0 S3_3_C13_C2_6 +#define AMCG1IDR_CTR_MASK ULL(0xffff) +#define AMCG1IDR_CTR_SHIFT U(0) +#define AMCG1IDR_VOFF_MASK ULL(0xffff) +#define AMCG1IDR_VOFF_SHIFT U(16) + +/* New bit added to AMCR_EL0 */ +#define AMCR_CG1RZ_BIT (ULL(0x1) << 17) + +/* Definitions for virtual offset registers for architected event counters. */ +/* AMEVCNTR01_EL0 intentionally left undefined, as it does not exist. */ +#define AMEVCNTVOFF00_EL2 S3_4_C13_C8_0 +#define AMEVCNTVOFF02_EL2 S3_4_C13_C8_2 +#define AMEVCNTVOFF03_EL2 S3_4_C13_C8_3 + +/* Definitions for virtual offset registers for auxiliary event counters. */ +#define AMEVCNTVOFF10_EL2 S3_4_C13_C10_0 +#define AMEVCNTVOFF11_EL2 S3_4_C13_C10_1 +#define AMEVCNTVOFF12_EL2 S3_4_C13_C10_2 +#define AMEVCNTVOFF13_EL2 S3_4_C13_C10_3 +#define AMEVCNTVOFF14_EL2 S3_4_C13_C10_4 +#define AMEVCNTVOFF15_EL2 S3_4_C13_C10_5 +#define AMEVCNTVOFF16_EL2 S3_4_C13_C10_6 +#define AMEVCNTVOFF17_EL2 S3_4_C13_C10_7 +#define AMEVCNTVOFF18_EL2 S3_4_C13_C11_0 +#define AMEVCNTVOFF19_EL2 S3_4_C13_C11_1 +#define AMEVCNTVOFF1A_EL2 S3_4_C13_C11_2 +#define AMEVCNTVOFF1B_EL2 S3_4_C13_C11_3 +#define AMEVCNTVOFF1C_EL2 S3_4_C13_C11_4 +#define AMEVCNTVOFF1D_EL2 S3_4_C13_C11_5 +#define AMEVCNTVOFF1E_EL2 S3_4_C13_C11_6 +#define AMEVCNTVOFF1F_EL2 S3_4_C13_C11_7 + +/******************************************************************************* * RAS system registers ******************************************************************************/ #define DISR_EL1 S3_0_C12_C1_1 diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index 6a96ea2f9..39f1e3b87 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -422,7 +422,10 @@ DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sgi1r, ICC_SGI1R) +DEFINE_RENAME_SYSREG_RW_FUNCS(amcr_el0, AMCR_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcgcr_el0, AMCGCR_EL0) +DEFINE_RENAME_SYSREG_READ_FUNC(amcfgr_el0, AMCFGR_EL0) +DEFINE_RENAME_SYSREG_READ_FUNC(amcg1idr_el0, AMCG1IDR_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr0_el0, AMCNTENCLR0_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0) diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h index 30714643b..f8301c6e2 100644 --- a/include/lib/extensions/amu.h +++ b/include/lib/extensions/amu.h @@ -1,35 +1,79 @@ /* - * Copyright (c) 2017, Arm Limited. All rights reserved. + * Copyright (c) 2017-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef __AMU_H__ -#define __AMU_H__ +#ifndef AMU_H +#define AMU_H -#include <platform_def.h> #include <stdint.h> -#define AMU_GROUP0_NR_COUNTERS 4 -#define AMU_GROUP0_COUNTERS_MASK 0xf +#include <cassert.h> +#include <platform_def.h> + +#define AMU_GROUP0_COUNTERS_MASK U(0xf) +#define AMU_GROUP0_NR_COUNTERS U(4) #ifdef PLAT_AMU_GROUP1_COUNTERS_MASK #define AMU_GROUP1_COUNTERS_MASK PLAT_AMU_GROUP1_COUNTERS_MASK #else -#define AMU_GROUP1_COUNTERS_MASK 0 +#define AMU_GROUP1_COUNTERS_MASK U(0) #endif -#ifdef PLAT_AMU_GROUP1_NR_COUNTERS -#define AMU_GROUP1_NR_COUNTERS PLAT_AMU_GROUP1_NR_COUNTERS +/* Calculate number of group 1 counters */ +#if (AMU_GROUP1_COUNTERS_MASK & (1 << 15)) +#define AMU_GROUP1_NR_COUNTERS 16U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 14)) +#define AMU_GROUP1_NR_COUNTERS 15U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 13)) +#define AMU_GROUP1_NR_COUNTERS 14U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 12)) +#define AMU_GROUP1_NR_COUNTERS 13U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 11)) +#define AMU_GROUP1_NR_COUNTERS 12U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 10)) +#define AMU_GROUP1_NR_COUNTERS 11U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 9)) +#define AMU_GROUP1_NR_COUNTERS 10U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 8)) +#define AMU_GROUP1_NR_COUNTERS 9U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 7)) +#define AMU_GROUP1_NR_COUNTERS 8U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 6)) +#define AMU_GROUP1_NR_COUNTERS 7U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 5)) +#define AMU_GROUP1_NR_COUNTERS 6U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 4)) +#define AMU_GROUP1_NR_COUNTERS 5U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 3)) +#define AMU_GROUP1_NR_COUNTERS 4U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 2)) +#define AMU_GROUP1_NR_COUNTERS 3U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 1)) +#define AMU_GROUP1_NR_COUNTERS 2U +#elif (AMU_GROUP1_COUNTERS_MASK & (1 << 0)) +#define AMU_GROUP1_NR_COUNTERS 1U #else -#define AMU_GROUP1_NR_COUNTERS 0 +#define AMU_GROUP1_NR_COUNTERS 0U #endif -#define AMU_GROUP0_MAX_NR_COUNTERS 4 -#define AMU_GROUP1_MAX_NR_COUNTERS 16 +CASSERT(AMU_GROUP1_COUNTERS_MASK <= 0xffff, invalid_amu_group1_counters_mask); + +unsigned int amu_get_version(void); -int amu_supported(void); -uint64_t amu_group0_cnt_read(int idx); -uint64_t amu_group1_cnt_read(int idx); +uint64_t amu_group0_cnt_read(unsigned int idx); +#if __aarch64__ +uint64_t amu_group0_voffset_read(unsigned int idx); +void amu_group0_voffset_write(unsigned int idx, uint64_t val); +#endif + +#if AMU_GROUP1_NR_COUNTERS +uint64_t amu_group1_cnt_read(unsigned int idx); +#if __aarch64__ +uint64_t amu_group1_voffset_read(unsigned int idx); +void amu_group1_voffset_write(unsigned int idx, uint64_t val); +#endif +#endif -#endif /* __AMU_H__ */ +#endif /* AMU_H */ diff --git a/include/lib/extensions/amu_private.h b/include/lib/extensions/amu_private.h index e6cd2906e..7ae17d94b 100644 --- a/include/lib/extensions/amu_private.h +++ b/include/lib/extensions/amu_private.h @@ -1,15 +1,23 @@ /* - * Copyright (c) 2017, Arm Limited. All rights reserved. + * Copyright (c) 2017-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef __AMU_PRIVATE_H__ -#define __AMU_PRIVATE_H__ +#ifndef AMU_PRIVATE_H +#define AMU_PRIVATE_H #include <stdint.h> -uint64_t amu_group0_cnt_read_internal(int idx); -uint64_t amu_group1_cnt_read_internal(int idx); +uint64_t amu_group0_cnt_read_internal(unsigned int idx); +uint64_t amu_group1_cnt_read_internal(unsigned int idx); -#endif /* __AMU_PRIVATE_H__ */ +#if __aarch64__ +uint64_t amu_group0_voffset_read_internal(unsigned int idx); +void amu_group0_voffset_write_internal(unsigned int idx, uint64_t val); + +uint64_t amu_group1_voffset_read_internal(unsigned int idx); +void amu_group1_voffset_write_internal(unsigned int idx, uint64_t val); +#endif + +#endif /* AMU_PRIVATE_H */ diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c index a923df32b..f73056891 100644 --- a/lib/extensions/amu/aarch32/amu.c +++ b/lib/extensions/amu/aarch32/amu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,28 +10,33 @@ #include <arch_helpers.h> #include <assert.h> -int amu_supported(void) +/* + * Get AMU version value from pfr0. + * Return values + * ID_PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4) + * ID_PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6) + * ID_PFR0_AMU_NOT_SUPPORTED: not supported + */ +unsigned int amu_get_version(void) { - uint64_t features; - - features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; - return (features & ID_PFR0_AMU_MASK) == 1; + return (unsigned int)(read_id_pfr0() >> ID_PFR0_AMU_SHIFT) & + ID_PFR0_AMU_MASK; } /* Read the group 0 counter identified by the given `idx`. */ -uint64_t amu_group0_cnt_read(int idx) +uint64_t amu_group0_cnt_read(unsigned int idx) { - assert(amu_supported()); - assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS); + assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED); + assert(idx < AMU_GROUP0_NR_COUNTERS); return amu_group0_cnt_read_internal(idx); } /* Read the group 1 counter identified by the given `idx`. */ -uint64_t amu_group1_cnt_read(int idx) +uint64_t amu_group1_cnt_read(unsigned int idx) { - assert(amu_supported()); - assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS); + assert(amu_get_version() != ID_PFR0_AMU_NOT_SUPPORTED); + assert(idx < AMU_GROUP1_NR_COUNTERS); return amu_group1_cnt_read_internal(idx); } diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c index 00253b35d..0a1e65384 100644 --- a/lib/extensions/amu/aarch64/amu.c +++ b/lib/extensions/amu/aarch64/amu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,28 +10,105 @@ #include <arch_helpers.h> #include <assert.h> -int amu_supported(void) +/* + * Get AMU version value from aa64pfr0. + * Return values + * ID_AA64PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4) + * ID_AA64PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6) + * ID_AA64PFR0_AMU_NOT_SUPPORTED: not supported + */ +unsigned int amu_get_version(void) +{ + return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) & + ID_AA64PFR0_AMU_MASK; +} + +/* Check if group 1 counters is implemented */ +int amu_group1_supported(void) { - uint64_t features; + uint64_t features = read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT; - features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT; - return (features & ID_AA64PFR0_AMU_MASK) == 1; + return (features & AMCFGR_EL0_NCG_MASK) == 1U; } /* Read the group 0 counter identified by the given `idx`. */ -uint64_t amu_group0_cnt_read(int idx) +uint64_t amu_group0_cnt_read(unsigned int idx) { - assert(amu_supported()); - assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS); + assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); + assert(idx < AMU_GROUP0_NR_COUNTERS); return amu_group0_cnt_read_internal(idx); } +/* + * Read the group 0 offset register for a given index. Index must be 0, 2, or + * 3, the register for 1 does not exist. + * + * Using this function requires v8.6 FEAT_AMUv1p1 support. + */ +uint64_t amu_group0_voffset_read(unsigned int idx) +{ + assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); + assert(idx < AMU_GROUP0_NR_COUNTERS); + assert(idx != 1U); + + return amu_group0_voffset_read_internal(idx); +} + +/* + * Write the group 0 offset register for a given index. Index must be 0, 2, or + * 3, the register for 1 does not exist. + * + * Using this function requires v8.6 FEAT_AMUv1p1 support. + */ +void amu_group0_voffset_write(unsigned int idx, uint64_t val) +{ + assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); + assert(idx < AMU_GROUP0_NR_COUNTERS); + assert(idx != 1U); + + amu_group0_voffset_write_internal(idx, val); + isb(); +} + /* Read the group 1 counter identified by the given `idx`. */ -uint64_t amu_group1_cnt_read(int idx) +uint64_t amu_group1_cnt_read(unsigned int idx) { - assert(amu_supported()); - assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS); + assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); + assert(idx < AMU_GROUP1_NR_COUNTERS); return amu_group1_cnt_read_internal(idx); } + +/* + * Read the group 1 offset register for a given index. + * + * Using this function requires v8.6 FEAT_AMUv1p1 support. + */ +uint64_t amu_group1_voffset_read(unsigned int idx) +{ + assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); + assert(amu_group1_supported()); + assert(idx < AMU_GROUP1_NR_COUNTERS); + assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & + (1U << idx)) != 0U); + + return amu_group1_voffset_read_internal(idx); +} + +/* + * Write the group 1 offset register for a given index. + * + * Using this function requires v8.6 FEAT_AMUv1p1 support. + */ +void amu_group1_voffset_write(unsigned int idx, uint64_t val) +{ + assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); + assert(amu_group1_supported()); + assert(idx < AMU_GROUP1_NR_COUNTERS); + assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & + (1U << idx)) != 0U); + + amu_group1_voffset_write_internal(idx, val); + isb(); +} diff --git a/lib/extensions/amu/aarch64/amu_helpers.S b/lib/extensions/amu/aarch64/amu_helpers.S index 061f3fd6c..b15daf32c 100644 --- a/lib/extensions/amu/aarch64/amu_helpers.S +++ b/lib/extensions/amu/aarch64/amu_helpers.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, Arm Limited. All rights reserved. + * Copyright (c) 2017-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,6 +11,12 @@ .globl amu_group0_cnt_read_internal .globl amu_group1_cnt_read_internal + /* FEAT_AMUv1p1 virtualisation offset register functions */ + .globl amu_group0_voffset_read_internal + .globl amu_group0_voffset_write_internal + .globl amu_group1_voffset_read_internal + .globl amu_group1_voffset_write_internal + /* * uint64_t amu_group0_cnt_read_internal(int idx); * @@ -86,3 +92,169 @@ func amu_group1_cnt_read_internal read AMEVCNTR1E_EL0 /* index 14 */ read AMEVCNTR1F_EL0 /* index 15 */ endfunc amu_group1_cnt_read_internal + +/* + * Accessor functions for virtual offset registers added with FEAT_AMUv1p1 + */ + +/* + * uint64_t amu_group0_voffset_read_internal(int idx); + * + * Given `idx`, read the corresponding AMU virtual offset register + * and return it in `x0`. + */ +func amu_group0_voffset_read_internal + adr x1, 1f +#if ENABLE_ASSERTIONS + /* + * It can be dangerous to call this function with an + * out of bounds index. Ensure `idx` is valid. + */ + tst x0, #~3 + ASM_ASSERT(eq) + /* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */ + cmp x0, #1 + ASM_ASSERT(ne) +#endif + /* + * Given `idx` calculate address of mrs/ret instruction pair + * in the table below. + */ + add x1, x1, x0, lsl #3 /* each mrs/ret sequence is 8 bytes */ +#if ENABLE_BTI + add x1, x1, x0, lsl #2 /* + "bti j" instruction */ +#endif + br x1 + +1: read AMEVCNTVOFF00_EL2 /* index 0 */ + .skip 8 /* AMEVCNTVOFF01_EL2 does not exist */ +#if ENABLE_BTI + .skip 4 /* Extra space for BTI instruction. */ +#endif + read AMEVCNTVOFF02_EL2 /* index 2 */ + read AMEVCNTVOFF03_EL2 /* index 3 */ +endfunc amu_group0_voffset_read_internal + +/* + * void amu_group0_voffset_write_internal(int idx, uint64_t val); + * + * Given `idx`, write `val` to the corresponding AMU virtual offset register. + */ +func amu_group0_voffset_write_internal + adr x2, 1f +#if ENABLE_ASSERTIONS + /* + * It can be dangerous to call this function with an + * out of bounds index. Ensure `idx` is valid. + */ + tst x0, #~3 + ASM_ASSERT(eq) + /* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */ + cmp x0, #1 + ASM_ASSERT(ne) +#endif + /* + * Given `idx` calculate address of mrs/ret instruction pair + * in the table below. + */ + add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ +#if ENABLE_BTI + add x2, x2, x0, lsl #2 /* + "bti j" instruction */ +#endif + br x2 + +1: write AMEVCNTVOFF00_EL2 /* index 0 */ + .skip 8 /* AMEVCNTVOFF01_EL2 does not exist */ +#if ENABLE_BTI + .skip 4 /* Extra space for BTI instruction. */ +#endif + write AMEVCNTVOFF02_EL2 /* index 2 */ + write AMEVCNTVOFF03_EL2 /* index 3 */ +endfunc amu_group0_voffset_write_internal + +/* + * uint64_t amu_group1_voffset_read_internal(int idx); + * + * Given `idx`, read the corresponding AMU virtual offset register + * and return it in `x0`. + */ +func amu_group1_voffset_read_internal + adr x1, 1f +#if ENABLE_ASSERTIONS + /* + * It can be dangerous to call this function with an + * out of bounds index. Ensure `idx` is valid. + */ + tst x0, #~0xF + ASM_ASSERT(eq) +#endif + /* + * Given `idx` calculate address of mrs/ret instruction pair + * in the table below. + */ + add x1, x1, x0, lsl #3 /* each mrs/ret sequence is 8 bytes */ +#if ENABLE_BTI + add x1, x1, x0, lsl #2 /* + "bti j" instruction */ +#endif + br x1 + +1: read AMEVCNTVOFF10_EL2 /* index 0 */ + read AMEVCNTVOFF11_EL2 /* index 1 */ + read AMEVCNTVOFF12_EL2 /* index 2 */ + read AMEVCNTVOFF13_EL2 /* index 3 */ + read AMEVCNTVOFF14_EL2 /* index 4 */ + read AMEVCNTVOFF15_EL2 /* index 5 */ + read AMEVCNTVOFF16_EL2 /* index 6 */ + read AMEVCNTVOFF17_EL2 /* index 7 */ + read AMEVCNTVOFF18_EL2 /* index 8 */ + read AMEVCNTVOFF19_EL2 /* index 9 */ + read AMEVCNTVOFF1A_EL2 /* index 10 */ + read AMEVCNTVOFF1B_EL2 /* index 11 */ + read AMEVCNTVOFF1C_EL2 /* index 12 */ + read AMEVCNTVOFF1D_EL2 /* index 13 */ + read AMEVCNTVOFF1E_EL2 /* index 14 */ + read AMEVCNTVOFF1F_EL2 /* index 15 */ +endfunc amu_group1_voffset_read_internal + +/* + * void amu_group1_voffset_write_internal(int idx, uint64_t val); + * + * Given `idx`, write `val` to the corresponding AMU virtual offset register. + */ +func amu_group1_voffset_write_internal + adr x2, 1f +#if ENABLE_ASSERTIONS + /* + * It can be dangerous to call this function with an + * out of bounds index. Ensure `idx` is valid. + */ + tst x0, #~0xF + ASM_ASSERT(eq) +#endif + /* + * Given `idx` calculate address of mrs/ret instruction pair + * in the table below. + */ + add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ +#if ENABLE_BTI + add x2, x2, x0, lsl #2 /* + "bti j" instruction */ +#endif + br x2 + +1: write AMEVCNTVOFF10_EL2 /* index 0 */ + write AMEVCNTVOFF11_EL2 /* index 1 */ + write AMEVCNTVOFF12_EL2 /* index 2 */ + write AMEVCNTVOFF13_EL2 /* index 3 */ + write AMEVCNTVOFF14_EL2 /* index 4 */ + write AMEVCNTVOFF15_EL2 /* index 5 */ + write AMEVCNTVOFF16_EL2 /* index 6 */ + write AMEVCNTVOFF17_EL2 /* index 7 */ + write AMEVCNTVOFF18_EL2 /* index 8 */ + write AMEVCNTVOFF19_EL2 /* index 9 */ + write AMEVCNTVOFF1A_EL2 /* index 10 */ + write AMEVCNTVOFF1B_EL2 /* index 11 */ + write AMEVCNTVOFF1C_EL2 /* index 12 */ + write AMEVCNTVOFF1D_EL2 /* index 13 */ + write AMEVCNTVOFF1E_EL2 /* index 14 */ + write AMEVCNTVOFF1F_EL2 /* index 15 */ +endfunc amu_group1_voffset_write_internal diff --git a/tftf/tests/extensions/amu/test_amu.c b/tftf/tests/extensions/amu/test_amu.c index 8799aa5f0..8d5c92bad 100644 --- a/tftf/tests/extensions/amu/test_amu.c +++ b/tftf/tests/extensions/amu/test_amu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -104,8 +104,9 @@ static int amu_group0_cnt_valid(unsigned int idx, uint64_t value) { int answer = 0; - if ((idx <= 2) && (value == 0)) + if ((idx <= 2) && (value == 0)) { answer = -1; + } return answer; } @@ -117,16 +118,18 @@ static int amu_group0_cnt_valid(unsigned int idx, uint64_t value) */ test_result_t test_amu_valid_ctr(void) { - int i; + unsigned int i; - if (!amu_supported()) + if (amu_get_version() == 0U) { return TEST_RESULT_SKIPPED; + } /* If counters are not enabled, then skip the test */ - if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) + if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) { return TEST_RESULT_SKIPPED; + } - for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) { + for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { uint64_t value; value = amu_group0_cnt_read(i); @@ -145,19 +148,49 @@ test_result_t test_amu_valid_ctr(void) */ test_result_t test_amu_suspend_resume(void) { - uint64_t group0_ctrs[AMU_GROUP0_MAX_NR_COUNTERS]; - int i; + uint64_t group0_ctrs[AMU_GROUP0_NR_COUNTERS]; + unsigned int i; - if (!amu_supported()) + if (amu_get_version() == 0U) { return TEST_RESULT_SKIPPED; + } /* If counters are not enabled, then skip the test */ if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) return TEST_RESULT_SKIPPED; /* Save counters values before suspend */ - for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) + for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { group0_ctrs[i] = amu_group0_cnt_read(i); + } + + /* + * If FEAT_AMUv1p1 supported then make sure the save/restore works for + * virtual counter values. Write known values into the virtual offsets + * and then make sure they are still there after resume. The virtual + * offset registers are only accessible in AARCH64 mode in EL2 or EL3. + */ +#if __aarch64__ + if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) { + /* Enabling voffsets in HCR_EL2. */ + write_hcr_el2(read_hcr_el2() | HCR_AMVOFFEN_BIT); + + /* Writing known values into voffset registers. */ + amu_group0_voffset_write(0U, 0xDEADBEEF); + amu_group0_voffset_write(2U, 0xDEADBEEF); + amu_group0_voffset_write(3U, 0xDEADBEEF); + +#if AMU_GROUP1_NR_COUNTERS + u_register_t amcg1idr = read_amcg1idr_el0() >> 16; + + for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { + if (((amcg1idr >> i) & 1U) != 0U) { + amu_group1_voffset_write(i, 0xDEADBEEF); + } + } +#endif + } +#endif /* Suspend/resume current core */ suspend_and_resume_this_cpu(); @@ -178,5 +211,34 @@ test_result_t test_amu_suspend_resume(void) } } +#if __aarch64__ + if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) { + for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { + if ((i != 1U) && + (amu_group0_voffset_read(i) != 0xDEADBEEF)) { + tftf_testcase_printf( + "Invalid G0 voffset %u: 0x%llx\n", i, + amu_group0_voffset_read(i)); + return TEST_RESULT_FAIL; + } + } + +#if AMU_GROUP1_NR_COUNTERS + u_register_t amcg1idr = read_amcg1idr_el0() >> 16; + + for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { + if (((amcg1idr >> i) & 1U) != 0U) { + if (amu_group1_voffset_read(i) != 0xDEADBEEF) { + tftf_testcase_printf("Invalid G1 " \ + "voffset %u: 0x%llx\n", i, + amu_group1_voffset_read(i)); + return TEST_RESULT_FAIL; + } + } + } +#endif + } +#endif + return TEST_RESULT_SUCCESS; } |