diff options
Diffstat (limited to 'arch/arm64/kernel/process.c')
-rw-r--r-- | arch/arm64/kernel/process.c | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 2dc0f8482210..b2adcce7bc18 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -49,6 +49,7 @@ #include <linux/notifier.h> #include <trace/events/power.h> #include <linux/percpu.h> +#include <linux/thread_info.h> #include <asm/alternative.h> #include <asm/compat.h> @@ -170,6 +171,39 @@ void machine_restart(char *cmd) while (1); } +static void print_pstate(struct pt_regs *regs) +{ + u64 pstate = regs->pstate; + + if (compat_user_mode(regs)) { + printk("pstate: %08llx (%c%c%c%c %c %s %s %c%c%c)\n", + pstate, + pstate & COMPAT_PSR_N_BIT ? 'N' : 'n', + pstate & COMPAT_PSR_Z_BIT ? 'Z' : 'z', + pstate & COMPAT_PSR_C_BIT ? 'C' : 'c', + pstate & COMPAT_PSR_V_BIT ? 'V' : 'v', + pstate & COMPAT_PSR_Q_BIT ? 'Q' : 'q', + pstate & COMPAT_PSR_T_BIT ? "T32" : "A32", + pstate & COMPAT_PSR_E_BIT ? "BE" : "LE", + pstate & COMPAT_PSR_A_BIT ? 'A' : 'a', + pstate & COMPAT_PSR_I_BIT ? 'I' : 'i', + pstate & COMPAT_PSR_F_BIT ? 'F' : 'f'); + } else { + printk("pstate: %08llx (%c%c%c%c %c%c%c%c %cPAN %cUAO)\n", + pstate, + pstate & PSR_N_BIT ? 'N' : 'n', + pstate & PSR_Z_BIT ? 'Z' : 'z', + pstate & PSR_C_BIT ? 'C' : 'c', + pstate & PSR_V_BIT ? 'V' : 'v', + pstate & PSR_D_BIT ? 'D' : 'd', + pstate & PSR_A_BIT ? 'A' : 'a', + pstate & PSR_I_BIT ? 'I' : 'i', + pstate & PSR_F_BIT ? 'F' : 'f', + pstate & PSR_PAN_BIT ? '+' : '-', + pstate & PSR_UAO_BIT ? '+' : '-'); + } +} + void __show_regs(struct pt_regs *regs) { int i, top_reg; @@ -186,10 +220,9 @@ void __show_regs(struct pt_regs *regs) } show_regs_print_info(KERN_DEFAULT); - print_symbol("PC is at %s\n", instruction_pointer(regs)); - print_symbol("LR is at %s\n", lr); - printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", - regs->pc, lr, regs->pstate); + print_pstate(regs); + print_symbol("pc : %s\n", regs->pc); + print_symbol("lr : %s\n", lr); printk("sp : %016llx\n", sp); i = top_reg; @@ -241,11 +274,27 @@ void release_thread(struct task_struct *dead_task) { } +void arch_release_task_struct(struct task_struct *tsk) +{ + fpsimd_release_task(tsk); +} + +/* + * src and dst may temporarily have aliased sve_state after task_struct + * is copied. We cannot fix this properly here, because src may have + * live SVE state and dst's thread_info may not exist yet, so tweaking + * either src's or dst's TIF_SVE is not safe. + * + * The unaliasing is done in copy_thread() instead. This works because + * dst is not schedulable or traceable until both of these functions + * have been called. + */ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { if (current->mm) fpsimd_preserve_current_state(); *dst = *src; + return 0; } @@ -258,6 +307,13 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); + /* + * Unalias p->thread.sve_state (if any) from the parent task + * and disable discard SVE state for p: + */ + clear_tsk_thread_flag(p, TIF_SVE); + p->thread.sve_state = NULL; + if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; |