162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef __ASM_CPUFEATURE_H
762306a36Sopenharmony_ci#define __ASM_CPUFEATURE_H
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/alternative-macros.h>
1062306a36Sopenharmony_ci#include <asm/cpucaps.h>
1162306a36Sopenharmony_ci#include <asm/cputype.h>
1262306a36Sopenharmony_ci#include <asm/hwcap.h>
1362306a36Sopenharmony_ci#include <asm/sysreg.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define MAX_CPU_FEATURES	128
1662306a36Sopenharmony_ci#define cpu_feature(x)		KERNEL_HWCAP_ ## x
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define ARM64_SW_FEATURE_OVERRIDE_NOKASLR	0
1962306a36Sopenharmony_ci#define ARM64_SW_FEATURE_OVERRIDE_HVHE		4
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#ifndef __ASSEMBLY__
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/bug.h>
2462306a36Sopenharmony_ci#include <linux/jump_label.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * CPU feature register tracking
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * The safe value of a CPUID feature field is dependent on the implications
3162306a36Sopenharmony_ci * of the values assigned to it by the architecture. Based on the relationship
3262306a36Sopenharmony_ci * between the values, the features are classified into 3 types - LOWER_SAFE,
3362306a36Sopenharmony_ci * HIGHER_SAFE and EXACT.
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * The lowest value of all the CPUs is chosen for LOWER_SAFE and highest
3662306a36Sopenharmony_ci * for HIGHER_SAFE. It is expected that all CPUs have the same value for
3762306a36Sopenharmony_ci * a field when EXACT is specified, failing which, the safe value specified
3862306a36Sopenharmony_ci * in the table is chosen.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cienum ftr_type {
4262306a36Sopenharmony_ci	FTR_EXACT,			/* Use a predefined safe value */
4362306a36Sopenharmony_ci	FTR_LOWER_SAFE,			/* Smaller value is safe */
4462306a36Sopenharmony_ci	FTR_HIGHER_SAFE,		/* Bigger value is safe */
4562306a36Sopenharmony_ci	FTR_HIGHER_OR_ZERO_SAFE,	/* Bigger value is safe, but 0 is biggest */
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define FTR_STRICT	true	/* SANITY check strict matching required */
4962306a36Sopenharmony_ci#define FTR_NONSTRICT	false	/* SANITY check ignored */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define FTR_SIGNED	true	/* Value should be treated as signed */
5262306a36Sopenharmony_ci#define FTR_UNSIGNED	false	/* Value should be treated as unsigned */
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define FTR_VISIBLE	true	/* Feature visible to the user space */
5562306a36Sopenharmony_ci#define FTR_HIDDEN	false	/* Feature is hidden from the user */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define FTR_VISIBLE_IF_IS_ENABLED(config)		\
5862306a36Sopenharmony_ci	(IS_ENABLED(config) ? FTR_VISIBLE : FTR_HIDDEN)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct arm64_ftr_bits {
6162306a36Sopenharmony_ci	bool		sign;	/* Value is signed ? */
6262306a36Sopenharmony_ci	bool		visible;
6362306a36Sopenharmony_ci	bool		strict;	/* CPU Sanity check: strict matching required ? */
6462306a36Sopenharmony_ci	enum ftr_type	type;
6562306a36Sopenharmony_ci	u8		shift;
6662306a36Sopenharmony_ci	u8		width;
6762306a36Sopenharmony_ci	s64		safe_val; /* safe value for FTR_EXACT features */
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Describe the early feature override to the core override code:
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * @val			Values that are to be merged into the final
7462306a36Sopenharmony_ci *			sanitised value of the register. Only the bitfields
7562306a36Sopenharmony_ci *			set to 1 in @mask are valid
7662306a36Sopenharmony_ci * @mask		Mask of the features that are overridden by @val
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * A @mask field set to full-1 indicates that the corresponding field
7962306a36Sopenharmony_ci * in @val is a valid override.
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * A @mask field set to full-0 with the corresponding @val field set
8262306a36Sopenharmony_ci * to full-0 denotes that this field has no override
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * A @mask field set to full-0 with the corresponding @val field set
8562306a36Sopenharmony_ci * to full-1 denotes thath this field has an invalid override.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistruct arm64_ftr_override {
8862306a36Sopenharmony_ci	u64		val;
8962306a36Sopenharmony_ci	u64		mask;
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * @arm64_ftr_reg - Feature register
9462306a36Sopenharmony_ci * @strict_mask		Bits which should match across all CPUs for sanity.
9562306a36Sopenharmony_ci * @sys_val		Safe value across the CPUs (system view)
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistruct arm64_ftr_reg {
9862306a36Sopenharmony_ci	const char			*name;
9962306a36Sopenharmony_ci	u64				strict_mask;
10062306a36Sopenharmony_ci	u64				user_mask;
10162306a36Sopenharmony_ci	u64				sys_val;
10262306a36Sopenharmony_ci	u64				user_val;
10362306a36Sopenharmony_ci	struct arm64_ftr_override	*override;
10462306a36Sopenharmony_ci	const struct arm64_ftr_bits	*ftr_bits;
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ciextern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/*
11062306a36Sopenharmony_ci * CPU capabilities:
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * We use arm64_cpu_capabilities to represent system features, errata work
11362306a36Sopenharmony_ci * arounds (both used internally by kernel and tracked in system_cpucaps) and
11462306a36Sopenharmony_ci * ELF HWCAPs (which are exposed to user).
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * To support systems with heterogeneous CPUs, we need to make sure that we
11762306a36Sopenharmony_ci * detect the capabilities correctly on the system and take appropriate
11862306a36Sopenharmony_ci * measures to ensure there are no incompatibilities.
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * This comment tries to explain how we treat the capabilities.
12162306a36Sopenharmony_ci * Each capability has the following list of attributes :
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * 1) Scope of Detection : The system detects a given capability by
12462306a36Sopenharmony_ci *    performing some checks at runtime. This could be, e.g, checking the
12562306a36Sopenharmony_ci *    value of a field in CPU ID feature register or checking the cpu
12662306a36Sopenharmony_ci *    model. The capability provides a call back ( @matches() ) to
12762306a36Sopenharmony_ci *    perform the check. Scope defines how the checks should be performed.
12862306a36Sopenharmony_ci *    There are three cases:
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci *     a) SCOPE_LOCAL_CPU: check all the CPUs and "detect" if at least one
13162306a36Sopenharmony_ci *        matches. This implies, we have to run the check on all the
13262306a36Sopenharmony_ci *        booting CPUs, until the system decides that state of the
13362306a36Sopenharmony_ci *        capability is finalised. (See section 2 below)
13462306a36Sopenharmony_ci *		Or
13562306a36Sopenharmony_ci *     b) SCOPE_SYSTEM: check all the CPUs and "detect" if all the CPUs
13662306a36Sopenharmony_ci *        matches. This implies, we run the check only once, when the
13762306a36Sopenharmony_ci *        system decides to finalise the state of the capability. If the
13862306a36Sopenharmony_ci *        capability relies on a field in one of the CPU ID feature
13962306a36Sopenharmony_ci *        registers, we use the sanitised value of the register from the
14062306a36Sopenharmony_ci *        CPU feature infrastructure to make the decision.
14162306a36Sopenharmony_ci *		Or
14262306a36Sopenharmony_ci *     c) SCOPE_BOOT_CPU: Check only on the primary boot CPU to detect the
14362306a36Sopenharmony_ci *        feature. This category is for features that are "finalised"
14462306a36Sopenharmony_ci *        (or used) by the kernel very early even before the SMP cpus
14562306a36Sopenharmony_ci *        are brought up.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci *    The process of detection is usually denoted by "update" capability
14862306a36Sopenharmony_ci *    state in the code.
14962306a36Sopenharmony_ci *
15062306a36Sopenharmony_ci * 2) Finalise the state : The kernel should finalise the state of a
15162306a36Sopenharmony_ci *    capability at some point during its execution and take necessary
15262306a36Sopenharmony_ci *    actions if any. Usually, this is done, after all the boot-time
15362306a36Sopenharmony_ci *    enabled CPUs are brought up by the kernel, so that it can make
15462306a36Sopenharmony_ci *    better decision based on the available set of CPUs. However, there
15562306a36Sopenharmony_ci *    are some special cases, where the action is taken during the early
15662306a36Sopenharmony_ci *    boot by the primary boot CPU. (e.g, running the kernel at EL2 with
15762306a36Sopenharmony_ci *    Virtualisation Host Extensions). The kernel usually disallows any
15862306a36Sopenharmony_ci *    changes to the state of a capability once it finalises the capability
15962306a36Sopenharmony_ci *    and takes any action, as it may be impossible to execute the actions
16062306a36Sopenharmony_ci *    safely. A CPU brought up after a capability is "finalised" is
16162306a36Sopenharmony_ci *    referred to as "Late CPU" w.r.t the capability. e.g, all secondary
16262306a36Sopenharmony_ci *    CPUs are treated "late CPUs" for capabilities determined by the boot
16362306a36Sopenharmony_ci *    CPU.
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci *    At the moment there are two passes of finalising the capabilities.
16662306a36Sopenharmony_ci *      a) Boot CPU scope capabilities - Finalised by primary boot CPU via
16762306a36Sopenharmony_ci *         setup_boot_cpu_capabilities().
16862306a36Sopenharmony_ci *      b) Everything except (a) - Run via setup_system_capabilities().
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * 3) Verification: When a CPU is brought online (e.g, by user or by the
17162306a36Sopenharmony_ci *    kernel), the kernel should make sure that it is safe to use the CPU,
17262306a36Sopenharmony_ci *    by verifying that the CPU is compliant with the state of the
17362306a36Sopenharmony_ci *    capabilities finalised already. This happens via :
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci *	secondary_start_kernel()-> check_local_cpu_capabilities()
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci *    As explained in (2) above, capabilities could be finalised at
17862306a36Sopenharmony_ci *    different points in the execution. Each newly booted CPU is verified
17962306a36Sopenharmony_ci *    against the capabilities that have been finalised by the time it
18062306a36Sopenharmony_ci *    boots.
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci *	a) SCOPE_BOOT_CPU : All CPUs are verified against the capability
18362306a36Sopenharmony_ci *	except for the primary boot CPU.
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci *	b) SCOPE_LOCAL_CPU, SCOPE_SYSTEM: All CPUs hotplugged on by the
18662306a36Sopenharmony_ci *	user after the kernel boot are verified against the capability.
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci *    If there is a conflict, the kernel takes an action, based on the
18962306a36Sopenharmony_ci *    severity (e.g, a CPU could be prevented from booting or cause a
19062306a36Sopenharmony_ci *    kernel panic). The CPU is allowed to "affect" the state of the
19162306a36Sopenharmony_ci *    capability, if it has not been finalised already. See section 5
19262306a36Sopenharmony_ci *    for more details on conflicts.
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * 4) Action: As mentioned in (2), the kernel can take an action for each
19562306a36Sopenharmony_ci *    detected capability, on all CPUs on the system. Appropriate actions
19662306a36Sopenharmony_ci *    include, turning on an architectural feature, modifying the control
19762306a36Sopenharmony_ci *    registers (e.g, SCTLR, TCR etc.) or patching the kernel via
19862306a36Sopenharmony_ci *    alternatives. The kernel patching is batched and performed at later
19962306a36Sopenharmony_ci *    point. The actions are always initiated only after the capability
20062306a36Sopenharmony_ci *    is finalised. This is usally denoted by "enabling" the capability.
20162306a36Sopenharmony_ci *    The actions are initiated as follows :
20262306a36Sopenharmony_ci *	a) Action is triggered on all online CPUs, after the capability is
20362306a36Sopenharmony_ci *	finalised, invoked within the stop_machine() context from
20462306a36Sopenharmony_ci *	enable_cpu_capabilitie().
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci *	b) Any late CPU, brought up after (1), the action is triggered via:
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci *	  check_local_cpu_capabilities() -> verify_local_cpu_capabilities()
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci * 5) Conflicts: Based on the state of the capability on a late CPU vs.
21162306a36Sopenharmony_ci *    the system state, we could have the following combinations :
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci *		x-----------------------------x
21462306a36Sopenharmony_ci *		| Type  | System   | Late CPU |
21562306a36Sopenharmony_ci *		|-----------------------------|
21662306a36Sopenharmony_ci *		|  a    |   y      |    n     |
21762306a36Sopenharmony_ci *		|-----------------------------|
21862306a36Sopenharmony_ci *		|  b    |   n      |    y     |
21962306a36Sopenharmony_ci *		x-----------------------------x
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci *     Two separate flag bits are defined to indicate whether each kind of
22262306a36Sopenharmony_ci *     conflict can be allowed:
22362306a36Sopenharmony_ci *		ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU - Case(a) is allowed
22462306a36Sopenharmony_ci *		ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU - Case(b) is allowed
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci *     Case (a) is not permitted for a capability that the system requires
22762306a36Sopenharmony_ci *     all CPUs to have in order for the capability to be enabled. This is
22862306a36Sopenharmony_ci *     typical for capabilities that represent enhanced functionality.
22962306a36Sopenharmony_ci *
23062306a36Sopenharmony_ci *     Case (b) is not permitted for a capability that must be enabled
23162306a36Sopenharmony_ci *     during boot if any CPU in the system requires it in order to run
23262306a36Sopenharmony_ci *     safely. This is typical for erratum work arounds that cannot be
23362306a36Sopenharmony_ci *     enabled after the corresponding capability is finalised.
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci *     In some non-typical cases either both (a) and (b), or neither,
23662306a36Sopenharmony_ci *     should be permitted. This can be described by including neither
23762306a36Sopenharmony_ci *     or both flags in the capability's type field.
23862306a36Sopenharmony_ci *
23962306a36Sopenharmony_ci *     In case of a conflict, the CPU is prevented from booting. If the
24062306a36Sopenharmony_ci *     ARM64_CPUCAP_PANIC_ON_CONFLICT flag is specified for the capability,
24162306a36Sopenharmony_ci *     then a kernel panic is triggered.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/*
24662306a36Sopenharmony_ci * Decide how the capability is detected.
24762306a36Sopenharmony_ci * On any local CPU vs System wide vs the primary boot CPU
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_LOCAL_CPU		((u16)BIT(0))
25062306a36Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_SYSTEM		((u16)BIT(1))
25162306a36Sopenharmony_ci/*
25262306a36Sopenharmony_ci * The capabilitiy is detected on the Boot CPU and is used by kernel
25362306a36Sopenharmony_ci * during early boot. i.e, the capability should be "detected" and
25462306a36Sopenharmony_ci * "enabled" as early as possibly on all booting CPUs.
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_BOOT_CPU		((u16)BIT(2))
25762306a36Sopenharmony_ci#define ARM64_CPUCAP_SCOPE_MASK			\
25862306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_SYSTEM	|	\
25962306a36Sopenharmony_ci	 ARM64_CPUCAP_SCOPE_LOCAL_CPU	|	\
26062306a36Sopenharmony_ci	 ARM64_CPUCAP_SCOPE_BOOT_CPU)
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci#define SCOPE_SYSTEM				ARM64_CPUCAP_SCOPE_SYSTEM
26362306a36Sopenharmony_ci#define SCOPE_LOCAL_CPU				ARM64_CPUCAP_SCOPE_LOCAL_CPU
26462306a36Sopenharmony_ci#define SCOPE_BOOT_CPU				ARM64_CPUCAP_SCOPE_BOOT_CPU
26562306a36Sopenharmony_ci#define SCOPE_ALL				ARM64_CPUCAP_SCOPE_MASK
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * Is it permitted for a late CPU to have this capability when system
26962306a36Sopenharmony_ci * hasn't already enabled it ?
27062306a36Sopenharmony_ci */
27162306a36Sopenharmony_ci#define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU	((u16)BIT(4))
27262306a36Sopenharmony_ci/* Is it safe for a late CPU to miss this capability when system has it */
27362306a36Sopenharmony_ci#define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU	((u16)BIT(5))
27462306a36Sopenharmony_ci/* Panic when a conflict is detected */
27562306a36Sopenharmony_ci#define ARM64_CPUCAP_PANIC_ON_CONFLICT		((u16)BIT(6))
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/*
27862306a36Sopenharmony_ci * CPU errata workarounds that need to be enabled at boot time if one or
27962306a36Sopenharmony_ci * more CPUs in the system requires it. When one of these capabilities
28062306a36Sopenharmony_ci * has been enabled, it is safe to allow any CPU to boot that doesn't
28162306a36Sopenharmony_ci * require the workaround. However, it is not safe if a "late" CPU
28262306a36Sopenharmony_ci * requires a workaround and the system hasn't enabled it already.
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_ci#define ARM64_CPUCAP_LOCAL_CPU_ERRATUM		\
28562306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
28662306a36Sopenharmony_ci/*
28762306a36Sopenharmony_ci * CPU feature detected at boot time based on system-wide value of a
28862306a36Sopenharmony_ci * feature. It is safe for a late CPU to have this feature even though
28962306a36Sopenharmony_ci * the system hasn't enabled it, although the feature will not be used
29062306a36Sopenharmony_ci * by Linux in this case. If the system has enabled this feature already,
29162306a36Sopenharmony_ci * then every late CPU must have it.
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_ci#define ARM64_CPUCAP_SYSTEM_FEATURE	\
29462306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_SYSTEM | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
29562306a36Sopenharmony_ci/*
29662306a36Sopenharmony_ci * CPU feature detected at boot time based on feature of one or more CPUs.
29762306a36Sopenharmony_ci * All possible conflicts for a late CPU are ignored.
29862306a36Sopenharmony_ci * NOTE: this means that a late CPU with the feature will *not* cause the
29962306a36Sopenharmony_ci * capability to be advertised by cpus_have_*cap()!
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_ci#define ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE		\
30262306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU		|	\
30362306a36Sopenharmony_ci	 ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU	|	\
30462306a36Sopenharmony_ci	 ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/*
30762306a36Sopenharmony_ci * CPU feature detected at boot time, on one or more CPUs. A late CPU
30862306a36Sopenharmony_ci * is not allowed to have the capability when the system doesn't have it.
30962306a36Sopenharmony_ci * It is Ok for a late CPU to miss the feature.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_ci#define ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE	\
31262306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_LOCAL_CPU		|	\
31362306a36Sopenharmony_ci	 ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/*
31662306a36Sopenharmony_ci * CPU feature used early in the boot based on the boot CPU. All secondary
31762306a36Sopenharmony_ci * CPUs must match the state of the capability as detected by the boot CPU. In
31862306a36Sopenharmony_ci * case of a conflict, a kernel panic is triggered.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_ci#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE		\
32162306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PANIC_ON_CONFLICT)
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci/*
32462306a36Sopenharmony_ci * CPU feature used early in the boot based on the boot CPU. It is safe for a
32562306a36Sopenharmony_ci * late CPU to have this feature even though the boot CPU hasn't enabled it,
32662306a36Sopenharmony_ci * although the feature will not be used by Linux in this case. If the boot CPU
32762306a36Sopenharmony_ci * has enabled this feature already, then every late CPU must have it.
32862306a36Sopenharmony_ci */
32962306a36Sopenharmony_ci#define ARM64_CPUCAP_BOOT_CPU_FEATURE                  \
33062306a36Sopenharmony_ci	(ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistruct arm64_cpu_capabilities {
33362306a36Sopenharmony_ci	const char *desc;
33462306a36Sopenharmony_ci	u16 capability;
33562306a36Sopenharmony_ci	u16 type;
33662306a36Sopenharmony_ci	bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * Take the appropriate actions to configure this capability
33962306a36Sopenharmony_ci	 * for this CPU. If the capability is detected by the kernel
34062306a36Sopenharmony_ci	 * this will be called on all the CPUs in the system,
34162306a36Sopenharmony_ci	 * including the hotplugged CPUs, regardless of whether the
34262306a36Sopenharmony_ci	 * capability is available on that specific CPU. This is
34362306a36Sopenharmony_ci	 * useful for some capabilities (e.g, working around CPU
34462306a36Sopenharmony_ci	 * errata), where all the CPUs must take some action (e.g,
34562306a36Sopenharmony_ci	 * changing system control/configuration). Thus, if an action
34662306a36Sopenharmony_ci	 * is required only if the CPU has the capability, then the
34762306a36Sopenharmony_ci	 * routine must check it before taking any action.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	void (*cpu_enable)(const struct arm64_cpu_capabilities *cap);
35062306a36Sopenharmony_ci	union {
35162306a36Sopenharmony_ci		struct {	/* To be used for erratum handling only */
35262306a36Sopenharmony_ci			struct midr_range midr_range;
35362306a36Sopenharmony_ci			const struct arm64_midr_revidr {
35462306a36Sopenharmony_ci				u32 midr_rv;		/* revision/variant */
35562306a36Sopenharmony_ci				u32 revidr_mask;
35662306a36Sopenharmony_ci			} * const fixed_revs;
35762306a36Sopenharmony_ci		};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		const struct midr_range *midr_range_list;
36062306a36Sopenharmony_ci		struct {	/* Feature register checking */
36162306a36Sopenharmony_ci			u32 sys_reg;
36262306a36Sopenharmony_ci			u8 field_pos;
36362306a36Sopenharmony_ci			u8 field_width;
36462306a36Sopenharmony_ci			u8 min_field_value;
36562306a36Sopenharmony_ci			u8 hwcap_type;
36662306a36Sopenharmony_ci			bool sign;
36762306a36Sopenharmony_ci			unsigned long hwcap;
36862306a36Sopenharmony_ci		};
36962306a36Sopenharmony_ci	};
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * An optional list of "matches/cpu_enable" pair for the same
37362306a36Sopenharmony_ci	 * "capability" of the same "type" as described by the parent.
37462306a36Sopenharmony_ci	 * Only matches(), cpu_enable() and fields relevant to these
37562306a36Sopenharmony_ci	 * methods are significant in the list. The cpu_enable is
37662306a36Sopenharmony_ci	 * invoked only if the corresponding entry "matches()".
37762306a36Sopenharmony_ci	 * However, if a cpu_enable() method is associated
37862306a36Sopenharmony_ci	 * with multiple matches(), care should be taken that either
37962306a36Sopenharmony_ci	 * the match criteria are mutually exclusive, or that the
38062306a36Sopenharmony_ci	 * method is robust against being called multiple times.
38162306a36Sopenharmony_ci	 */
38262306a36Sopenharmony_ci	const struct arm64_cpu_capabilities *match_list;
38362306a36Sopenharmony_ci};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	return cap->type & ARM64_CPUCAP_SCOPE_MASK;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/*
39162306a36Sopenharmony_ci * Generic helper for handling capabilities with multiple (match,enable) pairs
39262306a36Sopenharmony_ci * of call backs, sharing the same capability bit.
39362306a36Sopenharmony_ci * Iterate over each entry to see if at least one matches.
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistatic inline bool
39662306a36Sopenharmony_cicpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
39762306a36Sopenharmony_ci			       int scope)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	const struct arm64_cpu_capabilities *caps;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	for (caps = entry->match_list; caps->matches; caps++)
40262306a36Sopenharmony_ci		if (caps->matches(caps, scope))
40362306a36Sopenharmony_ci			return true;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return false;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic __always_inline bool is_vhe_hyp_code(void)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	/* Only defined for code run in VHE hyp context */
41162306a36Sopenharmony_ci	return __is_defined(__KVM_VHE_HYPERVISOR__);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic __always_inline bool is_nvhe_hyp_code(void)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	/* Only defined for code run in NVHE hyp context */
41762306a36Sopenharmony_ci	return __is_defined(__KVM_NVHE_HYPERVISOR__);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic __always_inline bool is_hyp_code(void)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	return is_vhe_hyp_code() || is_nvhe_hyp_code();
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciextern DECLARE_BITMAP(system_cpucaps, ARM64_NCAPS);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ciextern DECLARE_BITMAP(boot_cpucaps, ARM64_NCAPS);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci#define for_each_available_cap(cap)		\
43062306a36Sopenharmony_ci	for_each_set_bit(cap, system_cpucaps, ARM64_NCAPS)
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cibool this_cpu_has_cap(unsigned int cap);
43362306a36Sopenharmony_civoid cpu_set_feature(unsigned int num);
43462306a36Sopenharmony_cibool cpu_have_feature(unsigned int num);
43562306a36Sopenharmony_ciunsigned long cpu_get_elf_hwcap(void);
43662306a36Sopenharmony_ciunsigned long cpu_get_elf_hwcap2(void);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci#define cpu_set_named_feature(name) cpu_set_feature(cpu_feature(name))
43962306a36Sopenharmony_ci#define cpu_have_named_feature(name) cpu_have_feature(cpu_feature(name))
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic __always_inline bool system_capabilities_finalized(void)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	return alternative_has_cap_likely(ARM64_ALWAYS_SYSTEM);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/*
44762306a36Sopenharmony_ci * Test for a capability with a runtime check.
44862306a36Sopenharmony_ci *
44962306a36Sopenharmony_ci * Before the capability is detected, this returns false.
45062306a36Sopenharmony_ci */
45162306a36Sopenharmony_cistatic __always_inline bool cpus_have_cap(unsigned int num)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	if (num >= ARM64_NCAPS)
45462306a36Sopenharmony_ci		return false;
45562306a36Sopenharmony_ci	return arch_test_bit(num, system_cpucaps);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/*
45962306a36Sopenharmony_ci * Test for a capability without a runtime check.
46062306a36Sopenharmony_ci *
46162306a36Sopenharmony_ci * Before capabilities are finalized, this returns false.
46262306a36Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci * @num must be a compile-time constant.
46562306a36Sopenharmony_ci */
46662306a36Sopenharmony_cistatic __always_inline bool __cpus_have_const_cap(int num)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	if (num >= ARM64_NCAPS)
46962306a36Sopenharmony_ci		return false;
47062306a36Sopenharmony_ci	return alternative_has_cap_unlikely(num);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci/*
47462306a36Sopenharmony_ci * Test for a capability without a runtime check.
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * Before capabilities are finalized, this will BUG().
47762306a36Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
47862306a36Sopenharmony_ci *
47962306a36Sopenharmony_ci * @num must be a compile-time constant.
48062306a36Sopenharmony_ci */
48162306a36Sopenharmony_cistatic __always_inline bool cpus_have_final_cap(int num)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	if (system_capabilities_finalized())
48462306a36Sopenharmony_ci		return __cpus_have_const_cap(num);
48562306a36Sopenharmony_ci	else
48662306a36Sopenharmony_ci		BUG();
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * Test for a capability, possibly with a runtime check for non-hyp code.
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci * For hyp code, this behaves the same as cpus_have_final_cap().
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * For non-hyp code:
49562306a36Sopenharmony_ci * Before capabilities are finalized, this behaves as cpus_have_cap().
49662306a36Sopenharmony_ci * After capabilities are finalized, this is patched to avoid a runtime check.
49762306a36Sopenharmony_ci *
49862306a36Sopenharmony_ci * @num must be a compile-time constant.
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_cistatic __always_inline bool cpus_have_const_cap(int num)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	if (is_hyp_code())
50362306a36Sopenharmony_ci		return cpus_have_final_cap(num);
50462306a36Sopenharmony_ci	else if (system_capabilities_finalized())
50562306a36Sopenharmony_ci		return __cpus_have_const_cap(num);
50662306a36Sopenharmony_ci	else
50762306a36Sopenharmony_ci		return cpus_have_cap(num);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic inline int __attribute_const__
51162306a36Sopenharmony_cicpuid_feature_extract_signed_field_width(u64 features, int field, int width)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	return (s64)(features << (64 - width - field)) >> (64 - width);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic inline int __attribute_const__
51762306a36Sopenharmony_cicpuid_feature_extract_signed_field(u64 features, int field)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	return cpuid_feature_extract_signed_field_width(features, field, 4);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic __always_inline unsigned int __attribute_const__
52362306a36Sopenharmony_cicpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	return (u64)(features << (64 - width - field)) >> (64 - width);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic __always_inline unsigned int __attribute_const__
52962306a36Sopenharmony_cicpuid_feature_extract_unsigned_field(u64 features, int field)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	return cpuid_feature_extract_unsigned_field_width(features, field, 4);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/*
53562306a36Sopenharmony_ci * Fields that identify the version of the Performance Monitors Extension do
53662306a36Sopenharmony_ci * not follow the standard ID scheme. See ARM DDI 0487E.a page D13-2825,
53762306a36Sopenharmony_ci * "Alternative ID scheme used for the Performance Monitors Extension version".
53862306a36Sopenharmony_ci */
53962306a36Sopenharmony_cistatic inline u64 __attribute_const__
54062306a36Sopenharmony_cicpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	u64 val = cpuid_feature_extract_unsigned_field(features, field);
54362306a36Sopenharmony_ci	u64 mask = GENMASK_ULL(field + 3, field);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
54662306a36Sopenharmony_ci	if (val == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
54762306a36Sopenharmony_ci		val = 0;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (val > cap) {
55062306a36Sopenharmony_ci		features &= ~mask;
55162306a36Sopenharmony_ci		features |= (cap << field) & mask;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return features;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic inline u64 arm64_ftr_reg_user_value(const struct arm64_ftr_reg *reg)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	return (reg->user_val | (reg->sys_val & reg->user_mask));
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic inline int __attribute_const__
56862306a36Sopenharmony_cicpuid_feature_extract_field_width(u64 features, int field, int width, bool sign)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	if (WARN_ON_ONCE(!width))
57162306a36Sopenharmony_ci		width = 4;
57262306a36Sopenharmony_ci	return (sign) ?
57362306a36Sopenharmony_ci		cpuid_feature_extract_signed_field_width(features, field, width) :
57462306a36Sopenharmony_ci		cpuid_feature_extract_unsigned_field_width(features, field, width);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic inline int __attribute_const__
57862306a36Sopenharmony_cicpuid_feature_extract_field(u64 features, int field, bool sign)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	return cpuid_feature_extract_field_width(features, field, 4, sign);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic inline s64 arm64_ftr_value(const struct arm64_ftr_bits *ftrp, u64 val)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	return (s64)cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width, ftrp->sign);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_BIGEND_SHIFT) == 0x1 ||
59162306a36Sopenharmony_ci		cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_BIGENDEL0_SHIFT) == 0x1;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic inline bool id_aa64pfr0_32bit_el1(u64 pfr0)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL1_SHIFT);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL0_SHIFT);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic inline bool id_aa64pfr0_sve(u64 pfr0)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_SVE_SHIFT);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return val > 0;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic inline bool id_aa64pfr1_sme(u64 pfr1)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_SME_SHIFT);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return val > 0;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic inline bool id_aa64pfr1_mte(u64 pfr1)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_MTE_SHIFT);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	return val >= ID_AA64PFR1_EL1_MTE_MTE2;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_civoid __init setup_cpu_features(void);
63062306a36Sopenharmony_civoid check_local_cpu_capabilities(void);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ciu64 read_sanitised_ftr_reg(u32 id);
63362306a36Sopenharmony_ciu64 __read_sysreg_by_encoding(u32 sys_id);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic inline bool cpu_supports_mixed_endian_el0(void)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic inline bool supports_csv2p3(int scope)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	u64 pfr0;
64462306a36Sopenharmony_ci	u8 csv2_val;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (scope == SCOPE_LOCAL_CPU)
64762306a36Sopenharmony_ci		pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
64862306a36Sopenharmony_ci	else
64962306a36Sopenharmony_ci		pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
65262306a36Sopenharmony_ci							ID_AA64PFR0_EL1_CSV2_SHIFT);
65362306a36Sopenharmony_ci	return csv2_val == 3;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic inline bool supports_clearbhb(int scope)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	u64 isar2;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (scope == SCOPE_LOCAL_CPU)
66162306a36Sopenharmony_ci		isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
66262306a36Sopenharmony_ci	else
66362306a36Sopenharmony_ci		isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(isar2,
66662306a36Sopenharmony_ci						    ID_AA64ISAR2_EL1_CLRBHB_SHIFT);
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ciconst struct cpumask *system_32bit_el0_cpumask(void);
67062306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic inline bool system_supports_32bit_el0(void)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return static_branch_unlikely(&arm64_mismatched_32bit_el0) ||
67762306a36Sopenharmony_ci	       id_aa64pfr0_32bit_el0(pfr0);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic inline bool system_supports_4kb_granule(void)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	u64 mmfr0;
68362306a36Sopenharmony_ci	u32 val;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
68662306a36Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
68762306a36Sopenharmony_ci						ID_AA64MMFR0_EL1_TGRAN4_SHIFT);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	return (val >= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN) &&
69062306a36Sopenharmony_ci	       (val <= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic inline bool system_supports_64kb_granule(void)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	u64 mmfr0;
69662306a36Sopenharmony_ci	u32 val;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
69962306a36Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
70062306a36Sopenharmony_ci						ID_AA64MMFR0_EL1_TGRAN64_SHIFT);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	return (val >= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN) &&
70362306a36Sopenharmony_ci	       (val <= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic inline bool system_supports_16kb_granule(void)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	u64 mmfr0;
70962306a36Sopenharmony_ci	u32 val;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
71262306a36Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
71362306a36Sopenharmony_ci						ID_AA64MMFR0_EL1_TGRAN16_SHIFT);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return (val >= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN) &&
71662306a36Sopenharmony_ci	       (val <= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic inline bool system_supports_mixed_endian_el0(void)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	return id_aa64mmfr0_mixed_endian_el0(read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1));
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic inline bool system_supports_mixed_endian(void)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	u64 mmfr0;
72762306a36Sopenharmony_ci	u32 val;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
73062306a36Sopenharmony_ci	val = cpuid_feature_extract_unsigned_field(mmfr0,
73162306a36Sopenharmony_ci						ID_AA64MMFR0_EL1_BIGEND_SHIFT);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	return val == 0x1;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic __always_inline bool system_supports_fpsimd(void)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic inline bool system_uses_hw_pan(void)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PAN) &&
74462306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_PAN);
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic inline bool system_uses_ttbr0_pan(void)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
75062306a36Sopenharmony_ci		!system_uses_hw_pan();
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic __always_inline bool system_supports_sve(void)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SVE) &&
75662306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_SVE);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic __always_inline bool system_supports_sme(void)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SME) &&
76262306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_SME);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic __always_inline bool system_supports_sme2(void)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SME) &&
76862306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_SME2);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic __always_inline bool system_supports_fa64(void)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_SME) &&
77462306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_SME_FA64);
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic __always_inline bool system_supports_tpidr2(void)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	return system_supports_sme();
78062306a36Sopenharmony_ci}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic __always_inline bool system_supports_cnp(void)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_CNP) &&
78562306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_CNP);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic inline bool system_supports_address_auth(void)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
79162306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH);
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic inline bool system_supports_generic_auth(void)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
79762306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH);
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic inline bool system_has_full_ptr_auth(void)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	return system_supports_address_auth() && system_supports_generic_auth();
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic __always_inline bool system_uses_irq_prio_masking(void)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
80862306a36Sopenharmony_ci	       cpus_have_const_cap(ARM64_HAS_GIC_PRIO_MASKING);
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic inline bool system_supports_mte(void)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_MTE) &&
81462306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_MTE);
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic inline bool system_has_prio_mask_debugging(void)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING) &&
82062306a36Sopenharmony_ci	       system_uses_irq_prio_masking();
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic inline bool system_supports_bti(void)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_BTI) && cpus_have_const_cap(ARM64_BTI);
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic inline bool system_supports_tlb_range(void)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM64_TLB_RANGE) &&
83162306a36Sopenharmony_ci		cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ciint do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
83562306a36Sopenharmony_cibool try_emulate_mrs(struct pt_regs *regs, u32 isn);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	switch (parange) {
84062306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_32: return 32;
84162306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_36: return 36;
84262306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_40: return 40;
84362306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_42: return 42;
84462306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_44: return 44;
84562306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_48: return 48;
84662306a36Sopenharmony_ci	case ID_AA64MMFR0_EL1_PARANGE_52: return 52;
84762306a36Sopenharmony_ci	/*
84862306a36Sopenharmony_ci	 * A future PE could use a value unknown to the kernel.
84962306a36Sopenharmony_ci	 * However, by the "D10.1.4 Principles of the ID scheme
85062306a36Sopenharmony_ci	 * for fields in ID registers", ARM DDI 0487C.a, any new
85162306a36Sopenharmony_ci	 * value is guaranteed to be higher than what we know already.
85262306a36Sopenharmony_ci	 * As a safe limit, we return the limit supported by the kernel.
85362306a36Sopenharmony_ci	 */
85462306a36Sopenharmony_ci	default: return CONFIG_ARM64_PA_BITS;
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/* Check whether hardware update of the Access flag is supported */
85962306a36Sopenharmony_cistatic inline bool cpu_has_hw_af(void)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	u64 mmfr1;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ARM64_HW_AFDBM))
86462306a36Sopenharmony_ci		return false;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/*
86762306a36Sopenharmony_ci	 * Use cached version to avoid emulated msr operation on KVM
86862306a36Sopenharmony_ci	 * guests.
86962306a36Sopenharmony_ci	 */
87062306a36Sopenharmony_ci	mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
87162306a36Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(mmfr1,
87262306a36Sopenharmony_ci						ID_AA64MMFR1_EL1_HAFDBS_SHIFT);
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic inline bool cpu_has_pan(void)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	u64 mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
87862306a36Sopenharmony_ci	return cpuid_feature_extract_unsigned_field(mmfr1,
87962306a36Sopenharmony_ci						    ID_AA64MMFR1_EL1_PAN_SHIFT);
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci#ifdef CONFIG_ARM64_AMU_EXTN
88362306a36Sopenharmony_ci/* Check whether the cpu supports the Activity Monitors Unit (AMU) */
88462306a36Sopenharmony_ciextern bool cpu_has_amu_feat(int cpu);
88562306a36Sopenharmony_ci#else
88662306a36Sopenharmony_cistatic inline bool cpu_has_amu_feat(int cpu)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	return false;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci#endif
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci/* Get a cpu that supports the Activity Monitors Unit (AMU) */
89362306a36Sopenharmony_ciextern int get_cpu_with_amu_feat(void);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic inline unsigned int get_vmid_bits(u64 mmfr1)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	int vmid_bits;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	vmid_bits = cpuid_feature_extract_unsigned_field(mmfr1,
90062306a36Sopenharmony_ci						ID_AA64MMFR1_EL1_VMIDBits_SHIFT);
90162306a36Sopenharmony_ci	if (vmid_bits == ID_AA64MMFR1_EL1_VMIDBits_16)
90262306a36Sopenharmony_ci		return 16;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/*
90562306a36Sopenharmony_ci	 * Return the default here even if any reserved
90662306a36Sopenharmony_ci	 * value is fetched from the system register.
90762306a36Sopenharmony_ci	 */
90862306a36Sopenharmony_ci	return 8;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cis64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, s64 cur);
91262306a36Sopenharmony_cistruct arm64_ftr_reg *get_arm64_ftr_reg(u32 sys_id);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64mmfr1_override;
91562306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64pfr0_override;
91662306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64pfr1_override;
91762306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64zfr0_override;
91862306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64smfr0_override;
91962306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64isar1_override;
92062306a36Sopenharmony_ciextern struct arm64_ftr_override id_aa64isar2_override;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ciextern struct arm64_ftr_override arm64_sw_feature_override;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ciu32 get_kvm_ipa_limit(void);
92562306a36Sopenharmony_civoid dump_cpu_features(void);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci#endif
930