diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -65,9 +65,10 @@ mrs x10, elr_el1 mrs x11, spsr_el1 mrs x12, esr_el1 + mrs x13, far_el1 stp x18, lr, [sp, #(TF_SP - TF_X)]! - str x10, [sp, #(TF_ELR)] - stp x11, x12, [sp, #(TF_SPSR)] + stp x10, x11, [sp, #(TF_ELR)] + stp x12, x13, [sp, #(TF_ESR)] mrs x18, tpidr_el1 .endm @@ -211,25 +212,10 @@ END(handle_el1h_irq) ENTRY(handle_el0_sync) - /* - * Read the fault address early. The current thread structure may - * be transiently unmapped if it is part of a memory range being - * promoted or demoted to/from a superpage. As this involves a - * break-before-make sequence there is a short period of time where - * an access will raise an exception. If this happens the fault - * address will be changed to the kernel address so a later read of - * far_el1 will give the wrong value. - * - * The earliest memory access that could trigger a fault is in a - * function called by the save_registers macro so this is the latest - * we can read the userspace value. - */ - mrs x19, far_el1 save_registers 0 ldr x0, [x18, #PC_CURTHREAD] mov x1, sp str x1, [x0, #TD_FRAME] - mov x2, x19 bl do_el0_sync do_ast restore_registers 0 diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c --- a/sys/arm64/arm64/genassym.c +++ b/sys/arm64/arm64/genassym.c @@ -77,4 +77,5 @@ ASSYM(TF_SP, offsetof(struct trapframe, tf_sp)); ASSYM(TF_ELR, offsetof(struct trapframe, tf_elr)); ASSYM(TF_SPSR, offsetof(struct trapframe, tf_spsr)); +ASSYM(TF_ESR, offsetof(struct trapframe, tf_esr)); ASSYM(TF_X, offsetof(struct trapframe, tf_x)); diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -76,7 +76,7 @@ /* Called from exception.S */ void do_el1h_sync(struct thread *, struct trapframe *); -void do_el0_sync(struct thread *, struct trapframe *, uint64_t far); +void do_el0_sync(struct thread *, struct trapframe *); void do_el0_error(struct trapframe *); void do_serror(struct trapframe *); void unhandled_exception(struct trapframe *); @@ -465,6 +465,7 @@ uint64_t esr, far; int dfsc; + far = frame->tf_far; /* Read the esr register to get the exception details */ esr = frame->tf_esr; exception = ESR_ELx_EXCEPTION(esr); @@ -502,7 +503,6 @@ break; case EXCP_INSN_ABORT: case EXCP_DATA_ABORT: - far = READ_SPECIALREG(far_el1); dfsc = esr & ISS_DATA_DFSC_MASK; if (dfsc < nitems(abort_handlers) && abort_handlers[dfsc] != NULL) { @@ -541,7 +541,7 @@ case EXCP_FPAC: /* We can see this if the authentication on PAC fails */ print_registers(frame); - printf(" far: %16lx\n", READ_SPECIALREG(far_el1)); + print_gp_register("far", far); panic("FPAC kernel exception"); break; case EXCP_UNKNOWN: @@ -552,18 +552,18 @@ /* FALLTHROUGH */ default: print_registers(frame); - print_gp_register("far", READ_SPECIALREG(far_el1)); + print_gp_register("far", far); panic("Unknown kernel exception %x esr_el1 %lx", exception, esr); } } void -do_el0_sync(struct thread *td, struct trapframe *frame, uint64_t far) +do_el0_sync(struct thread *td, struct trapframe *frame) { pcpu_bp_harden bp_harden; uint32_t exception; - uint64_t esr; + uint64_t esr, far; int dfsc; /* Check we have a sane environment when entering from userland */ @@ -571,6 +571,7 @@ ("Invalid pcpu address from userland: %p (tpidr %lx)", get_pcpu(), READ_SPECIALREG(tpidr_el1))); + far = frame->tf_far; esr = frame->tf_esr; exception = ESR_ELx_EXCEPTION(esr); if (exception == EXCP_INSN_ABORT_L && far > VM_MAXUSER_ADDRESS) { @@ -711,7 +712,7 @@ { uint64_t esr, far; - far = READ_SPECIALREG(far_el1); + far = frame->tf_far; esr = frame->tf_esr; print_registers(frame); @@ -725,7 +726,7 @@ { uint64_t esr, far; - far = READ_SPECIALREG(far_el1); + far = frame->tf_far; esr = frame->tf_esr; print_registers(frame); diff --git a/sys/arm64/include/frame.h b/sys/arm64/include/frame.h --- a/sys/arm64/include/frame.h +++ b/sys/arm64/include/frame.h @@ -47,7 +47,7 @@ uint64_t tf_elr; uint64_t tf_spsr; uint64_t tf_esr; - uint64_t pad; /* struct must be 16B aligned */ + uint64_t tf_far; uint64_t tf_x[30]; };