Merge remote-tracking branch 'tip/sched/arm64' into for-next/core
authorCatalin Marinas <catalin.marinas@arm.com>
Tue, 31 Aug 2021 08:10:00 +0000 (09:10 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Tue, 31 Aug 2021 08:10:00 +0000 (09:10 +0100)
* tip/sched/arm64: (785 commits)
  Documentation: arm64: describe asymmetric 32-bit support
  arm64: Remove logic to kill 32-bit tasks on 64-bit-only cores
  arm64: Hook up cmdline parameter to allow mismatched 32-bit EL0
  arm64: Advertise CPUs capable of running 32-bit applications in sysfs
  arm64: Prevent offlining first CPU with 32-bit EL0 on mismatched system
  arm64: exec: Adjust affinity for compat tasks with mismatched 32-bit EL0
  arm64: Implement task_cpu_possible_mask()
  sched: Introduce dl_task_check_affinity() to check proposed affinity
  sched: Allow task CPU affinity to be restricted on asymmetric systems
  sched: Split the guts of sched_setaffinity() into a helper function
  sched: Introduce task_struct::user_cpus_ptr to track requested affinity
  sched: Reject CPU affinity changes based on task_cpu_possible_mask()
  cpuset: Cleanup cpuset_cpus_allowed_fallback() use in select_fallback_rq()
  cpuset: Honour task_cpu_possible_mask() in guarantee_online_cpus()
  cpuset: Don't use the cpu_possible_mask as a last resort for cgroup v1
  sched: Introduce task_cpu_possible_mask() to limit fallback rq selection
  sched: Cgroup SCHED_IDLE support
  sched/topology: Skip updating masks for non-online nodes
  Linux 5.14-rc6
  lib: use PFN_PHYS() in devmem_is_allowed()
  ...

1  2 
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/admin-guide/kernel-parameters.txt
arch/arm64/Makefile
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/signal.c

@@@ -494,6 -494,15 +494,15 @@@ Description:     AArch64 CPU register
                'identification' directory exposes the CPU ID registers for
                identifying model and revision of the CPU.
  
+ What:         /sys/devices/system/cpu/aarch32_el0
+ Date:         May 2021
+ Contact:      Linux ARM Kernel Mailing list <linux-arm-kernel@lists.infradead.org>
+ Description:  Identifies the subset of CPUs in the system that can execute
+               AArch32 (32-bit ARM) applications. If present, the same format as
+               /sys/devices/system/cpu/{offline,online,possible,present} is used.
+               If absent, then all or none of the CPUs can execute AArch32
+               applications and execve() will behave accordingly.
  What:         /sys/devices/system/cpu/cpu#/cpu_capacity
  Date:         December 2016
  Contact:      Linux kernel mailing list <linux-kernel@vger.kernel.org>
@@@ -640,20 -649,3 +649,20 @@@ Description:     SPURR ticks for cpuX when 
  
                This sysfs interface exposes the number of SPURR ticks
                for cpuX when it was idle.
 +
 +What:                 /sys/devices/system/cpu/cpuX/mte_tcf_preferred
 +Date:         July 2021
 +Contact:      Linux ARM Kernel Mailing list <linux-arm-kernel@lists.infradead.org>
 +Description:  Preferred MTE tag checking mode
 +
 +              When a user program specifies more than one MTE tag checking
 +              mode, this sysfs node is used to specify which mode should
 +              be preferred when scheduling a task on that CPU. Possible
 +              values:
 +
 +              ================  ==============================================
 +              "sync"            Prefer synchronous mode
 +              "async"           Prefer asynchronous mode
 +              ================  ==============================================
 +
 +              See also: Documentation/arm64/memory-tagging-extension.rst
                        do not want to use tracing_snapshot_alloc() as it needs
                        to be done where GFP_KERNEL allocations are allowed.
  
+       allow_mismatched_32bit_el0 [ARM64]
+                       Allow execve() of 32-bit applications and setting of the
+                       PER_LINUX32 personality on systems where only a strict
+                       subset of the CPUs support 32-bit EL0. When this
+                       parameter is present, the set of CPUs supporting 32-bit
+                       EL0 is indicated by /sys/devices/system/cpu/aarch32_el0
+                       and hot-unplug operations may be restricted.
+                       See Documentation/arm64/asymmetric-32bit.rst for more
+                       information.
        amd_iommu=      [HW,X86-64]
                        Pass parameters to the AMD IOMMU driver in the system.
                        Possible values are:
        arm64.nopauth   [ARM64] Unconditionally disable Pointer Authentication
                        support
  
 +      arm64.nomte     [ARM64] Unconditionally disable Memory Tagging Extension
 +                      support
 +
        ataflop=        [HW,M68k]
  
        atarimouse=     [HW,MOUSE] Atari Mouse
diff --combined arch/arm64/Makefile
@@@ -21,19 -21,11 +21,11 @@@ LDFLAGS_vmlinux            += -shared -Bsymbolic 
  endif
  
  ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
-   ifneq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
- $(warning ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum)
-   else
+   ifeq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
  LDFLAGS_vmlinux       += --fix-cortex-a53-843419
    endif
  endif
  
- ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS), y)
-   ifneq ($(CONFIG_ARM64_LSE_ATOMICS), y)
- $(warning LSE atomics not supported by binutils)
-   endif
- endif
  cc_has_k_constraint := $(call try-run,echo                            \
        'int main(void) {                                               \
                asm volatile("and w0, w0, %w0" :: "K" (4294967295));    \
@@@ -165,11 -157,8 +157,11 @@@ Image: vmlinu
  Image.%: Image
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
  
 -zinstall install:
 -      $(Q)$(MAKE) $(build)=$(boot) $@
 +install: install-image := Image
 +zinstall: install-image := Image.gz
 +install zinstall:
 +      $(CONFIG_SHELL) $(srctree)/$(boot)/install.sh $(KERNELRELEASE) \
 +      $(boot)/$(install-image) System.map "$(INSTALL_PATH)"
  
  PHONY += vdso_install
  vdso_install:
  
  archprepare:
        $(Q)$(MAKE) $(build)=arch/arm64/tools kapi
+ ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
+   ifneq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y)
+       @echo "warning: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum" >&2
+   endif
+ endif
+ ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS),y)
+   ifneq ($(CONFIG_ARM64_LSE_ATOMICS),y)
+       @echo "warning: LSE atomics not supported by binutils" >&2
+   endif
+ endif
  
  # We use MRPROPER_FILES and CLEAN_FILES now
  archclean:
