From 1f872c3c83076bc825d5b21e3983a632f48c1b7d Mon Sep 17 00:00:00 2001 From: Arunachalam Ganapathy Date: Mon, 8 Feb 2021 12:26:51 +0000 Subject: [PATCH] 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 Change-Id: Iab94b5c48b60aca4a71267ba1be1cb1836002d10 Signed-off-by: Jon Mason --- .../linux/linux-arm-platforms.inc | 2 + ...t-for-asymmetric-AArch32-EL0-configu.patch | 462 ++++++++++++++++++ ...t-hotplugging-the-last-AArch32-able-.patch | 89 ++++ .../linux/linux-arm64-ack-5.4/tc0/defconfig | 2 +- 4 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch create mode 100644 meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc index 9aba7623..b8526440 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm-platforms.inc @@ -81,6 +81,8 @@ SRC_URI_append_tc0 = " \ file://0011-tee-optee-Add-support-for-session-login-client-UUID-.patch \ file://0012-driver-optee-Support-for-ffa-transport.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 \ " # diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch new file mode 100644 index 00000000..7ca9c078 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0014-arm64-Add-support-for-asymmetric-AArch32-EL0-configu.patch @@ -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 + +From 0316669bc2a0e1279427b7a3ed01313b70544756 Mon Sep 17 00:00:00 2001 +From: Catalin Marinas +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 +Cc: Morten Rasmussen +Cc: Valentin Schneider +Cc: Qais Yousef +Signed-off-by: Catalin Marinas +Signed-off-by: Qais Yousef +--- + 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 ++#include + #include + #include + +@@ -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 +-#include + #include + #include + #include +@@ -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 + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch new file mode 100644 index 00000000..774721e0 --- /dev/null +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/0015-arm64-smp-Prevent-hotplugging-the-last-AArch32-able-.patch @@ -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 + +From d6acb605de7d40c295ada9b1f4c8336e4db71ae4 Mon Sep 17 00:00:00 2001 +From: Valentin Schneider +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 +Signed-off-by: Qais Yousef +--- + 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 + diff --git a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig index 0f44a949..c8caa05a 100644 --- a/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig +++ b/meta-arm-bsp/recipes-kernel/linux/linux-arm64-ack-5.4/tc0/defconfig @@ -2,6 +2,7 @@ CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_ASYMMETRIC_AARCH32=y CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_BSD_PROCESS_ACCT=y @@ -116,7 +117,6 @@ CONFIG_ACPI_APEI_PCIEAER=y CONFIG_ACPI_APEI_MEMORY_FAILURE=y CONFIG_ACPI_APEI_EINJ=y CONFIG_VIRTUALIZATION=y -CONFIG_KVM=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y