alternative_else_nop_endif
        .endm
 
+       .macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
+alternative_if ARM64_HAS_ADDRESS_AUTH
+       mov     \tmp1, #THREAD_KEYS_KERNEL
+       add     \tmp1, \tsk, \tmp1
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIA]
+       msr_s   SYS_APIAKEYLO_EL1, \tmp2
+       msr_s   SYS_APIAKEYHI_EL1, \tmp3
+       isb
+alternative_else_nop_endif
+       .endm
+
 #else /* CONFIG_ARM64_PTR_AUTH */
 
        .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
        .endm
 
+       .macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3
+       .endm
+
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 #endif /* __ASM_ASM_POINTER_AUTH_H */
 
        struct ptrauth_key apga;
 };
 
+struct ptrauth_keys_kernel {
+       struct ptrauth_key apia;
+};
+
 static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
 {
        if (system_supports_address_auth()) {
        write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);     \
 } while (0)
 
+static inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
+{
+       if (system_supports_address_auth())
+               get_random_bytes(&keys->apia, sizeof(keys->apia));
+}
+
 extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
 
 /*
 
 #define ptrauth_thread_init_user(tsk)                                  \
        ptrauth_keys_init_user(&(tsk)->thread.keys_user)
+#define ptrauth_thread_init_kernel(tsk)                                        \
+       ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
 
 #else /* CONFIG_ARM64_PTR_AUTH */
 #define ptrauth_prctl_reset_keys(tsk, arg)     (-EINVAL)
 #define ptrauth_strip_insn_pac(lr)     (lr)
 #define ptrauth_thread_init_user(tsk)
+#define ptrauth_thread_init_kernel(tsk)
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 #endif /* __ASM_POINTER_AUTH_H */
 
        struct debug_info       debug;          /* debugging */
 #ifdef CONFIG_ARM64_PTR_AUTH
        struct ptrauth_keys_user        keys_user;
+       struct ptrauth_keys_kernel      keys_kernel;
 #endif
 };
 
 
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
+#include <asm/pointer_auth.h>
 
 DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
 
 struct secondary_data {
        void *stack;
        struct task_struct *task;
+#ifdef CONFIG_ARM64_PTR_AUTH
+       struct ptrauth_keys_kernel ptrauth_key;
+#endif
        long status;
 };
 
 
   DEFINE(THREAD_CPU_CONTEXT,   offsetof(struct task_struct, thread.cpu_context));
 #ifdef CONFIG_ARM64_PTR_AUTH
   DEFINE(THREAD_KEYS_USER,     offsetof(struct task_struct, thread.keys_user));
+  DEFINE(THREAD_KEYS_KERNEL,   offsetof(struct task_struct, thread.keys_kernel));
 #endif
   BLANK();
   DEFINE(S_X0,                 offsetof(struct pt_regs, regs[0]));
   BLANK();
   DEFINE(CPU_BOOT_STACK,       offsetof(struct secondary_data, stack));
   DEFINE(CPU_BOOT_TASK,                offsetof(struct secondary_data, task));
+#ifdef CONFIG_ARM64_PTR_AUTH
+  DEFINE(CPU_BOOT_PTRAUTH_KEY, offsetof(struct secondary_data, ptrauth_key));
+#endif
   BLANK();
 #ifdef CONFIG_KVM_ARM_HOST
   DEFINE(VCPU_CONTEXT,         offsetof(struct kvm_vcpu, arch.ctxt));
   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
   return 0;
 
 
        apply_ssbd 1, x22, x23
 
+       ptrauth_keys_install_kernel tsk, x20, x22, x23
        .else
        add     x21, sp, #S_FRAME_SIZE
        get_current_task tsk
        msr     cntkctl_el1, x1
 4:
 #endif
+       /* No kernel C function calls after this as user keys are set. */
        ptrauth_keys_install_user tsk, x0, x1, x2
 
        apply_ssbd 0, x0, x1
        ldr     lr, [x8]
        mov     sp, x9
        msr     sp_el0, x1
+       ptrauth_keys_install_kernel x1, x8, x9, x10
        ret
 ENDPROC(cpu_switch_to)
 NOKPROBE(cpu_switch_to)
 
         */
        fpsimd_flush_task_state(p);
 
+       ptrauth_thread_init_kernel(p);
+
        if (likely(!(p->flags & PF_KTHREAD))) {
                *childregs = *current_pt_regs();
                childregs->regs[0] = 0;
 
         */
        secondary_data.task = idle;
        secondary_data.stack = task_stack_page(idle) + THREAD_SIZE;
+#if defined(CONFIG_ARM64_PTR_AUTH)
+       secondary_data.ptrauth_key.apia.lo = idle->thread.keys_kernel.apia.lo;
+       secondary_data.ptrauth_key.apia.hi = idle->thread.keys_kernel.apia.hi;
+#endif
        update_cpu_boot_status(CPU_MMU_OFF);
        __flush_dcache_area(&secondary_data, sizeof(secondary_data));
 
 
        secondary_data.task = NULL;
        secondary_data.stack = NULL;
+#if defined(CONFIG_ARM64_PTR_AUTH)
+       secondary_data.ptrauth_key.apia.lo = 0;
+       secondary_data.ptrauth_key.apia.hi = 0;
+#endif
        __flush_dcache_area(&secondary_data, sizeof(secondary_data));
        status = READ_ONCE(secondary_data.status);
        if (ret && status) {
 
        ubfx    x2, x2, #ID_AA64ISAR1_APA_SHIFT, #8
        cbz     x2, 3f
 
+       /*
+        * The primary cpu keys are reset here and can be
+        * re-initialised with some proper values later.
+        */
        msr_s   SYS_APIAKEYLO_EL1, xzr
        msr_s   SYS_APIAKEYHI_EL1, xzr
 
        b       3f
 alternative_else_nop_endif
 
+       /* Install ptrauth key for secondary cpus */
+       adr_l   x2, secondary_data
+       ldr     x3, [x2, #CPU_BOOT_TASK]        // get secondary_data.task
+       cbz     x3, 2f                          // check for slow booting cpus
+       ldp     x3, x4, [x2, #CPU_BOOT_PTRAUTH_KEY]
+       msr_s   SYS_APIAKEYLO_EL1, x3
+       msr_s   SYS_APIAKEYHI_EL1, x4
+
 2:     /* Enable ptrauth instructions */
        ldr     x2, =SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
                     SCTLR_ELx_ENDA | SCTLR_ELx_ENDB