@@@ -67,6 -67,7 +67,7 @@@
  #include <linux/crash_dump.h>
  #include <linux/sort.h>
  #include <linux/stop_machine.h>
+ #include <linux/sysfs.h>
  #include <linux/types.h>
  #include <linux/minmax.h>
  #include <linux/mm.h>
@@@ -1321,6 -1322,31 +1322,31 @@@ const struct cpumask *system_32bit_el0_
        return cpu_possible_mask;
  }
  
+ static int __init parse_32bit_el0_param(char *str)
+ {
+       allow_mismatched_32bit_el0 = true;
+       return 0;
+ }
+ early_param("allow_mismatched_32bit_el0", parse_32bit_el0_param);
+ static ssize_t aarch32_el0_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+ {
+       const struct cpumask *mask = system_32bit_el0_cpumask();
+       return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(mask));
+ }
+ static const DEVICE_ATTR_RO(aarch32_el0);
+ static int __init aarch32_el0_sysfs_init(void)
+ {
+       if (!allow_mismatched_32bit_el0)
+               return 0;
+       return device_create_file(cpu_subsys.dev_root, &dev_attr_aarch32_el0);
+ }
+ device_initcall(aarch32_el0_sysfs_init);
  static bool has_32bit_el0(const struct arm64_cpu_capabilities *entry, int scope)
  {
        if (!has_cpuid_feature(entry, scope))
@@@ -1561,6 -1587,8 +1587,6 @@@ kpti_install_ng_mappings(const struct a
  
        if (!cpu)
                arm64_use_ng_mappings = true;
 -
 -      return;
  }
  #else
  static void
@@@ -1732,7 -1760,7 +1758,7 @@@ static void cpu_has_fwb(const struct ar
        u64 val = read_sysreg_s(SYS_CLIDR_EL1);
  
        /* Check that CLIDR_EL1.LOU{U,IS} are both 0 */
 -      WARN_ON(val & (7 << 27 | 7 << 21));
 +      WARN_ON(CLIDR_LOUU(val) || CLIDR_LOUIS(val));
  }
  
  #ifdef CONFIG_ARM64_PAN
@@@ -1841,9 -1869,6 +1867,9 @@@ static void bti_enable(const struct arm
  #ifdef CONFIG_ARM64_MTE
  static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
  {
 +      sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_ATA | SCTLR_EL1_ATA0);
 +      isb();
 +
        /*
         * Clear the tags in the zero page. This needs to be done via the
         * linear map which has the Tagged attribute.
@@@ -2902,15 -2927,38 +2928,38 @@@ void __init setup_cpu_features(void
  
  static int enable_mismatched_32bit_el0(unsigned int cpu)
  {
+       /*
+        * The first 32-bit-capable CPU we detected and so can no longer
+        * be offlined by userspace. -1 indicates we haven't yet onlined
+        * a 32-bit-capable CPU.
+        */
+       static int lucky_winner = -1;
        struct cpuinfo_arm64 *info = &per_cpu(cpu_data, cpu);
        bool cpu_32bit = id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0);
  
        if (cpu_32bit) {
                cpumask_set_cpu(cpu, cpu_32bit_el0_mask);
                static_branch_enable_cpuslocked(&arm64_mismatched_32bit_el0);
-               setup_elf_hwcaps(compat_elf_hwcaps);
        }
  
+       if (cpumask_test_cpu(0, cpu_32bit_el0_mask) == cpu_32bit)
+               return 0;
+       if (lucky_winner >= 0)
+               return 0;
+       /*
+        * We've detected a mismatch. We need to keep one of our CPUs with
+        * 32-bit EL0 online so that is_cpu_allowed() doesn't end up rejecting
+        * every CPU in the system for a 32-bit task.
+        */
+       lucky_winner = cpu_32bit ? cpu : cpumask_any_and(cpu_32bit_el0_mask,
+                                                        cpu_active_mask);
+       get_cpu_device(lucky_winner)->offline_disabled = true;
+       setup_elf_hwcaps(compat_elf_hwcaps);
+       pr_info("Asymmetric 32-bit EL0 support detected on CPU %u; CPU hot-unplug disabled on CPU %u\n",
+               cpu, lucky_winner);
        return 0;
  }
  
