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)
 {
        /*
        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
  */
 void arch_setup_new_exec(void)
 {
-       current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
+       unsigned long mmflags = 0;
+
+       if (is_compat_task()) {
+               mmflags = MMCF_AARCH32;
+               if (static_branch_unlikely(&arm64_mismatched_32bit_el0))
+                       set_tsk_thread_flag(current, TIF_NOTIFY_RESUME);
+       }
 
+       current->mm->context.flags = mmflags;
        ptrauth_thread_init_user();
        mte_thread_init_user();
 
 
        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)
 {
                        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)