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