The branch main has been updated by dchagin:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c56480a832354aff995f9d0bc5da4ccf27dfe78a

commit c56480a832354aff995f9d0bc5da4ccf27dfe78a
Author:     Dmitry Chagin <[email protected]>
AuthorDate: 2022-05-15 18:10:50 +0000
Commit:     Dmitry Chagin <[email protected]>
CommitDate: 2022-05-15 18:10:50 +0000

    linux(4): Implement signal trampoline for arm64 in a FreeBSD-way
    
    The implemenation differs from others Linuxulators.
    For unwinders Linux ucontext_t is stored, however native machine context
    is used to store/restore process state to avoid code duplication.
    
    As DWARF Aarch64 does not define a register number for PC and provides no
    direct way to encode the PC of the previous frame, CFI cannot describe a
    signal trampoline frame. So, modified the vdso linker script to discard
    unused sections.
    
    Extensions are not implemented.
    
    MFC after:              2 weeks
---
 sys/arm64/linux/linux.h          |  2 +-
 sys/arm64/linux/linux_locore.asm | 15 +++++--
 sys/arm64/linux/linux_sigframe.h | 62 ++++++++++++++++++++++-----
 sys/arm64/linux/linux_sysvec.c   | 90 ++++++++++++++++++++++++++++++----------
 sys/arm64/linux/linux_vdso.lds.s | 33 ++++++++-------
 5 files changed, 150 insertions(+), 52 deletions(-)