@@@ -21,6 -21,7 +21,7 @@@
  #include <linux/mman.h>
  #include <linux/mm.h>
  #include <linux/nospec.h>
+ #include <linux/sched.h>
  #include <linux/stddef.h>
  #include <linux/sysctl.h>
  #include <linux/unistd.h>
@@@ -163,7 -164,7 +164,7 @@@ static void print_pstate(struct pt_reg
        u64 pstate = regs->pstate;
  
        if (compat_user_mode(regs)) {
 -              printk("pstate: %08llx (%c%c%c%c %c %s %s %c%c%c)\n",
 +              printk("pstate: %08llx (%c%c%c%c %c %s %s %c%c%c %cDIT %cSSBS)\n",
                        pstate,
                        pstate & PSR_AA32_N_BIT ? 'N' : 'n',
                        pstate & PSR_AA32_Z_BIT ? 'Z' : 'z',
                        pstate & PSR_AA32_E_BIT ? "BE" : "LE",
                        pstate & PSR_AA32_A_BIT ? 'A' : 'a',
                        pstate & PSR_AA32_I_BIT ? 'I' : 'i',
 -                      pstate & PSR_AA32_F_BIT ? 'F' : 'f');
 +                      pstate & PSR_AA32_F_BIT ? 'F' : 'f',
 +                      pstate & PSR_AA32_DIT_BIT ? '+' : '-',
 +                      pstate & PSR_AA32_SSBS_BIT ? '+' : '-');
        } else {
                const char *btype_str = btypes[(pstate & PSR_BTYPE_MASK) >>
                                               PSR_BTYPE_SHIFT];
  
 -              printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO %cTCO BTYPE=%s)\n",
 +              printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO %cTCO %cDIT %cSSBS BTYPE=%s)\n",
                        pstate,
                        pstate & PSR_N_BIT ? 'N' : 'n',
                        pstate & PSR_Z_BIT ? 'Z' : 'z',
                        pstate & PSR_PAN_BIT ? '+' : '-',
                        pstate & PSR_UAO_BIT ? '+' : '-',
                        pstate & PSR_TCO_BIT ? '+' : '-',
 +                      pstate & PSR_DIT_BIT ? '+' : '-',
 +                      pstate & PSR_SSBS_BIT ? '+' : '-',
                        btype_str);
        }
  }
