git: 74a2bf1b7a7f - main - libsys: add pdrfork_thread() on x86

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 26 Jan 2026 19:30:57 UTC
The branch main has been updated by kib:

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

commit 74a2bf1b7a7ff0c872499cb94df24713f61c872c
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-01-25 17:33:05 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-01-26 19:30:05 +0000

    libsys: add pdrfork_thread() on x86
    
    Reviewed by:    asomers
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54879
---
 lib/libsys/amd64/Makefile.sys     |   3 +-
 lib/libsys/amd64/Symbol.sys.map   |   4 ++
 lib/libsys/amd64/pdrfork_thread.S |  83 +++++++++++++++++++++++++++++++
 lib/libsys/i386/Makefile.sys      |   2 +-
 lib/libsys/i386/Symbol.sys.map    |   4 ++
 lib/libsys/i386/pdrfork_thread.S  | 101 ++++++++++++++++++++++++++++++++++++++
 sys/sys/procdesc.h                |   1 +
 7 files changed, 196 insertions(+), 2 deletions(-)

diff --git a/lib/libsys/amd64/Makefile.sys b/lib/libsys/amd64/Makefile.sys
index 8134bdc422a6..fc8ebe796081 100644
--- a/lib/libsys/amd64/Makefile.sys
+++ b/lib/libsys/amd64/Makefile.sys
@@ -4,6 +4,7 @@ SRCS+=	\
 	amd64_set_fsbase.c \
 	amd64_set_gsbase.c \
 	amd64_set_tlsbase.c \
-	rfork_thread.S
+	rfork_thread.S \
+	pdrfork_thread.S
 
 MDASM=	vfork.S cerror.S getcontext.S
diff --git a/lib/libsys/amd64/Symbol.sys.map b/lib/libsys/amd64/Symbol.sys.map
index 11e0507b6613..b037e12d45f5 100644
--- a/lib/libsys/amd64/Symbol.sys.map
+++ b/lib/libsys/amd64/Symbol.sys.map
@@ -17,6 +17,10 @@ FBSD_1.8 {
 	amd64_set_tlsbase;
 };
 
+FBSD_1.9 {
+	pdrfork_thread;
+};
+
 FBSDprivate_1.0 {
 	_vfork;
 };
diff --git a/lib/libsys/amd64/pdrfork_thread.S b/lib/libsys/amd64/pdrfork_thread.S
new file mode 100644
index 000000000000..cd187ae456ae
--- /dev/null
+++ b/lib/libsys/amd64/pdrfork_thread.S
@@ -0,0 +1,83 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright 2003 Alan L. Cox <alc@cs.rice.edu>
+ * Copyright 2026 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by
+ * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
+ * the FreeBSD Foundation.
+ */
+
+#include <machine/asm.h>
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ *                %rdi %esi     %rdx     %rcx        %r8        %r9
+ * pdrfork_thread(fdp, pdflags, rfflags, stack_addr, start_fnc, start_arg);
+ *
+ * fdp			Pointer for the resulting fd location
+ * pdflags		Flags as to pdfork.
+ * rfflags:		Flags as to rfork.
+ * stack_addr:		Top of stack for thread.
+ * start_fnc:		Address of thread function to call in child.
+ * start_arg:		Argument to pass to the thread function in child.
+ */
+
+ENTRY(pdrfork_thread)
+	pushq	%rbx
+	pushq	%r12
+	pushq	%r13
+	movq	%r8, %rbx
+	movq	%r9, %r12
+	movq	%rcx, %r13
+
+	/*
+	 * Prepare and execute the thread creation syscall
+	 */
+	_SYSCALL(pdrfork)
+	jb 	2f
+
+	/*
+	 * Check to see if we are in the parent or child
+	 */
+	cmpl	$0, %edx
+	jnz	1f
+	popq	%r13
+	popq	%r12
+	popq	%rbx
+	ret
+
+	/*
+	 * If we are in the child (new thread), then
+	 * set-up the call to the internal subroutine.  If it
+	 * returns, then call __exit.
+	 */
+1:
+	movq	%r13, %rsp
+	movq	%r12, %rdi
+	call	*%rbx
+	movl	%eax, %edi
+
+	/*
+	 * Exit system call
+	 */
+	_SYSCALL(exit)
+
+	/*
+	 * Branch here if the thread creation fails:
+	 */
+2:
+	popq	%r13
+	popq	%r12
+	popq	%rbx
+	jmp	HIDENAME(cerror)
+END(pdrfork_thread)
+
+	.section .note.GNU-stack,"",%progbits
diff --git a/lib/libsys/i386/Makefile.sys b/lib/libsys/i386/Makefile.sys
index 2957dc548cf8..69507d930f25 100644
--- a/lib/libsys/i386/Makefile.sys
+++ b/lib/libsys/i386/Makefile.sys
@@ -1,7 +1,7 @@
 SRCS+=	i386_get_fsbase.c i386_get_gsbase.c i386_get_ioperm.c i386_get_ldt.c \
 	i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c \
 	i386_clr_watch.c i386_set_watch.c i386_vm86.c \
