* so use the base value of ldp as thread.keys_user and offset as
  * thread.keys_user.ap*.
  */
-       .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
+       .macro __ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
        mov     \tmp1, #THREAD_KEYS_USER
        add     \tmp1, \tsk, \tmp1
-alternative_if_not ARM64_HAS_ADDRESS_AUTH
-       b       .Laddr_auth_skip_\@
-alternative_else_nop_endif
        ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
        msr_s   SYS_APIAKEYLO_EL1, \tmp2
        msr_s   SYS_APIAKEYHI_EL1, \tmp3
-       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIB]
-       msr_s   SYS_APIBKEYLO_EL1, \tmp2
-       msr_s   SYS_APIBKEYHI_EL1, \tmp3
-       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDA]
-       msr_s   SYS_APDAKEYLO_EL1, \tmp2
-       msr_s   SYS_APDAKEYHI_EL1, \tmp3
-       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDB]
-       msr_s   SYS_APDBKEYLO_EL1, \tmp2
-       msr_s   SYS_APDBKEYHI_EL1, \tmp3
-.Laddr_auth_skip_\@:
-alternative_if ARM64_HAS_GENERIC_AUTH
-       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APGA]
-       msr_s   SYS_APGAKEYLO_EL1, \tmp2
-       msr_s   SYS_APGAKEYHI_EL1, \tmp3
-alternative_else_nop_endif
        .endm
 
        .macro __ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3
 
        struct ptrauth_key apia;
 };
 
+#define __ptrauth_key_install_nosync(k, v)                     \
+do {                                                           \
+       struct ptrauth_key __pki_v = (v);                       \
+       write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1);     \
+       write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);     \
+} while (0)
+
+static inline void ptrauth_keys_install_user(struct ptrauth_keys_user *keys)
+{
+       if (system_supports_address_auth()) {
+               __ptrauth_key_install_nosync(APIB, keys->apib);
+               __ptrauth_key_install_nosync(APDA, keys->apda);
+               __ptrauth_key_install_nosync(APDB, keys->apdb);
+       }
+
+       if (system_supports_generic_auth())
+               __ptrauth_key_install_nosync(APGA, keys->apga);
+}
+
 static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
 {
        if (system_supports_address_auth()) {
 
        if (system_supports_generic_auth())
                get_random_bytes(&keys->apga, sizeof(keys->apga));
-}
 
-#define __ptrauth_key_install_nosync(k, v)                     \
-do {                                                           \
-       struct ptrauth_key __pki_v = (v);                       \
-       write_sysreg_s(__pki_v.lo, SYS_ ## k ## KEYLO_EL1);     \
-       write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);     \
-} while (0)
+       ptrauth_keys_install_user(keys);
+}
 
 static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
 {
        isb();
 }
 
+#define ptrauth_suspend_exit()                                                 \
+       ptrauth_keys_install_user(¤t->thread.keys_user)
+
 #define ptrauth_thread_init_user()                                             \
        do {                                                                   \
                ptrauth_keys_init_user(¤t->thread.keys_user);            \
                                           SCTLR_ELx_ENDA | SCTLR_ELx_ENDB);   \
        } while (0)
 
+#define ptrauth_thread_switch_user(tsk)                                        \
+       ptrauth_keys_install_user(&(tsk)->thread.keys_user)
+
 #define ptrauth_thread_init_kernel(tsk)                                        \
        ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
 #define ptrauth_thread_switch_kernel(tsk)                              \
 #define ptrauth_set_enabled_keys(tsk, keys, enabled)   (-EINVAL)
 #define ptrauth_get_enabled_keys(tsk)  (-EINVAL)
 #define ptrauth_strip_insn_pac(lr)     (lr)
+#define ptrauth_suspend_exit()
 #define ptrauth_thread_init_user()
 #define ptrauth_thread_init_kernel(tsk)
+#define ptrauth_thread_switch_user(tsk)
 #define ptrauth_thread_switch_kernel(tsk)
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 
 #endif
 #ifdef CONFIG_ARM64_PTR_AUTH
   DEFINE(PTRAUTH_USER_KEY_APIA,                offsetof(struct ptrauth_keys_user, apia));