@@@ -472,22 -469,7 +473,13 @@@ static void erratum_1418040_thread_swit
        write_sysreg(val, cntkctl_el1);
  }
  
- static void compat_thread_switch(struct task_struct *next)
- {
-       if (!is_compat_thread(task_thread_info(next)))
-               return;
-       if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
-               set_tsk_thread_flag(next, TIF_NOTIFY_RESUME);
- }
 -static void update_sctlr_el1(u64 sctlr)
 +/*
 + * __switch_to() checks current->thread.sctlr_user as an optimisation. Therefore
 + * this function must be called with preemption disabled and the update to
 + * sctlr_user must be made in the same preemption disabled block so that
 + * __switch_to() does not see the variable update before the SCTLR_EL1 one.
 + */
 +void update_sctlr_el1(u64 sctlr)
  {
        /*
         * EnIA must not be cleared while in the kernel as this is necessary for
        isb();
  }
  
 -void set_task_sctlr_el1(u64 sctlr)
 -{
 -      /*
 -       * __switch_to() checks current->thread.sctlr as an
 -       * optimisation. Disable preemption so that it does not see
 -       * the variable update before the SCTLR_EL1 one.
 -       */
 -      preempt_disable();
 -      current->thread.sctlr_user = sctlr;
 -      update_sctlr_el1(sctlr);
 -      preempt_enable();
 -}
 -
  /*
   * Thread switching.
   */
@@@ -515,7 -510,6 +507,6 @@@ __notrace_funcgraph struct task_struct 
        ssbs_thread_switch(next);
        erratum_1418040_thread_switch(prev, next);
        ptrauth_thread_switch_user(next);
-       compat_thread_switch(next);
  
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
@@@ -576,6 -570,28 +567,28 @@@ unsigned long arch_align_stack(unsigne
        return sp & ~0xf;
  }
  
+ #ifdef CONFIG_COMPAT
+ int compat_elf_check_arch(const struct elf32_hdr *hdr)
+ {
+       if (!system_supports_32bit_el0())
+               return false;
+       if ((hdr)->e_machine != EM_ARM)
+               return false;
+       if (!((hdr)->e_flags & EF_ARM_EABI_MASK))
+               return false;
+       /*
+        * Prevent execve() of a 32-bit program from a deadline task
+        * if the restricted affinity mask would be inadmissible on an
+        * asymmetric system.
+        */
+       return !static_branch_unlikely(&arm64_mismatched_32bit_el0) ||
+              !dl_task_check_affinity(current, system_32bit_el0_cpumask());
+ }
+ #endif
  /*
   * Called from setup_new_exec() after (COMPAT_)SET_PERSONALITY.
   */
