mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-25 06:19:56 +00:00

Due to their interrelationship in the architecture the SVE and SME features in TF-A are mutually exclusive. This means that a single binary can't be shared between systems with and without SME if the system without SME does support SVE, SVE will not be initialised so lower ELs will run into trouble trying to use it. This unusual behaviour for TF-A which normally gracefully handles situations where features are enabled but not supported on the current hardware. Address this by calling the SVE enable and disable functions if SME is not supported rather than immediately exiting, these perform their own feature checks so if neither SVE nor SME is supported behaviour is unchanged. Signed-off-by: Mark Brown <broonie@kernel.org> Change-Id: I2c606202fa6c040069f44e29d36b5abb48391874
107 lines
2.6 KiB
C
107 lines
2.6 KiB
C
/*
|
|
* Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <arch.h>
|
|
#include <arch_helpers.h>
|
|
#include <common/debug.h>
|
|
#include <lib/el3_runtime/context_mgmt.h>
|
|
#include <lib/extensions/sme.h>
|
|
#include <lib/extensions/sve.h>
|
|
|
|
static bool feat_sme_supported(void)
|
|
{
|
|
uint64_t features;
|
|
|
|
features = read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SME_SHIFT;
|
|
return (features & ID_AA64PFR1_EL1_SME_MASK) != 0U;
|
|
}
|
|
|
|
static bool feat_sme_fa64_supported(void)
|
|
{
|
|
uint64_t features;
|
|
|
|
features = read_id_aa64smfr0_el1();
|
|
return (features & ID_AA64SMFR0_EL1_FA64_BIT) != 0U;
|
|
}
|
|
|
|
void sme_enable(cpu_context_t *context)
|
|
{
|
|
u_register_t reg;
|
|
u_register_t cptr_el3;
|
|
el3_state_t *state;
|
|
|
|
/* Make sure SME is implemented in hardware before continuing. */
|
|
if (!feat_sme_supported()) {
|
|
/* Perhaps the hardware supports SVE only */
|
|
sve_enable(context);
|
|
return;
|
|
}
|
|
|
|
/* Get the context state. */
|
|
state = get_el3state_ctx(context);
|
|
|
|
/* Enable SME in CPTR_EL3. */
|
|
reg = read_ctx_reg(state, CTX_CPTR_EL3);
|
|
reg |= ESM_BIT;
|
|
write_ctx_reg(state, CTX_CPTR_EL3, reg);
|
|
|
|
/* Set the ENTP2 bit in SCR_EL3 to enable access to TPIDR2_EL0. */
|
|
reg = read_ctx_reg(state, CTX_SCR_EL3);
|
|
reg |= SCR_ENTP2_BIT;
|
|
write_ctx_reg(state, CTX_SCR_EL3, reg);
|
|
|
|
/* Set CPTR_EL3.ESM bit so we can write SMCR_EL3 without trapping. */
|
|
cptr_el3 = read_cptr_el3();
|
|
write_cptr_el3(cptr_el3 | ESM_BIT);
|
|
|
|
/*
|
|
* Set the max LEN value and FA64 bit. This register is set up globally
|
|
* to be the least restrictive, then lower ELs can restrict as needed
|
|
* using SMCR_EL2 and SMCR_EL1.
|
|
*/
|
|
reg = SMCR_ELX_LEN_MASK;
|
|
if (feat_sme_fa64_supported()) {
|
|
VERBOSE("[SME] FA64 enabled\n");
|
|
reg |= SMCR_ELX_FA64_BIT;
|
|
}
|
|
write_smcr_el3(reg);
|
|
|
|
/* Reset CPTR_EL3 value. */
|
|
write_cptr_el3(cptr_el3);
|
|
|
|
/* Enable SVE/FPU in addition to SME. */
|
|
sve_enable(context);
|
|
}
|
|
|
|
void sme_disable(cpu_context_t *context)
|
|
{
|
|
u_register_t reg;
|
|
el3_state_t *state;
|
|
|
|
/* Make sure SME is implemented in hardware before continuing. */
|
|
if (!feat_sme_supported()) {
|
|
/* Perhaps the hardware supports SVE only */
|
|
sve_disable(context);
|
|
return;
|
|
}
|
|
|
|
/* Get the context state. */
|
|
state = get_el3state_ctx(context);
|
|
|
|
/* Disable SME, SVE, and FPU since they all share registers. */
|
|
reg = read_ctx_reg(state, CTX_CPTR_EL3);
|
|
reg &= ~ESM_BIT; /* Trap SME */
|
|
reg &= ~CPTR_EZ_BIT; /* Trap SVE */
|
|
reg |= TFP_BIT; /* Trap FPU/SIMD */
|
|
write_ctx_reg(state, CTX_CPTR_EL3, reg);
|
|
|
|
/* Disable access to TPIDR2_EL0. */
|
|
reg = read_ctx_reg(state, CTX_SCR_EL3);
|
|
reg &= ~SCR_ENTP2_BIT;
|
|
write_ctx_reg(state, CTX_SCR_EL3, reg);
|
|
}
|