Date: Wed, 30 Oct 2019 10:42:52 +0000 (UTC) From: Andrew Turner <andrew@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354174 - head/sys/arm64/arm64 Message-ID: <201910301042.x9UAgq8w025127@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: andrew Date: Wed Oct 30 10:42:52 2019 New Revision: 354174 URL: https://svnweb.freebsd.org/changeset/base/354174 Log: Use an array of handlers in the data and instruction aborts Previously we would call data_abort on all data and instruction aborts however this is incorrect for most abort types. Move to use an array of function pointers to allow for more handlers to be easily added. Reviewed by: jhibbits Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D22170 Modified: head/sys/arm64/arm64/trap.c Modified: head/sys/arm64/arm64/trap.c ============================================================================== --- head/sys/arm64/arm64/trap.c Wed Oct 30 10:41:10 2019 (r354173) +++ head/sys/arm64/arm64/trap.c Wed Oct 30 10:42:52 2019 (r354174) @@ -84,6 +84,24 @@ static void print_registers(struct trapframe *frame); int (*dtrace_invop_jump_addr)(struct trapframe *); +typedef void (abort_handler)(struct thread *, struct trapframe *, uint64_t, + uint64_t, int); + +static abort_handler data_abort; + +static abort_handler *abort_handlers[] = { + [ISS_DATA_DFSC_TF_L0] = data_abort, + [ISS_DATA_DFSC_TF_L1] = data_abort, + [ISS_DATA_DFSC_TF_L2] = data_abort, + [ISS_DATA_DFSC_TF_L3] = data_abort, + [ISS_DATA_DFSC_AFF_L1] = data_abort, + [ISS_DATA_DFSC_AFF_L2] = data_abort, + [ISS_DATA_DFSC_AFF_L3] = data_abort, + [ISS_DATA_DFSC_PF_L1] = data_abort, + [ISS_DATA_DFSC_PF_L2] = data_abort, + [ISS_DATA_DFSC_PF_L3] = data_abort, +}; + static __inline void call_trapsignal(struct thread *td, int sig, int code, void *addr) { @@ -149,7 +167,7 @@ svc_handler(struct thread *td, struct trapframe *frame static void data_abort(struct thread *td, struct trapframe *frame, uint64_t esr, - uint64_t far, int lower, int exec) + uint64_t far, int lower) { struct vm_map *map; struct proc *p; @@ -212,11 +230,16 @@ data_abort(struct thread *td, struct trapframe *frame, panic("data abort in critical section or under mutex"); } - if (exec) + switch (ESR_ELx_EXCEPTION(esr)) { + case EXCP_INSN_ABORT: + case EXCP_INSN_ABORT_L: ftype = VM_PROT_EXECUTE; - else + break; + default: ftype = (esr & ISS_DATA_WnR) == 0 ? VM_PROT_READ : VM_PROT_READ | VM_PROT_WRITE; + break; + } /* Fault in the page. */ error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode); @@ -275,6 +298,7 @@ do_el1h_sync(struct thread *td, struct trapframe *fram struct trapframe *oframe; uint32_t exception; uint64_t esr, far; + int dfsc; /* Read the esr register to get the exception details */ esr = frame->tf_esr; @@ -318,8 +342,14 @@ do_el1h_sync(struct thread *td, struct trapframe *fram case EXCP_INSN_ABORT: case EXCP_DATA_ABORT: far = READ_SPECIALREG(far_el1); - data_abort(td, frame, esr, far, 0, - exception == EXCP_INSN_ABORT); + dfsc = esr & ISS_DATA_DFSC_MASK; + if (dfsc < nitems(abort_handlers) && + abort_handlers[dfsc] != NULL) + abort_handlers[dfsc](td, frame, esr, far, 0); + else + panic("Unhandled EL1 %s abort: %x", + exception == EXCP_INSN_ABORT ? "instruction" : + "data", dfsc); break; case EXCP_BRK: #ifdef KDTRACE_HOOKS @@ -365,6 +395,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame pcpu_bp_harden bp_harden; uint32_t exception; uint64_t esr, far; + int dfsc; /* Check we have a sane environment when entering from userland */ KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS, @@ -416,8 +447,14 @@ do_el0_sync(struct thread *td, struct trapframe *frame case EXCP_INSN_ABORT_L: case EXCP_DATA_ABORT_L: case EXCP_DATA_ABORT: - data_abort(td, frame, esr, far, 1, - exception == EXCP_INSN_ABORT_L); + dfsc = esr & ISS_DATA_DFSC_MASK; + if (dfsc < nitems(abort_handlers) && + abort_handlers[dfsc] != NULL) + abort_handlers[dfsc](td, frame, esr, far, 1); + else + panic("Unhandled EL0 %s abort: %x", + exception == EXCP_INSN_ABORT_L ? "instruction" : + "data", dfsc); break; case EXCP_UNKNOWN: if (!undef_insn(0, frame))
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910301042.x9UAgq8w025127>