git: f6f5d927bf75 - stable/15 - arm64: Have a common call to userret
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 08 Apr 2026 14:01:43 UTC
The branch stable/15 has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=f6f5d927bf756810bb16c5f90540453eb309eb21
commit f6f5d927bf756810bb16c5f90540453eb309eb21
Author: Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-03-17 17:10:07 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-04-08 13:59:54 +0000
arm64: Have a common call to userret
Rather than each exception calling userret use a common copy. As
syscallret already calls userret we need to skip it in that case.
Reviewed by: kib
Sponsored by: Arm Ltd
Differential Revision: https://reviews.freebsd.org/D55250
(cherry picked from commit 14e97448fcebbe4b038eaf5628933abe5f9e690d)
---
sys/arm64/arm64/trap.c | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index b3c68fa4826f..867e5c57f8e5 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -193,17 +193,19 @@ test_bs_fault(void *addr)
addr == &generic_bs_poke_8f);
}
-static void
+static bool
svc_handler(struct thread *td, struct trapframe *frame)
{
if ((frame->tf_esr & ESR_ELx_ISS_MASK) == 0) {
syscallenter(td);
syscallret(td);
+ /* Skip userret as syscallret already called it */
+ return (true);
} else {
call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
ESR_ELx_EXCEPTION(frame->tf_esr));
- userret(td, frame);
+ return (false);
}
}
@@ -220,7 +222,6 @@ align_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
ESR_ELx_EXCEPTION(frame->tf_esr));
- userret(td, frame);
}
@@ -231,7 +232,6 @@ external_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
if (lower) {
call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)far,
ESR_ELx_EXCEPTION(frame->tf_esr));
- userret(td, frame);
return;
}
@@ -411,9 +411,6 @@ bad_far:
frame->tf_elr, error);
}
}
-
- if (lower)
- userret(td, frame);
}
static void
@@ -667,6 +664,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
uint32_t exception;
uint64_t esr, far;
int dfsc;
+ bool skip_userret;
/* Check we have a sane environment when entering from userland */
KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
@@ -694,6 +692,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
CTR4(KTR_TRAP, "%s: exception=%lu, elr=0x%lx, esr=0x%lx",
__func__, exception, frame->tf_elr, esr);
+ skip_userret = false;
switch (exception) {
case EXCP_FP_SIMD:
#ifdef VFP
@@ -705,7 +704,6 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
case EXCP_TRAP_FP:
#ifdef VFP
fpe_trap(td, (void *)frame->tf_elr, esr);
- userret(td, frame);
#else
panic("VFP exception in userland");
#endif
@@ -715,11 +713,10 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
if (!sve_restore_state(td))
call_trapsignal(td, SIGILL, ILL_ILLTRP,
(void *)frame->tf_elr, exception);
- userret(td, frame);
break;
case EXCP_SVC32:
case EXCP_SVC64:
- svc_handler(td, frame);
+ skip_userret = svc_handler(td, frame);
break;
case EXCP_INSN_ABORT_L:
case EXCP_DATA_ABORT_L:
@@ -741,22 +738,18 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
if (!undef_insn(frame))
call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)far,
exception);
- userret(td, frame);
break;
case EXCP_FPAC:
call_trapsignal(td, SIGILL, ILL_ILLOPN, (void *)frame->tf_elr,
exception);
- userret(td, frame);
break;
case EXCP_SP_ALIGN:
call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_sp,
exception);
- userret(td, frame);
break;
case EXCP_PC_ALIGN:
call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr,
exception);
- userret(td, frame);
break;
case EXCP_BRKPT_EL0:
case EXCP_BRK:
@@ -765,12 +758,10 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
#endif /* COMPAT_FREEBSD32 */
call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr,
exception);
- userret(td, frame);
break;
case EXCP_WATCHPT_EL0:
call_trapsignal(td, SIGTRAP, TRAP_TRACE, (void *)far,
exception);
- userret(td, frame);
break;
case EXCP_MSR:
/*
@@ -781,7 +772,6 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
if (!undef_insn(frame))
call_trapsignal(td, SIGILL, ILL_PRVOPC,
(void *)frame->tf_elr, exception);
- userret(td, frame);
break;
case EXCP_SOFTSTP_EL0:
PROC_LOCK(td->td_proc);
@@ -794,24 +784,22 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
PROC_UNLOCK(td->td_proc);
call_trapsignal(td, SIGTRAP, TRAP_TRACE,
(void *)frame->tf_elr, exception);
- userret(td, frame);
break;
case EXCP_BTI:
call_trapsignal(td, SIGILL, ILL_ILLOPC, (void *)frame->tf_elr,
exception);
- userret(td, frame);
break;
case EXCP_MOE:
handle_moe(td, frame, esr);
- userret(td, frame);
break;
default:
call_trapsignal(td, SIGBUS, BUS_OBJERR, (void *)frame->tf_elr,
exception);
- userret(td, frame);
break;
}
+ if (!skip_userret)
+ userret(td, frame);
KASSERT(
(td->td_pcb->pcb_fpflags & ~(PCB_FP_USERMASK|PCB_FP_SVEVALID)) == 0,
("Kernel VFP flags set while entering userspace"));