diff --git a/sys/arm64/linux/linux.h b/sys/arm64/linux/linux.h
index 402f7aa39bb9..dafec928c7e4 100644
--- a/sys/arm64/linux/linux.h
+++ b/sys/arm64/linux/linux.h
@@ -164,7 +164,7 @@ struct l_newstat {
 #define        LINUX_SIG_SETMASK       2
 
 /* sigaltstack */
-#define        LINUX_MINSIGSTKSZ       2048            /* XXX */
+#define        LINUX_MINSIGSTKSZ       5664            /* sigframe */
 
 typedef void   (*l_handler_t)(l_int);
 
diff --git a/sys/arm64/linux/linux_locore.asm b/sys/arm64/linux/linux_locore.asm
index 0311c2e7e7e9..dfaafba155f2 100644
--- a/sys/arm64/linux/linux_locore.asm
+++ b/sys/arm64/linux/linux_locore.asm
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2018 Turing Robotic Industries Inc.
  * Copyright (C) 2020 Andrew Turner <[email protected]>
+ * Copyright (C) 2022 Dmitry Chagin <[email protected]>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,7 +30,7 @@
  */
 
 /*
- * arm64 Linux VDSO implementation.
+ * arm64 Linux VDSO signal trampoline.
  */
 
 #include <machine/asm.h>
@@ -45,8 +46,14 @@ linux_platform:
        .text
 
        nop     /* This is what Linux calls a "Mysterious NOP". */
-ENTRY(__kernel_rt_sigreturn)
+EENTRY(__kernel_rt_sigreturn)
        mov     x8, #LINUX_SYS_linux_rt_sigreturn
        svc     #0
-       ret
-END(__kernel_rt_sigreturn)
+EEND(__kernel_rt_sigreturn)
+
+EENTRY(linux_vdso_sigcode)
+       blr     x8
+
+       mov     x8, #LINUX_SYS_linux_rt_sigreturn
+       svc     #0
+EEND(linux_vdso_sigcode)
diff --git a/sys/arm64/linux/linux_sigframe.h b/sys/arm64/linux/linux_sigframe.h
index 060b89c920ac..d0d870e51375 100644
--- a/sys/arm64/linux/linux_sigframe.h
+++ b/sys/arm64/linux/linux_sigframe.h
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1994-1996 Søren Schmidt
- * Copyright (c) 2013 Dmitry Chagin <[email protected]>
  * Copyright (c) 2018 Turing Robotic Industries Inc.
+ * Copyright (c) 2022 Dmitry Chagin <[email protected]>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -23,22 +23,62 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- */
-
-/*
+ *
  * $FreeBSD$
  */
+
 #ifndef _ARM64_LINUX_SIGFRAME_H_
 #define        _ARM64_LINUX_SIGFRAME_H_
 
-/*
- * This structure is different from the one used by Linux,
- * but it doesn't matter - it's not user-accessible.  We need
- * it instead of the native one because of l_siginfo.
- */
+struct _l_aarch64_ctx {
+       uint32_t        magic;
+       uint32_t        size;
+};
+
+#define        L_FPSIMD_MAGIC  0x46508001
+#define        L_ESR_MAGIC     0x45535201
+
+struct l_fpsimd_context {
+       struct _l_aarch64_ctx head;
+       uint32_t        fpsr;
+       uint32_t        fpcr;
+       __uint128_t     vregs[32];
+};
+
+struct l_esr_context {
+       struct _l_aarch64_ctx head;
+       uint64_t        esr;
+};
+
+struct l_sigcontext {
+       uint64_t        fault_address;
+       uint64_t        regs[31];
+       uint64_t        sp;
+       uint64_t        pc;
+       uint64_t        pstate;
+       uint8_t         __reserved[4096] __attribute__((__aligned__(16)));
+};
+
+struct l_ucontext {
+       unsigned long   uc_flags;
+       struct l_ucontext *uc_link;
+       l_stack_t       uc_stack;
+       l_sigset_t      uc_sigmask;
+       uint8_t         __glibc_hole[1024 / 8 - sizeof(l_sigset_t)];
+       struct l_sigcontext uc_sc;
+};
+
+struct l_rt_sigframe {
+       l_siginfo_t     sf_si;
+       struct l_ucontext sf_uc;
+} __attribute__((__aligned__(16)));
+
 struct l_sigframe {
-       struct l_siginfo        sf_si;
-       ucontext_t              sf_uc;
+       struct l_rt_sigframe sf;
+       /* frame_record */
+       uint64_t        fp;
+       uint64_t        lr;
+       ucontext_t      uc;
 };
 
 #endif /* _ARM64_LINUX_SIGFRAME_H_ */
diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c
index 3d3e64f15c6c..461a00bf5b33 100644
--- a/sys/arm64/linux/linux_sysvec.c
+++ b/sys/arm64/linux/linux_sysvec.c
@@ -128,7 +128,7 @@ LIN_SDT_PROBE_DEFINE0(sysvec, linux_elf_fixup, todo);
 
 LINUX_VDSO_SYM_CHAR(linux_platform);
 LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
-LINUX_VDSO_SYM_INTPTR(__kernel_rt_sigreturn);
+LINUX_VDSO_SYM_INTPTR(linux_vdso_sigcode);
 
 /* LINUXTODO: do we have traps to translate? */
 static int
@@ -405,21 +405,23 @@ linux_exec_setregs(struct thread *td, struct image_params 
*imgp,
 int
 linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
 {
-       struct l_sigframe frame;
+       struct l_sigframe *frame;
+       ucontext_t uc;
        struct trapframe *tf;
        int error;
 
        tf = td->td_frame;
+       frame = (struct l_sigframe *)tf->tf_sp;
 
-       if (copyin((void *)tf->tf_sp, &frame, sizeof(frame)))
+       if (copyin((void *)&frame->uc, &uc, sizeof(uc)))
                return (EFAULT);
 
-       error = set_mcontext(td, &frame.sf_uc.uc_mcontext);
+       error = set_mcontext(td, &uc.uc_mcontext);
        if (error != 0)
                return (error);
 
        /* Restore signal mask. */
-       kern_sigprocmask(td, SIG_SETMASK, &frame.sf_uc.uc_sigmask, NULL, 0);
+       kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
 
        return (EJUSTRETURN);
 }
@@ -430,7 +432,12 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t 
*mask)
        struct thread *td;
        struct proc *p;
        struct trapframe *tf;
-       struct l_sigframe *fp, frame;
+       struct l_sigframe *fp, *frame;
+       struct l_fpsimd_context *fpsimd;
+       struct l_esr_context *esr;
+       l_stack_t uc_stack;
+       ucontext_t uc;
+       uint8_t *scr;
        struct sigacts *psp;
        int onstack, sig;
 
@@ -464,36 +471,77 @@ linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t 
*mask)
        fp--;
        fp = (struct l_sigframe *)STACKALIGN(fp);
 
