aboutsummaryrefslogtreecommitdiff
path: root/kernel/arch/hppa
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/arch/hppa')
-rw-r--r--kernel/arch/hppa/contextspfunc.S48
-rw-r--r--kernel/arch/hppa/execregs.c387
-rw-r--r--kernel/arch/hppa/execregs.h157
-rw-r--r--kernel/arch/hppa/execsp.S130
-rw-r--r--kernel/arch/hppa/h_execregs.S168
-rw-r--r--kernel/arch/hppa/signalsphandler.S46
-rw-r--r--kernel/arch/hppa/stack_pointer.h35
-rw-r--r--kernel/arch/hppa/threadspfunc.S43
8 files changed, 1014 insertions, 0 deletions
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)