From 400a4c87723d72604378af58b4ab3ba0c8a0d470 Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Wed, 13 Mar 2019 09:28:22 +0000 Subject: Store whether or not the VFP was active on entering the unhandled instruction trap and pass it to the VFP fault handler, so that it knows if we faulted with the VFP active or disabled. Reading the status in the VFP fault handler does not work since at that point the VFP already got disabled. ok kettenis@ --- sys/arch/arm/arm/db_interface.c | 7 ++++--- sys/arch/arm/arm/undefined.c | 11 ++++++----- sys/arch/arm/arm/vfp.c | 24 +++++++++++++----------- sys/arch/arm/include/undefined.h | 4 ++-- sys/arch/arm/include/vfp.h | 2 +- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/sys/arch/arm/arm/db_interface.c b/sys/arch/arm/arm/db_interface.c index 8534dda55c4..e1efe438c19 100644 --- a/sys/arch/arm/arm/db_interface.c +++ b/sys/arch/arm/arm/db_interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_interface.c,v 1.13 2018/03/20 15:45:32 mpi Exp $ */ +/* $OpenBSD: db_interface.c,v 1.14 2019/03/13 09:28:21 patrick Exp $ */ /* $NetBSD: db_interface.c,v 1.34 2003/10/26 23:11:15 chris Exp $ */ /* @@ -61,7 +61,7 @@ int db_access_abt_sp (struct db_variable *, db_expr_t *, int); int db_access_irq_sp (struct db_variable *, db_expr_t *, int); u_int db_fetch_reg (int, db_regs_t *); -int db_trapper (u_int, u_int, trapframe_t *, int); +int db_trapper (u_int, u_int, trapframe_t *, int, uint32_t); struct db_variable db_regs[] = { { "spsr", (long *)&ddb_regs.tf_spsr, FCN_NULL, }, @@ -352,7 +352,8 @@ struct db_command db_machine_command_table[] = { }; int -db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code) +db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code, + uint32_t fpexc) { if (fault_code == 0) { diff --git a/sys/arch/arm/arm/undefined.c b/sys/arch/arm/arm/undefined.c index b0745f072cc..d0acd459d41 100644 --- a/sys/arch/arm/arm/undefined.c +++ b/sys/arch/arm/arm/undefined.c @@ -1,4 +1,4 @@ -/* $OpenBSD: undefined.c,v 1.12 2018/08/06 18:39:13 kettenis Exp $ */ +/* $OpenBSD: undefined.c,v 1.13 2019/03/13 09:28:21 patrick Exp $ */ /* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */ /* @@ -66,7 +66,7 @@ #include -static int gdb_trapper(u_int, u_int, struct trapframe *, int); +static int gdb_trapper(u_int, u_int, struct trapframe *, int, uint32_t); LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; @@ -104,7 +104,7 @@ remove_coproc_handler(void *cookie) static int -gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code) +gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code, uint32_t fpexc) { union sigval sv; struct proc *p; @@ -148,13 +148,14 @@ undefinedinstruction(trapframe_t *frame) int fault_code; int coprocessor; struct undefined_handler *uh; + uint32_t fpexc; #ifdef VERBOSE_ARM32 int s; #endif union sigval sv; /* Before enabling interrupts, save FPU state */ - vfp_save(); + fpexc = vfp_save(); /* Enable interrupts if they were enabled before the exception. */ if (!(frame->tf_spsr & PSR_I)) @@ -224,7 +225,7 @@ undefinedinstruction(trapframe_t *frame) /* OK this is were we do something about the instruction. */ LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link) if (uh->uh_handler(fault_pc, fault_instruction, frame, - fault_code) == 0) + fault_code, fpexc) == 0) break; if (uh == NULL) { diff --git a/sys/arch/arm/arm/vfp.c b/sys/arch/arm/arm/vfp.c index f752afdeea9..8f61fc8d395 100644 --- a/sys/arch/arm/arm/vfp.c +++ b/sys/arch/arm/arm/vfp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfp.c,v 1.3 2019/01/24 13:19:19 kettenis Exp $ */ +/* $OpenBSD: vfp.c,v 1.4 2019/03/13 09:28:21 patrick Exp $ */ /* * Copyright (c) 2011 Dale Rahn @@ -43,7 +43,7 @@ get_vfp_fpexc(void) return val; } -int vfp_fault(unsigned int, unsigned int, trapframe_t *, int); +int vfp_fault(unsigned int, unsigned int, trapframe_t *, int, uint32_t); void vfp_load(struct proc *p); void vfp_store(struct fpreg *vfpsave); @@ -80,23 +80,23 @@ vfp_store(struct fpreg *vfpsave) set_vfp_fpexc(0); } -void +uint32_t vfp_save(void) { struct cpu_info *ci = curcpu(); struct pcb *pcb = curpcb; struct proc *p = curproc; - uint32_t cr_8; + uint32_t fpexc; if (ci->ci_fpuproc == 0) - return; + return 0; - cr_8 = get_vfp_fpexc(); + fpexc = get_vfp_fpexc(); - if ((cr_8 & VFPEXC_EN) == 0) - return; /* not enabled, nothing to do */ + if ((fpexc & VFPEXC_EN) == 0) + return fpexc; /* not enabled, nothing to do */ - if (cr_8 & VFPEXC_EX) + if (fpexc & VFPEXC_EX) panic("vfp exceptional data fault, time to write more code"); if (pcb->pcb_fpcpu == NULL || ci->ci_fpuproc == NULL || @@ -114,6 +114,7 @@ vfp_save(void) * curpcb()->pcb_fpucpu == ci && ci->ci_fpuproc == curproc() * is true FPU state is valid and can just be enabled without reload. */ + return fpexc; } void @@ -168,12 +169,13 @@ vfp_load(struct proc *p) } int -vfp_fault(unsigned int pc, unsigned int insn, trapframe_t *tf, int fault_code) +vfp_fault(unsigned int pc, unsigned int insn, trapframe_t *tf, int fault_code, + uint32_t fpexc) { struct proc *p = curproc; struct pcb *pcb = &p->p_addr->u_pcb; - if (get_vfp_fpexc() & VFPEXC_EN) { + if ((fpexc & VFPEXC_EN) != 0) { /* * We probably ran into an unsupported instruction, * like NEON on a non-NEON system. Let the process know. diff --git a/sys/arch/arm/include/undefined.h b/sys/arch/arm/include/undefined.h index b84670d2d6f..d9384755ee6 100644 --- a/sys/arch/arm/include/undefined.h +++ b/sys/arch/arm/include/undefined.h @@ -1,4 +1,4 @@ -/* $OpenBSD: undefined.h,v 1.3 2018/06/30 15:23:37 deraadt Exp $ */ +/* $OpenBSD: undefined.h,v 1.4 2019/03/13 09:28:21 patrick Exp $ */ /* $NetBSD: undefined.h,v 1.4 2001/12/20 01:20:23 thorpej Exp $ */ /* @@ -51,7 +51,7 @@ #include -typedef int (*undef_handler_t) (unsigned int, unsigned int, trapframe_t *, int); +typedef int (*undef_handler_t) (unsigned int, unsigned int, trapframe_t *, int, uint32_t); #define FP_COPROC 1 #define FP_COPROC2 2 diff --git a/sys/arch/arm/include/vfp.h b/sys/arch/arm/include/vfp.h index ea639745452..5cbee5d271a 100644 --- a/sys/arch/arm/include/vfp.h +++ b/sys/arch/arm/include/vfp.h @@ -129,7 +129,7 @@ void vfp_init(void); void vfp_discard(struct proc *); -void vfp_save(void); +uint32_t vfp_save(void); void vfp_enable(void); #endif /* _KERNEL */ -- cgit v1.2.3