+       get_mcontext(td, &uc.uc_mcontext, 0);
+       uc.uc_sigmask = *mask;
+
+       uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp);
+       uc_stack.ss_size = td->td_sigstk.ss_size;
+       uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
+           (onstack ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE;
+       mtx_unlock(&psp->ps_mtx);
+       PROC_UNLOCK(td->td_proc);
+
        /* Fill in the frame to copy out */
-       bzero(&frame, sizeof(frame));
-       get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+       frame = malloc(sizeof(*frame), M_LINUX, M_WAITOK | M_ZERO);
+
+       memcpy(&frame->sf.sf_uc.uc_sc.regs, tf->tf_x, sizeof(tf->tf_x));
+       frame->sf.sf_uc.uc_sc.regs[30] = tf->tf_lr;
+       frame->sf.sf_uc.uc_sc.sp = tf->tf_sp;
+       frame->sf.sf_uc.uc_sc.pc = tf->tf_lr;
+       frame->sf.sf_uc.uc_sc.pstate = tf->tf_spsr;
+       frame->sf.sf_uc.uc_sc.fault_address = (register_t)ksi->ksi_addr;
+
+       /* Stack frame for unwinding */
+       frame->fp = tf->tf_x[29];
+       frame->lr = tf->tf_lr;
 
        /* Translate the signal. */
        sig = bsd_to_linux_signal(sig);
+       siginfo_to_lsiginfo(&ksi->ksi_info, &frame->sf.sf_si, sig);
+       bsd_to_linux_sigset(mask, &frame->sf.sf_uc.uc_sigmask);
 
-       siginfo_to_lsiginfo(&ksi->ksi_info, &frame.sf_si, sig);
-       frame.sf_uc.uc_sigmask = *mask;
-       frame.sf_uc.uc_stack = td->td_sigstk;
-       frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) != 0 ?
-           (onstack ? SS_ONSTACK : 0) : SS_DISABLE;
-       mtx_unlock(&psp->ps_mtx);
-       PROC_UNLOCK(td->td_proc);
+       /*
+        * Prepare fpsimd & esr. Does not check sizes, as
+        * __reserved is big enougth.
+        */
+       scr = (uint8_t *)&frame->sf.sf_uc.uc_sc.__reserved;
+#ifdef VFP
+       fpsimd = (struct l_fpsimd_context *) scr;
+       fpsimd->head.magic = L_FPSIMD_MAGIC;
+       fpsimd->head.size = sizeof(struct l_fpsimd_context);
+       fpsimd->fpsr = uc.uc_mcontext.mc_fpregs.fp_sr;
+       fpsimd->fpcr = uc.uc_mcontext.mc_fpregs.fp_cr;
+
+       memcpy(fpsimd->vregs, &uc.uc_mcontext.mc_fpregs.fp_q,
+           sizeof(uc.uc_mcontext.mc_fpregs.fp_q));
+       scr += roundup(sizeof(struct l_fpsimd_context), 16);
+#endif
+       if (ksi->ksi_addr != 0) {
+               esr = (struct l_esr_context *) scr;
+               esr->head.magic = L_ESR_MAGIC;
+               esr->head.size = sizeof(struct l_esr_context);
+               esr->esr = tf->tf_esr;
+       }
+
+       memcpy(&frame->sf.sf_uc.uc_stack, &uc_stack, sizeof(uc_stack));
+       memcpy(&frame->uc, &uc, sizeof(uc));
 
        /* Copy the sigframe out to the user's stack. */
