#include "opt_m68k_arch.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sig_machdep.c,v 1.52 2026/03/28 04:32:03 thorpej Exp $");
#define __M68K_SIGNAL_PRIVATE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/cpu.h>
#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/ras.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/ucontext.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <machine/pcb.h>
#include <machine/frame.h>
#include <m68k/m68k.h>
#include <m68k/fpreg.h>
struct fpframe m68k_cached_fpu_idle_frame;
#ifdef DEBUG
int sigdebug = 0;
int sigpid = 0;
#define SDB_FOLLOW 0x01
#define SDB_KSTACK 0x02
#define SDB_FPSTATE 0x04
#endif
#if defined(M68020) || defined(M68030) || defined(M68040)
#if defined(M68060)
#define FPFRAME_IS_NULL(fp) \
((fputype == FPU_68060 && \
((struct fpframe060 *)(fp))->fpf6_frmfmt == FPF6_FMT_NULL) || \
(fputype != FPU_68060 && \
((union FPF_u1 *)(fp))->FPF_nonnull.FPF_version == 0))
#else
#define FPFRAME_IS_NULL(fp) \
(((union FPF_u1 *)(fp))->FPF_nonnull.FPF_version == 0)
#endif
#else
#define FPFRAME_IS_NULL(fp) \
(((struct fpframe060 *)(fp))->fpf6_frmfmt == FPF6_FMT_NULL)
#endif
u_int
fpsr2siginfocode(u_int fpsr)
{
if (fpsr & FPSR_DZ)
return FPE_FLTDIV;
if (fpsr & FPSR_UNFL)
return FPE_FLTUND;
if (fpsr & FPSR_OVFL)
return FPE_FLTOVF;
if (fpsr & FPSR_OPERR)
return FPE_FLTINV;
if (fpsr & (FPSR_INEX1|FPSR_INEX2))
return FPE_FLTRES;
return 0;
}
void *
getframe(struct lwp *l, int sig, int *onstack)
{
struct frame *tf = (struct frame *)l->l_md.md_regs;
*onstack =(l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0
&& (SIGACTION(l->l_proc, sig).sa_flags & SA_ONSTACK) != 0;
if (*onstack)
return (char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size;
else
return (void *)tf->f_regs[SP];
}
void
buildcontext(struct lwp *l, void *catcher, void *fp)
{
struct frame *frame = (struct frame *)l->l_md.md_regs;
frame->f_regs[SP] = (int)fp;
frame->f_pc = (int)catcher;
}
void
sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
{
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
struct sigacts *ps = p->p_sigacts;
int onstack, error;
int sig = ksi->ksi_signo;
struct sigframe_siginfo *fp = getframe(l, sig, &onstack), kf;
sig_t catcher = SIGACTION(p, sig).sa_handler;
fp--;
memset(&kf, 0, sizeof(kf));
kf.sf_ra = (int)ps->sa_sigdesc[sig].sd_tramp;
kf.sf_signum = sig;
kf.sf_sip = &fp->sf_si;
kf.sf_ucp = &fp->sf_uc;
kf.sf_si._info = ksi->ksi_info;
kf.sf_uc.uc_flags = _UC_SIGMASK;
kf.sf_uc.uc_sigmask = *mask;
kf.sf_uc.uc_link = l->l_ctxlink;
kf.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK)
? _UC_SETSTACK : _UC_CLRSTACK;
sendsig_reset(l, sig);
mutex_exit(p->p_lock);
cpu_getmcontext(l, &kf.sf_uc.uc_mcontext, &kf.sf_uc.uc_flags);
error = copyout(&kf, fp, sizeof(kf));
mutex_enter(p->p_lock);
if (error != 0) {
sigexit(l, SIGILL);
}
buildcontext(l, catcher, fp);
if (onstack)
l->l_sigstk.ss_flags |= SS_ONSTACK;
}
void
cpu_getmcontext(struct lwp *l, mcontext_t *mcp, u_int *flags)
{
__greg_t *gr = mcp->__gregs;
struct frame *frame = (struct frame *)l->l_md.md_regs;
unsigned int format = frame->f_format;
__greg_t ras_pc;
gr[_REG_D0] = frame->f_regs[D0];
gr[_REG_D1] = frame->f_regs[D1];
gr[_REG_D2] = frame->f_regs[D2];
gr[_REG_D3] = frame->f_regs[D3];
gr[_REG_D4] = frame->f_regs[D4];
gr[_REG_D5] = frame->f_regs[D5];
gr[_REG_D6] = frame->f_regs[D6];
gr[_REG_D7] = frame->f_regs[D7];
gr[_REG_A0] = frame->f_regs[A0];
gr[_REG_A1] = frame->f_regs[A1];
gr[_REG_A2] = frame->f_regs[A2];
gr[_REG_A3] = frame->f_regs[A3];
gr[_REG_A4] = frame->f_regs[A4];
gr[_REG_A5] = frame->f_regs[A5];
gr[_REG_A6] = frame->f_regs[A6];
gr[_REG_A7] = frame->f_regs[SP];
gr[_REG_PS] = frame->f_sr;
gr[_REG_PC] = frame->f_pc;
if ((ras_pc = (__greg_t)ras_lookup(l->l_proc,
(void *) gr[_REG_PC])) != -1)
gr[_REG_PC] = ras_pc;
*flags |= _UC_CPU;
mcp->_mc_tlsbase = (uintptr_t)l->l_private;
*flags |= _UC_TLSBASE;
mcp->__mc_pad.__mc_frame.__mcf_format = format;
if (format >= FMT4) {
mcp->__mc_pad.__mc_frame.__mcf_vector = frame->f_vector;
(void)memcpy(&mcp->__mc_pad.__mc_frame.__mcf_exframe,
&frame->F_u, (size_t)exframesize[format]);
frame->f_stackadj += exframesize[format];
frame->f_format = frame->f_vector = 0;
}
if (fputype != FPU_NONE) {
struct pcb *pcb = lwp_getpcb(l);
struct fpframe *fpf = &pcb->pcb_fpregs;
if (l == curlwp)
m68881_save(fpf);
mcp->__mc_pad.__mc_frame.__mcf_fpf_u1 = fpf->FPF_u1;
if (!FPFRAME_IS_NULL(fpf)) {
mcp->__mc_pad.__mc_frame.__mcf_fpf_u2 = fpf->FPF_u2;
(void)memcpy(mcp->__fpregs.__fp_fpregs,
fpf->fpf_regs, sizeof(fpf->fpf_regs));
mcp->__fpregs.__fp_pcr = fpf->fpf_fpcr;
mcp->__fpregs.__fp_psr = fpf->fpf_fpsr;
mcp->__fpregs.__fp_piaddr = fpf->fpf_fpiar;
*flags |= _UC_FPU;
}
}
}
int
cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
{
const __greg_t *gr = mcp->__gregs;
if ((gr[_REG_PS] & (PSL_MBZ|PSL_IPL|PSL_S)) != 0)
return EINVAL;
return 0;
}
int
cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, u_int flags)
{
const __greg_t *gr = mcp->__gregs;
struct frame *frame = (struct frame *)l->l_md.md_regs;
unsigned int format = mcp->__mc_pad.__mc_frame.__mcf_format;
int sz, error;
if ((flags & _UC_CPU) != 0) {
error = cpu_mcontext_validate(l, mcp);
if (error)
return error;
}
if ((flags & _UC_M68K_UC_USER) == 0 && format >= FMT4) {
if (format > FMTB)
return (EINVAL);
sz = exframesize[format];
if (sz < 0)
return (EINVAL);
if (frame->f_stackadj == 0) {
reenter_syscall(frame, sz);
}
#ifdef DIAGNOSTIC
if (sz != frame->f_stackadj)
panic("cpu_setmcontext: %d != %d",
sz, frame->f_stackadj);
#endif
frame->f_format = format;
frame->f_vector = mcp->__mc_pad.__mc_frame.__mcf_vector;
(void)memcpy(&frame->F_u,
&mcp->__mc_pad.__mc_frame.__mcf_exframe, (size_t)sz);
frame->f_stackadj -= sz;
}
if ((flags & _UC_CPU) != 0) {
frame->f_regs[D0] = gr[_REG_D0];
frame->f_regs[D1] = gr[_REG_D1];
frame->f_regs[D2] = gr[_REG_D2];
frame->f_regs[D3] = gr[_REG_D3];
frame->f_regs[D4] = gr[_REG_D4];
frame->f_regs[D5] = gr[_REG_D5];
frame->f_regs[D6] = gr[_REG_D6];
frame->f_regs[D7] = gr[_REG_D7];
frame->f_regs[A0] = gr[_REG_A0];
frame->f_regs[A1] = gr[_REG_A1];
frame->f_regs[A2] = gr[_REG_A2];
frame->f_regs[A3] = gr[_REG_A3];
frame->f_regs[A4] = gr[_REG_A4];
frame->f_regs[A5] = gr[_REG_A5];
frame->f_regs[A6] = gr[_REG_A6];
frame->f_regs[SP] = gr[_REG_A7];
frame->f_sr = gr[_REG_PS];
frame->f_pc = gr[_REG_PC];
}
if (fputype != FPU_NONE) {
const __fpregset_t *fpr = &mcp->__fpregs;
struct pcb *pcb = lwp_getpcb(l);
struct fpframe *fpf = &pcb->pcb_fpregs;
switch (flags & (_UC_FPU | _UC_M68K_UC_USER)) {
case _UC_FPU:
fpf->FPF_u1 = mcp->__mc_pad.__mc_frame.__mcf_fpf_u1;
if (!FPFRAME_IS_NULL(fpf)) {
fpf->FPF_u2 =
mcp->__mc_pad.__mc_frame.__mcf_fpf_u2;
(void)memcpy(fpf->fpf_regs,
fpr->__fp_fpregs, sizeof(fpf->fpf_regs));
fpf->fpf_fpcr = fpr->__fp_pcr;
fpf->fpf_fpsr = fpr->__fp_psr;
fpf->fpf_fpiar = fpr->__fp_piaddr;
}
break;
case _UC_FPU | _UC_M68K_UC_USER:
fpf->FPF_u1 = m68k_cached_fpu_idle_frame.FPF_u1;
fpf->FPF_u2 = m68k_cached_fpu_idle_frame.FPF_u2;
(void)memcpy(fpf->fpf_regs, fpr->__fp_fpregs,
sizeof(fpf->fpf_regs));
fpf->fpf_fpcr = fpr->__fp_pcr;
fpf->fpf_fpsr = fpr->__fp_psr;
fpf->fpf_fpiar = fpr->__fp_piaddr;
break;
default:
fpf->FPF_u1.FPF_null = 0;
break;
}
if (l == curlwp)
m68881_restore(fpf);
}
if ((flags & _UC_TLSBASE) != 0)
lwp_setprivate(l, (void *)(uintptr_t)mcp->_mc_tlsbase);
mutex_enter(l->l_proc->p_lock);
if (flags & _UC_SETSTACK)
l->l_sigstk.ss_flags |= SS_ONSTACK;
if (flags & _UC_CLRSTACK)
l->l_sigstk.ss_flags &= ~SS_ONSTACK;
mutex_exit(l->l_proc->p_lock);
return 0;
}