@@@ -585,8 -601,20 +598,20 @@@ void arch_setup_new_exec(void
  
        if (is_compat_task()) {
                mmflags = MMCF_AARCH32;
+               /*
+                * Restrict the CPU affinity mask for a 32-bit task so that
+                * it contains only 32-bit-capable CPUs.
+                *
+                * From the perspective of the task, this looks similar to
+                * what would happen if the 64-bit-only CPUs were hot-unplugged
+                * at the point of execve(), although we try a bit harder to
+                * honour the cpuset hierarchy.
+                */
                if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
-                       set_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
+                       force_compatible_cpus_allowed_ptr(current);
+       } else if (static_branch_unlikely(&arm64_mismatched_32bit_el0)) {
+               relax_compatible_cpus_allowed_ptr(current);
        }
  
        current->mm->context.flags = mmflags;
@@@ -845,11 -845,6 +845,11 @@@ static int sve_set(struct task_struct *
        }
  
        sve_alloc(target);
 +      if (!target->thread.sve_state) {
 +              ret = -ENOMEM;
 +              clear_tsk_thread_flag(target, TIF_SVE);
 +              goto out;
 +      }
  
        /*
         * Ensure target->thread.sve_state is up to date with target's
@@@ -1867,7 -1862,7 +1867,7 @@@ void syscall_trace_exit(struct pt_regs 
        audit_syscall_exit(regs);
  
        if (flags & _TIF_SYSCALL_TRACEPOINT)
-               trace_sys_exit(regs, regs_return_value(regs));
+               trace_sys_exit(regs, syscall_get_return_value(current, regs));
  
        if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
                tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
@@@ -29,6 -29,7 +29,7 @@@
  #include <asm/unistd.h>
  #include <asm/fpsimd.h>
  #include <asm/ptrace.h>
+ #include <asm/syscall.h>
  #include <asm/signal32.h>
  #include <asm/traps.h>
  #include <asm/vdso.h>
@@@ -289,11 -290,6 +290,11 @@@ static int restore_sve_fpsimd_context(s
        /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
  
        sve_alloc(current);
 +      if (!current->thread.sve_state) {
 +              clear_thread_flag(TIF_SVE);
 +              return -ENOMEM;
 +      }
 +
        err = __copy_from_user(current->thread.sve_state,
                               (char __user const *)user->sve +
                                        SVE_SIG_REGS_OFFSET,
@@@ -895,7 -891,7 +896,7 @@@ static void do_signal(struct pt_regs *r
                     retval == -ERESTART_RESTARTBLOCK ||
                     (retval == -ERESTARTSYS &&
                      !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
-                       regs->regs[0] = -EINTR;
+                       syscall_set_return_value(current, regs, -EINTR, 0);
                        regs->pc = continue_addr;
                }
  
        restore_saved_sigmask();
  }
  
- static bool cpu_affinity_invalid(struct pt_regs *regs)
- {
-       if (!compat_user_mode(regs))
-               return false;
-       /*
-        * We're preemptible, but a reschedule will cause us to check the
-        * affinity again.
-        */
-       return !cpumask_test_cpu(raw_smp_processor_id(),
-                                system_32bit_el0_cpumask());
- }
 -asmlinkage void do_notify_resume(struct pt_regs *regs,
 -                               unsigned long thread_flags)
 +void do_notify_resume(struct pt_regs *regs, unsigned long thread_flags)
  {
        do {
                if (thread_flags & _TIF_NEED_RESCHED) {
                        if (thread_flags & _TIF_NOTIFY_RESUME) {
                                tracehook_notify_resume(regs);
                                rseq_handle_notify_resume(NULL, regs);
-                               /*
-                                * If we reschedule after checking the affinity
-                                * then we must ensure that TIF_NOTIFY_RESUME
-                                * is set so that we check the affinity again.
-                                * Since tracehook_notify_resume() clears the
-                                * flag, ensure that the compiler doesn't move
-                                * it after the affinity check.
-                                */
-                               barrier();
-                               if (cpu_affinity_invalid(regs))
-                                       force_sig(SIGKILL);
                        }
  
                        if (thread_flags & _TIF_FOREIGN_FPSTATE)