-       if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+       if (copyout(frame, fp, sizeof(*fp)) != 0) {
                /* Process has trashed its stack. Kill it. */
+               free(frame, M_LINUX);
                CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
                PROC_LOCK(p);
                sigexit(td, SIGILL);
        }
+       free(frame, M_LINUX);
 
        tf->tf_x[0]= sig;
-       tf->tf_x[1] = (register_t)&fp->sf_si;
-       tf->tf_x[2] = (register_t)&fp->sf_uc;
-
-       tf->tf_elr = (register_t)catcher;
+       tf->tf_x[1] = (register_t)&fp->sf.sf_si;
+       tf->tf_x[2] = (register_t)&fp->sf.sf_uc;
+       tf->tf_x[8] = (register_t)catcher;
        tf->tf_sp = (register_t)fp;
-       tf->tf_lr = (register_t)__kernel_rt_sigreturn;
+       tf->tf_elr = (register_t)linux_vdso_sigcode;
 
        CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr,
            tf->tf_sp);
diff --git a/sys/arm64/linux/linux_vdso.lds.s b/sys/arm64/linux/linux_vdso.lds.s
index 98cbb9a5736b..8790e14bbb80 100644
--- a/sys/arm64/linux/linux_vdso.lds.s
+++ b/sys/arm64/linux/linux_vdso.lds.s
@@ -1,6 +1,6 @@
 /*
  * Linker script for 64-bit vDSO.
- * Copied from Linux kernel arch/x86/vdso/vdso-layout.lds.S
+ * Copied from Linux kernel arch/arm64/kernel/vdso/vdso.lds.S
  *
  * $FreeBSD$
  */
@@ -17,29 +17,32 @@ SECTIONS
        .gnu.version_d  : { *(.gnu.version_d) }
        .gnu.version_r  : { *(.gnu.version_r) }
 
+       /DISCARD/       : {
+               *(.note.GNU-stack .note.gnu.property)
+       }
+
        .note           : { *(.note.*) }                :text   :note
 
-       .eh_frame_hdr   : { *(.eh_frame_hdr) }          :text   :eh_frame_hdr
-       .eh_frame       : { KEEP (*(.eh_frame)) }       :text
+       . = ALIGN(0x100);
+
+       .text           : { *(.text*) }                 :text   =0x90909090
+       PROVIDE (__etext = .);
+       PROVIDE (_etext = .);
+       PROVIDE (etext = .);
 
        .dynamic        : { *(.dynamic) }               :text   :dynamic
 
        .rodata         : { *(.rodata*) }               :text
        .data           : {
-             *(.data*)
-             *(.sdata*)
-             *(.got.plt) *(.got)
-             *(.gnu.linkonce.d.*)
-             *(.bss*)
-             *(.dynbss*)
-             *(.gnu.linkonce.b.*)
+               *(.data*)
        }
 
-       .altinstructions        : { *(.altinstructions) }
-       .altinstr_replacement   : { *(.altinstr_replacement) }
+       _end = .;
+       PROVIDE(end = .);
 
-       . = ALIGN(0x100);
-       .text           : { *(.test .text*) }                   :text   
=0x90909090
+       /DISCARD/       : {
+               *(.eh_frame .eh_frame_hdr)
+       }
 }
 
 PHDRS
@@ -47,7 +50,6 @@ PHDRS
        text            PT_LOAD         FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
        dynamic         PT_DYNAMIC      FLAGS(4);               /* PF_R */
        note            PT_NOTE         FLAGS(4);               /* PF_R */
-       eh_frame_hdr    PT_GNU_EH_FRAME;
 }
 
 /*
@@ -68,6 +70,7 @@ VERSION
        global:
                linux_platform;
                kern_timekeep_base;
+               linux_vdso_sigcode;
        local: *;
        };
 }

Reply via email to