mirror of
https://git.yoctoproject.org/meta-arm
synced 2026-07-16 15:57:19 +00:00
arm-bsp/linux: add asymmetric AArch32 EL0 support for TC0
This adds patches for asymmetric AArch32 EL0 configuration support for android11-5.4-lts kernel. And enables CONFIG_ASYMMETRIC_AARCH32 and disables CONFIG_KVM in TC0 defconfig. Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com> Change-Id: Iab94b5c48b60aca4a71267ba1be1cb1836002d10 Signed-off-by: Jon Mason <jon.mason@arm.com>
This commit is contained in:
committed by
Tushar Khandelwal
parent
3be0996065
commit
88c201ca9d
@@ -81,6 +81,8 @@ SRC_URI_append_tc0 = " \
|
|||||||
file://0011-tee-optee-Add-support-for-session-login-client-UUID-.patch \
|
file://0011-tee-optee-Add-support-for-session-login-client-UUID-.patch \
|
||||||
file://0012-driver-optee-Support-for-ffa-transport.patch \
|
file://0012-driver-optee-Support-for-ffa-transport.patch \
|
||||||
file://0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch \
|
file://0013-tee-optee-fix-mem-handle-removal-in-ffa_shm_unregist.patch \
|
||||||
|
file://0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch \
|
||||||
|
file://0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch \
|
||||||
"
|
"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
+462
@@ -0,0 +1,462 @@
|
|||||||
|
Upstream-Status: Backport [http://www.linux-arm.org/git?p=linux-power.git;a=commit;h=ce7d6e205568b7949ff26f2b3c65dc4db1c15b96]
|
||||||
|
Signed-off-by: Usama Arif <usama.arif@arm.com>
|
||||||
|
|
||||||
|
From 0316669bc2a0e1279427b7a3ed01313b70544756 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Catalin Marinas <catalin.marinas@arm.com>
|
||||||
|
Date: Thu, 20 Jun 2019 17:59:25 +0100
|
||||||
|
Subject: [PATCH 1/2] arm64: Add support for asymmetric AArch32 EL0
|
||||||
|
configurations
|
||||||
|
|
||||||
|
There is a non-negligible chance that we may see asymmetric big.LITTLE
|
||||||
|
configurations where only the LITTLE CPUs have AArch32 support at EL0.
|
||||||
|
While Linux currently handles such configurations by not allowing
|
||||||
|
AArch32 tasks, there is a strong marketing push to investigate the
|
||||||
|
possibility of allowing compat applications. This patch is aimed to
|
||||||
|
facilitate internal testing and NOT FOR UPSTREAM.
|
||||||
|
|
||||||
|
When the CONFIG_ASYMMETRIC_AARCH32 option is enabled (EXPERT), the type
|
||||||
|
of the ARM64_HAS_32BIT_EL0 capability becomes WEAK_LOCAL_CPU_FEATURE.
|
||||||
|
The kernel will now return true for system_supports_32bit_el0() and
|
||||||
|
32-bit tasks will be migrated to the capable CPUs during
|
||||||
|
do_notify_resume(). If the last CPU supporting 32-bit is offlined, the
|
||||||
|
kernel will SIGKILL any scheduled 32-bit tasks (the alternative is to
|
||||||
|
prevent offlining through a new .cpu_disable feature entry).
|
||||||
|
|
||||||
|
In addition to the relaxation of the ARM64_HAS_32BIT_EL0 capability,
|
||||||
|
this patch factors out the 32-bit cpuinfo and features setting into
|
||||||
|
separate functions: __cpuinfo_store_cpu_32bit(),
|
||||||
|
init_cpu_32bit_features(). The cpuinfo of the booting CPU
|
||||||
|
(boot_cpu_data) is now updated on the first 32-bit capable CPU even if
|
||||||
|
it is a secondary one. The ID_AA64PFR0_EL0_64BIT_ONLY feature is relaxed
|
||||||
|
to FTR_NONSTRICT and FTR_HIGHER_SAFE when the asymmetric AArch32 support
|
||||||
|
is enabled. The compat_elf_hwcaps are only verified for the
|
||||||
|
AArch32-capable CPUs to still allow hotplugging AArch64-only CPUs.
|
||||||
|
|
||||||
|
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
|
||||||
|
Cc: Morten Rasmussen <Morten.Rasmussen@arm.com>
|
||||||
|
Cc: Valentin Schneider <valentin.schneider@arm.com>
|
||||||
|
Cc: Qais Yousef <qais.yousef@arm.com>
|
||||||
|
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
|
||||||
|
Signed-off-by: Qais Yousef <qais.yousef@arm.com>
|
||||||
|
---
|
||||||
|
arch/arm64/Kconfig | 13 ++++++
|
||||||
|
arch/arm64/include/asm/cpu.h | 2 +
|
||||||
|
arch/arm64/include/asm/cpufeature.h | 3 ++
|
||||||
|
arch/arm64/include/asm/thread_info.h | 5 ++-
|
||||||
|
arch/arm64/kernel/cpufeature.c | 64 ++++++++++++++++++----------
|
||||||
|
arch/arm64/kernel/cpuinfo.c | 61 +++++++++++++++++---------
|
||||||
|
arch/arm64/kernel/process.c | 17 ++++++++
|
||||||
|
arch/arm64/kernel/signal.c | 30 ++++++++++++-
|
||||||
|
8 files changed, 150 insertions(+), 45 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
||||||
|
index 71d23b5d10d4..068e9e9ffc40 100644
|
||||||
|
--- a/arch/arm64/Kconfig
|
||||||
|
+++ b/arch/arm64/Kconfig
|
||||||
|
@@ -1680,6 +1680,19 @@ config DMI
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
+config ASYMMETRIC_AARCH32
|
||||||
|
+ bool "Allow support for asymmetric AArch32 support"
|
||||||
|
+ depends on COMPAT && EXPERT && !KVM
|
||||||
|
+ help
|
||||||
|
+ Enable this option to allow support for asymmetric AArch32 EL0
|
||||||
|
+ CPU configurations. Once the AArch32 EL0 support is detected
|
||||||
|
+ on a CPU, the feature is made available to user space to allow
|
||||||
|
+ the execution of 32-bit (compat) applications by migrating
|
||||||
|
+ them to the capable CPUs. Offlining such CPUs leads to 32-bit
|
||||||
|
+ applications being killed.
|
||||||
|
+
|
||||||
|
+ If unsure say N.
|
||||||
|
+
|
||||||
|
config SYSVIPC_COMPAT
|
||||||
|
def_bool y
|
||||||
|
depends on COMPAT && SYSVIPC
|
||||||
|
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
|
||||||
|
index d72d995b7e25..39dbf5827070 100644
|
||||||
|
--- a/arch/arm64/include/asm/cpu.h
|
||||||
|
+++ b/arch/arm64/include/asm/cpu.h
|
||||||
|
@@ -15,6 +15,7 @@
|
||||||
|
struct cpuinfo_arm64 {
|
||||||
|
struct cpu cpu;
|
||||||
|
struct kobject kobj;
|
||||||
|
+ bool aarch32_valid;
|
||||||
|
u32 reg_ctr;
|
||||||
|
u32 reg_cntfrq;
|
||||||
|
u32 reg_dczid;
|
||||||
|
@@ -60,6 +61,7 @@ void cpuinfo_store_cpu(void);
|
||||||
|
void __init cpuinfo_store_boot_cpu(void);
|
||||||
|
|
||||||
|
void __init init_cpu_features(struct cpuinfo_arm64 *info);
|
||||||
|
+void init_cpu_32bit_features(struct cpuinfo_arm64 *info);
|
||||||
|
void update_cpu_features(int cpu, struct cpuinfo_arm64 *info,
|
||||||
|
struct cpuinfo_arm64 *boot);
|
||||||
|
|
||||||
|
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
|
||||||
|
index 9cde5d2e768f..d00d673d423b 100644
|
||||||
|
--- a/arch/arm64/include/asm/cpufeature.h
|
||||||
|
+++ b/arch/arm64/include/asm/cpufeature.h
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
#include <linux/bug.h>
|
||||||
|
+#include <linux/cpumask.h>
|
||||||
|
#include <linux/jump_label.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
@@ -370,6 +371,8 @@ cpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+extern cpumask_t aarch32_el0_mask;
|
||||||
|
+
|
||||||
|
extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
|
||||||
|
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
|
||||||
|
extern struct static_key_false arm64_const_caps_ready;
|
||||||
|
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
|
||||||
|
index 8c73764b9ed2..54a4c912a7ab 100644
|
||||||
|
--- a/arch/arm64/include/asm/thread_info.h
|
||||||
|
+++ b/arch/arm64/include/asm/thread_info.h
|
||||||
|
@@ -66,6 +66,7 @@ void arch_release_task_struct(struct task_struct *tsk);
|
||||||
|
#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
|
||||||
|
#define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */
|
||||||
|
#define TIF_FSCHECK 5 /* Check FS is USER_DS on return */
|
||||||
|
+#define TIF_SET_32BIT_AFFINITY 6 /* set thread affinity for asymmetric AArch32 */
|
||||||
|
#define TIF_NOHZ 7
|
||||||
|
#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
|
||||||
|
#define TIF_SYSCALL_AUDIT 9 /* syscall auditing */
|
||||||
|
@@ -95,11 +96,13 @@ void arch_release_task_struct(struct task_struct *tsk);
|
||||||
|
#define _TIF_UPROBE (1 << TIF_UPROBE)
|
||||||
|
#define _TIF_FSCHECK (1 << TIF_FSCHECK)
|
||||||
|
#define _TIF_32BIT (1 << TIF_32BIT)
|
||||||
|
+#define _TIF_SET_32BIT_AFFINITY (1 << TIF_SET_32BIT_AFFINITY)
|
||||||
|
#define _TIF_SVE (1 << TIF_SVE)
|
||||||
|
|
||||||
|
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
|
||||||
|
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \
|
||||||
|
- _TIF_UPROBE | _TIF_FSCHECK)
|
||||||
|
+ _TIF_UPROBE | _TIF_FSCHECK | \
|
||||||
|
+ _TIF_SET_32BIT_AFFINITY)
|
||||||
|
|
||||||
|
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
|
||||||
|
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
|
||||||
|
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
|
||||||
|
index da92693b202c..c0d656cfe5b8 100644
|
||||||
|
--- a/arch/arm64/kernel/cpufeature.c
|
||||||
|
+++ b/arch/arm64/kernel/cpufeature.c
|
||||||
|
@@ -8,7 +8,6 @@
|
||||||
|
#define pr_fmt(fmt) "CPU features: " fmt
|
||||||
|
|
||||||
|
#include <linux/bsearch.h>
|
||||||
|
-#include <linux/cpumask.h>
|
||||||
|
#include <linux/crash_dump.h>
|
||||||
|
#include <linux/sort.h>
|
||||||
|
#include <linux/stop_machine.h>
|
||||||
|
@@ -164,7 +163,11 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
||||||
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL3_SHIFT, 4, 0),
|
||||||
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL2_SHIFT, 4, 0),
|
||||||
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_SHIFT, 4, ID_AA64PFR0_EL1_64BIT_ONLY),
|
||||||
|
+#ifndef CONFIG_ASYMMETRIC_AARCH32
|
||||||
|
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
|
||||||
|
+#else
|
||||||
|
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_HIGHER_SAFE, ID_AA64PFR0_EL0_SHIFT, 4, ID_AA64PFR0_EL0_64BIT_ONLY),
|
||||||
|
+#endif
|
||||||
|
ARM64_FTR_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -509,7 +512,7 @@ static void __init sort_ftr_regs(void)
|
||||||
|
* Any bits that are not covered by an arm64_ftr_bits entry are considered
|
||||||
|
* RES0 for the system-wide value, and must strictly match.
|
||||||
|
*/
|
||||||
|
-static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
|
||||||
|
+static void init_cpu_ftr_reg(u32 sys_reg, u64 new)
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
u64 strict_mask = ~0x0ULL;
|
||||||
|
@@ -590,25 +593,6 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
|
||||||
|
init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
|
||||||
|
init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0);
|
||||||
|
|
||||||
|
- if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
|
||||||
|
- init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
|
||||||
|
- init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
|
||||||
|
- init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
|
||||||
|
- init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
|
||||||
|
init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
|
||||||
|
sve_init_vq_map();
|
||||||
|
@@ -627,6 +611,26 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
|
||||||
|
setup_boot_cpu_capabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
+void init_cpu_32bit_features(struct cpuinfo_arm64 *info)
|
||||||
|
+{
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0);
|
||||||
|
+ init_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1);
|
||||||
|
+ init_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0);
|
||||||
|
+ init_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1);
|
||||||
|
+ init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
|
||||||
|
{
|
||||||
|
const struct arm64_ftr_bits *ftrp;
|
||||||
|
@@ -1264,6 +1268,16 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef CONFIG_ASYMMETRIC_AARCH32
|
||||||
|
+cpumask_t aarch32_el0_mask;
|
||||||
|
+
|
||||||
|
+static void cpu_enable_aarch32_el0(struct arm64_cpu_capabilities const *cap)
|
||||||
|
+{
|
||||||
|
+ if (has_cpuid_feature(cap, SCOPE_LOCAL_CPU))
|
||||||
|
+ cpumask_set_cpu(smp_processor_id(), &aarch32_el0_mask);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||||
|
{
|
||||||
|
.desc = "GIC system register CPU interface",
|
||||||
|
@@ -1340,7 +1354,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||||
|
{
|
||||||
|
.desc = "32-bit EL0 Support",
|
||||||
|
.capability = ARM64_HAS_32BIT_EL0,
|
||||||
|
+#ifndef CONFIG_ASYMMETRIC_AARCH32
|
||||||
|
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||||
|
+#else
|
||||||
|
+ .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
|
||||||
|
+ .cpu_enable = cpu_enable_aarch32_el0,
|
||||||
|
+#endif
|
||||||
|
.matches = has_cpuid_feature,
|
||||||
|
.sys_reg = SYS_ID_AA64PFR0_EL1,
|
||||||
|
.sign = FTR_UNSIGNED,
|
||||||
|
@@ -1983,7 +2002,8 @@ static void verify_local_cpu_capabilities(void)
|
||||||
|
|
||||||
|
verify_local_elf_hwcaps(arm64_elf_hwcaps);
|
||||||
|
|
||||||
|
- if (system_supports_32bit_el0())
|
||||||
|
+ if (system_supports_32bit_el0() &&
|
||||||
|
+ this_cpu_has_cap(ARM64_HAS_32BIT_EL0))
|
||||||
|
verify_local_elf_hwcaps(compat_elf_hwcaps);
|
||||||
|
|
||||||
|
if (system_supports_sve())
|
||||||
|
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
|
||||||
|
index 05933c065732..bda37687bb66 100644
|
||||||
|
--- a/arch/arm64/kernel/cpuinfo.c
|
||||||
|
+++ b/arch/arm64/kernel/cpuinfo.c
|
||||||
|
@@ -351,27 +351,6 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
|
||||||
|
info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
|
||||||
|
info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
|
||||||
|
|
||||||
|
- /* Update the 32bit ID registers only if AArch32 is implemented */
|
||||||
|
- if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
|
||||||
|
- info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
|
||||||
|
- info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
|
||||||
|
- info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
|
||||||
|
- info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
|
||||||
|
- info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
|
||||||
|
- info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
|
||||||
|
- info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
|
||||||
|
- info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
|
||||||
|
- info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
|
||||||
|
- info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
|
||||||
|
- info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
|
||||||
|
- info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
|
||||||
|
- info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
|
||||||
|
-
|
||||||
|
- info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
|
||||||
|
- info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
|
||||||
|
- info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
|
||||||
|
id_aa64pfr0_sve(info->reg_id_aa64pfr0))
|
||||||
|
info->reg_zcr = read_zcr_features();
|
||||||
|
@@ -379,10 +358,46 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
|
||||||
|
cpuinfo_detect_icache_policy(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void __cpuinfo_store_cpu_32bit(struct cpuinfo_arm64 *info)
|
||||||
|
+{
|
||||||
|
+ info->aarch32_valid = true;
|
||||||
|
+
|
||||||
|
+ info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
|
||||||
|
+ info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
|
||||||
|
+ info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
|
||||||
|
+ info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
|
||||||
|
+ info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
|
||||||
|
+ info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
|
||||||
|
+ info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
|
||||||
|
+ info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
|
||||||
|
+ info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
|
||||||
|
+ info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
|
||||||
|
+ info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
|
||||||
|
+ info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
|
||||||
|
+ info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
|
||||||
|
+
|
||||||
|
+ info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
|
||||||
|
+ info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
|
||||||
|
+ info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void cpuinfo_store_cpu(void)
|
||||||
|
{
|
||||||
|
struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
|
||||||
|
__cpuinfo_store_cpu(info);
|
||||||
|
+ if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
|
||||||
|
+ __cpuinfo_store_cpu_32bit(info);
|
||||||
|
+ /*
|
||||||
|
+ * With asymmetric AArch32 support, populate the boot CPU information
|
||||||
|
+ * on the first 32-bit capable secondary CPU if the primary one
|
||||||
|
+ * skipped this step.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
|
||||||
|
+ !boot_cpu_data.aarch32_valid &&
|
||||||
|
+ id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
|
||||||
|
+ __cpuinfo_store_cpu_32bit(&boot_cpu_data);
|
||||||
|
+ init_cpu_32bit_features(&boot_cpu_data);
|
||||||
|
+ }
|
||||||
|
update_cpu_features(smp_processor_id(), info, &boot_cpu_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -390,9 +405,13 @@ void __init cpuinfo_store_boot_cpu(void)
|
||||||
|
{
|
||||||
|
struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
|
||||||
|
__cpuinfo_store_cpu(info);
|
||||||
|
+ if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0))
|
||||||
|
+ __cpuinfo_store_cpu_32bit(info);
|
||||||
|
|
||||||
|
boot_cpu_data = *info;
|
||||||
|
init_cpu_features(&boot_cpu_data);
|
||||||
|
+ if (id_aa64pfr0_32bit_el0(boot_cpu_data.reg_id_aa64pfr0))
|
||||||
|
+ init_cpu_32bit_features(&boot_cpu_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_initcall(cpuinfo_regs_init);
|
||||||
|
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
|
||||||
|
index cc1d8b1025b1..35f0c93699ce 100644
|
||||||
|
--- a/arch/arm64/kernel/process.c
|
||||||
|
+++ b/arch/arm64/kernel/process.c
|
||||||
|
@@ -494,6 +494,15 @@ static void entry_task_switch(struct task_struct *next)
|
||||||
|
__this_cpu_write(__entry_task, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void aarch32_thread_switch(struct task_struct *next)
|
||||||
|
+{
|
||||||
|
+ struct thread_info *ti = task_thread_info(next);
|
||||||
|
+
|
||||||
|
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) && is_compat_thread(ti) &&
|
||||||
|
+ !cpumask_test_cpu(smp_processor_id(), &aarch32_el0_mask))
|
||||||
|
+ set_ti_thread_flag(ti, TIF_SET_32BIT_AFFINITY);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Thread switching.
|
||||||
|
*/
|
||||||
|
@@ -511,6 +520,7 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
|
||||||
|
ptrauth_thread_switch(next);
|
||||||
|
ssbs_thread_switch(next);
|
||||||
|
scs_overflow_check(next);
|
||||||
|
+ aarch32_thread_switch(next);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Complete any pending TLB or cache maintenance on this CPU in case
|
||||||
|
@@ -569,6 +579,13 @@ void arch_setup_new_exec(void)
|
||||||
|
current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
|
||||||
|
|
||||||
|
ptrauth_thread_init_user(current);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If exec'ing a 32-bit task, force the asymmetric 32-bit feature
|
||||||
|
+ * check as the task may not go through a switch_to() call.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) && is_compat_task())
|
||||||
|
+ set_thread_flag(TIF_SET_32BIT_AFFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
|
||||||
|
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
|
||||||
|
index dd2cdc0d5be2..d8cdd3211d68 100644
|
||||||
|
--- a/arch/arm64/kernel/signal.c
|
||||||
|
+++ b/arch/arm64/kernel/signal.c
|
||||||
|
@@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
#include <linux/cache.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
+#include <linux/cpumask.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/signal.h>
|
||||||
|
@@ -896,6 +897,29 @@ static void do_signal(struct pt_regs *regs)
|
||||||
|
restore_saved_sigmask();
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void set_32bit_cpus_allowed(void)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Try to honour as best as possible whatever affinity request this
|
||||||
|
+ * task has. If it spans no compatible CPU, disregard it entirely.
|
||||||
|
+ */
|
||||||
|
+ if (cpumask_intersects(current->cpus_ptr, &aarch32_el0_mask)) {
|
||||||
|
+ cpumask_t cpus_allowed;
|
||||||
|
+
|
||||||
|
+ cpumask_and(&cpus_allowed, current->cpus_ptr, &aarch32_el0_mask);
|
||||||
|
+ ret = set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||||
|
+ } else {
|
||||||
|
+ ret = set_cpus_allowed_ptr(current, &aarch32_el0_mask);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (ret) {
|
||||||
|
+ pr_warn_once("No CPUs capable of running 32-bit tasks\n");
|
||||||
|
+ force_sig(SIGKILL);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
asmlinkage void do_notify_resume(struct pt_regs *regs,
|
||||||
|
unsigned long thread_flags)
|
||||||
|
{
|
||||||
|
@@ -910,7 +934,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
|
||||||
|
/* Check valid user FS if needed */
|
||||||
|
addr_limit_user_check();
|
||||||
|
|
||||||
|
- if (thread_flags & _TIF_NEED_RESCHED) {
|
||||||
|
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
|
||||||
|
+ thread_flags & _TIF_SET_32BIT_AFFINITY) {
|
||||||
|
+ clear_thread_flag(TIF_SET_32BIT_AFFINITY);
|
||||||
|
+ set_32bit_cpus_allowed();
|
||||||
|
+ } else if (thread_flags & _TIF_NEED_RESCHED) {
|
||||||
|
/* Unmask Debug and SError for the next task */
|
||||||
|
local_daif_restore(DAIF_PROCCTX_NOIRQ);
|
||||||
|
|
||||||
|
--
|
||||||
|
2.29.2
|
||||||
|
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
Upstream-Status: Backport [http://www.linux-arm.org/git?p=linux-power.git;a=commit;h=e6b567c1cc07dd1690e5d34b6a93ab9819ab2eeb]
|
||||||
|
Signed-off-by: Usama Arif <usama.arif@arm.com>
|
||||||
|
|
||||||
|
From d6acb605de7d40c295ada9b1f4c8336e4db71ae4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Valentin Schneider <valentin.schneider@arm.com>
|
||||||
|
Date: Thu, 5 Sep 2019 17:53:19 +0100
|
||||||
|
Subject: [PATCH 2/2] arm64: smp: Prevent hotplugging the last AArch32-able CPU
|
||||||
|
|
||||||
|
EL0 AArch32 tasks are now sigkilled when they can't run on any
|
||||||
|
compatible CPU, either because there aren't any left (hotplug) or
|
||||||
|
because they aren't allowed to run on those left (task affinity).
|
||||||
|
|
||||||
|
However, it has been deemed valuable to prevent the loss of
|
||||||
|
functionality resulting in offlining the last AArch32-compatible CPU.
|
||||||
|
|
||||||
|
Add arch-specific hook in _cpu_down() that allows checking whether we
|
||||||
|
can offline a cpu or not and use that hook to veto offlining the last
|
||||||
|
AArch32 CPU.
|
||||||
|
|
||||||
|
Signed-off-by: Valentin Schneider <valentin.schneider@arm.com>
|
||||||
|
Signed-off-by: Qais Yousef <qais.yousef@arm.com>
|
||||||
|
---
|
||||||
|
arch/arm64/kernel/smp.c | 22 ++++++++++++++++++++++
|
||||||
|
kernel/cpu.c | 9 +++++++++
|
||||||
|
2 files changed, 31 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
|
||||||
|
index 038ce6263d1c..c8ab4ee29f32 100644
|
||||||
|
--- a/arch/arm64/kernel/smp.c
|
||||||
|
+++ b/arch/arm64/kernel/smp.c
|
||||||
|
@@ -85,6 +85,28 @@ static inline int op_cpu_kill(unsigned int cpu)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+bool arch_allows_cpu_disable(int cpu, int tasks_frozen,
|
||||||
|
+ enum cpuhp_state target)
|
||||||
|
+{
|
||||||
|
+ /*
|
||||||
|
+ * Don't let the last AArch32-compatible CPU go down unless the request
|
||||||
|
+ * is related to suspend (!tasks_frozen) then allow it to be offlined
|
||||||
|
+ * or we'll break suspend-to-ram functionality.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_ASYMMETRIC_AARCH32) &&
|
||||||
|
+ !cpumask_empty(&aarch32_el0_mask) &&
|
||||||
|
+ !tasks_frozen) {
|
||||||
|
+ cpumask_t online;
|
||||||
|
+
|
||||||
|
+ cpumask_and(&online, &aarch32_el0_mask, cpu_online_mask);
|
||||||
|
+
|
||||||
|
+ if (cpumask_weight(&online) == 1)
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot a secondary CPU, and assign it the specified idle task.
|
||||||
|
diff --git a/kernel/cpu.c b/kernel/cpu.c
|
||||||
|
index 261b5098f81c..4fae9b61f442 100644
|
||||||
|
--- a/kernel/cpu.c
|
||||||
|
+++ b/kernel/cpu.c
|
||||||
|
@@ -134,6 +134,12 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
|
||||||
|
return cpuhp_hp_states + state;
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool __weak arch_allows_cpu_disable(int cpu, int tasks_frozen,
|
||||||
|
+ enum cpuhp_state target)
|
||||||
|
+{
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* cpuhp_invoke_callback _ Invoke the callbacks for a given state
|
||||||
|
* @cpu: The cpu for which the callback should be invoked
|
||||||
|
@@ -985,6 +991,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
|
||||||
|
if (!cpu_present(cpu))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
+ if (!arch_allows_cpu_disable(cpu, tasks_frozen, target))
|
||||||
|
+ return -EBUSY;
|
||||||
|
+
|
||||||
|
cpus_write_lock();
|
||||||
|
|
||||||
|
cpuhp_tasks_frozen = tasks_frozen;
|
||||||
|
--
|
||||||
|
2.29.2
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@ CONFIG_POSIX_MQUEUE=y
|
|||||||
CONFIG_AUDIT=y
|
CONFIG_AUDIT=y
|
||||||
CONFIG_NO_HZ=y
|
CONFIG_NO_HZ=y
|
||||||
CONFIG_HIGH_RES_TIMERS=y
|
CONFIG_HIGH_RES_TIMERS=y
|
||||||
|
CONFIG_ASYMMETRIC_AARCH32=y
|
||||||
CONFIG_PREEMPT=y
|
CONFIG_PREEMPT=y
|
||||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||||
CONFIG_BSD_PROCESS_ACCT=y
|
CONFIG_BSD_PROCESS_ACCT=y
|
||||||
@@ -116,7 +117,6 @@ CONFIG_ACPI_APEI_PCIEAER=y
|
|||||||
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
|
CONFIG_ACPI_APEI_MEMORY_FAILURE=y
|
||||||
CONFIG_ACPI_APEI_EINJ=y
|
CONFIG_ACPI_APEI_EINJ=y
|
||||||
CONFIG_VIRTUALIZATION=y
|
CONFIG_VIRTUALIZATION=y
|
||||||
CONFIG_KVM=y
|
|
||||||
CONFIG_ARM64_CRYPTO=y
|
CONFIG_ARM64_CRYPTO=y
|
||||||
CONFIG_CRYPTO_SHA1_ARM64_CE=y
|
CONFIG_CRYPTO_SHA1_ARM64_CE=y
|
||||||
CONFIG_CRYPTO_SHA2_ARM64_CE=y
|
CONFIG_CRYPTO_SHA2_ARM64_CE=y
|
||||||
|
|||||||
Reference in New Issue
Block a user