-	rfork_thread.S
+	rfork_thread.S pdrfork_thread.S
 
 MDASM=	vfork.S cerror.S getcontext.S syscall.S
 
diff --git a/lib/libsys/i386/Symbol.sys.map b/lib/libsys/i386/Symbol.sys.map
index 6b3169336a3f..a35349e4953b 100644
--- a/lib/libsys/i386/Symbol.sys.map
+++ b/lib/libsys/i386/Symbol.sys.map
@@ -20,6 +20,10 @@ FBSD_1.6 {
 	 x86_pkru_unprotect_range;
 };
 
+FBSD_1.9 {
+	pdrfork_thread;
+};
+
 FBSDprivate_1.0 {
 	_vfork;
 };
diff --git a/lib/libsys/i386/pdrfork_thread.S b/lib/libsys/i386/pdrfork_thread.S
new file mode 100644
index 000000000000..92a45fc4783f
--- /dev/null
+++ b/lib/libsys/i386/pdrfork_thread.S
@@ -0,0 +1,101 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright 2026 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by
+ * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
+ * the FreeBSD Foundation.
+ */
+
+#include <machine/asm.h>
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ *              8    12      16       20          24         28
+ * rfork_thread(fdp, pdflags rfflags, stack_addr, start_fnc, start_arg);
+ *
+ * fdp			Pointer for the resulting fd location
+ * pdflags		Flags as to pdfork.
+ * rfflags:		Flags as to rfork.
+ * stack_addr:		Top of stack for thread.
+ * start_fnc:		Address of thread function to call in child.
+ * start_arg:		Argument to pass to the thread function in child.
+ */
+
+ENTRY(pdrfork_thread)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%esi
+
+	/*
+	 * Push thread info onto the new thread's stack
+	 */
+	movl	20(%ebp), %esi	# get stack addr
+
+	subl	$4, %esi
+	movl	28(%ebp), %eax	# get start argument
+	movl	%eax, (%esi)
+
+	subl	$4, %esi
+	movl	24(%ebp), %eax	# get start thread address
+	movl	%eax, (%esi)
+
+	/*
+	 * Prepare and execute the thread creation syscall
+	 */
+	pushl	16(%ebp)
+	pushl	12(%ebp)
+	pushl	8(%ebp)
+	pushl	$0
+	_SYSCALL(pdrfork)
+	jb 	2f
+
+	/*
+	 * Check to see if we are in the parent or child
+	 */
+	cmpl	$0, %edx
+	jnz	1f
+	addl	$16, %esp
+	popl	%esi
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+	.p2align 2
+
+	/*
+	 * If we are in the child (new thread), then
+	 * set-up the call to the internal subroutine.  If it
+	 * returns, then call __exit.
+	 */
+1:
+	movl	%esi,%esp
+	popl	%eax
+	call	*%eax
+	addl	$4, %esp
+
+	/*
+	 * Exit system call
+	 */
+	pushl	%eax
+	pushl	$0
+	_SYSCALL(exit)
+
+	/*
+	 * Branch here if the thread creation fails:
+	 */
+2:
+	addl	$16, %esp
+	popl	%esi
+	movl	%ebp, %esp
+	popl	%ebp
+	jmp	HIDENAME(cerror)
+END(pdrfork_thread)
+
+	.section .note.GNU-stack,"",%progbits
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index 6a9168b04a68..b477903f8053 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -130,6 +130,7 @@ pid_t	 pdrfork(int *, int, int);
 int	 pdkill(int, int);
 int	 pdgetpid(int, pid_t *);
 int	 pdwait(int, int *, int, struct __wrusage *, struct __siginfo *);
+pid_t	 pdrfork_thread(int *, int, int, void *, int (*)(void *), void *);
 __END_DECLS
 
 #endif /* _KERNEL */