-  DEFINE(PTRAUTH_USER_KEY_APIB,                offsetof(struct ptrauth_keys_user, apib));
-  DEFINE(PTRAUTH_USER_KEY_APDA,                offsetof(struct ptrauth_keys_user, apda));
-  DEFINE(PTRAUTH_USER_KEY_APDB,                offsetof(struct ptrauth_keys_user, apdb));
-  DEFINE(PTRAUTH_USER_KEY_APGA,                offsetof(struct ptrauth_keys_user, apga));
   DEFINE(PTRAUTH_KERNEL_KEY_APIA,      offsetof(struct ptrauth_keys_kernel, apia));
   BLANK();
 #endif
 
        check_mte_async_tcf x19, x22
        apply_ssbd 1, x22, x23
 
-       ptrauth_keys_install_kernel_nosync tsk, x20, x22, x23
-
 #ifdef CONFIG_ARM64_PTR_AUTH
 alternative_if ARM64_HAS_ADDRESS_AUTH
        /*
         * Enable IA for in-kernel PAC if the task had it disabled. Although
         * this could be implemented with an unconditional MRS which would avoid
         * a load, this was measured to be slower on Cortex-A75 and Cortex-A76.
+        *
+        * Install the kernel IA key only if IA was enabled in the task. If IA
+        * was disabled on kernel exit then we would have left the kernel IA
+        * installed so there is no need to install it again.
         */
        ldr     x0, [tsk, THREAD_SCTLR_USER]
-       tbnz    x0, SCTLR_ELx_ENIA_SHIFT, 1f
+       tbz     x0, SCTLR_ELx_ENIA_SHIFT, 1f
+       __ptrauth_keys_install_kernel_nosync tsk, x20, x22, x23
+       b       2f
+1:
        mrs     x0, sctlr_el1
        orr     x0, x0, SCTLR_ELx_ENIA
        msr     sctlr_el1, x0
-1:
+2:
        isb
 alternative_else_nop_endif
 #endif
 3:
        scs_save tsk, x0
 
-       /*
-        * No kernel C function calls after this as user keys are set and IA may
-        * be disabled.
-        */
-       ptrauth_keys_install_user tsk, x0, x1, x2
-
 #ifdef CONFIG_ARM64_PTR_AUTH
 alternative_if ARM64_HAS_ADDRESS_AUTH
        /*
-        * IA was enabled for in-kernel PAC. Disable it now if needed.
-        * All other per-task SCTLR bits were updated on task switch.
+        * IA was enabled for in-kernel PAC. Disable it now if needed, or
+        * alternatively install the user's IA. All other per-task keys and
+        * SCTLR bits were updated on task switch.
+        *
+        * No kernel C function calls after this.
         */
        ldr     x0, [tsk, THREAD_SCTLR_USER]
-       tbnz    x0, SCTLR_ELx_ENIA_SHIFT, 1f
+       tbz     x0, SCTLR_ELx_ENIA_SHIFT, 1f
+       __ptrauth_keys_install_user tsk, x0, x1, x2
+       b       2f
+1:
        mrs     x0, sctlr_el1
        bic     x0, x0, SCTLR_ELx_ENIA
        msr     sctlr_el1, x0
-1:
+2:
 alternative_else_nop_endif
 #endif
 
 
                get_random_bytes(&keys->apdb, sizeof(keys->apdb));
        if (arg & PR_PAC_APGAKEY)
                get_random_bytes(&keys->apga, sizeof(keys->apga));
+       ptrauth_keys_install_user(keys);
 
        return 0;
 }
 
        entry_task_switch(next);
        ssbs_thread_switch(next);
        erratum_1418040_thread_switch(prev, next);
+       ptrauth_thread_switch_user(next);
 
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
 
         */
        spectre_v4_enable_mitigation(NULL);
 
-       /* Restore additional MTE-specific configuration */
+       /* Restore additional feature-specific configuration */
        mte_suspend_exit();
+       ptrauth_suspend_exit();
 }
 
 /*