diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 01:57:42 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 02:12:44 +0000 |
| commit | e8dbf2b6df199526a660f81de07d17925cfd8518 (patch) | |
| tree | cd0c09449bea5df56ef67059e797737d70587070 /kernel | |
| parent | 56a7ce8416d181a2060d7a428aed9c3c6a431e6d (diff) | |
Diffstat (limited to 'kernel')
83 files changed, 9485 insertions, 0 deletions
diff --git a/kernel/arch/aarch64/contextspfunc.S b/kernel/arch/aarch64/contextspfunc.S new file mode 100644 index 000000000000..9a4e3059a8e0 --- /dev/null +++ b/kernel/arch/aarch64/contextspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/06/08 18:55:35 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/06/08 18:55:35 christos Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + mov x0, sp + adrp x1, _C_LABEL(contextsp) + str x0, [x1, :lo12:_C_LABEL(contextsp)] + b _C_LABEL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/aarch64/execregs.c b/kernel/arch/aarch64/execregs.c new file mode 100644 index 000000000000..4c7697fe98c7 --- /dev/null +++ b/kernel/arch/aarch64/execregs.c @@ -0,0 +1,226 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* x0: used to pass exec arg0, nonnull anyway (path) */ + /* x1: used to pass exec arg1, nonnull anyway (argv) */ + /* x2: used to pass exec arg2, nonnull anyway (environ) */ + register long x3 __asm("x3") = nonnull(3); + register long x4 __asm("x4") = nonnull(4); + register long x5 __asm("x5") = nonnull(5); + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x3), + "+r"(x4), + "+r"(x5), + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x18), + "+r"(x19), + "+r"(x20), + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* x0: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* x1: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* x2: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + /* x3: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + /* x4: used to pass posix_spawn arg3, nonnull anyway (argv) */ + /* x5: used to pass posix_spawn arg3, nonnull anyway (environ) */ + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17), + "+r"(x18), + "+r"(x19), + "+r"(x20) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/aarch64/execregs.h b/kernel/arch/aarch64/execregs.h new file mode 100644 index 000000000000..471a3859c4d1 --- /dev/null +++ b/kernel/arch/aarch64/execregs.h @@ -0,0 +1,86 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H +#define TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 31 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct reg in sys/arch/aarch64/include/reg.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "x0", + "x1", + /* x2: ps_strings */ + "x3", + "x4", + "x5", + "x6", + "x7", + "x8", + "x9", + "x10", + "x11", + "x12", + "x13", + "x14", + "x15", + "x16", + "x17", + "x18", + "x19", + "x20", + "x21", + "x22", + "x23", + "x24", + "x25", + "x26", + "x27", + "x28", + "x29", + "x30", + "tpidr", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H */ diff --git a/kernel/arch/aarch64/execsp.S b/kernel/arch/aarch64/execsp.S new file mode 100644 index 000000000000..52c1472afef6 --- /dev/null +++ b/kernel/arch/aarch64/execsp.S @@ -0,0 +1,99 @@ +/* $NetBSD: execsp.S,v 1.3 2025/06/04 19:25:45 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.3 2025/06/04 19:25:45 christos Exp $") + +/* + * void execsp_start(void (*cleanup@x0)(void), void *obj_main@x1, + * struct ps_strings *ps_strings@x2) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + mov x16, sp + adrp x17, _C_LABEL(startsp) + str x16, [x17, :lo12:_C_LABEL(startsp)] + b _C_LABEL(__start) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + mov x16, sp + adrp x17, _C_LABEL(ctorsp) + str x16, [x17, :lo12:_C_LABEL(ctorsp)] + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw",%init_array + .p2align 3 + .xword _C_LABEL(execsp_ctor) + +/* + * int main(int argc@x0, char **argv@x1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + mov x16, sp + adrp x17, _C_LABEL(mainsp) + str x16, [x17, :lo12:_C_LABEL(mainsp)] + mov x0, #0 + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + mov x16, sp + adrp x17, _C_LABEL(dtorsp) + str x16, [x17, :lo12:_C_LABEL(dtorsp)] + b _C_LABEL(execsp_main) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw",%fini_array + .p2align 3 + .xword _C_LABEL(execsp_dtor) diff --git a/kernel/arch/aarch64/h_execregs.S b/kernel/arch/aarch64/h_execregs.S new file mode 100644 index 000000000000..f060911067f4 --- /dev/null +++ b/kernel/arch/aarch64/h_execregs.S @@ -0,0 +1,84 @@ +/* $NetBSD: h_execregs.S,v 1.2 2025/04/25 12:58:40 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + /* create a stack frame with NEXECREGS*8 bytes, aligned to 16-byte */ + stp fp, lr, [sp, #-(16 + ((NEXECREGS*8 + 15)/16)*16)]! + + /* store registers to buffer on stack */ + stp x0, x1, [sp, #16] /* order matches execregs.h */ + /* x2: ps_strings */ + stp x3, x4, [sp, #(16 + 1*2*8)] + stp x5, x6, [sp, #(16 + 2*2*8)] + stp x7, x8, [sp, #(16 + 3*2*8)] + stp x9, x10, [sp, #(16 + 4*2*8)] + stp x11, x12, [sp, #(16 + 5*2*8)] + stp x13, x14, [sp, #(16 + 6*2*8)] + stp x15, x16, [sp, #(16 + 7*2*8)] + stp x17, x18, [sp, #(16 + 8*2*8)] + stp x19, x20, [sp, #(16 + 9*2*8)] + stp x21, x22, [sp, #(16 + 10*2*8)] + stp x23, x24, [sp, #(16 + 11*2*8)] + stp x25, x26, [sp, #(16 + 12*2*8)] + stp x27, x28, [sp, #(16 + 13*2*8)] + stp x29, x30, [sp, #(16 + 14*2*8)] + mrs x0, tpidr_el0 + str x0, [sp, #(16 + 15*2*8)] + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + mov x0, #1 /* arg0 := STDOUT_FILENO */ + add x1, sp, #16 /* arg1 := regs */ + mov x2, #(NEXECREGS*8) /* arg2 := sizeof(regs) */ + svc #SYS_write + + b.cs 2f /* bail if write failed */ + cmp x0, #(NEXECREGS*8) /* bail if wrote wrong # of bytes */ + b.ne 2f + + /* call exit(0) */ + mov x0, #0 /* arg0 := 0 */ +1: svc #SYS_exit + brk #0xffff /* paranoia */ + +2: /* call exit(127) */ + mov x0, #127 /* arg0 := 127 */ + b 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + brk #0xffff +END(main) diff --git a/kernel/arch/aarch64/signalsphandler.S b/kernel/arch/aarch64/signalsphandler.S new file mode 100644 index 000000000000..246ed383273d --- /dev/null +++ b/kernel/arch/aarch64/signalsphandler.S @@ -0,0 +1,46 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/06/08 18:55:35 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/06/08 18:55:35 christos Exp $") + +/* + * signalsphandler(signo@x0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + mov x0, sp + adrp x1, _C_LABEL(signalsp) + str x0, [x1, :lo12:_C_LABEL(signalsp)] + ret +END(signalsphandler) diff --git a/kernel/arch/aarch64/stack_pointer.h b/kernel/arch/aarch64/stack_pointer.h new file mode 100644 index 000000000000..3bd7e6f65335 --- /dev/null +++ b/kernel/arch/aarch64/stack_pointer.h @@ -0,0 +1,42 @@ +/* $NetBSD: stack_pointer.h,v 1.2 2025/04/20 22:31:00 riastradh Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H + +#define MISALIGN_SP \ + __asm__ volatile ( \ + "sub sp, sp, #8" \ + ) + +#define FIX_SP \ + __asm__ volatile ( \ + "add sp, sp, #8" \ + ) + +#endif /* TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H */ diff --git a/kernel/arch/aarch64/threadspfunc.S b/kernel/arch/aarch64/threadspfunc.S new file mode 100644 index 000000000000..90f779d5e961 --- /dev/null +++ b/kernel/arch/aarch64/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@x0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov x0, sp + ret +END(threadspfunc) diff --git a/kernel/arch/alpha/contextspfunc.S b/kernel/arch/alpha/contextspfunc.S new file mode 100644 index 000000000000..da198f089124 --- /dev/null +++ b/kernel/arch/alpha/contextspfunc.S @@ -0,0 +1,50 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + + .set noat + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF(contextspfunc, 1) + LDGP(pv) + ldq at_reg, contextsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, contextdone(gp) !literal + jmp (pv), contextdone +END(contextspfunc) diff --git a/kernel/arch/alpha/execsp.S b/kernel/arch/alpha/execsp.S new file mode 100644 index 000000000000..08eaa521fa03 --- /dev/null +++ b/kernel/arch/alpha/execsp.S @@ -0,0 +1,106 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/21 02:31:22 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/21 02:31:22 riastradh Exp $") + + .set noat + .text + +/* + * void execsp_start(void *stackpointer@a0, void (*cleanup@a1)(void), + * void *obj_main@a2, struct ps_strings *ps_strings@a3) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF(execsp_start, 4) + LDGP(pv) + ldq at_reg, startsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, __start(gp) !literal + jmp (pv), __start +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF(execsp_ctor, 0) + LDGP(pv) + ldq at_reg, ctorsp(gp) !literal + stq sp, 0(at_reg) + RET +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align 3 + .quad execsp_ctor + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF(main, 2) + LDGP(pv) + ldq at_reg, mainsp(gp) !literal + stq sp, 0(at_reg) + mov zero, v0 + RET +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF(execsp_dtor, 0) + LDGP(pv) + ldq at_reg, dtorsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, execsp_main(gp) !literal + jmp (pv), execsp_main +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align 3 + .quad execsp_dtor + .popsection diff --git a/kernel/arch/alpha/signalsphandler.S b/kernel/arch/alpha/signalsphandler.S new file mode 100644 index 000000000000..eaa3f2cdb654 --- /dev/null +++ b/kernel/arch/alpha/signalsphandler.S @@ -0,0 +1,49 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:57 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:57 riastradh Exp $") + + .set noat + .text + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF(signalsphandler, 1) + LDGP(pv) + ldq at_reg, signalsp(gp) !literal + stq sp, 0(at_reg) + RET +END(signalsphandler) diff --git a/kernel/arch/alpha/stack_pointer.h b/kernel/arch/alpha/stack_pointer.h new file mode 100644 index 000000000000..58c581ffde0a --- /dev/null +++ b/kernel/arch/alpha/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:31:57 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("lda $sp,-1($sp)" ::: "memory") +#define FIX_SP __asm __volatile("lda $sp,1($sp)" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H */ diff --git a/kernel/arch/alpha/threadspfunc.S b/kernel/arch/alpha/threadspfunc.S new file mode 100644 index 000000000000..413387bb0867 --- /dev/null +++ b/kernel/arch/alpha/threadspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + + .set noat + .text + +/* + * void *threadspfunc(void *cookie@a0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF(threadspfunc, 1) + mov sp, v0 + RET +END(threadspfunc) diff --git a/kernel/arch/arm/contextspfunc.S b/kernel/arch/arm/contextspfunc.S new file mode 100644 index 000000000000..cf7fec19fb2a --- /dev/null +++ b/kernel/arch/arm/contextspfunc.S @@ -0,0 +1,51 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/05/07 16:26:47 uwe Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) +0: GOT_INIT(r0, .Lgot) + mov r1, sp + GOT_GET(r2, r0, .Lcontextsp) + str r1, [r2] + b PLT_SYM(_C_LABEL(contextdone)) + + GOT_INITSYM(.Lgot, 0b) +.Lcontextsp: + .word GOT_SYM(contextsp) +END(contextspfunc) diff --git a/kernel/arch/arm/execsp.S b/kernel/arch/arm/execsp.S new file mode 100644 index 000000000000..b02587ef2b33 --- /dev/null +++ b/kernel/arch/arm/execsp.S @@ -0,0 +1,119 @@ +/* $NetBSD: execsp.S,v 1.4 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.4 2025/05/07 16:26:47 uwe Exp $") + +/* + * void execsp_start(struct ps_strings *ps_strings@r0, void *obj_main@r1, + * void (*cleanup@r2)(void)) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) +0: GOT_INIT(r3, .Lgot.execsp_start) + mov r4, sp + GOT_GET(r5, r3, .Lstartsp) + str r4, [r5] + b PLT_SYM(_C_LABEL(__start)) + + GOT_INITSYM(.Lgot.execsp_start, 0b) +.Lstartsp: + .word GOT_SYM(startsp) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) +0: GOT_INIT(r0, .Lgot.execsp_ctor) + mov r1, sp + GOT_GET(r2, r0, .Lctorsp) + str r1, [r2] + RET + + GOT_INITSYM(.Lgot.execsp_ctor, 0b) +.Lctorsp: + .word GOT_SYM(ctorsp) +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw",%init_array + .p2align 2 + .word _C_LABEL(execsp_ctor) + +/* + * int main(int argc@r0, char **argv@r1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) +0: GOT_INIT(r0, .Lgot.main) + mov r1, sp + GOT_GET(r2, r0, .Lmainsp) + str r1, [r2] + mov r0, #0 + RET + + GOT_INITSYM(.Lgot.main, 0b) +.Lmainsp: + .word GOT_SYM(mainsp) +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) +0: GOT_INIT(r0, .Lgot.execsp_dtor) + mov r1, sp + GOT_GET(r2, r0, .Ldtorsp) + str r1, [r2] + b PLT_SYM(_C_LABEL(execsp_main)) + + GOT_INITSYM(.Lgot.execsp_dtor, 0b) +.Ldtorsp: + .word GOT_SYM(dtorsp) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw",%fini_array + .p2align 2 + .word _C_LABEL(execsp_dtor) diff --git a/kernel/arch/arm/signalsphandler.S b/kernel/arch/arm/signalsphandler.S new file mode 100644 index 000000000000..21b7d26a53b9 --- /dev/null +++ b/kernel/arch/arm/signalsphandler.S @@ -0,0 +1,51 @@ +/* $NetBSD: signalsphandler.S,v 1.3 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.3 2025/05/07 16:26:47 uwe Exp $") + +/* + * signalsphandler(signo@r0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) +0: GOT_INIT(r0, .Lgot) + mov r1, sp + GOT_GET(r2, r0, .Lsignalsp) + str r1, [r2] + RET + + GOT_INITSYM(.Lgot, 0b) +.Lsignalsp: + .word GOT_SYM(signalsp) +END(signalsphandler) diff --git a/kernel/arch/arm/stack_pointer.h b/kernel/arch/arm/stack_pointer.h new file mode 100644 index 000000000000..73d10c341138 --- /dev/null +++ b/kernel/arch/arm/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/25 02:24:01 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("sub sp, sp, #1") +#define FIX_SP __asm __volatile("add sp, sp, #1") + +#endif /* TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H */ diff --git a/kernel/arch/arm/threadspfunc.S b/kernel/arch/arm/threadspfunc.S new file mode 100644 index 000000000000..5f34c547cadf --- /dev/null +++ b/kernel/arch/arm/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/25 02:24:01 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/25 02:24:01 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@r0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov r0, sp + RET +END(threadspfunc) diff --git a/kernel/arch/hppa/contextspfunc.S b/kernel/arch/hppa/contextspfunc.S new file mode 100644 index 000000000000..683f59808c95 --- /dev/null +++ b/kernel/arch/hppa/contextspfunc.S @@ -0,0 +1,48 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF_ENTRY(contextspfunc) + addil LT%_C_LABEL(contextdone), %r19 /* r20 := contextdone */ + ldw RT%_C_LABEL(contextdone)(%r1), %r20 + addil LT%_C_LABEL(contextsp), %r19 /* r21 := &contextsp */ + ldw RT%_C_LABEL(contextsp)(%r1), %r21 + bv %r0(%r20) /* jump to contextdone */ + stw %sp, 0(%r21) /* contextsp := sp */ +EXIT(contextspfunc) diff --git a/kernel/arch/hppa/execregs.c b/kernel/arch/hppa/execregs.c new file mode 100644 index 000000000000..c064d3a36e37 --- /dev/null +++ b/kernel/arch/hppa/execregs.c @@ -0,0 +1,387 @@ +/* $NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +/* + * setfpregs() + * + * Set up all the floating-point registers with something nonzero + * in each one. We initialize the floating-point status register + * to set various bits so it's not all zero, but nothing that + * would trigger traps. + */ +static void +setfpregs(void) +{ + static const uint64_t fpe[] = { + (__BITS(63,59) /* all exception flags (VZOUI) set */ + | __BIT(58) /* C bit (comparison) set */ + | __BITS(54,43) /* CQ (comparison queue) all set */ + | __SHIFTIN(1, __BITS(42,41)) /* round toward zero */ + | __SHIFTIN(0, __BIT(38)) /* no delayed trap */ + | __SHIFTIN(1, __BIT(37)) /* Denormalized As Zero */ + | __SHIFTIN(0, __BITS(36,32)) /* exceptions masked */ + | 0x10101010), + 0x9191919111111111, + 0x9292929212121212, + 0x9393939313131313, + }; + const uint64_t *fpep = fpe; + + static const double fr[28] = { + 0x1.04p0, 0x1.05p0, 0x1.06p0, 0x1.07p0, + 0x1.08p0, 0x1.09p0, 0x1.0ap0, 0x1.0bp0, + 0x1.0cp0, 0x1.0dp0, 0x1.0ep0, 0x1.0fp0, + 0x1.10p0, 0x1.11p0, 0x1.12p0, 0x1.13p0, + 0x1.14p0, 0x1.15p0, 0x1.16p0, 0x1.17p0, + 0x1.18p0, 0x1.19p0, 0x1.1ap0, 0x1.1bp0, + 0x1.1cp0, 0x1.1dp0, 0x1.1ep0, 0x1.1fp0, + }; + const double *frp = fr; + + __asm volatile( + "fldds,ma 8(%0), %%fr0\n\t" + "fldds,ma 8(%0), %%fr1\n\t" + "fldds,ma 8(%0), %%fr2\n\t" + "fldds 0(%0), %%fr3" + : "+r"(fpep) + : "m"(fpe)); + + __asm volatile( + "fldds,ma 8(%0), %%fr4\n\t" + "fldds,ma 8(%0), %%fr5\n\t" + "fldds,ma 8(%0), %%fr6\n\t" + "fldds,ma 8(%0), %%fr7\n\t" + "fldds,ma 8(%0), %%fr8\n\t" + "fldds,ma 8(%0), %%fr9\n\t" + "fldds,ma 8(%0), %%fr10\n\t" + "fldds,ma 8(%0), %%fr11\n\t" + "fldds,ma 8(%0), %%fr12\n\t" + "fldds,ma 8(%0), %%fr13\n\t" + "fldds,ma 8(%0), %%fr14\n\t" + "fldds,ma 8(%0), %%fr15\n\t" + "fldds,ma 8(%0), %%fr16\n\t" + "fldds,ma 8(%0), %%fr17\n\t" + "fldds,ma 8(%0), %%fr18\n\t" + "fldds,ma 8(%0), %%fr19\n\t" + "fldds,ma 8(%0), %%fr20\n\t" + "fldds,ma 8(%0), %%fr21\n\t" + "fldds,ma 8(%0), %%fr22\n\t" + "fldds,ma 8(%0), %%fr23\n\t" + "fldds,ma 8(%0), %%fr24\n\t" + "fldds,ma 8(%0), %%fr25\n\t" + "fldds,ma 8(%0), %%fr26\n\t" + "fldds,ma 8(%0), %%fr27\n\t" + "fldds,ma 8(%0), %%fr28\n\t" + "fldds,ma 8(%0), %%fr29\n\t" + "fldds,ma 8(%0), %%fr30\n\t" + "fldds 0(%0), %%fr31" + : "+r"(frp) + : "m"(fr)); +} + +/* + * setpsw() + * + * Set some bits in PSW, the processor status word. + */ +static void +setpsw(void) +{ + uint32_t x = 0xe0000000, y = 0xffffffff, sum; + + /* + * Trigger some arithmetic that causes the carry/borrow + * (PSW[C/B]) bits to be set. + * + * XXX Also set PSW[V]. + */ + __asm volatile("sh3add %[sum], %[x], %[y]" + : /* outputs */ [sum] "=r"(sum) + : /* inputs */ [x] "r"(x), [y] "r"(y)); +} + +int +execregschild(char *path) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* r30/sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); /* cr11 */ + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* r2/rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + register long arg3 __asm("r23") = nonnull(23); + /* r24/arg2: envp, nonnull anyway */ + /* r25/arg1: argv, nonnull anyway */ + /* r26/arg0: path, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + setfpregs(); + setpsw(); + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" /* cr11 */ + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(arg3), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* r30/sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); /* cr11 */ + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* r2/rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + /* r23/arg3: attrp, nonnull anyway */ + /* r24/arg2: fileactsp, nonnull anyway */ + /* r25/arg1: path, nonnull anyway */ + /* r26/arg0: pidp, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + setfpregs(); + setpsw(); + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" /* cr11 */ + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/hppa/execregs.h b/kernel/arch/hppa/execregs.h new file mode 100644 index 000000000000..ae4dbb2e39c0 --- /dev/null +++ b/kernel/arch/hppa/execregs.h @@ -0,0 +1,157 @@ +/* $NetBSD: execregs.h,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_HPPA_EXECREGS_H +#define TESTS_KERNEL_ARCH_HPPA_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 96 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct struct trapframe in sys/arch/hppa/include/frame.h + * for convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "t1", + "t2", + /* sp: stack pointer */ + "t3", + /* various privileged stuff */ + "sar", + "r1", + "rp", + /* r3: frame pointer (set to initial stack pointer) */ + "r4", + "r5", + "r6", + "r70", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "t4", + "arg3", + "arg2", + "arg1", + /* arg0: ps_strings */ + "dp", + "ret0", + "ret1", + "r31", + "cr27", + "cr28", + + "psw", /* user-visible PSW bits: C/B and V */ + + /* Floating-point registers */ + "fr0l", + "fr0r", + "fr1l", + "fr1r", + "fr2l", + "fr2r", + "fr3l", + "fr3r", + "fr4l", + "fr4r", + "fr5l", + "fr5r", + "fr6l", + "fr6r", + "fr7l", + "fr7r", + "fr8l", + "fr8r", + "fr9l", + "fr9r", + "fr10l", + "fr10r", + "fr11l", + "fr11r", + "fr12l", + "fr12r", + "fr13l", + "fr13r", + "fr14l", + "fr14r", + "fr15l", + "fr15r", + "fr16l", + "fr16r", + "fr17l", + "fr17r", + "fr18l", + "fr18r", + "fr19l", + "fr19r", + "fr20l", + "fr20r", + "fr21l", + "fr21r", + "fr22l", + "fr22r", + "fr23l", + "fr23r", + "fr24l", + "fr24r", + "fr25l", + "fr25r", + "fr26l", + "fr26r", + "fr27l", + "fr27r", + "fr28l", + "fr28r", + "fr29l", + "fr29r", + "fr30l", + "fr30r", + "fr31l", + "fr31r", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_HPPA_EXECREGS_H */ diff --git a/kernel/arch/hppa/execsp.S b/kernel/arch/hppa/execsp.S new file mode 100644 index 000000000000..520421a1f1fc --- /dev/null +++ b/kernel/arch/hppa/execsp.S @@ -0,0 +1,130 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $") + + .import _GLOBAL_OFFSET_TABLE_ + +/* + * void execsp_start(struct ps_strings *ps_strings@arg0, + * void (*cleanup@arg1)(void), void *obj_main@arg2) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF_ENTRY(execsp_start) + /* + * Set up the data pointer (r19) and linkage table register + * (r27) like the real startup routine so we can get at the + * global symbols startsp and __start. + * + * XXX Not really sure why we need to set up r27, since we only + * use r19 here and the real startup routine, __start, will set + * up both r19 and r27 anyway. But this crashes with SIGSEGV + * shortly after startup if we don't set up r27, and gdb + * crashes on my attempts to single-step, so I'll just leave + * the initialization of r27 here for now until someone is + * motivated by the potential for a single-instruction + * micro-optimization in this test program to find out why r27 + * is needed too. + */ + bl L$lpc, %r27 + depi 0, 31, 2, %r27 +L$lpc: addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8), %r27 + ldo R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%r1), %r27 + copy %r27, %r19 + + addil LT%_C_LABEL(startsp), %r19 /* r20 := &startsp */ + ldw RT%_C_LABEL(startsp)(%r1), %r20 + + /* PIC_TAILCALL(__start), if we had it */ + addil LT%_C_LABEL(__start), %r19 /* r1 := __start */ + ldw RT%_C_LABEL(__start)(%r1), %r1 + bv %r0(%r1) /* jump to __start */ + stw %sp, 0(%r20) /* startsp := sp */ +EXIT(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF_ENTRY(execsp_ctor) + addil LT%_C_LABEL(ctorsp), %r19 /* r1 := &ctorsp */ + ldw RT%_C_LABEL(ctorsp)(%r1), %r1 + bv %r0(%rp) /* return */ + stw %sp, 0(%r1) /* ctorsp := sp */ +EXIT(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 2 + .word _C_LABEL(execsp_ctor) + +/* + * int main(int argc@arg0, char **argv@arg1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF_ENTRY(main) + addil LT%_C_LABEL(mainsp), %r19 /* r1 := &mainsp */ + ldw RT%_C_LABEL(mainsp)(%r1), %r1 + stw %sp, 0(%r1) /* ctorsp := sp */ + bv %r0(%rp) /* return... */ + copy %r0, %ret0 /* ...zero */ +EXIT(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF_ENTRY(execsp_dtor) + addil LT%_C_LABEL(dtorsp), %r19 /* r20 := &dtorsp */ + ldw RT%_C_LABEL(dtorsp)(%r1), %r20 + + /* PIC_TAILCALL(__start), if we had it */ + addil LT%_C_LABEL(execsp_main), %r19 /* r1 := execsp_main */ + ldw RT%_C_LABEL(execsp_main)(%r1), %r1 + bv %r0(%r1) /* jump to execsp_main */ + stw %sp, 0(%r20) /* startsp := sp */ +EXIT(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 2 + .word _C_LABEL(execsp_dtor) diff --git a/kernel/arch/hppa/h_execregs.S b/kernel/arch/hppa/h_execregs.S new file mode 100644 index 000000000000..ad7a50a5b932 --- /dev/null +++ b/kernel/arch/hppa/h_execregs.S @@ -0,0 +1,168 @@ +/* $NetBSD: h_execregs.S,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> +#include <machine/vmparam.h> + +#include "execregs.h" + +_ENTRY(execregs_start) + .callinfo frame=(NEXECREGS*4), calls + .entry + + ldo (NEXECREGS*4)(%sp), %sp /* space for NEXECREGS */ + stw %t1, (4*(0 - NEXECREGS))(%sp) /* order matches execregs.h */ + stw %t2, (4*(1 - NEXECREGS))(%sp) + /* sp: stack pointer */ + stw %t3, (4*(2 - NEXECREGS))(%sp) + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + stw %sar, (4*(3 - NEXECREGS))(%sp) + stw %r1, (4*(4 - NEXECREGS))(%sp) + stw %rp, (4*(5 - NEXECREGS))(%sp) + /* r3: frame pointer (set to initial stack pointer) */ + stw %r4, (4*(6 - NEXECREGS))(%sp) + stw %r5, (4*(7 - NEXECREGS))(%sp) + stw %r6, (4*(8 - NEXECREGS))(%sp) + stw %r7, (4*(9 - NEXECREGS))(%sp) + stw %r8, (4*(10 - NEXECREGS))(%sp) + stw %r9, (4*(11 - NEXECREGS))(%sp) + stw %r10, (4*(12 - NEXECREGS))(%sp) + stw %r11, (4*(13 - NEXECREGS))(%sp) + stw %r12, (4*(14 - NEXECREGS))(%sp) + stw %r13, (4*(15 - NEXECREGS))(%sp) + stw %r14, (4*(16 - NEXECREGS))(%sp) + stw %r15, (4*(17 - NEXECREGS))(%sp) + stw %r16, (4*(18 - NEXECREGS))(%sp) + stw %r17, (4*(19 - NEXECREGS))(%sp) + stw %r18, (4*(20 - NEXECREGS))(%sp) + stw %t4, (4*(21 - NEXECREGS))(%sp) + stw %arg3, (4*(22 - NEXECREGS))(%sp) + stw %arg2, (4*(23 - NEXECREGS))(%sp) + stw %arg1, (4*(24 - NEXECREGS))(%sp) + /* arg0: ps_strings */ + stw %dp, (4*(25 - NEXECREGS))(%sp) + stw %ret0, (4*(26 - NEXECREGS))(%sp) + stw %ret1, (4*(27 - NEXECREGS))(%sp) + stw %r31, (4*(28 - NEXECREGS))(%sp) + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr26: ??? */ + stw %cr27, (4*(29 - NEXECREGS))(%sp) + stw %cr28, (4*(30 - NEXECREGS))(%sp) + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + addc %t1, %r0, %r0 /* t1 := PSW[C/B]{0} */ + zdep %t1, 23, 8, %t1 /* t1 := PSW */ + stw %t1, (4*(31 - NEXECREGS))(%sp) + + /* store the fp registers */ + ldo (4*(32 - NEXECREGS))(%sp), %t1 + fstd,ma %fr0, 8(%t1) + fstd,ma %fr1, 8(%t1) + fstd,ma %fr2, 8(%t1) + fstd,ma %fr3, 8(%t1) + fstd,ma %fr4, 8(%t1) + fstd,ma %fr5, 8(%t1) + fstd,ma %fr6, 8(%t1) + fstd,ma %fr7, 8(%t1) + fstd,ma %fr8, 8(%t1) + fstd,ma %fr9, 8(%t1) + fstd,ma %fr10, 8(%t1) + fstd,ma %fr11, 8(%t1) + fstd,ma %fr12, 8(%t1) + fstd,ma %fr13, 8(%t1) + fstd,ma %fr14, 8(%t1) + fstd,ma %fr15, 8(%t1) + fstd,ma %fr16, 8(%t1) + fstd,ma %fr17, 8(%t1) + fstd,ma %fr18, 8(%t1) + fstd,ma %fr19, 8(%t1) + fstd,ma %fr20, 8(%t1) + fstd,ma %fr21, 8(%t1) + fstd,ma %fr22, 8(%t1) + fstd,ma %fr23, 8(%t1) + fstd,ma %fr24, 8(%t1) + fstd,ma %fr25, 8(%t1) + fstd,ma %fr26, 8(%t1) + fstd,ma %fr27, 8(%t1) + fstd,ma %fr28, 8(%t1) + fstd,ma %fr29, 8(%t1) + fstd,ma %fr30, 8(%t1) + fstd %fr31, 0(%t1) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + ldi 1, %arg0 /* arg0 := STDOUT_FILENO */ + ldo -(4*NEXECREGS)(%sp), %arg1 /* arg1 := regs */ + ldi (4*NEXECREGS), %arg2 /* arg2 := sizeof(regs) */ + ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_write, %t1 + + comb,<>,n %r0, %t1, 2f /* bail if write failed */ + ldi (4*NEXECREGS), %t1 /* bail if wrong # bytes */ + comb,<>,n %ret0, %t1, 2f + + /* call exit(0) */ + ldi 0, %arg0 +1: ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_exit, %t1 + break 0, 0 /* paranoia */ + +2: /* call exit(127) */ + b 1b + ldi 127, %arg0 +EXIT(execregs_start) + +/* main stub to simplify linking */ +LEAF_ENTRY(main) + break 0, 0 /* paranoia */ +EXIT(main) diff --git a/kernel/arch/hppa/signalsphandler.S b/kernel/arch/hppa/signalsphandler.S new file mode 100644 index 000000000000..01633d99ff8b --- /dev/null +++ b/kernel/arch/hppa/signalsphandler.S @@ -0,0 +1,46 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $") + +/* + * signalsphandler(signo@arg0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF_ENTRY(signalsphandler) + addil LT%_C_LABEL(signalsp), %r19 /* r1 := &signalsp */ + ldw RT%_C_LABEL(signalsp)(%r1), %r1 + bv %r0(%rp) /* return */ + stw %sp, 0(%r1) /* signalsp := sp */ +EXIT(signalsphandler) diff --git a/kernel/arch/hppa/stack_pointer.h b/kernel/arch/hppa/stack_pointer.h new file mode 100644 index 000000000000..acb73443621c --- /dev/null +++ b/kernel/arch/hppa/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("ldo 1(%%sp),%%sp" ::: "memory") +#define FIX_SP __asm __volatile("ldo -1(%%sp),%%sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H */ diff --git a/kernel/arch/hppa/threadspfunc.S b/kernel/arch/hppa/threadspfunc.S new file mode 100644 index 000000000000..f1b1d21fadfe --- /dev/null +++ b/kernel/arch/hppa/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@arg0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF_ENTRY(threadspfunc) + bv %r0(%rp) /* return to caller */ + copy %sp, %ret0 /* return sp */ +EXIT(threadspfunc) diff --git a/kernel/arch/i386/contextspfunc.S b/kernel/arch/i386/contextspfunc.S new file mode 100644 index 000000000000..cc097cc61325 --- /dev/null +++ b/kernel/arch/i386/contextspfunc.S @@ -0,0 +1,56 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(contextsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(contextdone)@PLT +END(contextspfunc) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/execregs.c b/kernel/arch/i386/execregs.c new file mode 100644 index 000000000000..477cd82989e9 --- /dev/null +++ b/kernel/arch/i386/execregs.c @@ -0,0 +1,132 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/i386/execregs.h b/kernel/arch/i386/execregs.h new file mode 100644 index 000000000000..f512bbabc1c7 --- /dev/null +++ b/kernel/arch/i386/execregs.h @@ -0,0 +1,69 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_I386_EXECREGS_H +#define TESTS_KERNEL_ARCH_I386_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 6 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct trapframe in sys/arch/i386/include/frame.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + /* gs/fs/es/ds: segment registers, not really registers */ + "edi", + "esi", + "ebp", + /* ebx: ps_strings */ + "edx", + "ecx", + "eax", + /* trapno: not a register */ + /* err: not a register */ + /* eip: instruction pointer */ + /* cs: segment register */ + /* eflags */ + /* esp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_I386_EXECREGS_H */ diff --git a/kernel/arch/i386/execsp.S b/kernel/arch/i386/execsp.S new file mode 100644 index 000000000000..133af37715ad --- /dev/null +++ b/kernel/arch/i386/execsp.S @@ -0,0 +1,112 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@edx)(void), void *obj_main@ecx, + * struct ps_strings *ps_strings@ebx) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(startsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(__start)@PLT +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(ctorsp)@GOT(%eax),%eax + movl %esp,(%eax) + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + +/* + * int main(int argc@rdi, char **argv@rsi, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(mainsp)@GOT(%eax),%eax + movl %esp,(%eax) + xorl %eax,%eax + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(dtorsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(execsp_main)@PLT +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/h_execregs.S b/kernel/arch/i386/h_execregs.S new file mode 100644 index 000000000000..ac9b843f9d86 --- /dev/null +++ b/kernel/arch/i386/h_execregs.S @@ -0,0 +1,85 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + andl $-0x4,%esp /* align stack to 4-byte boundary */ + + /* store registers to a buffer on stack */ + subl $(NEXECREGS*4),%esp /* space for NEXECREGS registers */ + movl %edi,0*4(%esp) /* order matches execregs.h */ + movl %esi,1*4(%esp) + movl %ebp,2*4(%esp) + movl %edx,3*4(%esp) + movl %ecx,4*4(%esp) + movl %eax,5*4(%esp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl %esp,%eax /* eax := regs */ + pushl $(NEXECREGS*4) /* arg2 := sizeof(regs) */ + pushl %eax /* arg1 := regs */ + pushl $0x1 /* arg0 := STDOUT_FILENO */ + call execregs_write + + jb 2f /* bail if write failed */ + cmpl $(NEXECREGS*4),%eax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: call execregs_exit + hlt /* paranoia */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +ENTRY(execregs_write) + movl $SYS_write,%eax /* syscall number */ + int $0x80 + retl +END(execregs_write) + +ENTRY(execregs_exit) + movl $SYS_exit,%eax /* syscall number */ + int $0x80 + hlt +END(execregs_exit) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff --git a/kernel/arch/i386/signalsphandler.S b/kernel/arch/i386/signalsphandler.S new file mode 100644 index 000000000000..418825e78ab6 --- /dev/null +++ b/kernel/arch/i386/signalsphandler.S @@ -0,0 +1,56 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $") + +/* + * signalsphandler(signo@esp[4]) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(signalsp)@GOT(%eax),%eax + movl %esp,(%eax) + ret +END(signalsphandler) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/stack_pointer.h b/kernel/arch/i386/stack_pointer.h new file mode 100644 index 000000000000..6c95a28ab7b6 --- /dev/null +++ b/kernel/arch/i386/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_I386_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_I386_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addl $-1,%esp") +#define FIX_SP __asm __volatile("addl $1,%esp") + +#endif /* TESTS_KERNEL_ARCH_I386_STACK_POINTER_H */ diff --git a/kernel/arch/i386/threadspfunc.S b/kernel/arch/i386/threadspfunc.S new file mode 100644 index 000000000000..af03ff4c550e --- /dev/null +++ b/kernel/arch/i386/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@esp[4]) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov %esp,%eax + ret +END(threadspfunc) diff --git a/kernel/arch/mips/contextspfunc.S b/kernel/arch/mips/contextspfunc.S new file mode 100644 index 000000000000..bee0a610dc86 --- /dev/null +++ b/kernel/arch/mips/contextspfunc.S @@ -0,0 +1,53 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF(contextspfunc) + PIC_PROLOGUE(contextspfunc) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(contextsp) /* load t1 := &contextsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store contextsp := stack pointer */ + + PIC_TAILCALL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/mips/execsp.S b/kernel/arch/mips/execsp.S new file mode 100644 index 000000000000..b4f2dcfd6e2c --- /dev/null +++ b/kernel/arch/mips/execsp.S @@ -0,0 +1,118 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * void execsp_start(void *stackpointer@a0, void (*cleanup@a1)(void), + * void *obj_main@a2, struct ps_strings *ps_strings@a3) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF(execsp_start) + PIC_PROLOGUE(execsp_start) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(startsp) /* load t1 := &startsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store startsp := stack pointer */ + + PIC_TAILCALL(__start) /* gp restore, uses t3 */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF(execsp_ctor) + PIC_PROLOGUE(execsp_ctor) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(ctorsp) /* load t1 := &ctorsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store ctorsp := stack pointer */ + + PIC_RETURN() /* gp restore, uses t3 */ +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_ctor) + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF(main) + PIC_PROLOGUE(main) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(mainsp) /* load t1 := &mainsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store mainsp := stack pointer */ + + move v0, zero /* return 0 */ + + PIC_RETURN() /* gp restore, uses t3 */ +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF(execsp_dtor) + PIC_PROLOGUE(execsp_dtor) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(dtorsp) /* load t1 := &dtorsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store dtorsp := stack pointer */ + + PIC_TAILCALL(execsp_main) /* gp restore, uses t3 */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/mips/signalsphandler.S b/kernel/arch/mips/signalsphandler.S new file mode 100644 index 000000000000..e742c2c95701 --- /dev/null +++ b/kernel/arch/mips/signalsphandler.S @@ -0,0 +1,53 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF(signalsphandler) + PIC_PROLOGUE(signalsphandler) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(signalsp) /* load t1 := &signalsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store signalsp := stack pointer */ + + PIC_RETURN() +END(signalsphandler) diff --git a/kernel/arch/mips/stack_pointer.h b/kernel/arch/mips/stack_pointer.h new file mode 100644 index 000000000000..288c58928526 --- /dev/null +++ b/kernel/arch/mips/stack_pointer.h @@ -0,0 +1,40 @@ +/* $NetBSD: stack_pointer.h,v 1.2 2025/04/21 14:17:38 rin Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H + +#ifdef __mips_o32 +#define MISALIGN_SP __asm __volatile("addiu $sp,$sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("addiu $sp,$sp,1" ::: "memory") +#else +#define MISALIGN_SP __asm __volatile("daddiu $sp,$sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("daddiu $sp,$sp,1" ::: "memory") +#endif + +#endif /* TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H */ diff --git a/kernel/arch/mips/threadspfunc.S b/kernel/arch/mips/threadspfunc.S new file mode 100644 index 000000000000..a42362fee67d --- /dev/null +++ b/kernel/arch/mips/threadspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: threadspfunc.S,v 1.2 2025/04/21 03:47:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.2 2025/04/21 03:47:32 riastradh Exp $") + + .text + .set noreorder + +/* + * void *threadspfunc(void *cookie@a0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF(threadspfunc) + j ra + move v0, sp +END(threadspfunc) diff --git a/kernel/arch/riscv/contextspfunc.S b/kernel/arch/riscv/contextspfunc.S new file mode 100644 index 000000000000..7f405123deb3 --- /dev/null +++ b/kernel/arch/riscv/contextspfunc.S @@ -0,0 +1,45 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + PTR_LA t0, _C_LABEL(contextsp) /* t0 := &contextsp */ + PTR_S sp, 0(t0) /* contextsp := sp */ + tail _C_LABEL(contextdone) /* tail call contextdone */ +END(contextspfunc) diff --git a/kernel/arch/riscv/execsp.S b/kernel/arch/riscv/execsp.S new file mode 100644 index 000000000000..d045cbf0d3af --- /dev/null +++ b/kernel/arch/riscv/execsp.S @@ -0,0 +1,100 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@a0)(void), + * struct ps_strings *ps_strings@a1) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + .option push + .option norelax /* Don't optimize this into `mv gp, gp'! */ + lla gp, __global_pointer$ + .option pop + + PTR_LA t0, _C_LABEL(startsp) /* t0 := &startsp */ + PTR_S sp, 0(t0) /* startsp := sp */ + tail _C_LABEL(__start) /* tail call __start */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + PTR_LA t0, _C_LABEL(ctorsp) /* t0 := &ctorsp */ + PTR_S sp, 0(t0) /* ctorsp := sp */ + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw" + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_ctor) + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + PTR_LA t0, _C_LABEL(mainsp) /* t0 := &mainsp */ + PTR_S sp, 0(t0) /* mainsp := sp */ + li a0, 0 /* return 0 */ + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + PTR_LA t0, _C_LABEL(dtorsp) /* t0 := &dtorsp */ + PTR_S sp, 0(t0) /* dtorsp := sp */ + tail _C_LABEL(execsp_main) /* tail call execsp_main */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw" + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_dtor) diff --git a/kernel/arch/riscv/signalsphandler.S b/kernel/arch/riscv/signalsphandler.S new file mode 100644 index 000000000000..6a5d2f752ee2 --- /dev/null +++ b/kernel/arch/riscv/signalsphandler.S @@ -0,0 +1,45 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $") + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + PTR_LA t0, _C_LABEL(signalsp) /* t0 := &signalsp */ + PTR_S sp, 0(t0) /* signalsp := sp */ + ret +END(signalsphandler) diff --git a/kernel/arch/riscv/stack_pointer.h b/kernel/arch/riscv/stack_pointer.h new file mode 100644 index 000000000000..22c246e4a86a --- /dev/null +++ b/kernel/arch/riscv/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addi sp,sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("addi sp,sp,1" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H */ diff --git a/kernel/arch/riscv/threadspfunc.S b/kernel/arch/riscv/threadspfunc.S new file mode 100644 index 000000000000..30291ad2eb73 --- /dev/null +++ b/kernel/arch/riscv/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@o0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mv a0, sp /* return sp */ + ret /* return to caller */ +END(threadspfunc) diff --git a/kernel/arch/sh3/asm.h b/kernel/arch/sh3/asm.h new file mode 100644 index 000000000000..16389b5c299e --- /dev/null +++ b/kernel/arch/sh3/asm.h @@ -0,0 +1,58 @@ +/* $NetBSD: asm.h,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_SH3_ASM_H +#define TESTS_KERNEL_ARCH_SH3_ASM_H + +#include <machine/asm.h> + +/* + * We define convenience macros to hide the difference between direct + * and PIC function calls, but with variable accesses it gets a bit + * more unwieldy, so don't impose this on the general audience + */ + +#ifdef __PIC__ + +#define VAR_DATUM(v) .long v@GOT + +#define MOVL_VAR(label, reg) \ + mov.l label, r0; \ + mov.l @(r0, r12), reg + +#else + +#define VAR_DATUM(v) .long v + +#define MOVL_VAR(label, reg) \ + mov.l label, reg; \ + +#endif + + +#endif /* TESTS_KERNEL_ARCH_SH3_ASM_H */ diff --git a/kernel/arch/sh3/contextspfunc.S b/kernel/arch/sh3/contextspfunc.S new file mode 100644 index 000000000000..51e91133417e --- /dev/null +++ b/kernel/arch/sh3/contextspfunc.S @@ -0,0 +1,55 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include "asm.h" + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $") + + +/* + * void contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + mov sp, r1 + PIC_PROLOGUE(.L_GOT) + + MOVL_VAR(.L_contextsp, r0) + mov.l r1, @r0 + + mov.l .L_contextdone, r0 +1: JUMP r0 + PIC_EPILOGUE_SLOT + + .p2align 2 +.L_GOT: PIC_GOT_DATUM +.L_contextsp: VAR_DATUM(contextsp) +.L_contextdone: CALL_DATUM(contextdone, 1b) + SET_ENTRY_SIZE(contextspfunc) diff --git a/kernel/arch/sh3/execsp.S b/kernel/arch/sh3/execsp.S new file mode 100644 index 000000000000..639ed4e6487b --- /dev/null +++ b/kernel/arch/sh3/execsp.S @@ -0,0 +1,146 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/27 00:03:46 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include "asm.h" + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/27 00:03:46 riastradh Exp $") + + +/* + * void execsp_start() + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + * + * See sys/arch/sh3/sh3/sh3_machdep.c setregs() + */ +ENTRY(execsp_start) + mov sp, r1 // for consistency, don't need to + PIC_PROLOGUE_NOSAVE(.L_start_GOT) + + MOVL_VAR(.L_startsp, r0) + mov.l r1, @r0 + + mov.l .L___start, r0 +1: JUMP r0 + nop + + .p2align 2 +.L_start_GOT: PIC_GOT_DATUM +.L_startsp: VAR_DATUM(startsp) +.L___start: CALL_DATUM(__start, 1b) + SET_ENTRY_SIZE(execsp_start) + + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + mov sp, r1 + PIC_PROLOGUE(.L_ctor_GOT) + + MOVL_VAR(.L_ctorsp, r0) + mov.l r1, @r0 + + rts + PIC_EPILOGUE_SLOT + + .p2align 2 +.L_ctor_GOT: PIC_GOT_DATUM +.L_ctorsp: VAR_DATUM(ctorsp) + SET_ENTRY_SIZE(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors, "aw", @progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + .popsection + + +/* + * int main(int argc, char **argv, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + mov sp, r1 + PIC_PROLOGUE(.L_main_GOT) + + MOVL_VAR(.L_mainsp, r0) + mov.l r1, @r0 + + PIC_EPILOGUE + rts + mov #0, r0 + + .p2align 2 +.L_main_GOT: PIC_GOT_DATUM +.L_mainsp: VAR_DATUM(mainsp) + SET_ENTRY_SIZE(main) + + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + mov sp, r1 + sts.l pr, @-sp + PIC_PROLOGUE(.L_dtor_GOT) + + MOVL_VAR(.L_dtorsp, r0) + mov.l r1, @r0 + + mov.l .L_execsp_main, r0 +1: CALL r0 + nop + + PIC_EPILOGUE + lds.l @sp+, pr + rts + nop + + .p2align 2 +.L_dtor_GOT: PIC_GOT_DATUM +.L_dtorsp: VAR_DATUM(dtorsp) +.L_execsp_main: CALL_DATUM(execsp_main, 1b) + SET_ENTRY_SIZE(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors, "aw", @progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/sh3/h_execregs.S b/kernel/arch/sh3/h_execregs.S new file mode 100644 index 000000000000..d7c91161c34a --- /dev/null +++ b/kernel/arch/sh3/h_execregs.S @@ -0,0 +1,86 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/04/27 02:24:07 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE +#include <machine/asm.h> +#include <machine/mcontext.h> +#include <sys/syscall.h> + + +// ELF entry point +ENTRY(execregs_start) + // __gregset_t r; // mcontext (but general regs only) + mov.l sp, @-sp + mov.l r0, @-sp + mov.l r1, @-sp + mov.l r2, @-sp + mov.l r3, @-sp + mov.l r4, @-sp + mov.l r5, @-sp + mov.l r6, @-sp + mov.l r7, @-sp + mov.l r8, @-sp + mov.l r9, @-sp + mov.l r10, @-sp + mov.l r11, @-sp + mov.l r12, @-sp + mov.l r13, @-sp + mov.l r14, @-sp + sts.l pr, @-sp + sts.l mach, @-sp + sts.l macl, @-sp + mov #0, r0 + mov.l r0, @-sp // _REG_SR is privileged + mova .Lend, r0 // _REG_PC + mov.l @r0, r1 + sub r1, r0 + mov.l r0, @-sp + stc.l gbr, @-sp + + // write(STDOUT_FILENO, &r, sizeof(__gregset_t)) + mov #1, r4 + mov sp, r5 + mov #(_NGREG * 4), r6 + mov #SYS_write, r0 + trapa #0x80 + + // _exit(0) + mov #0, r4 + mov #SYS_exit, r0 + trapa #0x80 + + .p2align 2 +.Lend: .long .Lend - execregs_start + SET_ENTRY_SIZE(execregs_start) + + +// main stub to simplify linking +ENTRY(main) + rts + mov #0, r0 + SET_ENTRY_SIZE(main) diff --git a/kernel/arch/sh3/signalsphandler.S b/kernel/arch/sh3/signalsphandler.S new file mode 100644 index 000000000000..e0a86ae40558 --- /dev/null +++ b/kernel/arch/sh3/signalsphandler.S @@ -0,0 +1,61 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/04/26 23:49:55 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include "asm.h" +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/04/26 23:49:55 uwe Exp $") + + +/* + * void signalsphandler(int signo) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + mov sp, r1 +#ifdef __PIC__ + // PR kern/59327: don't touch stack as SP may be misaligned + // and as SuperH is a strict alignment architecture, we will + // get SIGBUS if we try to save registers on the stack + mov r12, r2 +#endif + PIC_PROLOGUE_NOSAVE(.L_GOT) + + MOVL_VAR(.L_signalsp, r0) + mov.l r1, @r0 + +#ifdef __PIC__ + mov r2, r12 +#endif + rts + nop + + .p2align 2 +.L_GOT: PIC_GOT_DATUM +.L_signalsp: VAR_DATUM(signalsp) + SET_ENTRY_SIZE(signalsphandler) diff --git a/kernel/arch/sh3/stack_pointer.h b/kernel/arch/sh3/stack_pointer.h new file mode 100644 index 000000000000..ed3366602f56 --- /dev/null +++ b/kernel/arch/sh3/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("add #-1, sp" ::: "memory") +#define FIX_SP __asm __volatile("add #+1, sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H */ diff --git a/kernel/arch/sh3/threadspfunc.S b/kernel/arch/sh3/threadspfunc.S new file mode 100644 index 000000000000..de065e54191b --- /dev/null +++ b/kernel/arch/sh3/threadspfunc.S @@ -0,0 +1,41 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include "asm.h" +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $") + + +/* + * void *threadspfunc(void *cookie) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + rts + mov sp, r0 + SET_ENTRY_SIZE(threadspfunc) diff --git a/kernel/arch/sparc/contextspfunc.S b/kernel/arch/sparc/contextspfunc.S new file mode 100644 index 000000000000..a24185cabd73 --- /dev/null +++ b/kernel/arch/sparc/contextspfunc.S @@ -0,0 +1,64 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(contextsp), %g1, %o5) /* o5 := &contextsp */ + call _C_LABEL(contextdone) /* jump to contextdone */ + st %sp, [LO(_C_LABEL(contextsp), %o5)] /* contextsp := sp */ + /* don't care what happens here, caller must never return */ + ta 1 /* Tcc, trap always */ +END(contextspfunc) diff --git a/kernel/arch/sparc/execsp.S b/kernel/arch/sparc/execsp.S new file mode 100644 index 000000000000..4b225dd6d550 --- /dev/null +++ b/kernel/arch/sparc/execsp.S @@ -0,0 +1,123 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * void execsp_start(struct ps_strings *ps_strings@g1, + * void *obj_main@g2, void (*cleanup@g3)(void)) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + PIC_PROLOGUE(%o1, %o2) /* o1 := GOT, clobber o2 */ + SETHI(_C_LABEL(startsp), %o1, %o2) /* o2 := &startup */ + call _C_LABEL(__start) /* jump to start via PLT */ + st %sp, [LO(_C_LABEL(startsp), %o2)] /* startsp := sp */ + /* don't care what happens here, caller must never return */ + ta 1 /* Tcc, trap always */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(ctorsp), %g1, %o5) /* o5 := &ctorsp */ + retl /* return to caller */ + st %sp, [LO(_C_LABEL(ctorsp), %o5)] /* ctorsp := sp */ +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(mainsp), %g1, %o5) /* o5 := &mainsp */ + st %sp, [LO(_C_LABEL(mainsp), %o5)] /* mainsp := sp */ + retl /* return to caller */ + mov 0, %o0 /* return 0 */ +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(dtorsp), %g1, %o5) /* o5 := &dtorsp - &GOT */ + st %sp, [LO(_C_LABEL(dtorsp), %o5)] /* dtorsp := sp */ + mov %o7, %o5 /* save return address */ + call _C_LABEL(execsp_main) /* tail call to execsp_main */ + mov %o5, %o7 /* restore return address */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/sparc/signalsphandler.S b/kernel/arch/sparc/signalsphandler.S new file mode 100644 index 000000000000..187091d23c01 --- /dev/null +++ b/kernel/arch/sparc/signalsphandler.S @@ -0,0 +1,62 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * signalsphandler(signo@o0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(signalsp), %g1, %o5) /* o5 := &signalsp */ + retl /* return to caller */ + st %sp, [LO(_C_LABEL(signalsp), %o5)] /* signalsp := sp */ +END(signalsphandler) diff --git a/kernel/arch/sparc/stack_pointer.h b/kernel/arch/sparc/stack_pointer.h new file mode 100644 index 000000000000..20c06bec77cd --- /dev/null +++ b/kernel/arch/sparc/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("dec %%sp" ::: "memory") +#define FIX_SP __asm __volatile("inc %%sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H */ diff --git a/kernel/arch/sparc/threadspfunc.S b/kernel/arch/sparc/threadspfunc.S new file mode 100644 index 000000000000..794804d85741 --- /dev/null +++ b/kernel/arch/sparc/threadspfunc.S @@ -0,0 +1,45 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + + .text + +/* + * void *threadspfunc(void *cookie@o0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + retl /* return to caller */ + mov %sp, %o0 /* return sp */ +END(threadspfunc) diff --git a/kernel/arch/vax/execregs.c b/kernel/arch/vax/execregs.c new file mode 100644 index 000000000000..414b810336d8 --- /dev/null +++ b/kernel/arch/vax/execregs.c @@ -0,0 +1,166 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/vax/execregs.h b/kernel/arch/vax/execregs.h new file mode 100644 index 000000000000..882bcd1b6702 --- /dev/null +++ b/kernel/arch/vax/execregs.h @@ -0,0 +1,77 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_VAX_EXECREGS_H +#define TESTS_KERNEL_ARCH_VAX_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 12 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * The order matches that in struct trapframe in + * sys/arch/vax/include/trap.h + * + * Must match h_execregs.S. + * + * See also sys/arch/vax/vax/trap.c:setregs() + */ +static const char *const regname[] = { + "fp", /* Stack frame pointer */ + "ap", /* Argument pointer on user stack */ + /* sp: stack pointer */ + "r0", /* General registers saved upon trap/syscall */ + "r1", + "r2", + "r3", + "r4", + "r5", + /* r6: initial stack pointer */ + "r7", + "r8", + /* r9: ps_strings */ + "r10", + "r11", + /* trap: type of trap, not a register */ + /* code: trap specific code, not a register */ + /* pc: user PC */ + /* psl: processor status longword */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_VAX_EXECREGS_H */ diff --git a/kernel/arch/vax/h_execregs.S b/kernel/arch/vax/h_execregs.S new file mode 100644 index 000000000000..27c5c2052867 --- /dev/null +++ b/kernel/arch/vax/h_execregs.S @@ -0,0 +1,87 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +#define REGSIZE 4 +#define BUFSIZE (NEXECREGS * REGSIZE) +#define SLOT(n) (n)*REGSIZE(%sp) + +ENTRY(execregs_start, 0) + /* store registers to a buffer on stack */ + subl2 $BUFSIZE,%sp /* space for NEXECREGS registers */ + movl %fp,SLOT(0) /* order matches execregs.h */ + movl %ap,SLOT(1) + /* sp: stack pointer */ + movl %r0,SLOT(2) + movl %r1,SLOT(3) + movl %r2,SLOT(4) + movl %r3,SLOT(5) + movl %r4,SLOT(6) + movl %r5,SLOT(7) + /* r6: initial stack pointer */ + movl %r7,SLOT(8) + movl %r8,SLOT(9) + /* r9: ps_strings */ + movl %r10,SLOT(10) + movl %r11,SLOT(11) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + pushl $BUFSIZE /* arg2 := sizeof(regs) */ + pushal 4(%sp) /* arg1 := regs */ + pushl $1 /* arg0 := STDOUT_FILENO */ + pushl $3 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_write + + bcs 2f /* bail if write failed */ + cmpl $BUFSIZE,%r0 /* bail if wrote wrong # of bytes */ + bneq 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: pushl $1 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_exit + .word 0xffff /* paranoia -- illegal opcode */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main, 0) + .word 0xffff /* illegal opcode */ +END(main) diff --git a/kernel/arch/x86_64/contextspfunc.S b/kernel/arch/x86_64/contextspfunc.S new file mode 100644 index 000000000000..d01e1dcdcaf3 --- /dev/null +++ b/kernel/arch/x86_64/contextspfunc.S @@ -0,0 +1,55 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(contextsp)(%rip) + addq $-8,_C_LABEL(contextsp)(%rip) + call _C_LABEL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/x86_64/execregs.c b/kernel/arch/x86_64/execregs.c new file mode 100644 index 000000000000..fad1b40daa5e --- /dev/null +++ b/kernel/arch/x86_64/execregs.c @@ -0,0 +1,156 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* rdi: used to pass exec arg0, nonnull anyway (path) */ + /* rsi: used to pass exec arg1, nonnull anyway (argv) */ + /* rdx: used to pass exec arg2, nonnull anyway (environ) */ + register long r10 __asm("r10") = nonnull(10); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long rcx __asm("rcx") = nonnull('c'); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r8), + "+r"(r9), + "+r"(rcx), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* rdi: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* rsi: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* rdx: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + register long r10 __asm("r10") = nonnull(10); + /* r8: used to pass posix_spawn arg4, nonnull anyway (argv) */ + /* r9: used to pass posix_spawn arg5, nonnull anyway (environ) */ + /* rcx: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/x86_64/execregs.h b/kernel/arch/x86_64/execregs.h new file mode 100644 index 000000000000..904991777483 --- /dev/null +++ b/kernel/arch/x86_64/execregs.h @@ -0,0 +1,81 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_X86_64_EXECREGS_H +#define TESTS_KERNEL_ARCH_X86_64_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 14 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by _FRAME_REG in sys/arch/amd64/include/frame_regs.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "rdi", + "rsi", + "rdx", + "r10", + "r8", + "r9", + /* arg6: syscall arg from stack, not a real register */ + /* arg7: syscall arg from stack, not a real register */ + /* arg8: syscall arg from stack, not a real register */ + /* arg9: syscall arg from stack, not a real register */ + "rcx", + "r11", + "r12", + "r13", + "r14", + "r15", + "rbp", + /* rbx: ps_strings */ + "rax", + /* gs/fs/es/ds: segment registers, not really registers */ + /* trapno: not a register */ + /* err: not a register */ + /* rip: instruction pointer */ + /* cs: segment register */ + /* rflags */ + /* rsp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_X86_64_EXECREGS_H */ diff --git a/kernel/arch/x86_64/execsp.S b/kernel/arch/x86_64/execsp.S new file mode 100644 index 000000000000..d351dfb2d9e8 --- /dev/null +++ b/kernel/arch/x86_64/execsp.S @@ -0,0 +1,111 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/20 22:31:25 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@rbx)(void), void *obj_main@rcx, + * struct ps_strings *ps_strings@rbx) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + movq %rsp,_C_LABEL(startsp)(%rip) + /* + * No adjustment like in main because entry point is special + * and the amd64 csu __start routine takes care of it. + * + * XXX Why don't we just arrange to align it in the kernel + * anyway? + */ + jmp _C_LABEL(__start) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(ctorsp)(%rip) + addq $-8,_C_LABEL(ctorsp)(%rip) + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 3 + .quad _C_LABEL(execsp_ctor) + +/* + * int main(int argc@rdi, char **argv@rsi, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + movq %rsp,_C_LABEL(mainsp)(%rip) + addq $-8,_C_LABEL(mainsp)(%rip) + xorl %eax,%eax + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + movq %rsp,_C_LABEL(dtorsp)(%rip) + addq $-8,_C_LABEL(dtorsp)(%rip) + jmp _C_LABEL(execsp_main) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 3 + .quad _C_LABEL(execsp_dtor) diff --git a/kernel/arch/x86_64/h_execregs.S b/kernel/arch/x86_64/h_execregs.S new file mode 100644 index 000000000000..638f73940f06 --- /dev/null +++ b/kernel/arch/x86_64/h_execregs.S @@ -0,0 +1,82 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + andq $-0x10,%rsp /* align stack to 16-byte boundary */ + + /* store registers to a buffer on stack */ + subq $(NEXECREGS*8),%rsp /* space for NEXECREGS registers */ + movq %rdi,0*8(%rsp) /* order matches execregs.h */ + movq %rsi,1*8(%rsp) + movq %rdx,2*8(%rsp) + movq %r10,3*8(%rsp) + movq %r8,4*8(%rsp) + movq %r9,5*8(%rsp) + movq %rcx,6*8(%rsp) + movq %r11,7*8(%rsp) + movq %r12,8*8(%rsp) + movq %r13,9*8(%rsp) + movq %r14,10*8(%rsp) + movq %r15,11*8(%rsp) + movq %rbp,12*8(%rsp) + movq %rax,13*8(%rsp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl $0x1,%edi /* arg0 := STDOUT_FILENO */ + movq %rsp,%rsi /* arg1 := regs */ + movl $(NEXECREGS*8),%edx /* arg2 := sizeof(regs) */ + movl $SYS_write,%eax /* syscall number */ + syscall + + jb 2f /* bail if write failed */ + cmpq $(NEXECREGS*8),%rax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + xorl %edi,%edi /* arg0 := 0 */ +1: movl $SYS_exit,%eax /* syscall number */ + syscall + hlt /* paranoia */ + +2: /* call exit(127) */ + movl $127,%edi /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff --git a/kernel/arch/x86_64/signalsphandler.S b/kernel/arch/x86_64/signalsphandler.S new file mode 100644 index 000000000000..b53cb005d0b0 --- /dev/null +++ b/kernel/arch/x86_64/signalsphandler.S @@ -0,0 +1,55 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:01 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:01 riastradh Exp $") + +/* + * signalsphandler(signo@rdi) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(signalsp)(%rip) + addq $-8,_C_LABEL(signalsp)(%rip) + ret +END(signalsphandler) diff --git a/kernel/arch/x86_64/stack_pointer.h b/kernel/arch/x86_64/stack_pointer.h new file mode 100644 index 000000000000..6ea297cf97d9 --- /dev/null +++ b/kernel/arch/x86_64/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:31:01 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addq $-1,%rsp") +#define FIX_SP __asm __volatile("addq $1,%rsp") + +#endif /* TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H */ diff --git a/kernel/arch/x86_64/threadspfunc.S b/kernel/arch/x86_64/threadspfunc.S new file mode 100644 index 000000000000..c939f36b408a --- /dev/null +++ b/kernel/arch/x86_64/threadspfunc.S @@ -0,0 +1,54 @@ +/* $NetBSD: threadspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@rdi) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,%rax + addq $-8,%rax + ret +END(threadspfunc) diff --git a/kernel/h_cloexec.c b/kernel/h_cloexec.c new file mode 100644 index 000000000000..55ca4978497f --- /dev/null +++ b/kernel/h_cloexec.c @@ -0,0 +1,48 @@ +/* $NetBSD: h_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $"); + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(int argc, char **argv) +{ + int fd = atoi(argv[1]); + int flags; + + if (fcntl(fd, F_GETFL, &flags) == 0) + return 1; + if (errno != EBADF) + return 2; + return 0; +} diff --git a/kernel/h_execregs_unimpl.c b/kernel/h_execregs_unimpl.c new file mode 100644 index 000000000000..606781a2f745 --- /dev/null +++ b/kernel/h_execregs_unimpl.c @@ -0,0 +1,37 @@ +/* $NetBSD: h_execregs_unimpl.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_execregs_unimpl.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $"); + +int +main(void) +{ + + return 127; +} diff --git a/kernel/h_execsp.c b/kernel/h_execsp.c new file mode 100644 index 000000000000..dac1919e4417 --- /dev/null +++ b/kernel/h_execsp.c @@ -0,0 +1,68 @@ +/* $NetBSD: h_execsp.c,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_execsp.c,v 1.2 2025/04/20 22:31:25 riastradh Exp $"); + +#include <err.h> +#include <string.h> +#include <unistd.h> + +#include "h_execsp.h" + +/* + * The machine-dependent execsp.S assembly routines will initialize + * startsp, ctorsp, mainsp, and dtorsp, and then call execsp_main on + * program startup. + */ +void *startsp; +void *ctorsp; +void *mainsp; +void *dtorsp; + +int execsp_main(void); +int +execsp_main(void) +{ + struct execsp execsp; + ssize_t nwrit; + + memset(&execsp, 0, sizeof(execsp)); + execsp.startsp = startsp; + execsp.ctorsp = ctorsp; + execsp.mainsp = mainsp; + execsp.dtorsp = dtorsp; + + nwrit = write(STDOUT_FILENO, &execsp, sizeof(execsp)); + if (nwrit == -1) + err(1, "write"); + if ((size_t)nwrit != sizeof(execsp)) + errx(1, "wrote %zu != %zu", (size_t)nwrit, sizeof(execsp)); + + return 0; +} diff --git a/kernel/h_execsp.h b/kernel/h_execsp.h new file mode 100644 index 000000000000..e94ceaab9c1b --- /dev/null +++ b/kernel/h_execsp.h @@ -0,0 +1,47 @@ +/* $NetBSD: h_execsp.h,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#ifndef TESTS_KERNEL_H_EXECSP_H +#define TESTS_KERNEL_H_EXECSP_H + +/* + * struct execsp + * + * Structure passed from the h_execsp_* programs to the + * t_signal_and_sp test, giving the stack pointer as it was at the + * ELF entry point, an ELF constructor, the main function, and an + * ELF destructor. + */ +struct execsp { + void *startsp; + void *ctorsp; + void *mainsp; + void *dtorsp; +}; + +#endif /* TESTS_KERNEL_H_EXECSP_H */ diff --git a/kernel/setjmp_tester/Makefile b/kernel/setjmp_tester/Makefile new file mode 100644 index 000000000000..18492f35fd4a --- /dev/null +++ b/kernel/setjmp_tester/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.1 2025/04/27 16:22:26 riastradh Exp $ + +KMOD= setjmp_tester +KMODULEDIR= ${TESTSBASE}/kernel/${KMOD} + +SRCS= setjmp_tester.c + +ATFFILE= no +NOMAN= # defined + +.include <bsd.test.mk> +.include <bsd.kmodule.mk> diff --git a/kernel/setjmp_tester/setjmp_tester.c b/kernel/setjmp_tester/setjmp_tester.c new file mode 100644 index 000000000000..8b15b840effe --- /dev/null +++ b/kernel/setjmp_tester/setjmp_tester.c @@ -0,0 +1,147 @@ +/* $NetBSD: setjmp_tester.c,v 1.1 2025/04/27 16:22:26 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: setjmp_tester.c,v 1.1 2025/04/27 16:22:26 riastradh Exp $"); + +#include <sys/module.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +MODULE(MODULE_CLASS_MISC, setjmp_tester, NULL); + +static struct sysctllog *setjmp_tester_sysctllog; +static const struct sysctlnode *setjmp_tester_sysctlnode; +static kmutex_t setjmp_tester_lock; +static bool setjmp_tester_done; +static label_t setjmp_tester_label; + +__noinline +static void +setjmp_tester_subroutine(void) +{ + + printf("%s: call longjmp\n", __func__); + setjmp_tester_done = true; + longjmp(&setjmp_tester_label); + printf("%s: unreachable\n", __func__); +} + +static int +setjmp_tester_test(void) +{ + int result; + + mutex_enter(&setjmp_tester_lock); + + setjmp_tester_done = false; + result = setjmp(&setjmp_tester_label); + if (!setjmp_tester_done) { + printf("%s: setjmp returned %d at first\n", __func__, result); + if (result != 0) { + result = -1; + goto out; + } + setjmp_tester_subroutine(); + /*NOTREACHED*/ + printf("%s: setjmp_tester_subroutine returned\n", __func__); + result = -1; + } else { + printf("%s: setjmp returned %d at second\n", __func__, result); + if (result == 0) { + result = -2; + goto out; + } + } + +out: mutex_exit(&setjmp_tester_lock); + return result; +} + +static int +setjmp_tester_test_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + int v = 0; + int error; + + if (newp == NULL) { + error = ENOENT; + goto out; + } + error = sysctl_copyin(curlwp, newp, &v, sizeof(v)); + if (error) + goto out; + switch (v) { + case 1: + v = setjmp_tester_test(); + break; + default: + error = EINVAL; + break; + } + node.sysctl_data = &v; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + +out: return error; +} + +static int +setjmp_tester_modcmd(modcmd_t cmd, void *arg) +{ + int error = 0; + + switch (cmd) { + case MODULE_CMD_INIT: + mutex_init(&setjmp_tester_lock, MUTEX_DEFAULT, IPL_NONE); + error = sysctl_createv(&setjmp_tester_sysctllog, 0, + NULL, &setjmp_tester_sysctlnode, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "setjmp_tester", + SYSCTL_DESCR("setjmp/longjmp testing interface"), + NULL, 0, NULL, 0, + CTL_KERN, CTL_CREATE, CTL_EOL); + if (error) + goto fini; + error = sysctl_createv(&setjmp_tester_sysctllog, 0, + &setjmp_tester_sysctlnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "test", + SYSCTL_DESCR("setjmp/longjmp test trigger"), + &setjmp_tester_test_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto fini; + return error; + case MODULE_CMD_FINI: + fini: + sysctl_teardown(&setjmp_tester_sysctllog); + mutex_destroy(&setjmp_tester_lock); + return error; + default: + return ENOTTY; + } +} diff --git a/kernel/t_cloexec.c b/kernel/t_cloexec.c new file mode 100644 index 000000000000..c0150af8ca38 --- /dev/null +++ b/kernel/t_cloexec.c @@ -0,0 +1,457 @@ +/* $NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $"); + +#include <sys/types.h> + +#include <sys/bitops.h> +#include <sys/event.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <limits.h> +#include <spawn.h> +#include <stdio.h> +#include <unistd.h> + +#include "h_macros.h" + +/* + * Test close-on-exec as set in various ways + */ + +static int +open_via_accept4(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOEXEC. + */ + RL(saccept = accept4(slisten, /*addr*/NULL, /*addrlen*/NULL, + SOCK_CLOEXEC)); + return saccept; +} + +static int +open_via_clonedev(void) +{ + int fd; + + RL(fd = open("/dev/drvctl", O_RDONLY|O_CLOEXEC)); + + return fd; +} + +static int +open_via_dup3(void) +{ + int fd3; + + RL(fd3 = dup3(STDIN_FILENO, 3, O_CLOEXEC)); + ATF_REQUIRE_EQ_MSG(fd3, 3, "dup3(STDIN_FILENO, 3, ...)" + " failed to return 3: %d", fd3); + + return fd3; +} + +static int +open_via_fcntldupfd(void) +{ + int fd; + + RL(fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0)); + + return fd; +} + +static int +open_via_kqueue(void) +{ + int fd; + + RL(fd = kqueue1(O_CLOEXEC)); + + return fd; +} + +static int +open_via_opencloexec(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT|O_CLOEXEC, 0644)); + + return fd; +} + +static int +open_via_openfcntlcloexec(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(fcntl(fd, F_SETFD, FD_CLOEXEC)); + + return fd; +} + +static int +open_via_openioctlfioclex(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(ioctl(fd, FIOCLEX)); + + return fd; +} + +static int +open_via_pipe2rd(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOEXEC)); + + return fd[0]; +} + +static int +open_via_pipe2wr(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOEXEC)); + + return fd[1]; +} + +static int +open_via_paccept(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOEXEC. + */ + RL(saccept = paccept(slisten, /*addr*/NULL, /*addrlen*/NULL, + /*sigmask*/NULL, SOCK_CLOEXEC)); + return saccept; +} + +static int +open_via_socket(void) +{ + int fd; + + RL(fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0)); + + return fd; +} + +static int +open_via_socketpair0(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); + + return fd[0]; +} + +static int +open_via_socketpair1(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); + + return fd[1]; +} + +/* + * XXX Close-on-exec paths still missing: + * XXX + * XXX compat_linux inotify + * XXX compat_linux close_range + * XXX drm i915_perf_open_ioctl + * XXX drm dma_buf + * XXX eventfd(2) + * XXX memfd(2) + * XXX timerfd(2) + * XXX recvmsg/recvmmsg with MSG_CMSG_CLOEXEC + */ + +static void +check_cloexec(const struct atf_tc *tc, int fd, + pid_t (*execfn)(char *, char *const[])) +{ + char h_cloexec[PATH_MAX]; + char fdstr[(ilog2(INT_MAX) + 1)/(ilog2(10) - 1) + 1]; + char *const argv[] = {__UNCONST("h_cloexec"), fdstr, NULL}; + pid_t child, waitedpid; + int status; + + /* + * Format the h_cloexec helper executable path, which lives in + * the test's directory (typically /usr/tests/kernel), and the + * argument of a file descriptor in decimal. + */ + snprintf(h_cloexec, sizeof(h_cloexec), "%s/h_cloexec", + atf_tc_get_config_var(tc, "srcdir")); + snprintf(fdstr, sizeof(fdstr), "%d", fd); + + /* + * Execute h_cloexec as a subprocess. + */ + child = (*execfn)(h_cloexec, argv); + + /* + * Wait for the child to complete. + */ + RL(waitedpid = waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(child, waitedpid, "waited for %jd, got %jd", + (intmax_t)child, (intmax_t)waitedpid); + + /* + * Verify the child exited normally. + */ + if (WIFSIGNALED(status)) { + atf_tc_fail("subprocess terminated on signal %d", + WTERMSIG(status)); + return; + } else if (!WIFEXITED(status)) { + atf_tc_fail("subprocess failed to exit normally: status=0x%x", + status); + return; + } + + /* + * h_cloexec is supposed to exit status 0 if an operation on + * the fd failed with EBADFD, 1 if it unexpectedly succeeded, + * 127 if exec returned, or something else if anything else + * happened. + */ + switch (WEXITSTATUS(status)) { + case 0: /* success -- closed on exec */ + return; + case 1: /* fail -- not closed on exec */ + atf_tc_fail("fd was not closed on exec"); + return; + case 127: /* exec failed */ + atf_tc_fail("failed to exec h_cloexec"); + return; + default: /* something else went wong */ + atf_tc_fail("h_cloexec failed unexpectedly: %d", + WEXITSTATUS(status)); + return; + } +} + +static pid_t +exec_via_forkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = fork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_vforkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = vfork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_posixspawn(char *prog, char *const argv[]) +{ + pid_t pid; + + RZ(posix_spawn(&pid, prog, /*file_actions*/NULL, /*attrp*/NULL, argv, + /*envp*/NULL)); + + return pid; +} + +/* + * Full cartesian product is not really important here -- the paths for + * open and the paths for exec are independent. So we try + * pipe2(O_CLOEXEC) with each exec path, and we try each open path with + * posix_spawn. + */ + +#define CLOEXEC_TEST(test, openvia, execvia, descr) \ +ATF_TC(test); \ +ATF_TC_HEAD(test, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", descr); \ +} \ +ATF_TC_BODY(test, tc) \ +{ \ + check_cloexec(tc, openvia(), &execvia); \ +} + +CLOEXEC_TEST(pipe2rd_forkexecve, open_via_pipe2rd, exec_via_forkexecve, + "pipe2(O_CLOEXEC) reader is closed in child on fork/exec") +CLOEXEC_TEST(pipe2rd_vforkexecve, open_via_pipe2rd, exec_via_vforkexecve, + "pipe2(O_CLOEXEC) reader is closed in child on vfork/exec") +CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") + +CLOEXEC_TEST(accept4_posixspawn, open_via_accept4, exec_via_posixspawn, + "accept4(SOCK_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(clonedev_posixspawn, open_via_clonedev, exec_via_posixspawn, + "open(\"/dev/drvctl\") is closed in child on posix_spawn"); +CLOEXEC_TEST(dup3_posixspawn, open_via_dup3, exec_via_posixspawn, + "dup3(..., O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(fcntldupfd_posixspawn, open_via_fcntldupfd, exec_via_posixspawn, + "fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(kqueue_posixspawn, open_via_kqueue, exec_via_posixspawn, + "kqueue1(O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(opencloexec_posixspawn, open_via_opencloexec, exec_via_posixspawn, + "open(O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(openfcntlcloexec_posixspawn, open_via_openfcntlcloexec, + exec_via_posixspawn, + "fcntl(open(...), F_SETFD, O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(openioctlfioclex_posixspawn, open_via_openioctlfioclex, + exec_via_posixspawn, + "ioctl(open(...), FIOCLEX) is closed in child on posix_spawn"); +#if 0 /* already done above */ +CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") +#endif +CLOEXEC_TEST(pipe2wr_posixspawn, open_via_pipe2wr, exec_via_posixspawn, + "pipe2(O_CLOEXEC) writer is closed in child on posix_spawn") +CLOEXEC_TEST(paccept_posixspawn, open_via_paccept, exec_via_posixspawn, + "paccept(..., SOCK_CLOEXEC) is closed in child on posix_spawn") +CLOEXEC_TEST(socket_posixspawn, open_via_socket, exec_via_posixspawn, + "socket(SOCK_CLOEXEC) is closed in child on posix_spawn") +CLOEXEC_TEST(socketpair0_posixspawn, open_via_socketpair0, exec_via_posixspawn, + "socketpair(SOCK_CLOEXEC) side 0 is closed in child on posix_spawn") +CLOEXEC_TEST(socketpair1_posixspawn, open_via_socketpair1, exec_via_posixspawn, + "socketpair(SOCK_CLOEXEC) side 1 is closed in child on posix_spawn") + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, accept4_posixspawn); + ATF_TP_ADD_TC(tp, clonedev_posixspawn); + ATF_TP_ADD_TC(tp, dup3_posixspawn); + ATF_TP_ADD_TC(tp, fcntldupfd_posixspawn); + ATF_TP_ADD_TC(tp, kqueue_posixspawn); + ATF_TP_ADD_TC(tp, opencloexec_posixspawn); + ATF_TP_ADD_TC(tp, openfcntlcloexec_posixspawn); + ATF_TP_ADD_TC(tp, openioctlfioclex_posixspawn); + ATF_TP_ADD_TC(tp, paccept_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_forkexecve); + ATF_TP_ADD_TC(tp, pipe2rd_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_vforkexecve); + ATF_TP_ADD_TC(tp, pipe2wr_posixspawn); + ATF_TP_ADD_TC(tp, socket_posixspawn); + ATF_TP_ADD_TC(tp, socketpair0_posixspawn); + ATF_TP_ADD_TC(tp, socketpair1_posixspawn); + + return atf_no_error(); +} diff --git a/kernel/t_clofork.c b/kernel/t_clofork.c new file mode 100644 index 000000000000..9c1ba81c733a --- /dev/null +++ b/kernel/t_clofork.c @@ -0,0 +1,445 @@ +/* $NetBSD: t_clofork.c,v 1.1 2025/07/17 19:50:40 kre Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +/* Adapted from t_cloexec.c */ + +#include <sys/cdefs.h> + +#include <sys/types.h> + +#include <sys/bitops.h> +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <limits.h> +#include <spawn.h> +#include <stdio.h> +#include <unistd.h> + +#include "h_macros.h" + +#if defined(O_CLOFORK) && O_CLOFORK != 0 +/* + * Test close-on-fork as set in various ways + */ + +static int +open_via_accept4(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOFORK. + */ + RL(saccept = accept4(slisten, /*addr*/NULL, /*addrlen*/NULL, + SOCK_CLOFORK)); + return saccept; +} + +static int +open_via_clonedev(void) +{ + int fd; + + RL(fd = open("/dev/drvctl", O_RDONLY|O_CLOFORK)); + + return fd; +} + +static int +open_via_dup3(void) +{ + int fd3; + + RL(fd3 = dup3(STDIN_FILENO, 3, O_CLOFORK)); + ATF_REQUIRE_EQ_MSG(fd3, 3, "dup3(STDIN_FILENO, 3, ...)" + " failed to return 3: %d", fd3); + + return fd3; +} + +static int +open_via_fcntldupfd(void) +{ + int fd; + + RL(fd = fcntl(STDIN_FILENO, F_DUPFD_CLOFORK, 0)); + + return fd; +} + +static int +open_via_kqueue(void) +{ + int fd; + + RL(fd = kqueue1(O_CLOFORK)); + + return fd; +} + +static int +open_via_openclofork(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT|O_CLOFORK, 0644)); + + return fd; +} + +static int +open_via_openfcntlclofork(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(fcntl(fd, F_SETFD, FD_CLOFORK)); + + return fd; +} + +static int +open_via_pipe2rd(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOFORK)); + + return fd[0]; +} + +static int +open_via_pipe2wr(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOFORK)); + + return fd[1]; +} + +static int +open_via_paccept(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOFORK. + */ + RL(saccept = paccept(slisten, /*addr*/NULL, /*addrlen*/NULL, + /*sigmask*/NULL, SOCK_CLOFORK)); + return saccept; +} + +static int +open_via_socket(void) +{ + int fd; + + RL(fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0)); + + return fd; +} + +static int +open_via_socketpair0(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0, fd)); + + return fd[0]; +} + +static int +open_via_socketpair1(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0, fd)); + + return fd[1]; +} + +static void +check_clofork(const struct atf_tc *tc, int fd, + pid_t (*execfn)(char *, char *const[])) +{ + char h_clofork[PATH_MAX]; + char fdstr[(ilog2(INT_MAX) + 1)/(ilog2(10) - 1) + 1]; + char *const argv[] = {__UNCONST("h_cloexec"), fdstr, NULL}; + pid_t child, waitedpid; + int status; + + /* + * Format the h_clofork helper executable path, which lives in + * the test's directory (typically /usr/tests/kernel), and the + * argument of a file descriptor in decimal. + */ + snprintf(h_clofork, sizeof(h_clofork), "%s/h_cloexec", + atf_tc_get_config_var(tc, "srcdir")); + snprintf(fdstr, sizeof(fdstr), "%d", fd); + + /* + * Execute h_clofork as a subprocess. + */ + child = (*execfn)(h_clofork, argv); + + /* + * Wait for the child to complete. + */ + RL(waitedpid = waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(child, waitedpid, "waited for %jd, got %jd", + (intmax_t)child, (intmax_t)waitedpid); + + /* + * Verify the child exited normally. + */ + if (WIFSIGNALED(status)) { + atf_tc_fail("subprocess terminated on signal %d", + WTERMSIG(status)); + return; + } else if (!WIFEXITED(status)) { + atf_tc_fail("subprocess failed to exit normally: status=0x%x", + status); + return; + } + + /* + * h_clofork is supposed to exit status 0 if an operation on + * the fd failed with EBADFD, 1 if it unexpectedly succeeded, + * 127 if exec returned, or something else if anything else + * happened. + */ + switch (WEXITSTATUS(status)) { + case 0: /* success -- closed on exec */ + return; + case 1: /* fail -- not closed on exec */ + atf_tc_fail("fd was not closed on exec"); + return; + case 127: /* exec failed */ + atf_tc_fail("failed to exec h_cloexec"); + return; + default: /* something else went wong */ + atf_tc_fail("h_cloexec failed unexpectedly: %d", + WEXITSTATUS(status)); + return; + } +} + +static pid_t +exec_via_forkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = fork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_vforkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = vfork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_posixspawn(char *prog, char *const argv[]) +{ + pid_t pid; + + RZ(posix_spawn(&pid, prog, /*file_actions*/NULL, /*attrp*/NULL, argv, + /*envp*/NULL)); + + return pid; +} + +/* + * Full cartesian product is not really important here -- the paths for + * open and the paths for exec are independent. So we try + * pipe2(O_CLOFORK) with each exec path, and we try each open path with + * posix_spawn. + */ + +#define CLOFORK_TEST(test, openvia, execvia, descr) \ +ATF_TC(test); \ +ATF_TC_HEAD(test, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", descr); \ +} \ +ATF_TC_BODY(test, tc) \ +{ \ + check_clofork(tc, openvia(), &execvia); \ +} + +CLOFORK_TEST(pipe2rd_forkexecve, open_via_pipe2rd, exec_via_forkexecve, + "pipe2(O_CLOFORK) reader is closed in child on fork/exec") +CLOFORK_TEST(pipe2rd_vforkexecve, open_via_pipe2rd, exec_via_vforkexecve, + "pipe2(O_CLOFORK) reader is closed in child on vfork/exec") +CLOFORK_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOFORK) reader is closed in child on posix_spawn") + +CLOFORK_TEST(accept4_posixspawn, open_via_accept4, exec_via_posixspawn, + "accept4(SOCK_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(clonedev_posixspawn, open_via_clonedev, exec_via_posixspawn, + "open(\"/dev/drvctl\") is closed in child on posix_spawn"); +CLOFORK_TEST(dup3_posixspawn, open_via_dup3, exec_via_posixspawn, + "dup3(..., O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(fcntldupfd_posixspawn, open_via_fcntldupfd, exec_via_posixspawn, + "fcntl(STDIN_FILENO, F_DUPFD_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(kqueue_posixspawn, open_via_kqueue, exec_via_posixspawn, + "kqueue1(O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(openclofork_posixspawn, open_via_openclofork, exec_via_posixspawn, + "open(O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(openfcntlclofork_posixspawn, open_via_openfcntlclofork, + exec_via_posixspawn, + "fcntl(open(...), F_SETFD, O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(pipe2wr_posixspawn, open_via_pipe2wr, exec_via_posixspawn, + "pipe2(O_CLOFORK) writer is closed in child on posix_spawn") +CLOFORK_TEST(paccept_posixspawn, open_via_paccept, exec_via_posixspawn, + "paccept(..., SOCK_CLOFORK) is closed in child on posix_spawn") +CLOFORK_TEST(socket_posixspawn, open_via_socket, exec_via_posixspawn, + "socket(SOCK_CLOFORK) is closed in child on posix_spawn") +CLOFORK_TEST(socketpair0_posixspawn, open_via_socketpair0, exec_via_posixspawn, + "socketpair(SOCK_CLOFORK) side 0 is closed in child on posix_spawn") +CLOFORK_TEST(socketpair1_posixspawn, open_via_socketpair1, exec_via_posixspawn, + "socketpair(SOCK_CLOFORK) side 1 is closed in child on posix_spawn") + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, accept4_posixspawn); + ATF_TP_ADD_TC(tp, clonedev_posixspawn); + ATF_TP_ADD_TC(tp, dup3_posixspawn); + ATF_TP_ADD_TC(tp, fcntldupfd_posixspawn); + ATF_TP_ADD_TC(tp, kqueue_posixspawn); + ATF_TP_ADD_TC(tp, openclofork_posixspawn); + ATF_TP_ADD_TC(tp, openfcntlclofork_posixspawn); + ATF_TP_ADD_TC(tp, paccept_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_forkexecve); + ATF_TP_ADD_TC(tp, pipe2rd_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_vforkexecve); + ATF_TP_ADD_TC(tp, pipe2wr_posixspawn); + ATF_TP_ADD_TC(tp, socket_posixspawn); + ATF_TP_ADD_TC(tp, socketpair0_posixspawn); + ATF_TP_ADD_TC(tp, socketpair1_posixspawn); + + return atf_no_error(); +} + +#else /* No O_CLOFORK */ + +ATF_TC(not_implemented); +ATF_TC_HEAD(not_implemented, tc) +{ + atf_tc_set_md_var(tc, "descr", "Unimplemented O_CLOFORK"); +} +ATF_TC_BODY(not_implemented, tc) +{ + atf_tc_skip("close-on-fork not yet available"); +} +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, not_implemented); + + return atf_no_error(); +} +#endif diff --git a/kernel/t_execregs.c b/kernel/t_execregs.c new file mode 100644 index 000000000000..076a8de9547c --- /dev/null +++ b/kernel/t_execregs.c @@ -0,0 +1,197 @@ +/* $NetBSD: t_execregs.c,v 1.7 2025/04/27 14:30:03 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_execregs.c,v 1.7 2025/04/27 14:30:03 riastradh Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <err.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_EXECREGS_TEST + +#include "execregs.h" +#include "isqemu.h" +#include "h_macros.h" + +static void +readregs(int rfd, register_t regs[static NEXECREGS]) +{ + uint8_t *p; + size_t n; + ssize_t nread; + + p = (void *)regs; + n = NEXECREGS*sizeof(regs[0]); + while (n) { + RL(nread = read(rfd, p, n)); + ATF_CHECK_MSG((size_t)nread <= n, + "overlong read: %zu > %zu", (size_t)nread, n); + if (nread == 0) + break; + p += (size_t)nread; + n -= (size_t)nread; + } + ATF_CHECK_EQ_MSG(n, 0, + "truncated read, missing %zu of %zu bytes", + n, NEXECREGS*sizeof(regs[0])); +} + +static void +checkregs(const register_t regs[static NEXECREGS]) +{ + unsigned i; + +#ifdef __hppa__ + if (isQEMU()) { + atf_tc_expect_fail("PR port-hppa/59114: hppa:" + " eager fpu switching for qemu and/or spectre mitigation"); + } +#endif + + for (i = 0; i < NEXECREGS; i++) { + if (regs[i] != 0) { + for (i = 0; i < NEXECREGS; i++) { + fprintf(stderr, "[%s] %"PRIxREGISTER"\n", + regname[i], regs[i]); + } + fprintf(stderr, "\n"); + atf_tc_fail("registers not zeroed"); + } + } +} + +static void +testregs(int child, const int pipefd[static 2], + register_t regs[static NEXECREGS]) +{ + int status; + + RL(close(pipefd[1])); + + readregs(pipefd[0], regs); + + RL(waitpid(child, &status, 0)); + if (WIFSIGNALED(status)) { + atf_tc_fail_nonfatal("child terminated on signal %d (%s)", + WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (!WIFEXITED(status)) { + atf_tc_fail_nonfatal("child terminated mysteriously," + " status=0x%x", + status); + } else { + ATF_CHECK_MSG(WEXITSTATUS(status) == 0, + "child exited with code %d", WEXITSTATUS(status)); + } + + checkregs(regs); +} + +#endif + +ATF_TC(execregszero); +ATF_TC_HEAD(execregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test execve(2) zeroes registers"); +} +ATF_TC_BODY(execregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = fork()); + if (child == 0) { + if (dup2(pipefd[1], STDOUT_FILENO) == -1) + err(1, "dup2"); + if (closefrom(STDERR_FILENO + 1) == -1) + err(1, "closefrom"); + if (execregschild(h_execregs) == -1) + err(1, "execve"); + _exit(2); + } + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TC(spawnregszero); +ATF_TC_HEAD(spawnregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test posix_spawn(2) zeroes registers"); +} +ATF_TC_BODY(spawnregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = spawnregschild(h_execregs, pipefd[1])); + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, execregszero); + ATF_TP_ADD_TC(tp, spawnregszero); + + return atf_no_error(); +} diff --git a/kernel/t_fdrestart.c b/kernel/t_fdrestart.c new file mode 100644 index 000000000000..5449fcdaf18d --- /dev/null +++ b/kernel/t_fdrestart.c @@ -0,0 +1,274 @@ +/* $NetBSD: t_fdrestart.c,v 1.4 2023/11/18 19:46:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define _KMEMUSER /* ERESTART */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_fdrestart.c,v 1.4 2023/11/18 19:46:55 riastradh Exp $"); + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <atf-c.h> +#include <errno.h> +#include <pthread.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +struct fdrestart { + void (*op)(struct fdrestart *); + int fd; + pthread_barrier_t barrier; +}; + +static void +waitforbarrier(struct fdrestart *F, const char *caller) +{ + int error; + + error = pthread_barrier_wait(&F->barrier); + switch (error) { + case 0: + case PTHREAD_BARRIER_SERIAL_THREAD: + break; + default: + atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error, + strerror(error)); + } +} + +static void +doread(struct fdrestart *F) +{ + char c; + ssize_t nread; + int error; + + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "reader"); + + /* + * Start a read. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ + nread = rump_sys_read(F->fd, &c, sizeof(c)); + ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); + error = errno; + ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, + strerror(error)); + + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ + nread = rump_sys_read(F->fd, &c, sizeof(c)); + ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); + error = errno; + ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error, + strerror(error)); +} + +static void +dowrite(struct fdrestart *F) +{ + static const char buf[1024*1024]; /* XXX >BIG_PIPE_SIZE */ + ssize_t nwrit; + int error; + + /* + * Make sure the pipe's buffer is full first. + */ + for (;;) { + int nspace; + + RL(rump_sys_ioctl(F->fd, FIONSPACE, &nspace)); + ATF_REQUIRE_MSG(nspace >= 0, "nspace=%d", nspace); + if (nspace == 0) + break; + RL(rump_sys_write(F->fd, buf, (size_t)nspace)); + } + + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "writer"); + + /* + * Start a write. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ + nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); + ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); + error = errno; + ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, + strerror(error)); + + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ + nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); + ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); + error = errno; + ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error, + strerror(error)); +} + +static void * +doit(void *cookie) +{ + struct fdrestart *F = cookie; + + (*F->op)(F); + + return NULL; +} + +static void +on_sigalrm(int signo) +{ + + atf_tc_fail("timed out"); +} + +static void +testfdrestart(struct fdrestart *F) +{ + pthread_t t; + + ATF_REQUIRE_MSG(signal(SIGALRM, &on_sigalrm) != SIG_ERR, + "errno=%d (%s)", errno, strerror(errno)); + + RZ(pthread_barrier_init(&F->barrier, NULL, 2)); + RZ(pthread_create(&t, NULL, &doit, F)); + waitforbarrier(F, "closer"); /* wait for thread to start */ + (void)sleep(1); /* wait for op to start */ + (void)alarm(1); /* set a deadline */ + RL(rump_sys_close(F->fd)); /* wake op in other thread */ + RZ(pthread_join(t, NULL)); /* wait for op to wake and fail */ + (void)alarm(0); /* clear the deadline */ +} + +ATF_TC(pipe_read); +ATF_TC_HEAD(pipe_read, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pipe read fails on close"); +} +ATF_TC_BODY(pipe_read, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_pipe(fd)); + + memset(F, 0, sizeof(*F)); + F->op = &doread; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TC(pipe_write); +ATF_TC_HEAD(pipe_write, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pipe write fails on close"); +} +ATF_TC_BODY(pipe_write, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_pipe(fd)); + + memset(F, 0, sizeof(*F)); + F->op = &dowrite; + F->fd = fd[1]; + atf_tc_expect_fail("PR kern/57659"); + testfdrestart(F); +} + +ATF_TC(socketpair_read); +ATF_TC_HEAD(socketpair_read, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test socketpair read fails on close"); +} +ATF_TC_BODY(socketpair_read, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)); + + memset(F, 0, sizeof(*F)); + F->op = &doread; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TC(socketpair_write); +ATF_TC_HEAD(socketpair_write, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test socketpair write fails on close"); +} +ATF_TC_BODY(socketpair_write, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)); + + memset(F, 0, sizeof(*F)); + F->op = &dowrite; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, pipe_read); + ATF_TP_ADD_TC(tp, pipe_write); + ATF_TP_ADD_TC(tp, socketpair_read); + ATF_TP_ADD_TC(tp, socketpair_write); + + return atf_no_error(); +} diff --git a/kernel/t_nanosleep.c b/kernel/t_nanosleep.c new file mode 100644 index 000000000000..9ef752b37e60 --- /dev/null +++ b/kernel/t_nanosleep.c @@ -0,0 +1,246 @@ +/* $NetBSD: t_nanosleep.c,v 1.2 2025/10/07 20:09:27 andvar Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2024\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_nanosleep.c,v 1.2 2025/10/07 20:09:27 andvar Exp $"); + +#include <sys/types.h> +#include <sys/wait.h> + +#include <atf-c.h> + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +static void +sacrifice(void) +{ + pause(); +} + +static void +tester(pid_t victim, clockid_t clock, int flags) +{ + /* + * we need this sleep to be long enough that we + * can accurately detect when the sleep finishes + * early, but not so long that when there's no + * bug and things actually sleep this long, that + * the execution of a sleep this long, several + * times, won't slow down the overall testing + * process too much. Trial and error... + */ + struct timespec to_sleep = { 4, 0 }; + + struct timespec before, after; + struct timespec *ts; + int e; + + if (clock_gettime(clock, &before) != 0) + exit(1); + + if (flags & TIMER_ABSTIME) { + timespecadd(&to_sleep, &before, &after); + ts = &after; + } else + ts = &to_sleep; + + printf("Test: Clock=%d Flags=%x, starting at %jd.%.9ld\n", + (int)clock, flags, (intmax_t)before.tv_sec, before.tv_nsec); + if (flags & TIMER_ABSTIME) + printf("Sleeping until %jd.%.9ld\n", + (intmax_t)ts->tv_sec, ts->tv_nsec); + else + printf("Sleeping for %jd.%.9ld\n", + (intmax_t)ts->tv_sec, ts->tv_nsec); + + /* OK, we're ready */ + + /* these next two steps need to be as close together as possible */ + if (kill(victim, SIGKILL) == -1) + exit(2); + if ((e = clock_nanosleep(clock, flags, ts, &after)) != 0) + exit(20 + e); + + if (!(flags & TIMER_ABSTIME)) { + printf("Remaining to sleep: %jd.%.9ld\n", + (intmax_t)after.tv_sec, after.tv_nsec); + + if (after.tv_sec != 0 || after.tv_nsec != 0) + exit(3); + } + + if (clock_gettime(clock, &after) != 0) + exit(4); + + printf("Sleep ended at: %jd.%.9ld\n", + (intmax_t)after.tv_sec, after.tv_nsec); + + timespecadd(&before, &to_sleep, &before); + if (timespeccmp(&before, &after, >)) + exit(5); + + exit(0); +} + +/* + * The parent of the masochist/victim above, controls everything. + */ +static void +runit(clockid_t clock, int flags) +{ + pid_t v, m, x; + int status; + struct timespec brief = { 0, 3 * 100 * 1000 * 1000 }; /* 300 ms */ + + ATF_REQUIRE((v = fork()) != -1); + if (v == 0) + sacrifice(); + + ATF_REQUIRE((m = fork()) != -1); + if (m == 0) + tester(v, clock, flags); + + ATF_REQUIRE((x = wait(&status)) != -1); + + if (x == m) { + /* + * This is bad, the murderer shouldn't die first + */ + fprintf(stderr, "M exited first, status %#x\n", status); + (void)kill(v, SIGKILL); /* just in case */ + atf_tc_fail("2nd child predeceased first"); + } + if (x != v) { + fprintf(stderr, "Unknown exit from %d (status: %#x)" + "(M=%d V=%d)\n", x, status, m, v); + (void)kill(m, SIGKILL); + (void)kill(v, SIGKILL); + atf_tc_fail("Strange child died"); + } + + /* + * OK, the victim died, we don't really care why, + * (it should have been because of a SIGKILL, maybe + * test for that someday). + * + * Now we get to proceed to the real test. + * + * But we want to wait a short while to try and be sure + * that m (the child still running) has a chance to + * fall asleep. + */ + (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); + + /* + * This is the test, for PR kern/58733 + * - stop a process while in clock_nanosleep() + * - resume it again + * - see if it still sleeps as long as was requested (or longer) + */ + ATF_REQUIRE(kill(m, SIGSTOP) == 0); + (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); + ATF_REQUIRE(kill(m, SIGCONT) == 0); + + ATF_REQUIRE((x = wait(&status)) != -1); + + if (x != m) { + fprintf(stderr, "Unknown exit from %d (status: %#x)" + "(M=%d V=%d)\n", x, status, m, v); + (void) kill(m, SIGKILL); + atf_tc_fail("Strange child died"); + } + + if (status == 0) + atf_tc_pass(); + + /* + * Here we should decode the status, and give a better + * clue what really went wrong. Later... + */ + fprintf(stderr, "Test failed: status from M: %#x\n", status); + atf_tc_fail("M exited with non-zero status. PR kern/58733"); +} + + +ATF_TC(nanosleep_monotonic_absolute); +ATF_TC_HEAD(nanosleep_monotonic_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, ABS)"); +} +ATF_TC_BODY(nanosleep_monotonic_absolute, tc) +{ + runit(CLOCK_MONOTONIC, TIMER_ABSTIME); +} + +ATF_TC(nanosleep_monotonic_relative); +ATF_TC_HEAD(nanosleep_monotonic_relative, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, REL)"); +} +ATF_TC_BODY(nanosleep_monotonic_relative, tc) +{ + runit(CLOCK_MONOTONIC, TIMER_RELTIME); +} + +ATF_TC(nanosleep_realtime_absolute); +ATF_TC_HEAD(nanosleep_realtime_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, ABS)"); +} +ATF_TC_BODY(nanosleep_realtime_absolute, tc) +{ + runit(CLOCK_REALTIME, TIMER_ABSTIME); +} + +ATF_TC(nanosleep_realtime_relative); +ATF_TC_HEAD(nanosleep_realtime_relative, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, REL)"); +} +ATF_TC_BODY(nanosleep_realtime_relative, tc) +{ + runit(CLOCK_REALTIME, TIMER_RELTIME); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, nanosleep_monotonic_absolute); + ATF_TP_ADD_TC(tp, nanosleep_monotonic_relative); + ATF_TP_ADD_TC(tp, nanosleep_realtime_absolute); + ATF_TP_ADD_TC(tp, nanosleep_realtime_relative); + + return atf_no_error(); +} diff --git a/kernel/t_semtimedop.c b/kernel/t_semtimedop.c new file mode 100644 index 000000000000..daeaac6b3dab --- /dev/null +++ b/kernel/t_semtimedop.c @@ -0,0 +1,279 @@ +/* $NetBSD: t_semtimedop.c,v 1.2 2024/10/10 07:45:02 martin Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_semtimedop.c,v 1.2 2024/10/10 07:45:02 martin Exp $"); + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <errno.h> +#include <string.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <atf-c.h> +#include <sys/wait.h> + +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ + u_short *array; /* array for GETALL & SETALL */ +}; + +ATF_TC(semtimedop_basic); +ATF_TC_HEAD(semtimedop_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Basic semtimedop functionality"); +} + +ATF_TC_BODY(semtimedop_basic, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", + strerror(errno)); + } + + /* Define semtimedop operation: increment semaphore */ + sops.sem_num = 0; + sops.sem_op = 1; + sops.sem_flg = 0; + + /* Define timeout */ + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* Perform semtimedop */ + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + ATF_REQUIRE_MSG(0, "semtimedop failed: %s", strerror(errno)); + } + + /* Check semaphore value */ + int val = semctl(semid, 0, GETVAL); + ATF_REQUIRE_MSG(val == 1, + "Semaphore value incorrect: got %d, expected 1", val); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop blocks until timeout expires */ +ATF_TC(semtimedop_timeout); +ATF_TC_HEAD(semtimedop_timeout, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop blocks until timeout expires"); +} + +ATF_TC_BODY(semtimedop_timeout, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + pid_t pid; + int status; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + pid = fork(); + ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno)); + + if (pid == 0) { + /* + * Child: perform semtimedop with negative sem_op, should + * block until timeout + */ + sops.sem_num = 0; + sops.sem_op = -1; + sops.sem_flg = 0; + + timeout.tv_sec = 2; + timeout.tv_nsec = 0; + + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + if (errno == EAGAIN || errno == EINTR) { + exit(0); /* Expected */ + } + } + exit(1); /* Unexpected failure/success */ + } + + /* Parent: wait for child to finish */ + waitpid(pid, &status, 0); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop with SEM_UNDO adjusts semaphore on exit */ +ATF_TC(semtimedop_semundo); +ATF_TC_HEAD(semtimedop_semundo, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop with SEM_UNDO adjusts semaphore on exit"); +} + +ATF_TC_BODY(semtimedop_semundo, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + pid_t pid; + int val; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + pid = fork(); + ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno)); + + if (pid == 0) { + /* Child: perform semtimedop with SEM_UNDO */ + sops.sem_num = 0; + sops.sem_op = 1; + sops.sem_flg = SEM_UNDO; + + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + exit(1); /* Unexpected failure */ + } + + exit(0); /* Exit normally, SEM_UNDO should be triggered */ + } + + /* Parent: wait for child to exit */ + waitpid(pid, NULL, 0); + + /* Check semaphore value; should be 0 after SEM_UNDO */ + val = semctl(semid, 0, GETVAL); + ATF_REQUIRE_MSG(val == 0, + "Semaphore value incorrect after SEM_UNDO: got %d, " + "expected 0", val); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop handles invalid parameters correctly */ +ATF_TC(semtimedop_invalid); +ATF_TC_HEAD(semtimedop_invalid, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop handles invalid parameters correctly"); +} + +ATF_TC_BODY(semtimedop_invalid, tc) +{ + struct sembuf sops; + union semun sun; + struct timespec timeout; + + /* Invalid semaphore id */ + sops.sem_num = 0; + sops.sem_op = -1; + sops.sem_flg = 0; + + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* Attempt to perform semtimedop on invalid semid */ + ATF_REQUIRE_MSG(semtimedop(-1, &sops, 1, &timeout) == -1 + && errno == EINVAL, "semtimedop did not fail on invalid semid"); + + /* Create semaphore set */ + key_t key = IPC_PRIVATE; + int semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + /* Set an invalid semaphore number */ + sops.sem_num = 1; /* Only 1 semaphore in set, index 0 */ + sops.sem_op = 1; + sops.sem_flg = 0; + + /* Attempt semtimedop with invalid sem_num */ + ATF_REQUIRE_MSG(semtimedop(semid, &sops, 1, &timeout) == -1 + && errno == EFBIG, "semtimedop did not fail on invalid sem_num"); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, semtimedop_basic); + ATF_TP_ADD_TC(tp, semtimedop_timeout); + ATF_TP_ADD_TC(tp, semtimedop_semundo); + ATF_TP_ADD_TC(tp, semtimedop_invalid); + + return atf_no_error(); +} diff --git a/kernel/t_setjmp.sh b/kernel/t_setjmp.sh new file mode 100644 index 000000000000..1dbbd8504234 --- /dev/null +++ b/kernel/t_setjmp.sh @@ -0,0 +1,63 @@ +# $NetBSD: t_setjmp.sh,v 1.5 2025/04/29 10:57:17 martin Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT 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. +# + +module_loaded=no +atf_test_case setjmp cleanup +setjmp_head() +{ + atf_set "descr" "Test setjmp(9)/longjmp(9)" +} +setjmp_body() +{ + case `uname -p` in + vax) + atf_expect_fail "PR port-vax/59308:" \ + " kernel longjmp(9) fails to make setjmp(9) return 1" + ;; + esac + + err=$( modstat -e 2>&1 ) + if [ $? -gt 0 ]; then + atf_skip "${err##modstat:}" + fi + + module_loaded="yes" + modload "$(atf_get_srcdir)/setjmp_tester/setjmp_tester.kmod" + atf_check -s exit:0 -o inline:'1\n' \ + sysctl -n -w kern.setjmp_tester.test=1 +} +setjmp_cleanup() +{ + if [ "${module_loaded}" != "no" ]; then + modunload setjmp_tester + fi +} + +atf_init_test_cases() +{ + atf_add_test_case setjmp +} diff --git a/kernel/t_signal_and_sp.c b/kernel/t_signal_and_sp.c new file mode 100644 index 000000000000..1cef56cd3041 --- /dev/null +++ b/kernel/t_signal_and_sp.c @@ -0,0 +1,628 @@ +/* $NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#define __EXPOSE_STACK /* <sys/param.h>: expose STACK_ALIGNBYTES */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $"); + +#include <sys/param.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <limits.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ucontext.h> +#include <unistd.h> + +#include "h_execsp.h" +#include "h_macros.h" + +#ifdef HAVE_STACK_POINTER_H +# include "stack_pointer.h" +#endif + +#define PR_59327 "PR kern/59327: user stack pointer is not aligned properly" + +#ifdef HAVE_SIGNALSPHANDLER +void signalsphandler(int); /* signalsphandler.S assembly routine */ +#endif + +void *volatile signalsp; + +static void +test_execsp(const struct atf_tc *tc, const char *prog) +{ +#ifdef STACK_ALIGNBYTES + char h_execsp[PATH_MAX]; + struct execsp execsp; + int fd[2]; + pid_t pid; + struct pollfd pollfd; + int nfds; + ssize_t nread; + int status; + + /* + * Determine the full path to the helper program. + */ + RL(snprintf(h_execsp, sizeof(h_execsp), "%s/%s", + atf_tc_get_config_var(tc, "srcdir"), prog)); + + /* + * Create a pipe to read a bundle of stack pointer samples from + * the child, and fork the child. + */ + RL(pipe(fd)); + RL(pid = vfork()); + if (pid == 0) { /* child */ + char *const argv[] = {h_execsp, NULL}; + + if (dup2(fd[1], STDOUT_FILENO) == -1) + _exit(1); + if (closefrom(STDERR_FILENO + 1) == -1) + _exit(2); + if (execve(argv[0], argv, NULL) == -1) + _exit(3); + _exit(4); + } + + /* + * Close the writing end so, if something goes wrong in the + * child, we don't hang indefinitely waiting for output. + */ + RL(close(fd[1])); + + /* + * Wait up to 5sec for the child to return an answer. Any more + * than that, and we kill it. The child is mostly hand-written + * assembly routines where lots can go wrong, so don't bother + * waiting if it gets stuck in a loop. + */ + pollfd.fd = fd[0]; + pollfd.events = POLLIN; + RL(nfds = poll(&pollfd, 1, 5*1000/*ms*/)); + if (nfds == 0) { + fprintf(stderr, "child hung, killing\n"); + RL(kill(pid, SIGKILL)); + } + + /* + * Read a bundle of stack pointer samples from the child. + */ + RL(nread = read(fd[0], &execsp, sizeof(execsp))); + ATF_CHECK_MSG((size_t)nread == sizeof(execsp), + "nread=%zu sizeof(execsp)=%zu", + (size_t)nread, sizeof(execsp)); + + /* + * Wait for the child to terminate and report failure if it + * didn't exit cleanly. + */ + RL(waitpid(pid, &status, 0)); + if (WIFSIGNALED(status)) { + atf_tc_fail_nonfatal("child exited on signal %d (%s)", + WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (!WIFEXITED(status)) { + atf_tc_fail_nonfatal("child exited status=0x%x", status); + } else { + ATF_CHECK_MSG(WEXITSTATUS(status) == 0, + "child exited with code %d", + WEXITSTATUS(status)); + } + + /* + * Now that we have reaped the child, stop here if the stack + * pointer samples are bogus; otherwise verify they are all + * aligned. + */ + if ((size_t)nread != sizeof(execsp)) + return; /* failed already */ + + printf("start sp @ %p\n", execsp.startsp); + printf("ctor sp @ %p\n", execsp.ctorsp); + printf("main sp @ %p\n", execsp.mainsp); + printf("dtor sp @ %p\n", execsp.dtorsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.startsp & STACK_ALIGNBYTES) == 0, + "elf entry point was called with misaligned sp: %p", + execsp.startsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.ctorsp & STACK_ALIGNBYTES) == 0, + "elf constructor was called with misaligned sp: %p", + execsp.ctorsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.mainsp & STACK_ALIGNBYTES) == 0, + "main function was called with misaligned sp: %p", + execsp.mainsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.dtorsp & STACK_ALIGNBYTES) == 0, + "elf destructor was called with misaligned sp: %p", + execsp.dtorsp); + + /* + * Leave a reminder on architectures for which we haven't + * implemented execsp_start.S. + */ + if (execsp.startsp == NULL || + execsp.ctorsp == NULL || + execsp.mainsp == NULL || + execsp.dtorsp == NULL) + atf_tc_skip("Not fully supported on this architecture"); +#else + atf_tc_skip("Unknown STACK_ALIGNBYTES on this architecture"); +#endif +} + +ATF_TC(execsp_dynamic); +ATF_TC_HEAD(execsp_dynamic, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on dynamic program start"); +} +ATF_TC_BODY(execsp_dynamic, tc) +{ + test_execsp(tc, "h_execsp_dynamic"); +} + +ATF_TC(execsp_static); +ATF_TC_HEAD(execsp_static, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on static program start"); +} +ATF_TC_BODY(execsp_static, tc) +{ + test_execsp(tc, "h_execsp_static"); +} + +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC +void *volatile contextsp; /* set by contextspfunc.S */ +static ucontext_t return_context; +static volatile bool test_context_done; + +void contextspfunc(void); /* contextspfunc.S assembly routine */ + +static void +contextnoop(void) +{ + + fprintf(stderr, "contextnoop\n"); + /* control will return to contextspfunc via uc_link */ +} + +void contextdone(void); /* called by contextspfunc.S */ +void +contextdone(void) +{ + + fprintf(stderr, "contextdone\n"); + ATF_REQUIRE(!test_context_done); + test_context_done = true; + RL(setcontext(&return_context)); + atf_tc_fail("setcontext returned"); +} +#endif + +ATF_TC(contextsp); +ATF_TC_HEAD(contextsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on makecontext entry"); +} +ATF_TC_BODY(contextsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC + ucontext_t uc; + char *stack; + unsigned i; + + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p,%p)\n", stack, + stack + SIGSTKSZ + STACK_ALIGNBYTES); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc)); + uc.uc_stack.ss_sp = stack; + uc.uc_stack.ss_size = SIGSTKSZ + i; + makecontext(&uc, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc)); + uc.uc_stack.ss_sp = stack + i; + uc.uc_stack.ss_size = SIGSTKSZ; + makecontext(&uc, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack + i + SIGSTKSZ, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(contextsplink); +ATF_TC_HEAD(contextsplink, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on makecontext link entry"); +} +ATF_TC_BODY(contextsplink, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC + ucontext_t uc1, uc2; + char *stack1, *stack2; + unsigned i; + + REQUIRE_LIBC(stack1 = malloc(SIGSTKSZ), NULL); + fprintf(stderr, "stack1 @ [%p,%p)\n", stack1, stack1 + SIGSTKSZ); + REQUIRE_LIBC(stack2 = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack2 @ [%p,%p)\n", + stack2, stack2 + SIGSTKSZ + STACK_ALIGNBYTES); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc1)); + uc1.uc_stack.ss_sp = stack1; + uc1.uc_stack.ss_size = SIGSTKSZ; + uc1.uc_link = &uc2; + makecontext(&uc1, &contextnoop, 0); + + RL(getcontext(&uc2)); + uc2.uc_stack.ss_sp = stack2; + uc2.uc_stack.ss_size = SIGSTKSZ + i; + makecontext(&uc2, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc1)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack2 <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc1)); + uc1.uc_stack.ss_sp = stack1; + uc1.uc_stack.ss_size = SIGSTKSZ; + uc1.uc_link = &uc2; + makecontext(&uc1, &contextnoop, 0); + + RL(getcontext(&uc2)); + uc2.uc_stack.ss_sp = stack2 + i; + uc2.uc_stack.ss_size = SIGSTKSZ; + makecontext(&uc2, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc1)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack2 + i <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(signalsp); +ATF_TC_HEAD(signalsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on entry to signal handler"); +} +ATF_TC_BODY(signalsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + RL(sigaction(SIGUSR1, &sa, NULL)); + RL(raise(SIGUSR1)); + + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "signal handler was called with a misaligned sp: %p", + signalsp); +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(signalsp_sigaltstack); +ATF_TC_HEAD(signalsp_sigaltstack, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on entry to signal handler" + " with maximally misaligned sigaltstack"); +} +ATF_TC_BODY(signalsp_sigaltstack, tc) +{ +#if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER +#if defined(__sh__) + atf_tc_expect_fail(PR_59327); +#endif + char *stack; + struct sigaction sa; + struct sigaltstack ss; + unsigned i; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + sa.sa_flags = SA_ONSTACK; + RL(sigaction(SIGUSR1, &sa, NULL)); + + /* + * Allocate a signal stack with enough slop to try all possible + * misalignments of the stack pointer. Print it to stderr so + * it always appears in atf output before shenanigans happen. + */ + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p, %p)\n", + stack, stack + SIGSTKSZ + STACK_ALIGNBYTES); + + /* + * Try with all alignments of high addresses. + */ + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + ss.ss_sp = stack; + ss.ss_size = SIGSTKSZ + i; + ss.ss_flags = 0; + RL(sigaltstack(&ss, NULL)); + + signalsp = NULL; + RL(raise(SIGUSR1)); + ATF_CHECK(signalsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)signalsp && + (uintptr_t)signalsp <= (uintptr_t)stack + SIGSTKSZ + i, + "signalsp=%p", signalsp); + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "[%u] signal handler was called with a misaligned sp: %p", + i, signalsp); + } + + /* + * Try with all alignments of low addresses. + */ + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + ss.ss_sp = stack + i; + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + RL(sigaltstack(&ss, NULL)); + + signalsp = NULL; + RL(raise(SIGUSR1)); + ATF_CHECK(signalsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)signalsp && + (uintptr_t)signalsp <= (uintptr_t)stack + i + SIGSTKSZ, + "signalsp=%p", signalsp); + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "[%u] signal handler was called with a misaligned sp: %p", + i, signalsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +#if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC +void *threadspfunc(void *); /* threadspfunc.S assembly routine */ +#endif + +ATF_TC(threadsp); +ATF_TC_HEAD(threadsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on thread start"); +} +ATF_TC_BODY(threadsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC + pthread_t t; + void *sp; + char *stack; + unsigned i; + + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p,%p)\n", stack, + stack + SIGSTKSZ + STACK_ALIGNBYTES); + + RZ(pthread_create(&t, NULL, &threadspfunc, NULL)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "thread called with misaligned sp: %p", sp); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + pthread_attr_t attr; + + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i)); + RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); + RZ(pthread_attr_destroy(&attr)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)sp && + (uintptr_t)sp <= (uintptr_t)stack + SIGSTKSZ + i, + "sp=%p", sp); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "[%u] thread called with misaligned sp: %p", i, sp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + pthread_attr_t attr; + + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ)); + RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); + RZ(pthread_attr_destroy(&attr)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)sp && + (uintptr_t)sp <= (uintptr_t)stack + i + SIGSTKSZ, + "sp=%p", sp); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "[%u] thread called with misaligned sp: %p", i, sp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(misaligned_sp_and_signal); +ATF_TC_HEAD(misaligned_sp_and_signal, tc) +{ + atf_tc_set_md_var(tc, "descr", "process can return from a signal" + " handler even if the stack pointer is misaligned when a signal" + " arrives"); +} +ATF_TC_BODY(misaligned_sp_and_signal, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H +#if defined(__sh__) + atf_tc_expect_fail(PR_59327); +#endif + + /* + * Set up a handler for SIGALRM. + */ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + RL(sigaction(SIGALRM, &sa, NULL)); + + /* + * Set up an interval timer so that we receive SIGALRM after 50 ms. + */ + struct itimerval itv; + memset(&itv, 0, sizeof(itv)); + itv.it_value.tv_usec = 1000 * 50; + RL(setitimer(ITIMER_MONOTONIC, &itv, NULL)); + + /* + * Now misalign the SP. Wait for the signal to arrive and see what + * happens. This should be fine as long as we don't use it to + * access memory. + */ + MISALIGN_SP; + while (signalsp == NULL) { + /* + * Make sure the compiler does not optimize this busy loop + * away. + */ + __asm__("" ::: "memory"); + } + /* + * We could successfully return from a signal handler. Now we + * should fix the SP before calling any functions. + */ + FIX_SP; + + /* + * But was the stack pointer aligned when we were on the signal + * handler? + */ + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "signal handler was called with a misaligned sp: %p", + signalsp); +#else + atf_tc_skip("Not implemented for this platform"); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, contextsp); + ATF_TP_ADD_TC(tp, contextsplink); + ATF_TP_ADD_TC(tp, execsp_dynamic); + ATF_TP_ADD_TC(tp, execsp_static); + ATF_TP_ADD_TC(tp, misaligned_sp_and_signal); + ATF_TP_ADD_TC(tp, signalsp); + ATF_TP_ADD_TC(tp, signalsp_sigaltstack); + ATF_TP_ADD_TC(tp, threadsp); + return atf_no_error(); +} diff --git a/kernel/t_time_arith.c b/kernel/t_time_arith.c new file mode 100644 index 000000000000..0f738bfbe19a --- /dev/null +++ b/kernel/t_time_arith.c @@ -0,0 +1,1224 @@ +/* $NetBSD: t_time_arith.c,v 1.7 2025/10/06 12:05:04 riastradh Exp $ */ + +/*- + * Copyright (c) 2024-2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_time_arith.c,v 1.7 2025/10/06 12:05:04 riastradh Exp $"); + +#include <sys/timearith.h> + +#include <atf-c.h> +#include <errno.h> +#include <limits.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <util.h> + +#include "h_macros.h" + +enum { HZ = 100 }; + +int hz = HZ; +int tick = 1000000/HZ; + +static sig_atomic_t jmp_en; +static int jmp_sig; +static jmp_buf jmp; + +static void +handle_signal(int signo) +{ + const int errno_save = errno; + char buf[32]; + + snprintf_ss(buf, sizeof(buf), "signal %d\n", signo); + (void)write(STDERR_FILENO, buf, strlen(buf)); + + errno = errno_save; + + if (jmp_en) { + jmp_sig = signo; + jmp_en = 0; + longjmp(jmp, 1); + } else { + raise_default_signal(signo); + } +} + +const struct itimer_transition { + struct itimerspec it_time; + struct timespec it_now; + struct timespec it_next; + int it_overruns; + const char *it_xfail; +} itimer_transitions[] = { + /* + * Fired more than one interval early -- treat clock as wound + * backwards, not counting overruns. Advance to the next + * integral multiple of it_interval starting from it_value. + */ + [0] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,1}, {1,0}, 0, + NULL}, + [1] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,500000000}, {1,0}, 0, + NULL}, + [2] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,999999999}, {1,0}, 0, + NULL}, + [3] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,0}, {2,0}, 0, + NULL}, + [4] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,1}, {2,0}, 0, + NULL}, + [5] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,500000000}, {2,0}, 0, + NULL}, + [6] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,999999999}, {2,0}, 0, + NULL}, + + /* + * Fired exactly one interval early. Treat this too as clock + * wound backwards. + */ + [7] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,0}, {3,0}, 0, + NULL}, + + /* + * Fired less than one interval early -- callouts and real-time + * clock might not be perfectly synced, counted as zero + * overruns. Advance by one interval from the scheduled time. + */ + [8] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,1}, {3,0}, 0, + NULL}, + [9] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,500000000}, {3,0}, 0, + NULL}, + [10] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,999999999}, {3,0}, 0, + NULL}, + + /* + * Fired exactly on time. Advance by one interval. + */ + [11] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,0}, {4,0}, 0, NULL}, + + /* + * Fired late by less than one interval -- callouts and + * real-time clock might not be prefectly synced, counted as + * zero overruns. Advance by one interval from the scheduled + * time (even if it's very close to a full interval). + */ + [12] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,1}, {4,0}, 0, NULL}, + [14] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,500000000}, {4,0}, 0, NULL}, + [15] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,999999999}, {4,0}, 0, NULL}, + + /* + * Fired late by exactly one interval -- treat it as overrun. + */ + [16] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,0}, {5,0}, 1, + NULL}, + + /* + * Fired late by more than one interval but less than two -- + * overrun. + */ + [17] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,1}, {5,0}, 1, + NULL}, + [18] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,500000000}, {5,0}, 1, + NULL}, + [19] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,999999999}, {5,0}, 1, + NULL}, + + /* + * Fired late by exactly two intervals -- two overruns. + */ + [20] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {5,0}, {6,0}, 2, + NULL}, + + /* + * Fired late by more intervals plus slop, up to 32. + * + * XXX Define DELAYTIMER_MAX so we can write it in terms of + * that. + */ + [21] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {13,123456789}, {14,0}, 10, + NULL}, + [22] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {34,999999999}, {35,0}, 31, + NULL}, + + /* + * Fired late by roughly INT_MAX intervals. + */ + [23] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX - 1, 0}, + {(time_t)3 + INT_MAX, 0}, + INT_MAX - 1, + NULL}, + [24] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX, 0}, + {(time_t)3 + INT_MAX + 1, 0}, + INT_MAX, + NULL}, + [25] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX + 1, 0}, + {(time_t)3 + INT_MAX + 2, 0}, + INT_MAX, + NULL}, + + /* (2^63 - 1) ns */ + [26] = {{.it_value = {3,0}, .it_interval = {9223372036,854775807}}, + {3,1}, {9223372039,854775807}, 0, NULL}, + /* 2^63 ns */ + [27] = {{.it_value = {3,0}, .it_interval = {9223372036,854775808}}, + {3,1}, {9223372039,854775808}, 0, NULL}, + /* (2^63 + 1) ns */ + [28] = {{.it_value = {3,0}, .it_interval = {9223372036,854775809}}, + {3,1}, {9223372039,854775809}, 0, NULL}, + + /* + * Overflows -- we should (XXX but currently don't) reject + * intervals of at least 2^64 nanoseconds up front, since this + * is more time than it is reasonable to wait (more than 584 + * years). + */ + + /* (2^64 - 1) ns */ + [29] = {{.it_value = {3,0}, .it_interval = {18446744073,709551615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 ns */ + [30] = {{.it_value = {3,0}, .it_interval = {18446744073,709551616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) ns */ + [31] = {{.it_value = {3,0}, .it_interval = {18446744073,709551617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^63 - 1) us */ + [32] = {{.it_value = {3,0}, .it_interval = {9223372036854,775807}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^63 us */ + [33] = {{.it_value = {3,0}, .it_interval = {9223372036854,775808}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^63 + 1) us */ + [34] = {{.it_value = {3,0}, .it_interval = {9223372036854,775809}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^64 - 1) us */ + [35] = {{.it_value = {3,0}, .it_interval = {18446744073709,551615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 us */ + [36] = {{.it_value = {3,0}, .it_interval = {18446744073709,551616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) us */ + [37] = {{.it_value = {3,0}, .it_interval = {18446744073709,551617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^63 - 1) ms */ + [38] = {{.it_value = {3,0}, .it_interval = {9223372036854775,807}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^63 ms */ + [39] = {{.it_value = {3,0}, .it_interval = {9223372036854775,808}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^63 + 1) ms */ + [40] = {{.it_value = {3,0}, .it_interval = {9223372036854775,809}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^64 - 1) ms */ + [41] = {{.it_value = {3,0}, .it_interval = {18446744073709551,615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 ms */ + [42] = {{.it_value = {3,0}, .it_interval = {18446744073709551,616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) ms */ + [43] = {{.it_value = {3,0}, .it_interval = {18446744073709551,617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* invalid intervals */ + [44] = {{.it_value = {3,0}, .it_interval = {-1,0}}, + {3,1}, {0,0}, 0, NULL}, + [45] = {{.it_value = {3,0}, .it_interval = {0,-1}}, + {3,1}, {0,0}, 0, NULL}, + [46] = {{.it_value = {3,0}, .it_interval = {0,1000000000}}, + {3,1}, {0,0}, 0, NULL}, + + /* + * Overflow nanosecond arithmetic. The magic interval number + * here is ceiling(INT64_MAX/2) nanoseconds. The interval + * start value will be rounded to an integral number of ticks, + * so rather than write exactly `4611686018,427387905', just + * round up the `now' value to the next second. This forces an + * overrun _and_ triggers int64_t arithmetic overflow. + */ + [47] = {{.it_value = {0,1}, + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {4611686019,0}, {0,0}, 1, + NULL}, + + /* interval ~ 1/4 * (2^63 - 1) ns, now ~ 3/4 * (2^63 - 1) ns */ + [48] = {{.it_value = {0,1}, + .it_interval = {2305843009,213693952}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 3, + NULL}, + [49] = {{.it_value = {6917529027,0}, + .it_interval = {2305843009,213693952}}, + {6917529028,0}, {9223372036,213693952}, 0, NULL}, + [50] = {{.it_value = {6917529029,0}, + .it_interval = {2305843009,213693952}}, + {6917529028,0}, {6917529029,0}, 0, + NULL}, + + /* interval ~ 1/2 * (2^63 - 1) ns, now ~ 3/4 * (2^63 - 1) ns */ + [51] = {{.it_value = {0,1}, + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 1, + NULL}, + [52] = {{.it_value = {2305843009,213693951}, /* ~1/4 * (2^63 - 1) */ + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 1, + NULL}, + [54] = {{.it_value = {6917529027,0}, + .it_interval = {4611686018,427387904}}, + {6917529028,0}, {11529215045,427387904}, 0, NULL}, + [55] = {{.it_value = {6917529029,0}, + .it_interval = {4611686018,427387904}}, + {6917529028,0}, {6917529029,0}, 0, + NULL}, + + [56] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + /* XXX needless overflow */ + {INT64_MAX - 2,999999999}, {0,0}, 0, + NULL}, + [57] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,0}, {INT64_MAX,0}, 0, NULL}, + [58] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,1}, {INT64_MAX,0}, 0, NULL}, + [59] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,999999999}, {INT64_MAX,0}, 0, NULL}, + [60] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,0}, {0,0}, 0, + NULL}, + [61] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,1}, {0,0}, 0, + NULL}, + [62] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,999999999}, {0,0}, 0, + NULL}, + + [63] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,1}, {0,0}, 0, + NULL}, + [64] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,999999999}, {0,0}, 0, + NULL}, + [65] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,0}, {0,0}, 0, + NULL}, + [66] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,1}, {0,0}, 0, + NULL}, + [67] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,999999999}, {0,0}, 0, + NULL}, +}; + +ATF_TC(itimer_transitions); +ATF_TC_HEAD(itimer_transitions, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Tests interval timer transitions"); +} +ATF_TC_BODY(itimer_transitions, tc) +{ + volatile unsigned i; + + REQUIRE_LIBC(signal(SIGFPE, handle_signal), SIG_ERR); + REQUIRE_LIBC(signal(SIGABRT, handle_signal), SIG_ERR); + + for (i = 0; i < __arraycount(itimer_transitions); i++) { + struct itimer_transition it = itimer_transitions[i]; + struct timespec next; + int overruns; + volatile bool aborted = true; + volatile bool expect_abort = false; + + fprintf(stderr, "case %u\n", i); + + if (it.it_xfail) + atf_tc_expect_fail("%s", it.it_xfail); + + if (itimespecfix(&it.it_time.it_value) != 0 || + itimespecfix(&it.it_time.it_interval) != 0) { + fprintf(stderr, "rejected by itimerspecfix\n"); + expect_abort = true; + } + + if (setjmp(jmp) == 0) { + jmp_en = 1; + itimer_transition(&it.it_time, &it.it_now, + &next, &overruns); + jmp_en = 0; + aborted = false; + } + ATF_CHECK(!jmp_en); + jmp_en = 0; /* paranoia */ + if (expect_abort) { + fprintf(stderr, "expected abort\n"); + ATF_CHECK_MSG(aborted, + "[%u] missing invariant assertion", i); + ATF_CHECK_MSG(jmp_sig == SIGABRT, + "[%u] missing invariant assertion", i); + } else { + ATF_CHECK_MSG(!aborted, "[%u] raised signal %d: %s", i, + jmp_sig, strsignal(jmp_sig)); + } + + ATF_CHECK_MSG((next.tv_sec == it.it_next.tv_sec && + next.tv_nsec == it.it_next.tv_nsec), + "[%u] periodic intervals of %lld.%09d from %lld.%09d" + " last expired at %lld.%09d:" + " next expiry at %lld.%09d, expected %lld.%09d", i, + (long long)it.it_time.it_interval.tv_sec, + (int)it.it_time.it_interval.tv_nsec, + (long long)it.it_time.it_value.tv_sec, + (int)it.it_time.it_value.tv_nsec, + (long long)it.it_now.tv_sec, (int)it.it_now.tv_nsec, + (long long)next.tv_sec, (int)next.tv_nsec, + (long long)it.it_next.tv_sec, (int)it.it_next.tv_nsec); + ATF_CHECK_EQ_MSG(overruns, it.it_overruns, + "[%u] periodic intervals of %lld.%09d from %lld.%09d" + " last expired at %lld.%09d:" + " overruns %d, expected %d", i, + (long long)it.it_time.it_interval.tv_sec, + (int)it.it_time.it_interval.tv_nsec, + (long long)it.it_time.it_value.tv_sec, + (int)it.it_time.it_value.tv_nsec, + (long long)it.it_now.tv_sec, (int)it.it_now.tv_nsec, + overruns, it.it_overruns); + + if (it.it_xfail) + atf_tc_expect_pass(); + } +} + +/* + * { 0, if t <= 0; + * tstohz(t sec) @ f Hz = { ceil(t/(1/f)), if that's below INT_MAX; + * { INT_MAX, otherwise. + */ + +#define TSTOHZ_ROUND_XFAIL \ + "PR kern/59691: tstohz(9) rounding errors" + +const struct tstohz_case { + int ts_hz; + struct timespec ts_ts; + int ts_ticks; + const char *ts_xfail; +} tstohz_cases[] = { + /* + * hz = 10 + */ + + /* negative inputs yield 0 ticks */ + [0] = {10, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [1] = {10, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + + /* zero input yields 0 ticks */ + [2] = {10, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + + /* + * Nonzero input always yields >=2 ticks, because the time from + * now until the next tick may be arbitrarily short, and we + * need to wait one full tick, so we have to wait for two + * ticks. + */ + [3] = {10, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [4] = {10, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [5] = {10, {.tv_sec = 0, .tv_nsec = 99999999}, 2, NULL}, + [6] = {10, {.tv_sec = 0, .tv_nsec = 100000000}, 2, NULL}, + [7] = {10, {.tv_sec = 0, .tv_nsec = 100000001}, 3, NULL}, + [8] = {10, {.tv_sec = 0, .tv_nsec = 100000002}, 3, NULL}, + [9] = {10, {.tv_sec = 0, .tv_nsec = 199999999}, 3, NULL}, + [10] = {10, {.tv_sec = 0, .tv_nsec = 200000000}, 3, NULL}, + [11] = {10, {.tv_sec = 0, .tv_nsec = 200000001}, 4, NULL}, + [12] = {10, {.tv_sec = 0, .tv_nsec = 200000002}, 4, NULL}, + [13] = {10, {.tv_sec = 0, .tv_nsec = 999999999}, 11, NULL}, + [14] = {10, {.tv_sec = 1, .tv_nsec = 0}, 11, NULL}, + [15] = {10, {.tv_sec = 1, .tv_nsec = 1}, 12, NULL}, + [16] = {10, {.tv_sec = 1, .tv_nsec = 2}, 12, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [17] = {10, {.tv_sec = 2147, .tv_nsec = 999999999}, 21481, NULL}, + [18] = {10, {.tv_sec = 2148, .tv_nsec = 0}, 21481, NULL}, + [19] = {10, {.tv_sec = 2148, .tv_nsec = 1}, 21482, NULL}, + [20] = {10, {.tv_sec = 2148, .tv_nsec = 2}, 21482, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [21] = {10, {.tv_sec = 214748364, .tv_nsec = 499999999}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [22] = {10, {.tv_sec = 214748364, .tv_nsec = 500000000}, 2147483646, + NULL}, + [23] = {10, {.tv_sec = 214748364, .tv_nsec = 500000001}, 2147483647, + NULL}, + [24] = {10, {.tv_sec = 214748364, .tv_nsec = 500000002}, 2147483647, + NULL}, + [25] = {10, {.tv_sec = 214748364, .tv_nsec = 599999999}, 2147483647, + NULL}, + [26] = {10, {.tv_sec = 214748364, .tv_nsec = 600000000}, 2147483647, + NULL}, + [27] = {10, {.tv_sec = 214748364, .tv_nsec = 999999999}, 2147483647, + NULL}, + [28] = {10, {.tv_sec = 214748365, .tv_nsec = 0}, 2147483647, + NULL}, + [29] = {10, {.tv_sec = 214748365, .tv_nsec = 1}, 2147483647, + NULL}, + [30] = {10, {.tv_sec = 214748365, .tv_nsec = 2}, 2147483647, + NULL}, + [31] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [32] = {10, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [33] = {10, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [34] = {10, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [35] = {10, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [36] = {10, {.tv_sec = 922337203685477580, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [37] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 0}, + INT_MAX, NULL}, + [38] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 1}, + INT_MAX, NULL}, + [39] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 2}, + INT_MAX, NULL}, + [40] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 100 + */ + + [41] = {100, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [42] = {100, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [43] = {100, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [44] = {100, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [45] = {100, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [46] = {100, {.tv_sec = 0, .tv_nsec = 9999999}, 2, NULL}, + [47] = {100, {.tv_sec = 0, .tv_nsec = 10000000}, 2, NULL}, + [48] = {100, {.tv_sec = 0, .tv_nsec = 10000001}, 3, NULL}, + [49] = {100, {.tv_sec = 0, .tv_nsec = 10000002}, 3, NULL}, + [50] = {100, {.tv_sec = 0, .tv_nsec = 19999999}, 3, NULL}, + [51] = {100, {.tv_sec = 0, .tv_nsec = 20000000}, 3, NULL}, + [52] = {100, {.tv_sec = 0, .tv_nsec = 20000001}, 4, NULL}, + [53] = {100, {.tv_sec = 0, .tv_nsec = 20000002}, 4, NULL}, + [54] = {100, {.tv_sec = 0, .tv_nsec = 99999999}, 11, NULL}, + [55] = {100, {.tv_sec = 0, .tv_nsec = 100000000}, 11, NULL}, + [56] = {100, {.tv_sec = 0, .tv_nsec = 100000001}, 12, NULL}, + [57] = {100, {.tv_sec = 0, .tv_nsec = 100000002}, 12, NULL}, + [58] = {100, {.tv_sec = 0, .tv_nsec = 999999999}, 101, NULL}, + [59] = {100, {.tv_sec = 1, .tv_nsec = 0}, 101, NULL}, + [60] = {100, {.tv_sec = 1, .tv_nsec = 1}, 102, NULL}, + [61] = {100, {.tv_sec = 1, .tv_nsec = 2}, 102, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [62] = {100, {.tv_sec = 2147, .tv_nsec = 999999999}, 214801, NULL}, + [63] = {100, {.tv_sec = 2148, .tv_nsec = 0}, 214801, NULL}, + [64] = {100, {.tv_sec = 2148, .tv_nsec = 1}, 214802, NULL}, + [65] = {100, {.tv_sec = 2148, .tv_nsec = 2}, 214802, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [66] = {100, {.tv_sec = 21474836, .tv_nsec = 439999999}, 2147483645, + NULL}, + [67] = {100, {.tv_sec = 21474836, .tv_nsec = 440000000}, 2147483645, + NULL}, + [68] = {100, {.tv_sec = 21474836, .tv_nsec = 440000001}, 2147483646, + NULL}, + [69] = {100, {.tv_sec = 21474836, .tv_nsec = 440000002}, 2147483646, + NULL}, + [70] = {100, {.tv_sec = 21474836, .tv_nsec = 449999999}, 2147483646, + NULL}, + [71] = {100, {.tv_sec = 21474836, .tv_nsec = 450000000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [72] = {100, {.tv_sec = 21474836, .tv_nsec = 450000001}, 2147483647, + NULL}, + [73] = {100, {.tv_sec = 21474836, .tv_nsec = 450000002}, 2147483647, + NULL}, + [74] = {100, {.tv_sec = 21474836, .tv_nsec = 459999999}, 2147483647, + NULL}, + [75] = {100, {.tv_sec = 21474836, .tv_nsec = 460000000}, 2147483647, + NULL}, + [76] = {100, {.tv_sec = 21474836, .tv_nsec = 460000001}, 2147483647, + NULL}, + [77] = {100, {.tv_sec = 21474836, .tv_nsec = 460000002}, 2147483647, + NULL}, + [78] = {100, {.tv_sec = 21474836, .tv_nsec = 999999999}, 2147483647, + NULL}, + [79] = {100, {.tv_sec = 21474837, .tv_nsec = 0}, 2147483647, + NULL}, + [80] = {100, {.tv_sec = 21474837, .tv_nsec = 1}, 2147483647, + NULL}, + [81] = {100, {.tv_sec = 21474837, .tv_nsec = 2}, 2147483647, + NULL}, + [82] = {100, {.tv_sec = 21474837, .tv_nsec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000 */ + [83] = {100, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [84] = {100, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [85] = {100, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [86] = {100, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [87] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [88] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [89] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [90] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [91] = {100, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 1000 + */ + + [92] = {1000, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [93] = {1000, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [94] = {1000, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [95] = {1000, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [96] = {1000, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [97] = {1000, {.tv_sec = 0, .tv_nsec = 999999}, 2, NULL}, + [98] = {1000, {.tv_sec = 0, .tv_nsec = 1000000}, 2, NULL}, + [99] = {1000, {.tv_sec = 0, .tv_nsec = 1000001}, 3, NULL}, + [100] = {1000, {.tv_sec = 0, .tv_nsec = 1000002}, 3, NULL}, + [101] = {1000, {.tv_sec = 0, .tv_nsec = 1999999}, 3, NULL}, + [102] = {1000, {.tv_sec = 0, .tv_nsec = 2000000}, 3, NULL}, + [103] = {1000, {.tv_sec = 0, .tv_nsec = 2000001}, 4, NULL}, + [104] = {1000, {.tv_sec = 0, .tv_nsec = 2000002}, 4, NULL}, + [105] = {1000, {.tv_sec = 0, .tv_nsec = 999999999}, 1001, NULL}, + [106] = {1000, {.tv_sec = 1, .tv_nsec = 0}, 1001, NULL}, + [107] = {1000, {.tv_sec = 1, .tv_nsec = 1}, 1002, NULL}, + [108] = {1000, {.tv_sec = 1, .tv_nsec = 2}, 1002, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [109] = {1000, {.tv_sec = 2147, .tv_nsec = 999999999}, 2148001, NULL}, + [110] = {1000, {.tv_sec = 2148, .tv_nsec = 0}, 2148001, NULL}, + [111] = {1000, {.tv_sec = 2148, .tv_nsec = 1}, 2148002, NULL}, + [112] = {1000, {.tv_sec = 2148, .tv_nsec = 2}, 2148002, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [113] = {1000, {.tv_sec = 2147483, .tv_nsec = 643999999}, 2147483645, + NULL}, + [114] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000000}, 2147483645, + NULL}, + [115] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000001}, 2147483646, + NULL}, + [116] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000002}, 2147483646, + NULL}, + [117] = {1000, {.tv_sec = 2147483, .tv_nsec = 644999999}, 2147483646, + NULL}, + [118] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [119] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000001}, 2147483647, + NULL}, + [120] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000002}, 2147483647, + NULL}, + [121] = {1000, {.tv_sec = 2147483, .tv_nsec = 645999999}, 2147483647, + NULL}, + [122] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000000}, 2147483647, + NULL}, + [123] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000001}, 2147483647, + NULL}, + [124] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000002}, 2147483647, + NULL}, + [125] = {1000, {.tv_sec = 2147483, .tv_nsec = 699999999}, 2147483647, + NULL}, + [126] = {1000, {.tv_sec = 2147484, .tv_nsec = 0}, 2147483647, + NULL}, + [127] = {1000, {.tv_sec = 2147484, .tv_nsec = 1}, 2147483647, + NULL}, + [128] = {1000, {.tv_sec = 2147484, .tv_nsec = 2}, 2147483647, + NULL}, + [129] = {1000, {.tv_sec = 2147484, .tv_nsec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [130] = {1000, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [131] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [132] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [133] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [134] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [135] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [136] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [137] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [138] = {1000, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 8191, prime non-divisor of 10^k or 2^k + */ + + [139] = {8191, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [140] = {8191, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [141] = {8191, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [142] = {8191, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [143] = {8191, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [144] = {8191, {.tv_sec = 0, .tv_nsec = 122084}, 2, + TSTOHZ_ROUND_XFAIL}, + [145] = {8191, {.tv_sec = 0, .tv_nsec = 122085}, 2, + TSTOHZ_ROUND_XFAIL}, + [146] = {8191, {.tv_sec = 0, .tv_nsec = 122086}, 3, NULL}, + [147] = {8191, {.tv_sec = 0, .tv_nsec = 244168}, 3, + TSTOHZ_ROUND_XFAIL}, + [148] = {8191, {.tv_sec = 0, .tv_nsec = 244169}, 3, + TSTOHZ_ROUND_XFAIL}, + [149] = {8191, {.tv_sec = 0, .tv_nsec = 244170}, 3, + TSTOHZ_ROUND_XFAIL}, + [150] = {8191, {.tv_sec = 0, .tv_nsec = 244171}, 4, NULL}, + [151] = {8191, {.tv_sec = 0, .tv_nsec = 244172}, 4, NULL}, + [152] = {8191, {.tv_sec = 0, .tv_nsec = 999999999}, 8192, NULL}, + [153] = {8191, {.tv_sec = 1, .tv_nsec = 0}, 8192, NULL}, + [154] = {8191, {.tv_sec = 1, .tv_nsec = 1}, 8193, NULL}, + [155] = {8191, {.tv_sec = 1, .tv_nsec = 2}, 8193, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [156] = {8191, {.tv_sec = 2147, .tv_nsec = 999999999}, 17594269, NULL}, + [157] = {8191, {.tv_sec = 2148, .tv_nsec = 0}, 17594269, NULL}, + [158] = {8191, {.tv_sec = 2148, .tv_nsec = 1}, 17594270, NULL}, + [159] = {8191, {.tv_sec = 2148, .tv_nsec = 2}, 17594270, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [160] = {8191, {.tv_sec = 262176, .tv_nsec = 3540471}, 2147483646, + NULL}, + [161] = {8191, {.tv_sec = 262176, .tv_nsec = 3540472}, 2147483647, + NULL}, + [162] = {8191, {.tv_sec = 262176, .tv_nsec = 3540473}, 2147483647, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [163] = {8191, {.tv_sec = 262176, .tv_nsec = 3662556}, 2147483647, + NULL}, + [164] = {8191, {.tv_sec = 262176, .tv_nsec = 3662557}, 2147483647, + NULL}, + [165] = {8191, {.tv_sec = 262176, .tv_nsec = 3662558}, 2147483647, + NULL}, + [166] = {8191, {.tv_sec = 262176, .tv_nsec = 999999999}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [167] = {8191, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [168] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [169] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [170] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [171] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [172] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [173] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [174] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [175] = {8191, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, +}; + +ATF_TC(tstohz); +ATF_TC_HEAD(tstohz, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test tstohz(9)"); +} +ATF_TC_BODY(tstohz, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(tstohz_cases); i++) { + const struct tstohz_case *ts = &tstohz_cases[i]; + int ticks; + + /* set system parameters */ + hz = ts->ts_hz; + tick = 1000000/hz; + + ticks = tstohz(&ts->ts_ts); + if (ts->ts_xfail) + atf_tc_expect_fail("%s", ts->ts_xfail); + + /* + * Allow some slop of one part per thousand in the + * arithmetic, but ensure we round up, not down. + */ + ATF_CHECK_MSG(((unsigned)(ticks - ts->ts_ticks) <= + (unsigned)ts->ts_ticks/1000), + "[%zu] tstohz(%lld.%09ld sec) @ %d Hz:" + " expected %d, got %d", + i, + (long long)ts->ts_ts.tv_sec, + (long)ts->ts_ts.tv_nsec, + ts->ts_hz, + ts->ts_ticks, + ticks); + if (ts->ts_xfail) + atf_tc_expect_pass(); + } +} + +/* + * { 0, if t <= 0; + * tvtohz(t sec) @ f Hz = { ceil(t/(1/f)), if that's below INT_MAX; + * { INT_MAX, otherwise. + */ + +const struct tvtohz_case { + int tv_hz; + struct timeval tv_tv; + int tv_ticks; + const char *tv_xfail; +} tvtohz_cases[] = { + /* + * hz = 10 + */ + + /* negative inputs yield 0 ticks */ + [0] = {10, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [1] = {10, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + + /* zero input yields 0 ticks */ + [2] = {10, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + + /* + * Nonzero input always yields >=2 ticks, because the time from + * now until the next tick may be arbitrarily short, and we + * need to wait one full tick, so we have to wait for two + * ticks. + */ + [3] = {10, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [4] = {10, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [5] = {10, {.tv_sec = 0, .tv_usec = 99999}, 2, NULL}, + [6] = {10, {.tv_sec = 0, .tv_usec = 100000}, 2, NULL}, + [7] = {10, {.tv_sec = 0, .tv_usec = 100001}, 3, NULL}, + [8] = {10, {.tv_sec = 0, .tv_usec = 100002}, 3, NULL}, + [9] = {10, {.tv_sec = 0, .tv_usec = 199999}, 3, NULL}, + [10] = {10, {.tv_sec = 0, .tv_usec = 200000}, 3, NULL}, + [11] = {10, {.tv_sec = 0, .tv_usec = 200001}, 4, NULL}, + [12] = {10, {.tv_sec = 0, .tv_usec = 200002}, 4, NULL}, + [13] = {10, {.tv_sec = 0, .tv_usec = 999999}, 11, NULL}, + [14] = {10, {.tv_sec = 1, .tv_usec = 0}, 11, NULL}, + [15] = {10, {.tv_sec = 1, .tv_usec = 1}, 12, NULL}, + [16] = {10, {.tv_sec = 1, .tv_usec = 2}, 12, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [17] = {10, {.tv_sec = 2147, .tv_usec = 999999}, 21481, NULL}, + [18] = {10, {.tv_sec = 2148, .tv_usec = 0}, 21481, NULL}, + [19] = {10, {.tv_sec = 2148, .tv_usec = 1}, 21482, NULL}, + [20] = {10, {.tv_sec = 2148, .tv_usec = 2}, 21482, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [21] = {10, {.tv_sec = 214748364, .tv_usec = 499999}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [22] = {10, {.tv_sec = 214748364, .tv_usec = 500000}, 2147483646, + NULL}, + [23] = {10, {.tv_sec = 214748364, .tv_usec = 500001}, 2147483647, + NULL}, + [24] = {10, {.tv_sec = 214748364, .tv_usec = 500002}, 2147483647, + NULL}, + [25] = {10, {.tv_sec = 214748364, .tv_usec = 599999}, 2147483647, + NULL}, + [26] = {10, {.tv_sec = 214748364, .tv_usec = 600000}, 2147483647, + NULL}, + [27] = {10, {.tv_sec = 214748364, .tv_usec = 999999}, 2147483647, + NULL}, + [28] = {10, {.tv_sec = 214748365, .tv_usec = 0}, 2147483647, + NULL}, + [29] = {10, {.tv_sec = 214748365, .tv_usec = 1}, 2147483647, + NULL}, + [30] = {10, {.tv_sec = 214748365, .tv_usec = 2}, 2147483647, + NULL}, + [31] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [32] = {10, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [33] = {10, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [34] = {10, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [35] = {10, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [36] = {10, {.tv_sec = 922337203685477580, .tv_usec = 999999}, + INT_MAX, NULL}, + [37] = {10, {.tv_sec = 922337203685477581, .tv_usec = 0}, + INT_MAX, NULL}, + [38] = {10, {.tv_sec = 922337203685477581, .tv_usec = 1}, + INT_MAX, NULL}, + [39] = {10, {.tv_sec = 922337203685477581, .tv_usec = 2}, + INT_MAX, NULL}, + [40] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 100 + */ + + [41] = {100, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [42] = {100, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [43] = {100, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [44] = {100, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [45] = {100, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [46] = {100, {.tv_sec = 0, .tv_usec = 9999}, 2, NULL}, + [47] = {100, {.tv_sec = 0, .tv_usec = 10000}, 2, NULL}, + [48] = {100, {.tv_sec = 0, .tv_usec = 10001}, 3, NULL}, + [49] = {100, {.tv_sec = 0, .tv_usec = 10002}, 3, NULL}, + [50] = {100, {.tv_sec = 0, .tv_usec = 19999}, 3, NULL}, + [51] = {100, {.tv_sec = 0, .tv_usec = 20000}, 3, NULL}, + [52] = {100, {.tv_sec = 0, .tv_usec = 20001}, 4, NULL}, + [53] = {100, {.tv_sec = 0, .tv_usec = 20002}, 4, NULL}, + [54] = {100, {.tv_sec = 0, .tv_usec = 99999}, 11, NULL}, + [55] = {100, {.tv_sec = 0, .tv_usec = 100000}, 11, NULL}, + [56] = {100, {.tv_sec = 0, .tv_usec = 100001}, 12, NULL}, + [57] = {100, {.tv_sec = 0, .tv_usec = 100002}, 12, NULL}, + [58] = {100, {.tv_sec = 0, .tv_usec = 999999}, 101, NULL}, + [59] = {100, {.tv_sec = 1, .tv_usec = 0}, 101, NULL}, + [60] = {100, {.tv_sec = 1, .tv_usec = 1}, 102, NULL}, + [61] = {100, {.tv_sec = 1, .tv_usec = 2}, 102, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [62] = {100, {.tv_sec = 2147, .tv_usec = 999999}, 214801, NULL}, + [63] = {100, {.tv_sec = 2148, .tv_usec = 0}, 214801, NULL}, + [64] = {100, {.tv_sec = 2148, .tv_usec = 1}, 214802, NULL}, + [65] = {100, {.tv_sec = 2148, .tv_usec = 2}, 214802, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [66] = {100, {.tv_sec = 21474836, .tv_usec = 439999}, 2147483645, + NULL}, + [67] = {100, {.tv_sec = 21474836, .tv_usec = 440000}, 2147483645, + NULL}, + [68] = {100, {.tv_sec = 21474836, .tv_usec = 440001}, 2147483646, + NULL}, + [69] = {100, {.tv_sec = 21474836, .tv_usec = 440002}, 2147483646, + NULL}, + [70] = {100, {.tv_sec = 21474836, .tv_usec = 449999}, 2147483646, + NULL}, + [71] = {100, {.tv_sec = 21474836, .tv_usec = 450000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [72] = {100, {.tv_sec = 21474836, .tv_usec = 450001}, 2147483647, + NULL}, + [73] = {100, {.tv_sec = 21474836, .tv_usec = 450002}, 2147483647, + NULL}, + [74] = {100, {.tv_sec = 21474836, .tv_usec = 459999}, 2147483647, + NULL}, + [75] = {100, {.tv_sec = 21474836, .tv_usec = 460000}, 2147483647, + NULL}, + [76] = {100, {.tv_sec = 21474836, .tv_usec = 460001}, 2147483647, + NULL}, + [77] = {100, {.tv_sec = 21474836, .tv_usec = 460002}, 2147483647, + NULL}, + [78] = {100, {.tv_sec = 21474836, .tv_usec = 999999}, 2147483647, + NULL}, + [79] = {100, {.tv_sec = 21474837, .tv_usec = 0}, 2147483647, + NULL}, + [80] = {100, {.tv_sec = 21474837, .tv_usec = 1}, 2147483647, + NULL}, + [81] = {100, {.tv_sec = 21474837, .tv_usec = 2}, 2147483647, + NULL}, + [82] = {100, {.tv_sec = 21474837, .tv_usec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000 */ + [83] = {100, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [84] = {100, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [85] = {100, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [86] = {100, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [87] = {100, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [88] = {100, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [89] = {100, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [90] = {100, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [91] = {100, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 1000 + */ + + [92] = {1000, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [93] = {1000, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [94] = {1000, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [95] = {1000, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [96] = {1000, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [97] = {1000, {.tv_sec = 0, .tv_usec = 999}, 2, NULL}, + [98] = {1000, {.tv_sec = 0, .tv_usec = 1000}, 2, NULL}, + [99] = {1000, {.tv_sec = 0, .tv_usec = 1001}, 3, NULL}, + [100] = {1000, {.tv_sec = 0, .tv_usec = 1002}, 3, NULL}, + [101] = {1000, {.tv_sec = 0, .tv_usec = 1999}, 3, NULL}, + [102] = {1000, {.tv_sec = 0, .tv_usec = 2000}, 3, NULL}, + [103] = {1000, {.tv_sec = 0, .tv_usec = 2001}, 4, NULL}, + [104] = {1000, {.tv_sec = 0, .tv_usec = 2002}, 4, NULL}, + [105] = {1000, {.tv_sec = 0, .tv_usec = 999999}, 1001, NULL}, + [106] = {1000, {.tv_sec = 1, .tv_usec = 0}, 1001, NULL}, + [107] = {1000, {.tv_sec = 1, .tv_usec = 1}, 1002, NULL}, + [108] = {1000, {.tv_sec = 1, .tv_usec = 2}, 1002, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [109] = {1000, {.tv_sec = 2147, .tv_usec = 999999}, 2148001, NULL}, + [110] = {1000, {.tv_sec = 2148, .tv_usec = 0}, 2148001, NULL}, + [111] = {1000, {.tv_sec = 2148, .tv_usec = 1}, 2148002, NULL}, + [112] = {1000, {.tv_sec = 2148, .tv_usec = 2}, 2148002, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [113] = {1000, {.tv_sec = 2147483, .tv_usec = 643999}, 2147483645, + NULL}, + [114] = {1000, {.tv_sec = 2147483, .tv_usec = 644000}, 2147483645, + NULL}, + [115] = {1000, {.tv_sec = 2147483, .tv_usec = 644001}, 2147483646, + NULL}, + [116] = {1000, {.tv_sec = 2147483, .tv_usec = 644002}, 2147483646, + NULL}, + [117] = {1000, {.tv_sec = 2147483, .tv_usec = 644999}, 2147483646, + NULL}, + [118] = {1000, {.tv_sec = 2147483, .tv_usec = 645000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [119] = {1000, {.tv_sec = 2147483, .tv_usec = 645001}, 2147483647, + NULL}, + [120] = {1000, {.tv_sec = 2147483, .tv_usec = 645002}, 2147483647, + NULL}, + [121] = {1000, {.tv_sec = 2147483, .tv_usec = 645999}, 2147483647, + NULL}, + [122] = {1000, {.tv_sec = 2147483, .tv_usec = 646000}, 2147483647, + NULL}, + [123] = {1000, {.tv_sec = 2147483, .tv_usec = 646001}, 2147483647, + NULL}, + [124] = {1000, {.tv_sec = 2147483, .tv_usec = 646002}, 2147483647, + NULL}, + [125] = {1000, {.tv_sec = 2147483, .tv_usec = 699999}, 2147483647, + NULL}, + [126] = {1000, {.tv_sec = 2147484, .tv_usec = 0}, 2147483647, + NULL}, + [127] = {1000, {.tv_sec = 2147484, .tv_usec = 1}, 2147483647, + NULL}, + [128] = {1000, {.tv_sec = 2147484, .tv_usec = 2}, 2147483647, + NULL}, + [129] = {1000, {.tv_sec = 2147484, .tv_usec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [130] = {1000, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [131] = {1000, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [132] = {1000, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [133] = {1000, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [134] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [135] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [136] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [137] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [138] = {1000, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 8191, prime non-divisor of 10^k or 2^k + */ + + [139] = {8191, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [140] = {8191, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [141] = {8191, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [142] = {8191, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [143] = {8191, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [144] = {8191, {.tv_sec = 0, .tv_usec = 121}, 2, NULL}, + [145] = {8191, {.tv_sec = 0, .tv_usec = 122}, 2, NULL}, + [146] = {8191, {.tv_sec = 0, .tv_usec = 123}, 3, NULL}, + [147] = {8191, {.tv_sec = 0, .tv_usec = 242}, 3, NULL}, + [148] = {8191, {.tv_sec = 0, .tv_usec = 243}, 3, NULL}, + [149] = {8191, {.tv_sec = 0, .tv_usec = 244}, 3, NULL}, + [150] = {8191, {.tv_sec = 0, .tv_usec = 245}, 4, NULL}, + [151] = {8191, {.tv_sec = 0, .tv_usec = 246}, 4, NULL}, + [152] = {8191, {.tv_sec = 0, .tv_usec = 999999}, 8192, NULL}, + [153] = {8191, {.tv_sec = 1, .tv_usec = 0}, 8192, NULL}, + [154] = {8191, {.tv_sec = 1, .tv_usec = 1}, 8193, NULL}, + [155] = {8191, {.tv_sec = 1, .tv_usec = 2}, 8193, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [156] = {8191, {.tv_sec = 2147, .tv_usec = 999999}, 17594269, NULL}, + [157] = {8191, {.tv_sec = 2148, .tv_usec = 0}, 17594269, NULL}, + [158] = {8191, {.tv_sec = 2148, .tv_usec = 1}, 17594270, NULL}, + [159] = {8191, {.tv_sec = 2148, .tv_usec = 2}, 17594270, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [160] = {8191, {.tv_sec = 262176, .tv_usec = 3540}, 2147483646, + NULL}, + [161] = {8191, {.tv_sec = 262176, .tv_usec = 3541}, 2147483647, + NULL}, + [162] = {8191, {.tv_sec = 262176, .tv_usec = 3542}, 2147483647, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [163] = {8191, {.tv_sec = 262176, .tv_usec = 3662}, 2147483647, + NULL}, + [164] = {8191, {.tv_sec = 262176, .tv_usec = 3663}, 2147483647, + NULL}, + [165] = {8191, {.tv_sec = 262176, .tv_usec = 3664}, 2147483647, + NULL}, + [166] = {8191, {.tv_sec = 262176, .tv_usec = 999999}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [167] = {8191, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [168] = {8191, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [169] = {8191, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [170] = {8191, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [171] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [172] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [173] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [174] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [175] = {8191, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, +}; + +ATF_TC(tvtohz); +ATF_TC_HEAD(tvtohz, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test tvtohz(9)"); +} +ATF_TC_BODY(tvtohz, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(tvtohz_cases); i++) { + const struct tvtohz_case *tv = &tvtohz_cases[i]; + int ticks; + + /* set system parameters */ + hz = tv->tv_hz; + tick = 1000000/hz; + + ticks = tvtohz(&tv->tv_tv); + if (tv->tv_xfail) + atf_tc_expect_fail("%s", tv->tv_xfail); + + /* + * Allow some slop of one part per thousand in the + * arithmetic, but ensure we round up, not down. + * + * XXX Analytically determine error bounds on the + * formulae we use and assess them. + */ + ATF_CHECK_MSG(((unsigned)(ticks - tv->tv_ticks) <= + (unsigned)tv->tv_ticks/1000), + "[%zu] tvtohz(%lld.%06ld sec) @ %d Hz:" + " expected %d, got %d", + i, + (long long)tv->tv_tv.tv_sec, + (long)tv->tv_tv.tv_usec, + tv->tv_hz, + tv->tv_ticks, + ticks); + if (tv->tv_xfail) + atf_tc_expect_pass(); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, itimer_transitions); + ATF_TP_ADD_TC(tp, tstohz); + ATF_TP_ADD_TC(tp, tvtohz); + + return atf_no_error(); +} + diff --git a/kernel/t_unmount.c b/kernel/t_unmount.c new file mode 100644 index 000000000000..41ed39082e61 --- /dev/null +++ b/kernel/t_unmount.c @@ -0,0 +1,106 @@ +/* $NetBSD: t_unmount.c,v 1.4 2024/10/02 17:16:32 bad Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT 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. + */ +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2024\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_unmount.c,v 1.4 2024/10/02 17:16:32 bad Exp $"); + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/vnode.h> + +#include <rump/rump.h> +#include <rump/rumpvnode_if.h> +#include <rump/rump_syscalls.h> + +#include <fs/tmpfs/tmpfs_args.h> + +#include <atf-c.h> +#include <errno.h> +#include <stdio.h> + +#include "h_macros.h" + +ATF_TC(async); +ATF_TC_HEAD(async, tc) +{ + atf_tc_set_md_var(tc, + "descr", "failed unmount of async fs should stay async"); +} + +#define MP "/mnt" + +ATF_TC_BODY(async, tc) +{ + struct tmpfs_args args; + struct vnode *vp; + extern struct vnode *rumpns_rootvnode; + + RZ(rump_init()); + + memset(&args, 0, sizeof(args)); + args.ta_version = TMPFS_ARGS_VERSION; + args.ta_root_mode = 0777; + + /* create mount point and mount a tmpfs on it */ + RL(rump_sys_mkdir(MP, 0777)); + RL(rump_sys_mount(MOUNT_TMPFS, MP, MNT_ASYNC, &args, sizeof(args))); + + /* make sure the tmpfs is busy */ + RL(rump_sys_chdir(MP)); + + /* need a stable lwp for componentname */ + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + + /* get vnode of MP, unlocked */ + RZ(rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, MP, NULL, &vp, NULL)); + + /* make sure we didn't just get the root vnode */ + ATF_REQUIRE_MSG((rumpns_rootvnode != vp), "drat! got the root vnode"); + + printf("mnt_iflag & IMNT_ONWORKLIST == %d\n", + (vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) != 0); + + /* can't unmount a busy file system */ + ATF_REQUIRE_ERRNO(EBUSY, rump_sys_unmount(MP, 0) == -1); + + printf("mnt_iflag & IMNT_ONWORKLIST == %d\n", + (vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) != 0); + + + ATF_REQUIRE_MSG(((vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) == 0), + "mount point on syncer work list"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, async); + + return atf_no_error(); +} |
