All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/41] Misc 2026q2 v4 patches
@ 2026-09-18  4:23 Warner Losh
  2026-09-18  4:23 ` [PULL 01/41] bsd-user: Upstream most of the remaining system calls Warner Losh
                   ` (41 more replies)
  0 siblings, 42 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Pierrick Bouvier,
	Philippe Mathieu-Daudé

The following changes since commit 3b5d71cc3652fa7f5ecc449f05dae3ead2b718d7:

  Merge tag 'pull-ufs-20260918' of https://gitlab.com/jeuk20.kim/qemu into staging (2026-09-17 15:18:09 -1000)

are available in the Git repository at:

  git@gitlab.com:bsdimp/qemu-from-official.git tags/misc-2026q2-v4-pull-request

for you to fetch changes up to 1f71ada86d7ad43c7241a6ae96912139ec3a6a7e:

  bsd-user Update random_seed on thread creation (2026-09-17 22:07:42 -0600)

----------------------------------------------------------------
bsd-user: Upstream most of the remaining system calls

Upstream the file, thread, socket and remaining signal system calls (too
numerous to list here).

This series is an ambitous use of claude to help me upstream all the
remaining system calls. I've batched them together in what I think are
reasonable chunks, and had claude do the grunt work of copying the code
over and attributing the commits from our complex branching history. The
chopping up was a bit arbitrary, but I think it's good. The commit
messages may be a little weak, but may also be OK. I've also double
checked the style and made fixes upstream for them as well. Claude also
reviewed all these changes and found a few bugs that I've fixed. I've
personally read through them all and haven't found anything glaring. I
fixed all the bugs that were found, in most cases differently than
claude's suggestions.

I've added 'Assisted-by: Claude...' to all these commits to reflect my
leaning on Claude so hard. This use falls within the 'non-creative' use
that the Qemu project has said is OK. If that's not the right thing to
do, I can remove them.

This leaves sysctl translation, the powerpc architecture support,
coredumps and a transition to 'truss' based system call tracing. With
these changes applied we'er down from a high of about 30k lines of diffs
to only 5k (not counting genereted, but checked in files in blitz). The
changes are 8k, so maybe a bit ambitious from that perspective as well.

There's a few lines over 80 that I've not cleaned up. Let me know if
that's a problem. The other warnings are about adding files, and there's
no new MAINTAINERS entry needed. And the 'arch dependent defines should
be avoided' are needed to cope with different FreeBSD build systems
having different system calls.

Note, this is called out below too, but in v2 I've folded back all the
fixes based on some out-of-band feedback I recieved to do this the
normal way and the qemu project isn't interested in the fixes to fixes.

Note that in v3 I've added a rather long generated file. I generated it
automatically looking at the type annocations in FreeBSD on the socket
options in comments. I had to augment the annotations, so I can't just
generate it within the build from the installed headers until it's
merged from head and then merges to stable branches and then waiting for
a release on each of them (6-9 months given FreeBSD's release schedule).
Also note: there's a couple left over issues from v2, so if I've not
taken care of them all, please gently remind me if you think action
is still needed after my comments before.

And in v3 I've added some random_seed fixes for fork/new threads
since we're upstreaming those files. These should be correct now,
but I'm looking for the correction.

In v4, I've rebased to post 11.1.0 master, and fixed the issues that
were highlighted in the last review. Some comments I rejected, for now,
since they were refactoring code that's hard to test. I've also juggled
many patch hunks between revisions so they all compile w/o warnings.

I've created annotation in FreeBSD to allow us, in the future, to
generate os-sockopt.h from the installed headers. It will take a while
for that to work its way into all the supported releases, so in the mean
time I'm committing the generated os-sockopt.h file. I've ignored the
too-long-line warnings and errors for this file because there's no
reason for this file to conform to style.

To: qemu-devel@nongnu.org
Cc: Kyle Evans <kevans@freebsd.org>
Cc: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Warner Losh <imp@bsdimp.com>

---
Changes in v5:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v4: https://lore.kernel.org/qemu-devel/20260818-misc-2026q2-v4-0-09bf5647c98e@bsdimp.com

Changes in v4:
- Fix the rebase errors in v3.
- Rebase to post 11.1.0.
- Fix overly large chunking with syscalls-defs.h by breaking it up
- Tweak syscalls-defs.h with an eye toward diff reduction to blitz
- Break out realpath fix
- Various chunks shuffled to make each patch compile w/o warnings
- better get/setsockopt implementaiton
- Link to v3: https://lore.kernel.org/qemu-devel/20260620-misc-2026q2-v3-0-f6ce23ad8dda@bsdimp.com

Changes in v3:
- refactor get/setsockopt, including new generated file
- add random_seed fixes to fork
- move adding of .c files to meson.build to where we add the file.
- Fix acl bounds checking
- Fix indentation and other misc nits
- copy_to/from_user needs to be abi_long
- Fix toggling of the _ at the end of BSD_PROC_H
- Fix leak in error paths in do_freebsd_ktimer_create
- Don't write back on ktimer_gettime errors
- Be more careful about EINTR returns
- do_freebsd_ntp_adjtime needs to return failures from h2t_freebsd_timex
- do_freebsd_ktimer_gettime shouldn't writeback on error
- t2h_freebsd_umtx_time needs to unlock_user on error path
- Prefer abi_long for all pointers in extattr
- Remove accidentally duplicated prototypes.
- Don't writeback the eventlist, we're just reading it
- Add missing 'do' to the macro
- Byte swap sival_ptr in convertion
- Add missing get_errno call to safe___umtx_op
- Don't write back if getsockopt fails
- Write back correct number of bytes for do_bsd_recvfrom
- Loop through cnt, not maxcnt for acl conversion
- Fix getsockopt size computation
- Return ret, not errno, since do_freebsd_new_thr doesn't touch errno
- Fixed off by one in connectat: we need the bug compat fix here too
- Fixed error in preadv: copy params backwards
- Link to v2: https://lore.kernel.org/qemu-devel/20260518-misc-2026q2-v2-0-6c16fe448301@bsdimp.com

Changes in v2:
- don't write offsets on errors for copy_file_range
- pipe2: Check the raw system call value directly
- setsockopt: Check target_to_host_ip_mreq return value
- <several places>: Check return value of host_to_target_sockaddr
- do_bsd_setsockopt: Read in the socket option
- ntp_gettime: write back time on non-errors, not just 0
- do_freebsd_sigtimedwait check t2h_freebsd_timespec return
- do_freebsd_swapcontext writing incorrectly, readonly data (0 to user_unlock)
- do_thr_set_name needs get_errno()
- Have ntp_adjtime write back the structure
- kevent_freebsd11 no need to explicitly mask, datatypes do this for us
- do_freebsd_setcontext just reads the mcontext, 0 in unlock_user
- target_to_host_sigevent is read-only, so pass 0 in unlock_user
- target_to_host_ip_mreq needs tswap32 for int32_t
- use get_errno on kenv return values to report errors better
- kevent: only copy the number of events returns, not whole buffer
- Copy tolerance field of timex
- freebsd_umtx_sem_wake use VERIFY_READ instead of write to read struct
- Avoid double g2h_untagged mistakes in !_UMTX_OPTIMIZED
- Fixed additional missing unlock in freebsd_rw_rdlock and freebsd_rw_wrlock in !_UMTX_OPTIMIZED
- Squashed all the bug commit back to the appropriate earleir patch
- Link to v1: https://lore.kernel.org/qemu-devel/20260515-misc-2026q2-v1-0-5438ca41b27a@bsdimp.com
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - https://gpgtools.org

iQJPBAABCgA5FiEEIDX4lLAKo898zeG3bBzRKH2wEQAFAmqsvHsbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwzAAoJEGwc0Sh9sBEAhSgP/2ZXhHkkhQVUYzUhhM5K
vsOO/cJXMoTdvGlW8fG1bofHm4znS/WQvMxTaCOW6b472YLmRWkg+DSp5LqwZp/n
4VjQE0guaxUS9fQloPKFslfCmWaeszfiFR3W3VX2qxIZngMDbBLPJwwj5m8HHorG
oEYNTxW9kEIXBMlDeFW0A/rU+tQJSlfjaktbmCB03AvS9NpJNt0l1koA4IFwA0bO
9dK1hIXTQp/7iDcukRg6Q0PY12N0plI359hEz1O4A/sOcc9tFJ747Jeltw7TBCIH
A9sKPhwXsQYeWecCvSjyeYVa0A8BEC+bL2Ii2/g4waf6eYLy5UR6vLzQwsNsRy5w
CkLb614MXlpPPmxlWIo7Kr2aM6ZC8ictg0LBofxlqUz2Fn7rNVpEMFM23GgW+wgW
LeA4QVmN7jrMNdW0gOnsbMp8XPtJXkgaYj6xFzlRlI0PMTLMiwy2EF+9uuoRy+4k
2gnmcwOvZ3bnNRkCootzSGrrPQ1myUlqQlrHTCDPJxuPMRPP/mG9vYk0QcKAtZ5o
qR3El++zg0W+/kYH1/VQK+ekST07R161uOyItm8zPqq4SikhGRRujHUu0nLiL8t5
UU1ARZ63rDXZSnrS/ZI5iHkdFhM71Bf+wsHRjLsqtla1nbjp6Tmc4i19NX8PZwTW
0x8IkZhNH3ewbdFWb9p3MeTU
=DGJO
-----END PGP SIGNATURE-----

----------------------------------------------------------------

Warner Losh (41):
  bsd-user: Upstream most of the remaining system calls
  bsd-user: Rename cpu_env to env throughout bsd-user
  bsd-user: Fix copy direciton in preadv
  bsd-user: Add bsd-signal.h with sigaction through sigreturn
  bsd-user: Add signal shims sigwait through kill and os-signal.h
  bsd-user: Add signal system call dispatch
  bsd-user: move sys/shm.h lines
  bsd-user: Remove mmap defines
  bsd-user: Use target_suseconds_t
  bsd-user: Move sys/uuid.h defines
  bsd-user: Fix realpathat for FreeBSD 15.0 and newer
  bsd-user: Add os-file.h with chflagsat, close_range, and more
  bsd-user: Add poll, poll2, lseek, pipe, and swap system call shims
  bsd-user: Add FreeBSD socket helpers and sockaddr conversion
  bsd-user: Add bsd-socket.h with bind through getsockname
  bsd-user: Add socket shims socketpair through shutdown
  bsd-user: Commit the generated os-sockopt.h files
  bsd-user: Implement both getsockopt and setsockopt
  bsd-user: Add FreeBSD socket system calls
  bsd-user: Add os-socket.[ch] sendmsg, recvmsg and cmsg
  bsd-user: Add socket system call dispatch
  bsd-user: Add os-time.h with clock and time-of-day functions
  bsd-user: Add utimes, futimes, and ktimer functions to os-time.h
  bsd-user: Add select, pselect, and ppoll to os-time.h
  bsd-user: Add kqueue and kevent functions to os-time.h
  bsd-user: Add sigtimedwait, itimer, and futimens to os-time.h
  bsd-user: Add os-time.c and time-related type definitions
  bsd-user: Add time system call dispatch
  bsd-user: Add cpu_copy and make init_task_state non-static
  bsd-user: Add os-thread.h with thr and context functions
  bsd-user: Add do_freebsd__umtx_op to os-thread.h
  bsd-user: Add thread system call dispatch
  bsd-user: Add os-extattr.h with file and fd extattr functions
  bsd-user: Add link and list extattr functions to os-extattr.h
  bsd-user: Add ACL system call shims to os-extattr.h
  bsd-user: Add os-extattr.c with ACL conversion functions
  bsd-user: Add extended attribute and ACL system call dispatch
  bsd-user: Add scheduler and cpuset functions to os-misc.h
  bsd-user: Add scheduler, cpuset, kmod, and misc syscall dispatch
  bsd-user: Move qemu_guest_random_seed_main to same as linux-user
  bsd-user Update random_seed on thread creation

 bsd-user/aarch64/target.h     |    2 +-
 bsd-user/arm/target.h         |    2 +-
 bsd-user/bsd-file.h           |  168 +++-
 bsd-user/bsd-mem.h            |    4 +-
 bsd-user/bsd-proc.h           |   26 +-
 bsd-user/bsd-signal.h         |  231 +++++
 bsd-user/bsd-socket.c         |   98 ++
 bsd-user/bsd-socket.h         |  283 ++++++
 bsd-user/freebsd/meson.build  |    8 +-
 bsd-user/freebsd/os-extattr.c |  118 +++
 bsd-user/freebsd/os-extattr.h |  661 +++++++++++++
 bsd-user/freebsd/os-file.h    |  129 +++
 bsd-user/freebsd/os-misc.h    |  466 ++++++++-
 bsd-user/freebsd/os-proc.c    |    4 +-
 bsd-user/freebsd/os-proc.h    |   26 +-
 bsd-user/freebsd/os-signal.h  |   20 +
 bsd-user/freebsd/os-socket.c  |  239 +++++
 bsd-user/freebsd/os-socket.h  |  428 +++++++++
 bsd-user/freebsd/os-sockopt.h |  316 +++++++
 bsd-user/freebsd/os-stat.h    |    8 +-
 bsd-user/freebsd/os-sys.c     |    4 +-
 bsd-user/freebsd/os-syscall.c |  790 ++++++++++++++--
 bsd-user/freebsd/os-thread.c  | 1684 +++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-thread.h  |  596 ++++++++++++
 bsd-user/freebsd/os-time.c    |  347 +++++++
 bsd-user/freebsd/os-time.h    |  989 +++++++++++++++++++
 bsd-user/freebsd/qemu-os.h    |   48 +
 bsd-user/i386/target.h        |    2 +-
 bsd-user/main.c               |   38 +-
 bsd-user/meson.build          |    1 +
 bsd-user/qemu-bsd.h           |    8 +
 bsd-user/qemu.h               |   48 +-
 bsd-user/riscv/target.h       |    2 +-
 bsd-user/signal-common.h      |    4 +
 bsd-user/signal.c             |   67 ++
 bsd-user/syscall_defs.h       |  449 +++++++--
 bsd-user/x86_64/target.h      |    2 +-
 37 files changed, 8110 insertions(+), 206 deletions(-)
 create mode 100644 bsd-user/bsd-signal.h
 create mode 100644 bsd-user/bsd-socket.c
 create mode 100644 bsd-user/bsd-socket.h
 create mode 100644 bsd-user/freebsd/os-extattr.c
 create mode 100644 bsd-user/freebsd/os-extattr.h
 create mode 100644 bsd-user/freebsd/os-file.h
 create mode 100644 bsd-user/freebsd/os-signal.h
 create mode 100644 bsd-user/freebsd/os-socket.c
 create mode 100644 bsd-user/freebsd/os-socket.h
 create mode 100644 bsd-user/freebsd/os-sockopt.h
 create mode 100644 bsd-user/freebsd/os-thread.c
 create mode 100644 bsd-user/freebsd/os-thread.h
 create mode 100644 bsd-user/freebsd/os-time.c
 create mode 100644 bsd-user/freebsd/os-time.h

-- 
2.55.0



^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PULL 01/41] bsd-user: Upstream most of the remaining system calls
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 02/41] bsd-user: Rename cpu_env to env throughout bsd-user Warner Losh
                   ` (40 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Pierrick Bouvier,
	Philippe Mathieu-Daudé

Upstream the file, thread, socket and remaining signal system calls (too
numerous to list here).

This series is an ambitous use of claude to help me upstream all the
remaining system calls. I've batched them together in what I think are
reasonable chunks, and had claude do the grunt work of copying the code
over and attributing the commits from our complex branching history. The
chopping up was a bit arbitrary, but I think it's good. The commit
messages may be a little weak, but may also be OK. I've also double
checked the style and made fixes upstream for them as well. Claude also
reviewed all these changes and found a few bugs that I've fixed. I've
personally read through them all and haven't found anything glaring. I
fixed all the bugs that were found, in most cases differently than
claude's suggestions.

I've added 'Assisted-by: Claude...' to all these commits to reflect my
leaning on Claude so hard. This use falls within the 'non-creative' use
that the Qemu project has said is OK. If that's not the right thing to
do, I can remove them.

This leaves sysctl translation, the powerpc architecture support,
coredumps and a transition to 'truss' based system call tracing. With
these changes applied we'er down from a high of about 30k lines of diffs
to only 5k (not counting genereted, but checked in files in blitz). The
changes are 8k, so maybe a bit ambitious from that perspective as well.

There's a few lines over 80 that I've not cleaned up. Let me know if
that's a problem. The other warnings are about adding files, and there's
no new MAINTAINERS entry needed. And the 'arch dependent defines should
be avoided' are needed to cope with different FreeBSD build systems
having different system calls.

Note, this is called out below too, but in v2 I've folded back all the
fixes based on some out-of-band feedback I recieved to do this the
normal way and the qemu project isn't interested in the fixes to fixes.

Note that in v3 I've added a rather long generated file. I generated it
automatically looking at the type annocations in FreeBSD on the socket
options in comments. I had to augment the annotations, so I can't just
generate it within the build from the installed headers until it's
merged from head and then merges to stable branches and then waiting for
a release on each of them (6-9 months given FreeBSD's release schedule).
Also note: there's a couple left over issues from v2, so if I've not
taken care of them all, please gently remind me if you think action
is still needed after my comments before.

And in v3 I've added some random_seed fixes for fork/new threads
since we're upstreaming those files. These should be correct now,
but I'm looking for the correction.

In v4, I've rebased to post 11.1.0 master, and fixed the issues that
were highlighted in the last review. Some comments I rejected, for now,
since they were refactoring code that's hard to test. I've also juggled
many patch hunks between revisions so they all compile w/o warnings.

I've created annotation in FreeBSD to allow us, in the future, to
generate os-sockopt.h from the installed headers. It will take a while
for that to work its way into all the supported releases, so in the mean
time I'm committing the generated os-sockopt.h file. I've ignored the
too-long-line warnings and errors for this file because there's no
reason for this file to conform to style.

To: qemu-devel@nongnu.org
Cc: Kyle Evans <kevans@freebsd.org>
Cc: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Warner Losh <imp@bsdimp.com>

---
Changes in v5:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v4: https://lore.kernel.org/qemu-devel/20260818-misc-2026q2-v4-0-09bf5647c98e@bsdimp.com

Changes in v4:
- Fix the rebase errors in v3.
- Rebase to post 11.1.0.
- Fix overly large chunking with syscalls-defs.h by breaking it up
- Tweak syscalls-defs.h with an eye toward diff reduction to blitz
- Break out realpath fix
- Various chunks shuffled to make each patch compile w/o warnings
- better get/setsockopt implementaiton
- Link to v3: https://lore.kernel.org/qemu-devel/20260620-misc-2026q2-v3-0-f6ce23ad8dda@bsdimp.com

Changes in v3:
- refactor get/setsockopt, including new generated file
- add random_seed fixes to fork
- move adding of .c files to meson.build to where we add the file.
- Fix acl bounds checking
- Fix indentation and other misc nits
- copy_to/from_user needs to be abi_long
- Fix toggling of the _ at the end of BSD_PROC_H
- Fix leak in error paths in do_freebsd_ktimer_create
- Don't write back on ktimer_gettime errors
- Be more careful about EINTR returns
- do_freebsd_ntp_adjtime needs to return failures from h2t_freebsd_timex
- do_freebsd_ktimer_gettime shouldn't writeback on error
- t2h_freebsd_umtx_time needs to unlock_user on error path
- Prefer abi_long for all pointers in extattr
- Remove accidentally duplicated prototypes.
- Don't writeback the eventlist, we're just reading it
- Add missing 'do' to the macro
- Byte swap sival_ptr in convertion
- Add missing get_errno call to safe___umtx_op
- Don't write back if getsockopt fails
- Write back correct number of bytes for do_bsd_recvfrom
- Loop through cnt, not maxcnt for acl conversion
- Fix getsockopt size computation
- Return ret, not errno, since do_freebsd_new_thr doesn't touch errno
- Fixed off by one in connectat: we need the bug compat fix here too
- Fixed error in preadv: copy params backwards
- Link to v2: https://lore.kernel.org/qemu-devel/20260518-misc-2026q2-v2-0-6c16fe448301@bsdimp.com

Changes in v2:
- don't write offsets on errors for copy_file_range
- pipe2: Check the raw system call value directly
- setsockopt: Check target_to_host_ip_mreq return value
- <several places>: Check return value of host_to_target_sockaddr
- do_bsd_setsockopt: Read in the socket option
- ntp_gettime: write back time on non-errors, not just 0
- do_freebsd_sigtimedwait check t2h_freebsd_timespec return
- do_freebsd_swapcontext writing incorrectly, readonly data (0 to user_unlock)
- do_thr_set_name needs get_errno()
- Have ntp_adjtime write back the structure
- kevent_freebsd11 no need to explicitly mask, datatypes do this for us
- do_freebsd_setcontext just reads the mcontext, 0 in unlock_user
- target_to_host_sigevent is read-only, so pass 0 in unlock_user
- target_to_host_ip_mreq needs tswap32 for int32_t
- use get_errno on kenv return values to report errors better
- kevent: only copy the number of events returns, not whole buffer
- Copy tolerance field of timex
- freebsd_umtx_sem_wake use VERIFY_READ instead of write to read struct
- Avoid double g2h_untagged mistakes in !_UMTX_OPTIMIZED
- Fixed additional missing unlock in freebsd_rw_rdlock and freebsd_rw_wrlock in !_UMTX_OPTIMIZED
- Squashed all the bug commit back to the appropriate earleir patch
- Link to v1: https://lore.kernel.org/qemu-devel/20260515-misc-2026q2-v1-0-5438ca41b27a@bsdimp.com

--- b4-submit-tracking ---
# This section is used internally by b4 prep for tracking purposes.
{
  "series": {
    "revision": 5,
    "change-id": "20260504-misc-2026q2-a5af31ac032a",
    "prefixes": [],
    "history": {
      "v1": [
        "20260515-misc-2026q2-v1-0-5438ca41b27a@bsdimp.com"
      ],
      "v2": [
        "20260518-misc-2026q2-v2-0-6c16fe448301@bsdimp.com"
      ],
      "v3": [
        "20260620-misc-2026q2-v3-0-f6ce23ad8dda@bsdimp.com"
      ],
      "v4": [
        "20260818-misc-2026q2-v4-0-09bf5647c98e@bsdimp.com"
      ]
    }
  }
}
-- 
2.55.0



^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PULL 02/41] bsd-user: Rename cpu_env to env throughout bsd-user
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
  2026-09-18  4:23 ` [PULL 01/41] bsd-user: Upstream most of the remaining system calls Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 03/41] bsd-user: Fix copy direciton in preadv Warner Losh
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Replace 'void *cpu_env' parameters with 'CPUArchState *env' across all
bsd-user source files. This improves type safety and aligns with the
convention used in the rest of the codebase.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/aarch64/target.h     |  2 +-
 bsd-user/arm/target.h         |  2 +-
 bsd-user/bsd-file.h           | 28 +++++++++++-----------
 bsd-user/bsd-mem.h            |  4 ++--
 bsd-user/bsd-proc.h           |  8 +++----
 bsd-user/freebsd/os-proc.c    |  4 ++--
 bsd-user/freebsd/os-proc.h    | 26 ++++++++++-----------
 bsd-user/freebsd/os-sys.c     |  4 ++--
 bsd-user/freebsd/os-syscall.c | 44 +++++++++++++++++------------------
 bsd-user/i386/target.h        |  2 +-
 bsd-user/qemu.h               |  6 ++---
 bsd-user/riscv/target.h       |  2 +-
 bsd-user/x86_64/target.h      |  2 +-
 13 files changed, 67 insertions(+), 67 deletions(-)

diff --git a/bsd-user/aarch64/target.h b/bsd-user/aarch64/target.h
index 702aeb7fc5..37b9817fe1 100644
--- a/bsd-user/aarch64/target.h
+++ b/bsd-user/aarch64/target.h
@@ -12,7 +12,7 @@
 /*
  * aaarch64 ABI does not 'lump' the registers for 64-bit args.
  */
-static inline bool regpairs_aligned(void *cpu_env)
+static inline bool regpairs_aligned(CPUArchState *env)
 {
     return false;
 }
diff --git a/bsd-user/arm/target.h b/bsd-user/arm/target.h
index 7c423ec575..cf131f29fb 100644
--- a/bsd-user/arm/target.h
+++ b/bsd-user/arm/target.h
@@ -12,7 +12,7 @@
 /*
  * arm EABI 'lumps' the registers for 64-bit args.
  */
-static inline bool regpairs_aligned(void *cpu_env)
+static inline bool regpairs_aligned(CPUArchState *env)
 {
     return true;
 }
diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
index dca1518cb1..dec59bd80b 100644
--- a/bsd-user/bsd-file.h
+++ b/bsd-user/bsd-file.h
@@ -72,7 +72,7 @@ static abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
 }
 
 /* pread(2) */
-static abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_pread(CPUArchState *env, abi_long arg1,
     abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
 {
     abi_long ret;
@@ -82,7 +82,7 @@ static abi_long do_bsd_pread(void *cpu_env, abi_long arg1,
     if (p == NULL) {
         return -TARGET_EFAULT;
     }
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         arg4 = arg5;
         arg5 = arg6;
     }
@@ -109,14 +109,14 @@ static abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
 }
 
 /* preadv(2) */
-static abi_long do_bsd_preadv(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_preadv(CPUArchState *env, abi_long arg1,
     abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
 {
     abi_long ret;
     struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 1);
 
     if (vec != NULL) {
-        if (regpairs_aligned(cpu_env) != 0) {
+        if (regpairs_aligned(env) != 0) {
             arg4 = arg5;
             arg5 = arg6;
         }
@@ -151,7 +151,7 @@ static abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
 }
 
 /* pwrite(2) */
-static abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_pwrite(CPUArchState *env, abi_long arg1,
     abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
 {
     abi_long ret;
@@ -161,7 +161,7 @@ static abi_long do_bsd_pwrite(void *cpu_env, abi_long arg1,
     if (p == NULL) {
         return -TARGET_EFAULT;
     }
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         arg4 = arg5;
         arg5 = arg6;
     }
@@ -188,14 +188,14 @@ static abi_long do_bsd_writev(abi_long arg1, abi_long arg2, abi_long arg3)
 }
 
 /* pwritev(2) */
-static abi_long do_bsd_pwritev(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_pwritev(CPUArchState *env, abi_long arg1,
     abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
 {
     abi_long ret;
     struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
 
     if (vec != NULL) {
-        if (regpairs_aligned(cpu_env) != 0) {
+        if (regpairs_aligned(env) != 0) {
             arg4 = arg5;
             arg5 = arg6;
         }
@@ -484,14 +484,14 @@ static abi_long do_bsd_dup2(abi_long arg1, abi_long arg2)
 }
 
 /* truncate(2) */
-static abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_truncate(CPUArchState *env, abi_long arg1,
         abi_long arg2, abi_long arg3, abi_long arg4)
 {
     abi_long ret;
     void *p;
 
     LOCK_PATH(p, arg1);
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         arg2 = arg3;
         arg3 = arg4;
     }
@@ -502,10 +502,10 @@ static abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
 }
 
 /* ftruncate(2) */
-static abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_ftruncate(CPUArchState *env, abi_long arg1,
         abi_long arg2, abi_long arg3, abi_long arg4)
 {
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         arg2 = arg3;
         arg3 = arg4;
     }
@@ -735,7 +735,7 @@ static abi_long do_bsd_freebsd11_mknodat(abi_long arg1, abi_long arg2,
 }
 
 /* post-ino64 mknodat(2) */
-static abi_long do_bsd_mknodat(void *cpu_env, abi_long arg1,
+static abi_long do_bsd_mknodat(CPUArchState *env, abi_long arg1,
         abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5,
         abi_long arg6)
 {
@@ -744,7 +744,7 @@ static abi_long do_bsd_mknodat(void *cpu_env, abi_long arg1,
 
     LOCK_PATH(p, arg2);
        /* 32-bit arch's use two 32 registers for 64 bit return value */
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         ret = get_errno(mknodat(arg1, p, arg3, target_arg64(arg5, arg6)));
     } else {
         ret = get_errno(mknodat(arg1, p, arg3, target_arg64(arg4, arg5)));
diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h
index 9d7b60d3c3..3086143d40 100644
--- a/bsd-user/bsd-mem.h
+++ b/bsd-user/bsd-mem.h
@@ -51,11 +51,11 @@ extern abi_ulong target_brk;
 extern abi_ulong initial_target_brk;
 
 /* mmap(2) */
-static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
+static inline abi_long do_bsd_mmap(CPUArchState *env, abi_long arg1, abi_long arg2,
     abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
     abi_long arg8)
 {
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         arg6 = arg7;
         arg7 = arg8;
     }
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
index b1d4446ff1..7efc5b4c92 100644
--- a/bsd-user/bsd-proc.h
+++ b/bsd-user/bsd-proc.h
@@ -6,8 +6,8 @@
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#ifndef BSD_PROC_H_
-#define BSD_PROC_H_
+#ifndef BSD_PROC_H
+#define BSD_PROC_H
 
 #include <sys/resource.h>
 
@@ -19,7 +19,7 @@ extern int _getlogin(char*, int);
 int bsd_get_ncpu(void);
 
 /* exit(2) */
-static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
+static inline abi_long do_bsd_exit(CPUArchState *env, abi_long arg1)
 {
     gdb_exit(arg1);
     qemu_plugin_user_exit();
@@ -400,4 +400,4 @@ static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
     return get_errno(setpriority(which, who, prio));
 }
 
-#endif /* !BSD_PROC_H_ */
+#endif /* !BSD_PROC_H */
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
index 0309036178..0a0cea5bb2 100644
--- a/bsd-user/freebsd/os-proc.c
+++ b/bsd-user/freebsd/os-proc.c
@@ -238,7 +238,7 @@ h2t_procctl_reaper_pidinfo(struct procctl_reaper_pidinfo *host_pi,
 }
 
 abi_long
-do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3,
+do_freebsd_procctl(CPUArchState *env, int idtype, abi_ulong arg2, abi_ulong arg3,
        abi_ulong arg4, abi_ulong arg5, abi_ulong arg6)
 {
     abi_long error = 0, target_rp_pids;
@@ -257,7 +257,7 @@ do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2, abi_ulong arg3,
 
 #if TARGET_ABI_BITS == 32
     /* See if we need to align the register pairs. */
-    if (regpairs_aligned(cpu_env)) {
+    if (regpairs_aligned(env)) {
         id = (id_t)target_arg64(arg3, arg4);
         target_cmd = (int)arg5;
         target_arg = arg6;
diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h
index 1cf3c43de3..7a035f5481 100644
--- a/bsd-user/freebsd/os-proc.h
+++ b/bsd-user/freebsd/os-proc.h
@@ -68,7 +68,7 @@ static inline abi_long do_freebsd_wait4(abi_long arg1, abi_ulong target_status,
 }
 
 /* wait6(2) */
-static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype,
+static inline abi_long do_freebsd_wait6(CPUArchState *env, abi_long idtype,
     abi_long id1, abi_long id2,
     abi_ulong target_status, abi_long options, abi_ulong target_wrusage,
     abi_ulong target_infop, abi_ulong pad1)
@@ -79,7 +79,7 @@ static inline abi_long do_freebsd_wait6(void *cpu_env, abi_long idtype,
     siginfo_t info;
     void *p;
 
-    if (regpairs_aligned(cpu_env) != 0) {
+    if (regpairs_aligned(env) != 0) {
         /* printf("shifting args\n"); */
         /* 64-bit id is aligned, so shift all the arguments over by one */
         id1 = id2;
@@ -173,7 +173,7 @@ static inline abi_long do_freebsd___setugid(abi_long arg1)
 }
 
 /* fork(2) */
-static inline abi_long do_freebsd_fork(void *cpu_env)
+static inline abi_long do_freebsd_fork(CPUArchState *env)
 {
     abi_long ret;
     abi_ulong child_flag;
@@ -183,7 +183,7 @@ static inline abi_long do_freebsd_fork(void *cpu_env)
     if (ret == 0) {
         /* child */
         child_flag = 1;
-        target_cpu_clone_regs(cpu_env, 0);
+        target_cpu_clone_regs(env, 0);
     } else {
         /* parent */
         child_flag = 0;
@@ -193,7 +193,7 @@ static inline abi_long do_freebsd_fork(void *cpu_env)
      * The fork system call sets a child flag in the second return
      * value: 0 for parent process, 1 for child process.
      */
-    set_second_rval(cpu_env, child_flag);
+    set_second_rval(env, child_flag);
 
     fork_end(ret);
 
@@ -201,13 +201,13 @@ static inline abi_long do_freebsd_fork(void *cpu_env)
 }
 
 /* vfork(2) */
-static inline abi_long do_freebsd_vfork(void *cpu_env)
+static inline abi_long do_freebsd_vfork(CPUArchState *env)
 {
-    return do_freebsd_fork(cpu_env);
+    return do_freebsd_fork(env);
 }
 
 /* rfork(2) */
-static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
+static inline abi_long do_freebsd_rfork(CPUArchState *env, abi_long flags)
 {
     abi_long ret;
     abi_ulong child_flag;
@@ -228,7 +228,7 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
     if (ret == 0) {
         /* child */
         child_flag = 1;
-        target_cpu_clone_regs(cpu_env, 0);
+        target_cpu_clone_regs(env, 0);
     } else {
         /* parent */
         child_flag = 0;
@@ -238,7 +238,7 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
      * The fork system call sets a child flag in the second return
      * value: 0 for parent process, 1 for child process.
      */
-    set_second_rval(cpu_env, child_flag);
+    set_second_rval(env, child_flag);
     fork_end(ret);
 
     return ret;
@@ -246,7 +246,7 @@ static inline abi_long do_freebsd_rfork(void *cpu_env, abi_long flags)
 }
 
 /* pdfork(2) */
-static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
+static inline abi_long do_freebsd_pdfork(CPUArchState *env, abi_ulong target_fdp,
         abi_long flags)
 {
     abi_long ret;
@@ -258,7 +258,7 @@ static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
     if (ret == 0) {
         /* child */
         child_flag = 1;
-        target_cpu_clone_regs(cpu_env, 0);
+        target_cpu_clone_regs(env, 0);
     } else {
         /* parent */
         child_flag = 0;
@@ -271,7 +271,7 @@ static inline abi_long do_freebsd_pdfork(void *cpu_env, abi_ulong target_fdp,
      * The fork system call sets a child flag in the second return
      * value: 0 for parent process, 1 for child process.
      */
-    set_second_rval(cpu_env, child_flag);
+    set_second_rval(env, child_flag);
     fork_end(ret);
 
     return ret;
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
index df31706558..d6f7c92420 100644
--- a/bsd-user/freebsd/os-sys.c
+++ b/bsd-user/freebsd/os-sys.c
@@ -593,7 +593,7 @@ out:
 }
 
 /* sysarch() is architecture dependent. */
-abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+abi_long do_freebsd_sysarch(CPUArchState *env, abi_long arg1, abi_long arg2)
 {
-    return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
+    return do_freebsd_arch_sysarch(env, arg1, arg2);
 }
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 90ef1bd916..d402c64726 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -215,7 +215,7 @@ void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
 /*
  * All errnos that freebsd_syscall() returns must be -TARGET_<errcode>.
  */
-static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
                                 abi_long arg2, abi_long arg3, abi_long arg4,
                                 abi_long arg5, abi_long arg6, abi_long arg7,
                                 abi_long arg8)
@@ -227,19 +227,19 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
          * process system calls
          */
     case TARGET_FREEBSD_NR_fork: /* fork(2) */
-        ret = do_freebsd_fork(cpu_env);
+        ret = do_freebsd_fork(env);
         break;
 
     case TARGET_FREEBSD_NR_vfork: /* vfork(2) */
-        ret = do_freebsd_vfork(cpu_env);
+        ret = do_freebsd_vfork(env);
         break;
 
     case TARGET_FREEBSD_NR_rfork: /* rfork(2) */
-        ret = do_freebsd_rfork(cpu_env, arg1);
+        ret = do_freebsd_rfork(env, arg1);
         break;
 
     case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */
-        ret = do_freebsd_pdfork(cpu_env, arg1, arg2);
+        ret = do_freebsd_pdfork(env, arg1, arg2);
         break;
 
     case TARGET_FREEBSD_NR_execve: /* execve(2) */
@@ -255,12 +255,12 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_wait6: /* wait6(2) */
-        ret = do_freebsd_wait6(cpu_env, arg1, arg2, arg3,
+        ret = do_freebsd_wait6(env, arg1, arg2, arg3,
                                arg4, arg5, arg6, arg7, arg8);
         break;
 
     case TARGET_FREEBSD_NR_exit: /* exit(2) */
-        ret = do_bsd_exit(cpu_env, arg1);
+        ret = do_bsd_exit(env, arg1);
         break;
 
     case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */
@@ -424,7 +424,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_procctl: /* procctl(2) */
-        ret = do_freebsd_procctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_freebsd_procctl(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
         /*
@@ -435,7 +435,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_pread: /* pread(2) */
-        ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_bsd_pread(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_readv: /* readv(2) */
@@ -443,7 +443,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_preadv: /* preadv(2) */
-        ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_bsd_preadv(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_write: /* write(2) */
@@ -451,7 +451,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
-        ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_bsd_pwrite(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_writev: /* writev(2) */
@@ -459,7 +459,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
-        ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_bsd_pwritev(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_open: /* open(2) */
@@ -559,11 +559,11 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
-        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
+        ret = do_bsd_truncate(env, arg1, arg2, arg3, arg4);
         break;
 
     case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
-        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
+        ret = do_bsd_ftruncate(env, arg1, arg2, arg3, arg4);
         break;
 
     case TARGET_FREEBSD_NR_acct: /* acct(2) */
@@ -595,7 +595,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
-        ret = do_bsd_readlink(cpu_env, arg1, arg2, arg3);
+        ret = do_bsd_readlink(env, arg1, arg2, arg3);
         break;
 
     case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
@@ -627,7 +627,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
-        ret = do_bsd_mknodat(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_bsd_mknodat(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_chown: /* chown(2) */
@@ -807,7 +807,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
          * Memory management system calls.
          */
     case TARGET_FREEBSD_NR_mmap: /* mmap(2) */
-        ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+        ret = do_bsd_mmap(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                           arg8);
         break;
 
@@ -953,15 +953,15 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
          * sys{ctl, arch, call}
          */
     case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
-        ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_freebsd_sysctl(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR___sysctlbyname: /* sysctlbyname(2) */
-        ret = do_freebsd_sysctlbyname(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = do_freebsd_sysctlbyname(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
     case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */
-        ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
+        ret = do_freebsd_sysarch(env, arg1, arg2);
         break;
 
     default:
@@ -979,7 +979,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
  * as a wrapper around freebsd_syscall() so that actually happens. Since
  * that is a singleton, modern compilers will inline it anyway...
  */
-abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+abi_long do_freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
                             abi_long arg2, abi_long arg3, abi_long arg4,
                             abi_long arg5, abi_long arg6, abi_long arg7,
                             abi_long arg8)
@@ -990,7 +990,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
     }
 
-    ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6,
+    ret = freebsd_syscall(env, num, arg1, arg2, arg3, arg4, arg5, arg6,
                           arg7, arg8);
     if (do_strace) {
         print_freebsd_syscall_ret(num, ret);
diff --git a/bsd-user/i386/target.h b/bsd-user/i386/target.h
index ddd3b8ec08..9cd158fc11 100644
--- a/bsd-user/i386/target.h
+++ b/bsd-user/i386/target.h
@@ -12,7 +12,7 @@
 /*
  * i386 doesn't 'lump' the registers for 64-bit args.
  */
-static inline bool regpairs_aligned(void *cpu_env)
+static inline bool regpairs_aligned(CPUArchState *env)
 {
     return false;
 }
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index b0b2c249fb..60d1adf560 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -176,7 +176,7 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
 void target_set_brk(abi_ulong new_brk);
 abi_long do_brk(abi_ulong new_brk);
 void syscall_init(void);
-abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+abi_long do_freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
                             abi_long arg2, abi_long arg3, abi_long arg4,
                             abi_long arg5, abi_long arg6, abi_long arg7,
                             abi_long arg8);
@@ -238,7 +238,7 @@ int host_to_target_errno(int err);
 /* os-proc.c */
 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
         abi_ulong guest_envp, int do_fexec);
-abi_long do_freebsd_procctl(void *cpu_env, int idtype, abi_ulong arg2,
+abi_long do_freebsd_procctl(CPUArchState *env, int idtype, abi_ulong arg2,
         abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6);
 
 /* os-sys.c */
@@ -247,7 +247,7 @@ abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
 abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
         int32_t namelen, abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp,
         abi_ulong newlen);
-abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
+abi_long do_freebsd_sysarch(CPUArchState *env, abi_long arg1, abi_long arg2);
 
 /* user access */
 
diff --git a/bsd-user/riscv/target.h b/bsd-user/riscv/target.h
index 036ddd185e..dc3e0be795 100644
--- a/bsd-user/riscv/target.h
+++ b/bsd-user/riscv/target.h
@@ -12,7 +12,7 @@
 /*
  * riscv64 ABI does not 'lump' the registers for 64-bit args.
  */
-static inline bool regpairs_aligned(void *cpu_env)
+static inline bool regpairs_aligned(CPUArchState *env)
 {
     return false;
 }
diff --git a/bsd-user/x86_64/target.h b/bsd-user/x86_64/target.h
index 0cf0e2a14a..fccfc593bd 100644
--- a/bsd-user/x86_64/target.h
+++ b/bsd-user/x86_64/target.h
@@ -12,7 +12,7 @@
 /*
  * x86 doesn't 'lump' the registers for 64-bit args, all args are 64 bits.
  */
-static inline bool regpairs_aligned(void *cpu_env)
+static inline bool regpairs_aligned(CPUArchState *env)
 {
     return false;
 }
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 03/41] bsd-user: Fix copy direciton in preadv
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
  2026-09-18  4:23 ` [PULL 01/41] bsd-user: Upstream most of the remaining system calls Warner Losh
  2026-09-18  4:23 ` [PULL 02/41] bsd-user: Rename cpu_env to env throughout bsd-user Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 04/41] bsd-user: Add bsd-signal.h with sigaction through sigreturn Warner Losh
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Richard Henderson

As written, we copy in the vector and data then don't copy it out, when
instead. Instead, we should copy the data out. pread and read are
already correct.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-file.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
index dec59bd80b..7ef9470c4e 100644
--- a/bsd-user/bsd-file.h
+++ b/bsd-user/bsd-file.h
@@ -113,7 +113,7 @@ static abi_long do_bsd_preadv(CPUArchState *env, abi_long arg1,
     abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 1);
+    struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
 
     if (vec != NULL) {
         if (regpairs_aligned(env) != 0) {
@@ -121,7 +121,7 @@ static abi_long do_bsd_preadv(CPUArchState *env, abi_long arg1,
             arg5 = arg6;
         }
         ret = get_errno(safe_preadv(arg1, vec, arg3, target_arg64(arg4, arg5)));
-        unlock_iovec(vec, arg2, arg3, 0);
+        unlock_iovec(vec, arg2, arg3, 1);
     } else {
         ret = -host_to_target_errno(errno);
     }
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 04/41] bsd-user: Add bsd-signal.h with sigaction through sigreturn
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (2 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 03/41] bsd-user: Fix copy direciton in preadv Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 05/41] bsd-user: Add signal shims sigwait through kill and os-signal.h Warner Losh
                   ` (37 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Jessica Clarke,
	Mikaël Urankar, Pierrick Bouvier, Richard Henderson

Add the first set of signal-related system call shims: sigaction,
sigprocmask, sigpending, sigsuspend, and sigreturn. Also add the
do_sigprocmask and target_to_host_sigevent helper functions to signal.c
and their declarations to signal-common.h.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-signal.h         | 151 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-syscall.c |   1 +
 bsd-user/signal-common.h      |   4 +
 bsd-user/signal.c             |  67 +++++++++++++++
 4 files changed, 223 insertions(+)
 create mode 100644 bsd-user/bsd-signal.h

diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
new file mode 100644
index 0000000000..49e58d7436
--- /dev/null
+++ b/bsd-user/bsd-signal.h
@@ -0,0 +1,151 @@
+/*
+ * signal related system call shims
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef BSD_SIGNAL_H
+#define BSD_SIGNAL_H
+
+#include <signal.h>
+
+/* sigaction(2) */
+static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2,
+                                        abi_long arg3)
+{
+    abi_long ret;
+    struct target_sigaction *old_act, act, oact, *pact;
+
+    if (arg2) {
+        if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) {
+            return -TARGET_EFAULT;
+        }
+        act._sa_handler = old_act->_sa_handler;
+        act.sa_flags = old_act->sa_flags;
+        memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg2, 0);
+        pact = &act;
+    } else {
+        pact = NULL;
+    }
+    ret = get_errno(do_sigaction(arg1, pact, &oact));
+    if (!is_error(ret) && arg3) {
+        if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) {
+            return -TARGET_EFAULT;
+        }
+        old_act->_sa_handler = oact._sa_handler;
+        old_act->sa_flags = oact.sa_flags;
+        memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t));
+        unlock_user_struct(old_act, arg3, 1);
+    }
+    return ret;
+}
+
+
+/* sigprocmask(2) */
+static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2,
+                                          abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set, oldset, *set_ptr;
+    int how;
+
+    ret = 0;
+    if (arg2) {
+        p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&set, p);
+        unlock_user(p, arg2, 0);
+        set_ptr = &set;
+        switch (arg1) {
+        case TARGET_SIG_BLOCK:
+            how = SIG_BLOCK;
+            break;
+        case TARGET_SIG_UNBLOCK:
+            how = SIG_UNBLOCK;
+            break;
+        case TARGET_SIG_SETMASK:
+            how = SIG_SETMASK;
+            break;
+        default:
+            return -TARGET_EINVAL;
+        }
+    } else {
+        how = 0;
+        set_ptr = NULL;
+    }
+    ret = do_sigprocmask(how, set_ptr, &oldset);
+    if (!is_error(ret) && arg3) {
+        p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &oldset);
+        unlock_user(p, arg3, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigpending(2) */
+static inline abi_long do_bsd_sigpending(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+
+    ret = get_errno(sigpending(&set));
+    if (!is_error(ret)) {
+        p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_sigset(p, &set);
+        unlock_user(p, arg1, sizeof(target_sigset_t));
+    }
+    return ret;
+}
+
+/* sigsuspend(2) */
+static inline abi_long do_bsd_sigsuspend(CPUArchState *env, abi_long arg1,
+                                         abi_long arg2)
+{
+    CPUState *cpu = env_cpu(env);
+    TaskState *ts = cpu->opaque;
+    void *p;
+    abi_long ret;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&ts->sigsuspend_mask, p);
+    unlock_user(p, arg1, 0);
+
+    ret = get_errno(sigsuspend(&ts->sigsuspend_mask));
+    /* XXX Trivially true until safe_syscall */
+    if (ret != -TARGET_ERESTART) {
+        ts->in_sigsuspend = true;
+    }
+
+    return ret;
+}
+
+/* sigreturn(2) */
+static inline abi_long do_bsd_sigreturn(CPUArchState *env, abi_long arg1)
+{
+    if (block_signals()) {
+        return -TARGET_ERESTART;
+    }
+    return do_sigreturn(env, arg1);
+}
+
+/* sigvec(2) - not defined */
+/* sigblock(2) - not defined */
+/* sigsetmask(2) - not defined */
+/* sigstack(2) - not defined */
+
+#endif /* BSD_SIGNAL_H */
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index d402c64726..7fefdb569f 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -38,6 +38,7 @@
 #include "bsd-mem.h"
 #include "bsd-proc.h"
 #include "bsd-misc.h"
+#include "bsd-signal.h"
 
 /* BSD dependent syscall shims */
 #include "os-stat.h"
diff --git a/bsd-user/signal-common.h b/bsd-user/signal-common.h
index 4e634e04a3..9071757873 100644
--- a/bsd-user/signal-common.h
+++ b/bsd-user/signal-common.h
@@ -32,6 +32,7 @@ int block_signals(void); /* Returns non zero if signal pending */
 long do_rt_sigreturn(CPUArchState *env);
 int do_sigaction(int sig, const struct target_sigaction *act,
                 struct target_sigaction *oact);
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
 long do_sigreturn(CPUArchState *env, abi_ulong addr);
 void force_sig_fault(int sig, int code, abi_ulong addr);
@@ -42,6 +43,9 @@ void process_pending_signals(CPUArchState *env);
 void queue_signal(CPUArchState *env, int sig, int si_type,
                   target_siginfo_t *info);
 void signal_init(void);
+abi_long target_to_host_sigevent(struct sigevent *host_sevp,
+                                 abi_ulong target_addr);
+int target_to_host_signal(int sig);
 void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
 
 /*
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 3e5e41e1b1..da7cf1d60b 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -346,6 +346,33 @@ int block_signals(void)
     return qatomic_xchg(&ts->signal_pending, 1);
 }
 
+abi_long target_to_host_sigevent(struct sigevent *host_sevp,
+                                               abi_ulong target_addr)
+{
+    struct target_sigevent *target_sevp;
+
+    if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * This union is awkward on 64 bit systems because it has a 32 bit
+     * integer and a pointer in it; we follow the conversion approach
+     * used for handling sigval types in signal.c so the guest should get
+     * the correct value back even if we did a 64 bit byteswap and it's
+     * using the 32 bit integer.
+     */
+    host_sevp->sigev_value.sival_ptr =
+        (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr);
+    host_sevp->sigev_signo =
+        target_to_host_signal(tswap32(target_sevp->sigev_signo));
+    host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify);
+    host_sevp->_sigev_un._threadid = tswap32(target_sevp->_sigev_un._threadid);
+
+    unlock_user_struct(target_sevp, target_addr, 0);
+    return 0;
+}
+
 /* Returns 1 if given signal should dump core if not handled. */
 static int core_dump_signal(int sig)
 {
@@ -725,6 +752,46 @@ int do_sigaction(int sig, const struct target_sigaction *act,
     return ret;
 }
 
+int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+    TaskState *ts = get_task_state(thread_cpu);
+
+    if (oldset) {
+        *oldset = ts->signal_mask;
+    }
+
+    if (set) {
+        int i;
+
+        if (block_signals()) {
+            return -TARGET_ERESTART;
+        }
+
+        switch (how) {
+        case SIG_BLOCK:
+            sigorset(&ts->signal_mask, &ts->signal_mask, set);
+            break;
+        case SIG_UNBLOCK:
+            for (i = 1; i <= NSIG; ++i) {
+                if (sigismember(set, i)) {
+                    sigdelset(&ts->signal_mask, i);
+                }
+            }
+            break;
+        case SIG_SETMASK:
+            ts->signal_mask = *set;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+
+        /* Silently ignore attempts to change blocking status of KILL or STOP */
+        sigdelset(&ts->signal_mask, SIGKILL);
+        sigdelset(&ts->signal_mask, SIGSTOP);
+    }
+    return 0;
+}
+
 static inline abi_ulong get_sigframe(struct target_sigaction *ka,
         CPUArchState *env, size_t frame_size)
 {
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 05/41] bsd-user: Add signal shims sigwait through kill and os-signal.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (3 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 04/41] bsd-user: Add bsd-signal.h with sigaction through sigreturn Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 06/41] bsd-user: Add signal system call dispatch Warner Losh
                   ` (36 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Complete bsd-signal.h with sigwait, sigwaitinfo, sigqueue,
sigaltstack, kill, and killpg. Add FreeBSD-specific os-signal.h
with pdkill.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-signal.h        | 80 ++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-signal.h | 20 +++++++++
 2 files changed, 100 insertions(+)
 create mode 100644 bsd-user/freebsd/os-signal.h

diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h
index 49e58d7436..09c5b30913 100644
--- a/bsd-user/bsd-signal.h
+++ b/bsd-user/bsd-signal.h
@@ -148,4 +148,84 @@ static inline abi_long do_bsd_sigreturn(CPUArchState *env, abi_long arg1)
 /* sigsetmask(2) - not defined */
 /* sigstack(2) - not defined */
 
+/* sigwait(2) */
+static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2,
+                                      abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    int sig;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwait(&set, &sig));
+    if (!is_error(ret) && arg2) {
+        ret = put_user_s32(sig, arg2);
+    }
+    return ret;
+}
+
+/* sigwaitinfo(2) */
+static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    ret = get_errno(sigwaitinfo(&set, &uinfo));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* sigqueue(2) */
+static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2,
+                                       abi_ulong arg3)
+{
+    union sigval value;
+    target_sigval_t *tvalue = (target_sigval_t *)&arg3;
+    abi_ulong sival_ptr;
+
+    __get_user(sival_ptr, &tvalue->sival_ptr);
+    value.sival_ptr = (void *)(uintptr_t)sival_ptr;
+    return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value));
+}
+
+/* sigaltstck(2) */
+static inline abi_long do_bsd_sigaltstack(CPUArchState *env, abi_ulong arg1,
+                                          abi_ulong arg2)
+{
+    return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(env));
+}
+
+/* kill(2) */
+static inline abi_long do_bsd_kill(abi_long pid, abi_long sig)
+{
+    return get_errno(kill(pid, target_to_host_signal(sig)));
+}
+
+/* killpg(2) */
+static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig)
+{
+   return get_errno(killpg(pg, target_to_host_signal(sig)));
+}
+
 #endif /* BSD_SIGNAL_H */
diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h
new file mode 100644
index 0000000000..fe102c33e4
--- /dev/null
+++ b/bsd-user/freebsd/os-signal.h
@@ -0,0 +1,20 @@
+/*
+ * FreeBSD signal system call shims
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef FREEBSD_OS_SIGNAL_H
+#define FREEBSD_OS_SIGNAL_H
+
+#include <sys/procdesc.h>
+
+/* pdkill(2) */
+static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(pdkill(arg1, target_to_host_signal(arg2)));
+}
+
+#endif /* FREEBSD_OS_SIGNAL_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 06/41] bsd-user: Add signal system call dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (4 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 05/41] bsd-user: Add signal shims sigwait through kill and os-signal.h Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 07/41] bsd-user: move sys/shm.h lines Warner Losh
                   ` (35 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Wire up the signal-related system calls in the FreeBSD syscall
dispatcher: sigaction, sigprocmask, sigpending, sigsuspend, sigreturn,
sigwait, sigwaitinfo, sigqueue, sigaltstack, kill, and pdkill.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 48 +++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 7fefdb569f..06148fe3ce 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -43,6 +43,7 @@
 /* BSD dependent syscall shims */
 #include "os-stat.h"
 #include "os-proc.h"
+#include "os-signal.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -950,6 +951,53 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_getdtablesize();
         break;
 
+        /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
         /*
          * sys{ctl, arch, call}
          */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 07/41] bsd-user: move sys/shm.h lines
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (5 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 06/41] bsd-user: Add signal system call dispatch Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 08/41] bsd-user: Remove mmap defines Warner Losh
                   ` (34 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Pierrick Bouvier, Richard Henderson

Diff reduction with blitz: move these lines to the same place in the
blitz branch.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/syscall_defs.h | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 0612be8bbb..7e70d6ad57 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -42,26 +42,6 @@ struct target_ipc_perm {
 #define TARGET_IPC_SET  1   /* set options */
 #define TARGET_IPC_STAT 2   /* get options */
 
-/*
- * sys/shm.h
- */
-struct target_shmid_ds {
-    struct  target_ipc_perm shm_perm; /* peration permission structure */
-    abi_ulong   shm_segsz;  /* size of segment in bytes */
-    int32_t     shm_lpid;   /* process ID of last shared memory op */
-    int32_t     shm_cpid;   /* process ID of creator */
-    int32_t     shm_nattch; /* number of current attaches */
-    target_time_t shm_atime;  /* time of last shmat() */
-    target_time_t shm_dtime;  /* time of last shmdt() */
-    target_time_t shm_ctime;  /* time of last change by shmctl() */
-};
-
-#define N_BSD_SHM_REGIONS   32
-struct bsd_shm_regions {
-    abi_long start;
-    abi_long size;
-};
-
 /*
  * sys/sem.h
  */
@@ -93,6 +73,26 @@ struct target_semid_ds {
     target_time_t   sem_ctime;  /* times measured in secs */
 };
 
+/*
+ * sys/shm.h
+ */
+struct target_shmid_ds {
+    struct  target_ipc_perm shm_perm; /* peration permission structure */
+    abi_ulong   shm_segsz;  /* size of segment in bytes */
+    int32_t     shm_lpid;   /* process ID of last shared memory op */
+    int32_t     shm_cpid;   /* process ID of creator */
+    int32_t     shm_nattch; /* number of current attaches */
+    target_time_t shm_atime;  /* time of last shmat() */
+    target_time_t shm_dtime;  /* time of last shmdt() */
+    target_time_t shm_ctime;  /* time of last change by shmctl() */
+};
+
+#define N_BSD_SHM_REGIONS   32
+struct bsd_shm_regions {
+    abi_long start;
+    abi_long size;
+};
+
 /*
  * sys/msg.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 08/41] bsd-user: Remove mmap defines
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (6 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 07/41] bsd-user: move sys/shm.h lines Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 09/41] bsd-user: Use target_suseconds_t Warner Losh
                   ` (33 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Pierrick Bouvier, Richard Henderson

These defines are not used, remove them. They aren't in blitz anymore.
A future commit will cleanup several mmap issues, not least the obvious
mismatch in the flags here.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/syscall_defs.h | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 7e70d6ad57..7646a52744 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -121,20 +121,6 @@ struct target_msgbuf {
 /*
  *  sys/mman.h
  */
-#define TARGET_MADV_DONTNEED            4       /* dont need these pages */
-
-#define TARGET_FREEBSD_MAP_RESERVED0080 0x0080  /* previously misimplemented */
-                                                /* MAP_INHERIT */
-#define TARGET_FREEBSD_MAP_RESERVED0100 0x0100  /* previously unimplemented */
-                                                /* MAP_NOEXTEND */
-#define TARGET_FREEBSD_MAP_STACK        0x0400  /* region grows down, like a */
-                                                /* stack */
-#define TARGET_FREEBSD_MAP_NOSYNC       0x0800  /* page to but do not sync */
-                                                /* underlying file */
-
-#define TARGET_FREEBSD_MAP_FLAGMASK     0x1ff7
-
-/* XXX */
 #define TARGET_BSD_MAP_FLAGMASK         0x3ff7
 
 /*
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 09/41] bsd-user: Use target_suseconds_t
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (7 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 08/41] bsd-user: Remove mmap defines Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 10/41] bsd-user: Move sys/uuid.h defines Warner Losh
                   ` (32 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Pierrick Bouvier, Richard Henderson

We no longer need target_freebsd_suseconds_t, so use target_suseconds_t
instead.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/syscall_defs.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 7646a52744..4af79669e2 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -128,8 +128,6 @@ struct target_msgbuf {
  * sys/timex.h
  */
 
-typedef abi_long target_freebsd_suseconds_t;
-
 /* compare to sys/timespec.h */
 struct target_freebsd_timespec {
     target_time_t   tv_sec;     /* seconds */
@@ -151,7 +149,7 @@ struct target_freebsd__umtx_time {
 
 struct target_freebsd_timeval {
     target_time_t       tv_sec; /* seconds */
-    target_freebsd_suseconds_t  tv_usec;/* and microseconds */
+    target_suseconds_t  tv_usec;/* and microseconds */
 #if !defined(TARGET_I386) && TARGET_ABI_BITS == 32
     abi_long _pad;
 #endif
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 10/41] bsd-user: Move sys/uuid.h defines
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (8 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 09/41] bsd-user: Use target_suseconds_t Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 11/41] bsd-user: Fix realpathat for FreeBSD 15.0 and newer Warner Losh
                   ` (31 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Pierrick Bouvier, Richard Henderson

Diff reduction to blitz. Move sys/uuid.h to the location in the blitz
branch.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/syscall_defs.h | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 4af79669e2..47aa01fbb5 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -418,6 +418,21 @@ struct target_freebsd_flock {
 /* user: vfork(2) semantics, clear signals */
 #define TARGET_RFSPAWN (1U << 31)
 
+/*
+ *  sys/uuid.h
+ */
+
+#define TARGET_UUID_NODE_LEN    6
+
+struct target_uuid {
+    uint32_t    time_low;
+    uint16_t    time_mid;
+    uint16_t    time_hi_and_version;
+    uint8_t     clock_seq_hi_and_reserved;
+    uint8_t     clock_seq_low;
+    uint8_t     node[TARGET_UUID_NODE_LEN];
+};
+
 /*
  * from sys/procctl.h
  */
@@ -459,21 +474,6 @@ struct target_procctl_reaper_kill {
     uint32_t rk_pad0[15];
 };
 
-/*
- * sys/uuid.h
- */
-#define TARGET_UUID_NODE_LEN    6
-
-struct target_uuid {
-    uint32_t    time_low;
-    uint16_t    time_mid;
-    uint16_t    time_hi_and_version;
-    uint8_t     clock_seq_hi_and_reserved;
-    uint8_t     clock_seq_low;
-    uint8_t     node[TARGET_UUID_NODE_LEN];
-};
-
-
 #define safe_syscall0(type, name) \
 type safe_##name(void) \
 { \
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 11/41] bsd-user: Fix realpathat for FreeBSD 15.0 and newer
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (9 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 10/41] bsd-user: Move sys/uuid.h defines Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 12/41] bsd-user: Add os-file.h with chflagsat, close_range, and more Warner Losh
                   ` (30 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Pierrick Bouvier, Richard Henderson

Fix __realpathat to use __sys___realpathat on FreeBSD >= 15.0.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-stat.h | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h
index ea95aa6344..4e5fc30de4 100644
--- a/bsd-user/freebsd/os-stat.h
+++ b/bsd-user/freebsd/os-stat.h
@@ -622,11 +622,6 @@ static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
     return ret;
 }
 
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300080
-extern int __realpathat(int fd, const char *path, char *buf, size_t size,
-        int flags);
-/* https://svnweb.freebsd.org/base?view=revision&revision=358172 */
-/* no man page */
 static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2,
         abi_long arg3, abi_long arg4, abi_long arg5)
 {
@@ -640,12 +635,11 @@ static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2,
         return -TARGET_EFAULT;
     }
 
-    ret = get_errno(__realpathat(arg1, p, b, arg4, arg5));
+    ret = get_errno(syscall(SYS___realpathat, arg1, p, b, arg4, arg5));
     UNLOCK_PATH(p, arg2);
     unlock_user(b, arg3, ret);
 
     return ret;
 }
-#endif
 
 #endif /* BSD_USER_FREEBSD_OS_STAT_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 12/41] bsd-user: Add os-file.h with chflagsat, close_range, and more
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (10 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 11/41] bsd-user: Fix realpathat for FreeBSD 15.0 and newer Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 13/41] bsd-user: Add poll, poll2, lseek, pipe, and swap system call shims Warner Losh
                   ` (29 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Add FreeBSD-specific file operation shims: chflagsat, close_range,
copy_file_range, and __specialfd. Also add the safe_copy_file_range and
safe_ppoll syscall wrappers and the target_specialfd_eventfd type
definitions.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-file.h    | 103 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-syscall.c |  25 +++++++++
 bsd-user/syscall_defs.h       |  10 ++++
 3 files changed, 138 insertions(+)
 create mode 100644 bsd-user/freebsd/os-file.h

diff --git a/bsd-user/freebsd/os-file.h b/bsd-user/freebsd/os-file.h
new file mode 100644
index 0000000000..d5d91336ea
--- /dev/null
+++ b/bsd-user/freebsd/os-file.h
@@ -0,0 +1,103 @@
+/*
+ * FreeBSD file related system call shims and definitions
+ *
+ * Copyright (c) 2014 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef FREEBSD_OS_FILE_H
+#define FREEBSD_OS_FILE_H
+
+#include <sys/specialfd.h>
+
+/*
+ * Asynchronous I/O.
+ */
+
+/* chflagsat(2) */
+static inline abi_long do_bsd_chflagsat(int fd, abi_ulong path,
+        abi_ulong flags, int atflags)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, path);
+    ret = get_errno(chflagsat(fd, p, flags, atflags)); /* XXX path(p)? */
+    UNLOCK_PATH(p, path);
+
+    return ret;
+}
+
+/* close_range(2) */
+static inline abi_long do_freebsd_close_range(unsigned int lowfd,
+    unsigned int highfd, int flags)
+{
+
+    return get_errno(close_range(lowfd, highfd, flags));
+}
+
+ssize_t safe_copy_file_range(int, off_t *, int, off_t *, size_t, unsigned int);
+
+/* copy_file_range(2) */
+static inline abi_long do_freebsd_copy_file_range(int infd,
+    abi_ulong inofftp, int outfd, abi_ulong outofftp, size_t len,
+    unsigned int flags)
+{
+    off_t inoff, outoff, *inp, *outp;
+    abi_long ret;
+
+    inp = outp = NULL;
+    if (inofftp != 0 && !access_ok(VERIFY_WRITE, inofftp, sizeof(off_t))) {
+        return -TARGET_EFAULT;
+    } else if (inofftp != 0) {
+        inoff = tswap64(*(off_t *)g2h_untagged(inofftp));
+        inp = &inoff;
+    }
+    if (outofftp != 0 && !access_ok(VERIFY_WRITE, outofftp, sizeof(off_t))) {
+        return -TARGET_EFAULT;
+    } else if (outofftp != 0) {
+        outoff = tswap64(*(off_t *)g2h_untagged(outofftp));
+        outp = &outoff;
+    }
+
+    ret = get_errno(safe_copy_file_range(infd, inp, outfd, outp, len,
+        flags));
+
+    if (!is_error(ret)) {
+        if (inofftp != 0) {
+            *(off_t *)g2h_untagged(inofftp) = tswap64(inoff);
+        }
+        if (outofftp != 0) {
+            *(off_t *)g2h_untagged(outofftp) = tswap64(outoff);
+        }
+    }
+    return ret;
+}
+
+static inline abi_long do_freebsd___specialfd(int type, abi_ulong req,
+    size_t len)
+{
+    abi_long ret;
+
+    ret = -TARGET_EINVAL;
+    switch (type) {
+    case TARGET_SPECIALFD_EVENT: {
+        struct specialfd_eventfd evfd;
+        struct target_specialfd_eventfd *target_eventfd;
+
+        if (!lock_user_struct(VERIFY_READ, target_eventfd, req, 1)) {
+            return -TARGET_EFAULT;
+        }
+
+        evfd.initval = tswap32(target_eventfd->initval);
+        evfd.flags = tswap32(target_eventfd->flags);
+        ret = get_errno(syscall(SYS___specialfd, type, &evfd, sizeof(evfd)));
+        unlock_user_struct(target_eventfd, req, 0);
+        break;
+    }
+    }
+
+    return ret;
+}
+
+#endif /* FREEBSD_OS_FILE_H */
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 06148fe3ce..4fc230e8e5 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -44,6 +44,7 @@
 #include "os-stat.h"
 #include "os-proc.h"
 #include "os-signal.h"
+#include "os-file.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -65,6 +66,9 @@ safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt);
 safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
     off_t, offset);
 
+safe_syscall6(ssize_t, copy_file_range, int, infd, off_t *, inoffp, int, outfd,
+    off_t *, outoffp, size_t, len, unsigned int, flags);
+
 /* used in os-proc */
 safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
     struct rusage *, rusage);
@@ -692,6 +696,27 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_undelete(arg1);
         break;
 
+    case TARGET_FREEBSD_NR_chflagsat: /* chflagsat(2) */
+        ret = do_bsd_chflagsat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_close_range: /* close_range(2) */
+        ret = do_freebsd_close_range(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___realpathat:
+        /* __realpathat(2) (XXX no realpathat()) */
+        ret = do_freebsd_realpathat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_copy_file_range:
+        ret = do_freebsd_copy_file_range(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR___specialfd:
+        ret = do_freebsd___specialfd(arg1, arg2, arg3);
+        break;
+
         /*
          * ioctl(2)
          */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 47aa01fbb5..88dd7a763a 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -418,6 +418,16 @@ struct target_freebsd_flock {
 /* user: vfork(2) semantics, clear signals */
 #define TARGET_RFSPAWN (1U << 31)
 
+/* sys/specialfd.h */
+enum target_specialfd_type {
+    TARGET_SPECIALFD_EVENT         = 1,
+};
+
+struct target_specialfd_eventfd {
+    unsigned int initval;
+    int flags;
+};
+
 /*
  *  sys/uuid.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 13/41] bsd-user: Add poll, poll2, lseek, pipe, and swap system call shims
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (11 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 12/41] bsd-user: Add os-file.h with chflagsat, close_range, and more Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 14/41] bsd-user: Add FreeBSD socket helpers and sockaddr conversion Warner Losh
                   ` (28 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Add do_bsd_poll, do_bsd_lseek, do_bsd_pipe, do_bsd_swapon,
do_freebsd13_swapoff, and do_bsd_swapoff to bsd-file.h. Also add
target_pollfd structure to syscall_defs.h and include poll.h in
os-syscall.c.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-file.h           | 136 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-file.h    |  26 +++++++
 bsd-user/freebsd/os-syscall.c |  34 +++++++++
 bsd-user/syscall_defs.h       |   6 ++
 4 files changed, 202 insertions(+)

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
index 7ef9470c4e..0fefc07232 100644
--- a/bsd-user/bsd-file.h
+++ b/bsd-user/bsd-file.h
@@ -55,6 +55,10 @@ ssize_t safe_pwrite(int fd, void *buf, size_t nbytes, off_t offset);
 ssize_t safe_writev(int fd, const struct iovec *iov, int iovcnt);
 ssize_t safe_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
 
+int safe_ppoll(struct pollfd *fds, nfds_t nfds,
+               const struct timespec *restrict timeout,
+               const sigset_t *restrict newsigmask);
+
 /* read(2) */
 static abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
 {
@@ -925,4 +929,136 @@ static abi_long do_bsd_undelete(abi_long arg1)
     return ret;
 }
 
+/* poll(2) */
+static abi_long do_bsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    int timeout = arg3;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+    struct timespec ts, *pts = NULL;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+            sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    }
+
+    if (timeout != INFTIM) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = (timeout % 1000) * 1000000;
+        pts = &ts;
+    }
+
+    ret = get_errno(safe_ppoll(pfd, nfds, pts, NULL));
+
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/* lseek(2) */
+static abi_long do_bsd_lseek(CPUArchState *env, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+#if TARGET_ABI_BITS == 32
+    int64_t res;
+
+    /* 32-bit arch's use two 32 registers for 64 bit return value */
+    if (regpairs_aligned(env) != 0) {
+        res = lseek(arg1, target_arg64(arg3, arg4), arg5);
+    } else {
+        res = lseek(arg1, target_arg64(arg2, arg3), arg4);
+    }
+    if (res == -1) {
+        ret = get_errno(res);
+        set_second_rval(env, 0xFFFFFFFF);
+    } else {
+#ifdef TARGET_BIG_ENDIAN
+        ret = ((res >> 32) & 0xFFFFFFFF);
+        set_second_rval(env, res & 0xFFFFFFFF);
+#else
+        ret = res & 0xFFFFFFFF;
+        set_second_rval(env, (res >> 32) & 0xFFFFFFFF);
+#endif
+    }
+#else
+    ret = get_errno(lseek(arg1, arg2, arg3));
+#endif
+    return ret;
+}
+
+/* pipe(2) */
+static abi_long do_bsd_pipe(CPUArchState *env, abi_ulong pipedes)
+{
+    abi_long ret;
+    int host_pipe[2];
+    int host_ret = pipe(host_pipe);
+
+    if (host_ret != -1) {
+        set_second_rval(env, host_pipe[1]);
+        ret = host_pipe[0];
+    } else {
+        ret = get_errno(host_ret);
+    }
+    return ret;
+}
+
+/* swapon(2) */
+static abi_long do_bsd_swapon(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapon(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+#ifdef TARGET_FREEBSD_NR_freebsd13_swapoff
+/* swapoff(2) */
+static abi_long do_freebsd13_swapoff(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapoff(path(p), 0));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+#endif
+
+/* swapoff(2) */
+static abi_long do_bsd_swapoff(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+#ifdef TARGET_FREEBSD_NR_freebsd13_swapoff
+    ret = get_errno(swapoff(path(p), arg2));
+#else
+    ret = get_errno(swapoff(path(p)));
+#endif
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
 #endif /* BSD_FILE_H */
diff --git a/bsd-user/freebsd/os-file.h b/bsd-user/freebsd/os-file.h
index d5d91336ea..c1da52789a 100644
--- a/bsd-user/freebsd/os-file.h
+++ b/bsd-user/freebsd/os-file.h
@@ -14,6 +14,32 @@
  * Asynchronous I/O.
  */
 
+/* pipe2(2) */
+static abi_long do_bsd_pipe2(CPUArchState *env, abi_ulong pipedes, int flags)
+{
+    int host_pipe[2];
+    int host_ret = pipe2(host_pipe, flags);
+    /* XXXss - flags should be translated from target to host. */
+
+    if (host_ret == -1) {
+        return get_errno(host_ret);
+    }
+
+    /*
+     * pipe2() returns it's second FD by copying it back to userspace and not in
+     * a second register like pipe(2): set_second_rval(env, host_pipe[1]);
+     *
+     * Copy the FD's back to userspace:
+     */
+    if (put_user_s32(host_pipe[0], pipedes) ||
+        put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0]))) {
+        close(host_pipe[0]);
+        close(host_pipe[1]);
+        return -TARGET_EFAULT;
+    }
+    return 0;
+}
+
 /* chflagsat(2) */
 static inline abi_long do_bsd_chflagsat(int fd, abi_ulong path,
         abi_ulong flags, int atflags)
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 4fc230e8e5..228daed4c4 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -26,6 +26,7 @@
 #include <sys/mount.h>
 #include <sys/sysctl.h>
 #include <utime.h>
+#include <poll.h>
 
 #include "include/gdbstub/syscalls.h"
 
@@ -66,6 +67,9 @@ safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt);
 safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
     off_t, offset);
 
+safe_syscall4(int, ppoll, struct pollfd *, fds, nfds_t, nfds,
+    const struct timespec *, restrict_timeout, const sigset_t *,
+    restrict_newsigmask);
 safe_syscall6(ssize_t, copy_file_range, int, infd, off_t *, inoffp, int, outfd,
     off_t *, outoffp, size_t, len, unsigned int, flags);
 
@@ -696,6 +700,36 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_undelete(arg1);
         break;
 
+    case TARGET_FREEBSD_NR_poll: /* poll(2) */
+        ret = do_bsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
+        ret = do_bsd_lseek(env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd10_pipe: /* pipe(2) */
+        ret = do_bsd_pipe(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_pipe2: /* pipe2(2) */
+        ret = do_bsd_pipe2(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_swapon: /* swapon(2) */
+        ret = do_bsd_swapon(arg1);
+        break;
+
+#if TARGET_FREEBSD_NR_freebsd13_swapoff
+    case TARGET_FREEBSD_NR_freebsd13_swapoff: /* freebsd13_swapoff(2) */
+        ret = do_freebsd13_swapoff(arg1);
+        break;
+#endif
+
+    case TARGET_FREEBSD_NR_swapoff: /* swapoff(2) */
+        ret = do_bsd_swapoff(arg1, arg2);
+        break;
+
     case TARGET_FREEBSD_NR_chflagsat: /* chflagsat(2) */
         ret = do_bsd_chflagsat(arg1, arg2, arg3, arg4);
         break;
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 88dd7a763a..75122ad521 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -547,6 +547,12 @@ struct target_in_addr {
 #define safe_ioctl(...) safe_syscall(SYS_ioctl, __VA_ARGS__)
 #define safe_fcntl(...) safe_syscall(SYS_fcntl, __VA_ARGS__)
 
+struct target_pollfd {
+    int32_t fd;         /* file descriptor */
+    int16_t events;     /* requested events */
+    int16_t revents;    /* returned events */
+};
+
 /* So far all target and host bitmasks are the same */
 #undef  target_to_host_bitmask
 #define target_to_host_bitmask(x, tbl) (x)
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 14/41] bsd-user: Add FreeBSD socket helpers and sockaddr conversion
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (12 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 13/41] bsd-user: Add poll, poll2, lseek, pipe, and swap system call shims Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 15/41] bsd-user: Add bsd-socket.h with bind through getsockname Warner Losh
                   ` (27 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Add bsd-socket.c with target_to_host_sockaddr, host_to_target_sockaddr,
and target_to_host_ip_mreq helper functions, and add it to the build.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-socket.c   | 98 +++++++++++++++++++++++++++++++++++++++++
 bsd-user/meson.build    |  1 +
 bsd-user/qemu-bsd.h     |  8 ++++
 bsd-user/syscall_defs.h | 49 +++++++++++++++------
 4 files changed, 143 insertions(+), 13 deletions(-)
 create mode 100644 bsd-user/bsd-socket.c

diff --git a/bsd-user/bsd-socket.c b/bsd-user/bsd-socket.c
new file mode 100644
index 0000000000..cc45400e4c
--- /dev/null
+++ b/bsd-user/bsd-socket.c
@@ -0,0 +1,98 @@
+/*
+ * BSD socket system call related helpers
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-bsd.h"
+
+/*
+ * socket conversion
+ */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+                                 socklen_t len)
+{
+    const socklen_t unix_maxlen = sizeof(struct sockaddr_un);
+    sa_family_t sa_family;
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+
+    sa_family = target_saddr->sa_family;
+
+    /*
+     * Oops. The caller might send a incomplete sun_path; sun_path
+     * must be terminated by \0 (see the manual page), but unfortunately
+     * it is quite common to specify sockaddr_un length as
+     * "strlen(x->sun_path)" while it should be "strlen(...) + 1". We will
+     * fix that here if needed.
+     */
+    if (target_saddr->sa_family == AF_UNIX) {
+        if (len < unix_maxlen && len > 0) {
+            char *cp = (char *)target_saddr;
+
+            if (cp[len - 1] && !cp[len]) {
+                len++;
+            }
+        }
+        if (len > unix_maxlen) {
+            len = unix_maxlen;
+        }
+    }
+
+    memcpy(addr, target_saddr, len);
+    addr->sa_family = sa_family;        /* type uint8_t */
+    addr->sa_len = target_saddr->sa_len;    /* type uint8_t */
+    unlock_user(target_saddr, target_addr, 0);
+
+    return 0;
+}
+
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+                                 socklen_t len)
+{
+    struct target_sockaddr *target_saddr;
+
+    target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+    if (target_saddr == 0) {
+        return -TARGET_EFAULT;
+    }
+    memcpy(target_saddr, addr, len);
+    target_saddr->sa_family = addr->sa_family;  /* type uint8_t */
+    target_saddr->sa_len = addr->sa_len;        /* type uint8_t */
+    unlock_user(target_saddr, target_addr, len);
+
+    return 0;
+}
+
+abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
+                                socklen_t len)
+{
+    struct target_ip_mreqn *target_smreqn;
+
+    target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (target_smreqn == 0) {
+        return -TARGET_EFAULT;
+    }
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn)) {
+        mreqn->imr_ifindex = tswap32(target_smreqn->imr_ifindex);
+    }
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
diff --git a/bsd-user/meson.build b/bsd-user/meson.build
index 2abcae5122..ab6ddf2e9f 100644
--- a/bsd-user/meson.build
+++ b/bsd-user/meson.build
@@ -11,6 +11,7 @@ bsd_user_ss.add(files(
   'bsd-mem.c',
   'bsd-misc.c',
   'bsd-proc.c',
+  'bsd-socket.c',
   'bsdload.c',
   'elfload.c',
   'main.c',
diff --git a/bsd-user/qemu-bsd.h b/bsd-user/qemu-bsd.h
index 756425d18e..e32a09b37c 100644
--- a/bsd-user/qemu-bsd.h
+++ b/bsd-user/qemu-bsd.h
@@ -32,6 +32,14 @@ int host_to_target_waitstatus(int status);
 void h2g_rusage(const struct rusage *rusage,
         struct target_freebsd_rusage *target_rusage);
 
+/* bsd-socket.c */
+abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr,
+        socklen_t len);
+abi_long host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr,
+        socklen_t len);
+abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr,
+        socklen_t len);
+
 /* bsd-mem.c */
 void target_to_host_ipc_perm__locked(struct ipc_perm *host_ip,
         struct target_ipc_perm *target_ip);
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 75122ad521..1a85ceb464 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -203,6 +203,42 @@ struct target_freebsd__wrusage {
     struct target_freebsd_rusage wru_children;
 };
 
+/*
+ * sys/socket.h
+ */
+struct target_msghdr {
+    abi_long    msg_name;       /* Socket name */
+    int32_t     msg_namelen;    /* Length of name */
+    abi_long    msg_iov;        /* Data blocks */
+    int32_t     msg_iovlen;     /* Number of blocks */
+    abi_long    msg_control;    /* Per protocol magic (eg BSD fd passing) */
+    int32_t     msg_controllen; /* Length of cmsg list */
+    int32_t     msg_flags;      /* flags on received message */
+};
+
+struct target_sockaddr {
+    uint8_t sa_len;
+    uint8_t sa_family;
+    uint8_t sa_data[14];
+} QEMU_PACKED;
+
+struct target_in_addr {
+    uint32_t s_addr; /* big endian */
+};
+/*
+ * netinet/in.h
+ */
+struct target_ip_mreq {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_interface;
+};
+
+struct target_ip_mreqn {
+    struct target_in_addr   imr_multiaddr;
+    struct target_in_addr   imr_address;
+    int32_t                 imr_ifindex;
+};
+
 /*
  * sys/stat.h
  */
@@ -531,19 +567,6 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
     return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
 }
 
-/*
- * sys/socket.h
- */
-struct target_sockaddr {
-    uint8_t sa_len;
-    uint8_t sa_family;
-    uint8_t sa_data[14];
-} QEMU_PACKED;
-
-struct target_in_addr {
-    uint32_t s_addr; /* big endian */
-};
-
 #define safe_ioctl(...) safe_syscall(SYS_ioctl, __VA_ARGS__)
 #define safe_fcntl(...) safe_syscall(SYS_fcntl, __VA_ARGS__)
 
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 15/41] bsd-user: Add bsd-socket.h with bind through getsockname
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (13 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 14/41] bsd-user: Add FreeBSD socket helpers and sockaddr conversion Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 16/41] bsd-user: Add socket shims socketpair through shutdown Warner Losh
                   ` (26 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Add the first set of socket system call shims: bind, connect,
accept, getpeername, and getsockname. Also add safe_syscall wrappers
for sendto, recvfrom, select, and pselect.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-socket.h         | 167 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-syscall.c |  13 +++
 bsd-user/syscall_defs.h       | 112 +++++++++++++++++++++++
 3 files changed, 292 insertions(+)
 create mode 100644 bsd-user/bsd-socket.h

diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
new file mode 100644
index 0000000000..c786d6717a
--- /dev/null
+++ b/bsd-user/bsd-socket.h
@@ -0,0 +1,167 @@
+/*
+ * socket related system call shims
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef BSD_SOCKET_H
+#define BSD_SOCKET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-bsd.h"
+
+ssize_t safe_recvfrom(int s, void *buf, size_t len, int flags,
+    struct sockaddr *restrict from, socklen_t *restrict fromlen);
+ssize_t safe_sendto(int s, const void *buf, size_t len, int flags,
+    const struct sockaddr *to, socklen_t tolen);
+int safe_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds,
+    struct timeval *timeout);
+int safe_pselect(int nfds, fd_set *restrict readfds,
+    fd_set *restrict writefds, fd_set *restrict exceptfds,
+    const struct timespec *restrict timeout,
+    const sigset_t *restrict newsigmask);
+
+/* bind(2) */
+static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
+                                   socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* connect(2) */
+static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
+                                      socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen + 1);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* accept(2) */
+static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
+                                     abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        if (is_error(host_to_target_sockaddr(target_addr, addr, addrlen))) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getpeername(2) */
+static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
+                                          abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (is_error(ret)) {
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getsockname(2) */
+static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
+                                          abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (is_error(ret)) {
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#endif /* BSD_SOCKET_H */
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 228daed4c4..7bc9fedfb7 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -40,6 +40,7 @@
 #include "bsd-proc.h"
 #include "bsd-misc.h"
 #include "bsd-signal.h"
+#include "bsd-socket.h"
 
 /* BSD dependent syscall shims */
 #include "os-stat.h"
@@ -73,6 +74,18 @@ safe_syscall4(int, ppoll, struct pollfd *, fds, nfds_t, nfds,
 safe_syscall6(ssize_t, copy_file_range, int, infd, off_t *, inoffp, int, outfd,
     off_t *, outoffp, size_t, len, unsigned int, flags);
 
+/* used in bsd-socket */
+safe_syscall5(int, select, int, nfds, fd_set *, readfs, fd_set *, writefds,
+    fd_set *, exceptfds, struct timeval *, timeout);
+safe_syscall6(int, pselect, int, nfds, fd_set *restrict, readfs,
+    fd_set *restrict, writefds, fd_set *restrict, exceptfds,
+    const struct timespec *restrict, timeout, const sigset_t *restrict,
+    newsigmask);
+safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len, int, flags,
+    struct sockaddr *restrict, from, socklen_t *restrict, fromlen);
+safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
+    flags, const struct sockaddr *, to, socklen_t, tolen);
+
 /* used in os-proc */
 safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
     struct rusage *, rusage);
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 1a85ceb464..0d7002312f 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -203,6 +203,73 @@ struct target_freebsd__wrusage {
     struct target_freebsd_rusage wru_children;
 };
 
+/*
+ * sys/socket.h
+ */
+
+/*
+ * Types
+ */
+#define TARGET_SOCK_STREAM      1   /* stream socket */
+#define TARGET_SOCK_DGRAM       2   /* datagram socket */
+#define TARGET_SOCK_RAW         3   /* raw-protocol interface */
+#define TARGET_SOCK_RDM         4   /* reliably-delivered message */
+#define TARGET_SOCK_SEQPACKET   5   /* sequenced packet stream */
+
+
+/*
+ * Option flags per-socket.
+ */
+
+#define TARGET_SO_DEBUG         0x0001  /* turn on debugging info recording */
+#define TARGET_SO_ACCEPTCONN    0x0002  /* socket has had listen() */
+#define TARGET_SO_REUSEADDR     0x0004  /* allow local address reuse */
+#define TARGET_SO_KEEPALIVE     0x0008  /* keep connections alive */
+#define TARGET_SO_DONTROUTE     0x0010  /* just use interface addresses */
+#define TARGET_SO_BROADCAST     0x0020  /* permit sending of broadcast msgs */
+#define TARGET_SO_USELOOPBACK   0x0040  /* bypass hardware when possible */
+#define TARGET_SO_LINGER        0x0080  /* linger on close if data present */
+#define TARGET_SO_OOBINLINE     0x0100  /* leave received OOB data in line */
+#define TARGET_SO_REUSEPORT     0x0200  /* allow local address & port reuse */
+#define TARGET_SO_TIMESTAMP     0x0400  /* timestamp received dgram traffic */
+#define TARGET_SO_NOSIGPIPE     0x0800  /* no SIGPIPE from EPIPE */
+#define TARGET_SO_ACCEPTFILTER  0x1000  /* there is an accept filter */
+#define TARGET_SO_BINTIME       0x2000  /* timestamp received dgram traffic */
+#define TARGET_SO_NO_OFFLOAD    0x4000  /* socket cannot be offloaded */
+#define TARGET_SO_NO_DDP        0x8000  /* disable direct data placement */
+
+/*
+ * Additional options, not kept in so_options.
+ */
+#define TARGET_SO_SNDBUF        0x1001  /* send buffer size */
+#define TARGET_SO_RCVBUF        0x1002  /* receive buffer size */
+#define TARGET_SO_SNDLOWAT      0x1003  /* send low-water mark */
+#define TARGET_SO_RCVLOWAT      0x1004  /* receive low-water mark */
+#define TARGET_SO_SNDTIMEO      0x1005  /* send timeout */
+#define TARGET_SO_RCVTIMEO      0x1006  /* receive timeout */
+#define TARGET_SO_ERROR         0x1007  /* get error status and clear */
+#define TARGET_SO_TYPE          0x1008  /* get socket type */
+#define TARGET_SO_LABEL         0x1009  /* socket's MAC label */
+#define TARGET_SO_PEERLABEL     0x1010  /* socket's peer's MAC label */
+#define TARGET_SO_LISTENQLIMIT  0x1011  /* socket's backlog limit */
+#define TARGET_SO_LISTENQLEN    0x1012  /* socket's complete queue length */
+#define TARGET_SO_LISTENINCQLEN 0x1013  /* socket's incomplete queue length */
+#define TARGET_SO_SETFIB        0x1014  /* use this FIB to route */
+#define TARGET_SO_USER_COOKIE   0x1015  /* user cookie (dummynet etc.) */
+#define TARGET_SO_PROTOCOL      0x1016  /* get socket protocol (Linux name) */
+
+/* alias for SO_PROTOCOL (SunOS name) */
+#define TARGET_SO_PROTOTYPE     TARGET_SO_PROTOCOL
+
+/*
+ * Level number for (get/set)sockopt() to apply to socket itself.
+ */
+#define TARGET_SOL_SOCKET       0xffff  /* options for socket level */
+
+#ifndef CMSG_ALIGN
+#define CMSG_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
+#endif
+
 /*
  * sys/socket.h
  */
@@ -225,6 +292,51 @@ struct target_sockaddr {
 struct target_in_addr {
     uint32_t s_addr; /* big endian */
 };
+
+struct target_cmsghdr {
+    uint32_t    cmsg_len;
+    int32_t     cmsg_level;
+    int32_t     cmsg_type;
+};
+
+/*
+ * mips32 is the exception to the general rule of long-alignment; it
+ * unconditionally uses 64-bit alignment instead.
+ */
+#if defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+#define TARGET_ALIGNBYTES   (sizeof(abi_llong) - 1)
+#else
+#define TARGET_ALIGNBYTES   (sizeof(abi_long) - 1)
+#endif
+
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg, cmsg_start) \
+                               __target_cmsg_nxthdr(mhdr, cmsg, cmsg_start)
+#define TARGET_CMSG_ALIGN(len) (((len) + TARGET_ALIGNBYTES) \
+                               & (size_t) ~TARGET_ALIGNBYTES)
+#define TARGET_CMSG_DATA(cmsg) \
+    ((unsigned char *)(cmsg) + TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)))
+#define TARGET_CMSG_SPACE(len) \
+    (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + TARGET_CMSG_ALIGN(len))
+#define TARGET_CMSG_LEN(len) \
+    (TARGET_CMSG_ALIGN(sizeof(struct target_cmsghdr)) + (len))
+
+static inline struct target_cmsghdr *
+__target_cmsg_nxthdr(struct target_msghdr *__mhdr,
+                     struct target_cmsghdr *__cmsg,
+                     struct target_cmsghdr *__cmsg_start)
+{
+    struct target_cmsghdr *__ptr;
+
+    __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg +
+        TARGET_CMSG_ALIGN(tswap32(__cmsg->cmsg_len)));
+    if ((unsigned long)((char *)(__ptr + 1) - (char *)__cmsg_start) >
+        tswap32(__mhdr->msg_controllen)) {
+        /* No more entries.  */
+        return (struct target_cmsghdr *)0;
+    }
+    return __ptr;
+}
+
 /*
  * netinet/in.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 16/41] bsd-user: Add socket shims socketpair through shutdown
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (14 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 15/41] bsd-user: Add bsd-socket.h with bind through getsockname Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 17/41] bsd-user: Commit the generated os-sockopt.h files Warner Losh
                   ` (25 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Complete bsd-socket.h with socketpair, sendto, recvfrom, socket,
and shutdown system call shims.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-socket.h | 116 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
index c786d6717a..43aacce5dc 100644
--- a/bsd-user/bsd-socket.h
+++ b/bsd-user/bsd-socket.h
@@ -164,4 +164,120 @@ static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
     return ret;
 }
 
+/* socketpair(2) */
+static inline abi_long do_bsd_socketpair(int domain, int type, int protocol,
+                                         abi_ulong target_tab_addr)
+{
+    int tab[2];
+    abi_long ret;
+
+    if (!access_ok(VERIFY_WRITE, target_tab_addr, sizeof(tab[0]) * 2)) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(socketpair(domain, type, protocol, tab));
+    if (!is_error(ret)) {
+        if (put_user_s32(tab[0], target_tab_addr) ||
+                put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* sendto(2) */
+static inline abi_long do_bsd_sendto(int fd, abi_ulong msg, size_t len,
+                                     int flags, abi_ulong target_addr,
+                                     socklen_t addrlen)
+{
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (len != 0) {
+        host_msg = lock_user(VERIFY_READ, msg, len, 1);
+        if (!host_msg) {
+            return -TARGET_EFAULT;
+        }
+    } else {
+        host_msg = NULL;
+    }
+    if (target_addr) {
+        saddr = alloca(addrlen + 1);
+        ret = target_to_host_sockaddr(saddr, target_addr, addrlen);
+        if (is_error(ret)) {
+            unlock_user(host_msg, msg, 0);
+            return ret;
+        }
+        ret = get_errno(safe_sendto(fd, host_msg, len, flags, saddr, addrlen));
+    } else {
+        ret = get_errno(send(fd, host_msg, len, flags));
+    }
+    unlock_user(host_msg, msg, 0);
+    return ret;
+}
+
+/* recvfrom(2) */
+static inline abi_long do_bsd_recvfrom(int fd, abi_ulong msg, size_t len,
+                                       int flags, abi_ulong target_addr,
+                                       abi_ulong target_addrlen)
+{
+    socklen_t addrlen;
+    struct sockaddr *saddr;
+    void *host_msg;
+    abi_long ret;
+
+    host_msg = lock_user(VERIFY_WRITE, msg, len, 0);
+    if (!host_msg) {
+        return -TARGET_EFAULT;
+    }
+    if (target_addr) {
+        if (get_user_u32(addrlen, target_addrlen)) {
+            ret = -TARGET_EFAULT;
+            goto fail;
+        }
+        if ((int)addrlen < 0) {
+            ret = -TARGET_EINVAL;
+            goto fail;
+        }
+        saddr = alloca(addrlen + 1);
+        ret = get_errno(safe_recvfrom(fd, host_msg, len, flags, saddr,
+                    &addrlen));
+    } else {
+        saddr = NULL; /* To keep compiler quiet.  */
+        ret = get_errno(recv(fd, host_msg, len, flags));
+    }
+    if (!is_error(ret)) {
+        if (target_addr) {
+            if (is_error(host_to_target_sockaddr(target_addr, saddr, addrlen))) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            } else if (put_user_u32(addrlen, target_addrlen)) {
+                ret = -TARGET_EFAULT;
+                goto fail;
+            }
+        }
+        unlock_user(host_msg, msg, ret);
+    } else {
+fail:
+        unlock_user(host_msg, msg, 0);
+    }
+    return ret;
+}
+
+/* socket(2) */
+static inline abi_long do_bsd_socket(abi_long domain, abi_long type,
+                                     abi_long protocol)
+{
+    return get_errno(socket(domain, type, protocol));
+}
+
+/* shutdown(2) */
+static inline abi_long do_bsd_shutdown(abi_long s, abi_long how)
+{
+    return get_errno(shutdown(s, how));
+}
+
 #endif /* BSD_SOCKET_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 17/41] bsd-user: Commit the generated os-sockopt.h files
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (15 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 16/41] bsd-user: Add socket shims socketpair through shutdown Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:23 ` [PULL 18/41] bsd-user: Implement both getsockopt and setsockopt Warner Losh
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Richard Henderson

Generate the table of all socket options in FreeBSD. This only works
against the latest FreeBSD, so we have to commit this table for
now. Once the supporting machinery is merged to the stable branches, we
can move to generating it as a build artifact.

This uses BSD-2-Clause because it's derived from BSD-2-Clause
material. It's likely in the public domain, though, since it's a
generated file.

Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-sockopt.h | 316 ++++++++++++++++++++++++++++++++++
 1 file changed, 316 insertions(+)
 create mode 100644 bsd-user/freebsd/os-sockopt.h

diff --git a/bsd-user/freebsd/os-sockopt.h b/bsd-user/freebsd/os-sockopt.h
new file mode 100644
index 0000000000..2f984cf8e3
--- /dev/null
+++ b/bsd-user/freebsd/os-sockopt.h
@@ -0,0 +1,316 @@
+/* Auto-generated by gen_sockopt.sh -- do not edit */
+/* SPDX-License-Identifier: BSD-2-Clause */
+#pragma once
+
+#define SOCK_LEVEL_NONE -1234
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+enum sockopt_type {
+        SOCKOPT_TYPE_NONE = 0,
+        SOCKOPT_TYPE___MSFILTERREQ,
+        SOCKOPT_TYPE_ACCEPT_FILTER_ARG,
+        SOCKOPT_TYPE_BOOL,
+        SOCKOPT_TYPE_DUMP,
+        SOCKOPT_TYPE_ICMP6_FILTER,
+        SOCKOPT_TYPE_IN6_PKTINFO,
+        SOCKOPT_TYPE_INT,
+        SOCKOPT_TYPE_IP_MREQ_SOURCE,
+        SOCKOPT_TYPE_IP_MREQ,
+        SOCKOPT_TYPE_IP_OPTS,
+        SOCKOPT_TYPE_IP6_DEST,
+        SOCKOPT_TYPE_IP6_HBH,
+        SOCKOPT_TYPE_IP6_RTHDR,
+        SOCKOPT_TYPE_IPV6_MREQ,
+        SOCKOPT_TYPE_LINGER,
+        SOCKOPT_TYPE_SADB_X_POLICY,
+        SOCKOPT_TYPE_SOCKADDR,
+        SOCKOPT_TYPE_SPLICE,
+        SOCKOPT_TYPE_TCP_FASTOPEN,
+        SOCKOPT_TYPE_TCP_FUNCTION_SET,
+        SOCKOPT_TYPE_TCP_INFO,
+        SOCKOPT_TYPE_TCP_PERF_INFO,
+        SOCKOPT_TYPE_TIMEVAL,
+        SOCKOPT_TYPE_U_CHAR,
+        SOCKOPT_TYPE_U_INT,
+        SOCKOPT_TYPE_UINT32_T,
+        SOCKOPT_TYPE_UINT64_T,
+};
+
+struct sockopt_entry {
+        int level;
+        int optname;
+        enum sockopt_type type[5];
+};
+static struct sockopt_entry sol_socket[] = {
+        { SOL_SOCKET  , SO_DEBUG            , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_ACCEPTCONN       , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_REUSEADDR        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_KEEPALIVE        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_DONTROUTE        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_BROADCAST        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_USELOOPBACK      , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_LINGER           , { SOCKOPT_TYPE_LINGER, } },
+        { SOL_SOCKET  , SO_OOBINLINE        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_REUSEPORT        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_TIMESTAMP        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_NOSIGPIPE        , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_ACCEPTFILTER     , { SOCKOPT_TYPE_ACCEPT_FILTER_ARG, } },
+        { SOL_SOCKET  , SO_BINTIME          , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_NO_OFFLOAD       , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_NO_DDP           , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_REUSEPORT_LB     , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_RERROR           , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_SNDBUF           , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_RCVBUF           , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_SNDLOWAT         , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_RCVLOWAT         , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_SNDTIMEO         , { SOCKOPT_TYPE_TIMEVAL, } },
+        { SOL_SOCKET  , SO_RCVTIMEO         , { SOCKOPT_TYPE_TIMEVAL, } },
+        { SOL_SOCKET  , SO_ERROR            , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_TYPE             , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_LISTENQLIMIT     , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_LISTENQLEN       , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_LISTENINCQLEN    , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_FIB              , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_USER_COOKIE      , { SOCKOPT_TYPE_UINT32_T, } },
+        { SOL_SOCKET  , SO_PROTOCOL         , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_TS_CLOCK         , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_MAX_PACING_RATE  , { SOCKOPT_TYPE_UINT32_T, } },
+        { SOL_SOCKET  , SO_DOMAIN           , { SOCKOPT_TYPE_INT, } },
+        { SOL_SOCKET  , SO_SPLICE           , { SOCKOPT_TYPE_SPLICE, } },
+        { SOL_SOCKET  , NET_RT_DUMP         , { SOCKOPT_TYPE_DUMP, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_entry ipproto_ip[] = {
+        { IPPROTO_IP  , IP_HDRINCL          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_TOS              , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_TTL              , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RECVOPTS         , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_RECVRETOPTS      , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_RECVDSTADDR      , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_RETOPTS          , { SOCKOPT_TYPE_IP_OPTS, } },
+        { IPPROTO_IP  , IP_MULTICAST_TTL    , { SOCKOPT_TYPE_U_INT, SOCKOPT_TYPE_U_CHAR, } },
+        { IPPROTO_IP  , IP_MULTICAST_LOOP   , { SOCKOPT_TYPE_U_INT, SOCKOPT_TYPE_U_CHAR, } },
+        { IPPROTO_IP  , IP_ADD_MEMBERSHIP   , { SOCKOPT_TYPE_IP_MREQ, } },
+        { IPPROTO_IP  , IP_DROP_MEMBERSHIP  , { SOCKOPT_TYPE_IP_MREQ, } },
+        { IPPROTO_IP  , IP_MULTICAST_VIF    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RSVP_ON          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RSVP_OFF         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RSVP_VIF_ON      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RSVP_VIF_OFF     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_PORTRANGE        , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RECVIF           , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_IPSEC_POLICY     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_ONESBCAST        , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_BINDANY          , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_ORIGDSTADDR      , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_RECVTTL          , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_MINTTL           , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_DONTFRAG         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RECVTOS          , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_ADD_SOURCE_MEMBERSHIP, { SOCKOPT_TYPE_IP_MREQ_SOURCE, } },
+        { IPPROTO_IP  , IP_DROP_SOURCE_MEMBERSHIP, { SOCKOPT_TYPE_IP_MREQ_SOURCE, } },
+        { IPPROTO_IP  , IP_BLOCK_SOURCE     , { SOCKOPT_TYPE_IP_MREQ_SOURCE, } },
+        { IPPROTO_IP  , IP_UNBLOCK_SOURCE   , { SOCKOPT_TYPE_IP_MREQ_SOURCE, } },
+        { IPPROTO_IP  , IP_MSFILTER         , { SOCKOPT_TYPE___MSFILTERREQ, } },
+        { IPPROTO_IP  , IP_VLAN_PCP         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_FLOWID           , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_FLOWTYPE         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RSSBUCKETID      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IP  , IP_RECVFLOWID       , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IP  , IP_RECVRSSBUCKETID  , { SOCKOPT_TYPE_BOOL, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_entry ipproto_ipv6[] = {
+        { IPPROTO_IPV6, IPV6_UNICAST_HOPS   , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_MULTICAST_IF   , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_IPV6, IPV6_MULTICAST_HOPS , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_IPV6, IPV6_MULTICAST_LOOP , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_IPV6, IPV6_JOIN_GROUP     , { SOCKOPT_TYPE_IPV6_MREQ, } },
+        { IPPROTO_IPV6, IPV6_LEAVE_GROUP    , { SOCKOPT_TYPE_IPV6_MREQ, } },
+        { IPPROTO_IPV6, IPV6_PORTRANGE      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, ICMP6_FILTER        , { SOCKOPT_TYPE_ICMP6_FILTER, } },
+        { IPPROTO_IPV6, IPV6_CHECKSUM       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_V6ONLY         , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_IPSEC_POLICY   , { SOCKOPT_TYPE_SADB_X_POLICY, } },
+        { IPPROTO_IPV6, IPV6_RTHDRDSTOPTS   , { SOCKOPT_TYPE_IP6_DEST, } },
+        { IPPROTO_IPV6, IPV6_RECVPKTINFO    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVHOPLIMIT   , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVRTHDR      , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVHOPOPTS    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVDSTOPTS    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_USE_MIN_MTU    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVPATHMTU    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_PKTINFO        , { SOCKOPT_TYPE_IN6_PKTINFO, } },
+        { IPPROTO_IPV6, IPV6_HOPLIMIT       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_NEXTHOP        , { SOCKOPT_TYPE_SOCKADDR, } },
+        { IPPROTO_IPV6, IPV6_HOPOPTS        , { SOCKOPT_TYPE_IP6_HBH, } },
+        { IPPROTO_IPV6, IPV6_DSTOPTS        , { SOCKOPT_TYPE_IP6_DEST, } },
+        { IPPROTO_IPV6, IPV6_RTHDR          , { SOCKOPT_TYPE_IP6_RTHDR, } },
+        { IPPROTO_IPV6, IPV6_RECVTCLASS     , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_AUTOFLOWLABEL  , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_TCLASS         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_DONTFRAG       , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_BINDANY        , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_FLOWID         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_FLOWTYPE       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_RSSBUCKETID    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_IPV6, IPV6_RECVFLOWID     , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_RECVRSSBUCKETID, { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_ORIGDSTADDR    , { SOCKOPT_TYPE_BOOL, } },
+        { IPPROTO_IPV6, IPV6_VLAN_PCP       , { SOCKOPT_TYPE_INT, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_entry ipproto_tcp[] = {
+        { IPPROTO_TCP , TCP_NODELAY         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_MAXSEG          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_NOPUSH          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_NOOPT           , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_MD5SIG          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_INFO            , { SOCKOPT_TYPE_TCP_INFO, } },
+        { IPPROTO_TCP , TCP_LOG             , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_TXTLS_MODE      , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_RXTLS_MODE      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_IWND_NB         , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_IWND_NSEG       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_LOGID_CNT       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_USER_LOG        , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_MAXUNACKTIME    , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_IDLE_REDUCE     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_REMOTE_UDP_ENCAPS_PORT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_DELACK          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_FIN_IS_RST      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_LOG_LIMIT       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_SHARED_CWND_ALLOWED, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_PROC_ACCOUNTING , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_USE_CMP_ACKS    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_PERF_INFO       , { SOCKOPT_TYPE_TCP_PERF_INFO, } },
+        { IPPROTO_TCP , TCP_KEEPINIT        , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_KEEPIDLE        , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_KEEPINTVL       , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_KEEPCNT         , { SOCKOPT_TYPE_U_INT, } },
+        { IPPROTO_TCP , TCP_FASTOPEN        , { SOCKOPT_TYPE_TCP_FASTOPEN, } },
+        { IPPROTO_TCP , TCP_FUNCTION_BLK    , { SOCKOPT_TYPE_TCP_FUNCTION_SET, } },
+        { IPPROTO_TCP , TCP_FUNCTION_ALIAS  , { SOCKOPT_TYPE_TCP_FUNCTION_SET, } },
+        { IPPROTO_TCP , TCP_REUSPORT_LB_NUMA, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_MBUF_QUEUE , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_TLP_REDUCE , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_MAX_SEG, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_ALWAYS, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PRR_SENDALOT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_MIN_TO     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_EARLY_SEG  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_REORD_THRESH, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_REORD_FADE , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_TLP_THRESH , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PKT_DELAY  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_IWINTSO     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_STARTUP_PG  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_DRAIN_PG    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PROBE_RTT_INT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_STARTUP_LOSS_EXIT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_TSLIMITS    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_OH     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_USEDEL_RATE , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_MIN_RTO     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_MAX_RTO     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_ALGORITHM   , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_PER_SEC, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_DEL_TAR, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_SEG_MAX, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_SEG_MIN, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PACE_CROSS  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_TLP_USE    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_TMR_PACE_OH , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_DO_DETECTION, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_RACK_RTT_USE, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_RETRAN_WTSO , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_DATA_AFTER_CLOSE, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PROBE_RTT_GAIN, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_PROBE_RTT_LEN, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_SEND_IWND_IN_TSO, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_USE_RACK_RR , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_HDWR_PACE   , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_UTTER_MAX_TSO, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_EXTRA_STATE , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_FLOOR_MIN_TSO, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_MIN_TOPACEOUT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_TSTMP_RAISES, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_POLICER_DETECT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_BBR_RACK_INIT_RATE, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_RR_CONF    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_GP_INCREASE_CA, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_GP_INCREASE_SS, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_GP_INCREASE_REC, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_FORCE_MSEG , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_RATE_CA, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_RATE_SS, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_RATE_REC, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_NO_PRR          , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_NONRXT_CFG_RATE, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_SHARED_CWND_ENABLE, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_TIMELY_DYN_ADJ  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_NO_PUSH_AT_MAX, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_TO_FILL, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_SHARED_CWND_TIME_LIMIT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PROFILE    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_HDWR_RATE_CAP   , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_PACING_RATE_CAP , { SOCKOPT_TYPE_UINT64_T, } },
+        { IPPROTO_TCP , TCP_HDWR_UP_ONLY    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_ABC_VAL    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_REC_ABC_VAL     , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_MEASURE_CNT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_DEFER_OPTIONS   , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACING_BETA, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACING_BETA_ECN, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_TIMER_SLOP , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_DSACK_OPT  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_ENABLE_HYSTART, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_SET_RXT_OPTIONS, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_HI_BETA    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_SPLIT_LIMIT, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACING_DIVISOR, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_PACE_MIN_SEG, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_RACK_DGP_IN_REC , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_PACING_DND      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_SS_EEXIT        , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_DGP_UPPER_BOUNDS, { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_NO_TIMELY       , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_HONOR_HPTS_MIN  , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_REC_IS_DYN      , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_SIDECHAN_DIS    , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_FILLCW_RATE_CAP , { SOCKOPT_TYPE_INT, } },
+        { IPPROTO_TCP , TCP_GP_USE_LTBW     , { SOCKOPT_TYPE_INT, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_entry ipproto_udp[] = {
+        { IPPROTO_UDP , UDP_ENCAP           , { SOCKOPT_TYPE_INT, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_entry sol_local[] = {
+        { SOL_LOCAL   , LOCAL_CREDS         , { SOCKOPT_TYPE_INT, } },
+        { SOL_LOCAL   , LOCAL_CREDS_PERSISTENT, { SOCKOPT_TYPE_INT, } },
+        { SOCK_LEVEL_NONE }
+};
+
+static struct sockopt_cache {
+        int level;
+        struct sockopt_entry *entry;
+} so_cache[] = {
+        { SOL_SOCKET,   sol_socket },
+        { IPPROTO_IP,   ipproto_ip },
+        { IPPROTO_IPV6, ipproto_ipv6 },
+        { IPPROTO_TCP,  ipproto_tcp },
+        { IPPROTO_UDP,  ipproto_udp },
+        { SOL_LOCAL,    sol_local },
+};
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 18/41] bsd-user: Implement both getsockopt and setsockopt
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (16 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 17/41] bsd-user: Commit the generated os-sockopt.h files Warner Losh
@ 2026-09-18  4:23 ` Warner Losh
  2026-09-18  4:24 ` [PULL 19/41] bsd-user: Add FreeBSD socket system calls Warner Losh
                   ` (23 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Richard Henderson

Implement get/setsockopt with the generated file describing the socket
options. This uses a table driven conversion. At the moment, we only
implement the simple types. For 64 on 64 with the same endian, we also
try to just copy in/out since the representation should be the same.

Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-socket.h | 340 +++++++++++++++++++++++++++++++++++
 1 file changed, 340 insertions(+)
 create mode 100644 bsd-user/freebsd/os-socket.h

diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
new file mode 100644
index 0000000000..126e49b282
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.h
@@ -0,0 +1,340 @@
+/*
+ * FreeBSD socket related system call shims
+ *
+ * Copyright (c) 2013-2014 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef BSD_USER_FREEBSD_OS_SOCKET_H
+#define BSD_USER_FREEBSD_OS_SOCKET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-os.h"
+#include "os-sockopt.h"
+
+ssize_t safe_recvmsg(int s, struct msghdr *msg, int flags);
+ssize_t safe_sendmsg(int s, const struct msghdr *msg, int flags);
+
+/* do_sendrecvmsg_locked() Must return target values and target errnos. */
+static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
+                                      int flags, int send)
+{
+    abi_long ret, len;
+    struct msghdr msg;
+    abi_ulong count;
+    struct iovec *vec;
+    abi_ulong target_vec;
+
+    if (msgp->msg_name) {
+        msg.msg_namelen = tswap32(msgp->msg_namelen);
+        msg.msg_name = alloca(msg.msg_namelen + 1);
+        ret = target_to_host_sockaddr(msg.msg_name,
+                                      tswapal(msgp->msg_name),
+                                      msg.msg_namelen);
+        if (ret == -TARGET_EFAULT) {
+            /*
+             * For connected sockets msg_name and msg_namelen must be ignored,
+             * so returning EFAULT immediately is wrong.  Instead, pass a bad
+             * msg_name to the host kernel, and let it decide whether to return
+             * EFAULT or not.
+             */
+            msg.msg_name = (void *)-1;
+        } else if (ret) {
+            goto out2;
+        }
+    } else {
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+    }
+    msg.msg_controllen = 2 * tswap32(msgp->msg_controllen);
+    if (msgp->msg_control) {
+        msg.msg_control = alloca(msg.msg_controllen);
+        memset(msg.msg_control, 0, msg.msg_controllen);
+    } else {
+        msg.msg_control = NULL;
+    }
+
+    msg.msg_flags = tswap32(msgp->msg_flags);
+
+    count = tswap32(msgp->msg_iovlen);
+    target_vec = tswapal(msgp->msg_iov);
+
+    if (count > IOV_MAX) {
+        /*
+         * sendrcvmsg returns a different errno for this condition than
+         * readv/writev, so we must catch it here before lock_iovec() does.
+         */
+        ret = -TARGET_EMSGSIZE;
+        goto out2;
+    }
+
+    vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE,
+                     target_vec, count, send);
+    if (vec == NULL) {
+        ret = -host_to_target_errno(errno);
+        goto out2;
+    }
+    msg.msg_iovlen = count;
+    msg.msg_iov = vec;
+
+    if (send) {
+        if (msg.msg_control != NULL) {
+            ret = t2h_freebsd_cmsg(&msg, msgp);
+        } else {
+            ret = 0;
+        }
+        if (ret == 0) {
+            ret = get_errno(safe_sendmsg(fd, &msg, flags));
+        }
+    } else {
+        ret = get_errno(safe_recvmsg(fd, &msg, flags));
+        if (!is_error(ret)) {
+            len = ret;
+            if (msg.msg_control != NULL) {
+                ret = h2t_freebsd_cmsg(msgp, &msg);
+            } else {
+                ret = 0;
+            }
+            if (!is_error(ret)) {
+                msgp->msg_namelen = tswap32(msg.msg_namelen);
+                msgp->msg_flags = tswap32(msg.msg_flags);
+                if (msg.msg_name != NULL && msg.msg_name != (void *)-1) {
+                    ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
+                                    msg.msg_name, msg.msg_namelen);
+                    if (ret) {
+                        goto out;
+                    }
+                }
+
+                ret = len;
+            }
+        }
+    }
+
+out:
+    unlock_iovec(vec, target_vec, count, !send);
+out2:
+    return ret;
+}
+
+
+static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
+                               int flags, int send)
+{
+    abi_long ret;
+    struct target_msghdr *msgp;
+
+    if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE,
+                          msgp,
+                          target_msg,
+                          send ? 1 : 0)) {
+        return -TARGET_EFAULT;
+    }
+    ret = do_sendrecvmsg_locked(fd, msgp, flags, send);
+    unlock_user_struct(msgp, target_msg, send ? 0 : 1);
+    return ret;
+}
+
+static inline struct sockopt_entry *get_sockopt_entry(int level)
+{
+    for (int i = 0; i < ARRAY_SIZE(so_cache); i++) {
+        if (so_cache[i].level == level) {
+            return so_cache[i].entry;
+        }
+    }
+    return NULL;
+}
+
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, socklen_t optlen)
+{
+    abi_long ret;
+    int val;
+    u_char ch;
+    uint64_t val64;
+    struct sockopt_entry *e = get_sockopt_entry(level);
+    void *p;
+
+    if (e == NULL) {
+        gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+                 level, optname);
+        return -TARGET_ENOPROTOOPT;
+    }
+
+    while (e->level != SOCK_LEVEL_NONE && e->optname != optname) {
+        e++;
+    }
+
+    if (e->level == SOCK_LEVEL_NONE) {
+        gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+                 level, optname);
+        return -TARGET_ENOPROTOOPT;
+    }
+
+    for (int i = 0; i < ARRAY_SIZE(e->type) && e->type[i] != 0; i++) {
+        switch (e->type[i]) {
+        case SOCKOPT_TYPE_BOOL:
+        case SOCKOPT_TYPE_INT:
+        case SOCKOPT_TYPE_U_INT:
+        case SOCKOPT_TYPE_UINT32_T:
+            if (optlen != sizeof(int)) {
+                continue;
+            }
+            if (get_user_u32(val, optval_addr)) {
+                return -TARGET_EFAULT;
+            }
+            return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+        case SOCKOPT_TYPE_U_CHAR:
+            if (optlen != sizeof(u_char)) {
+                continue;
+            }
+            if (get_user_u8(ch, optval_addr)) {
+                return -TARGET_EFAULT;
+            }
+            return get_errno(setsockopt(sockfd, level, optname, &ch, sizeof(ch)));
+        case SOCKOPT_TYPE_UINT64_T:
+            if (optlen != sizeof(uint64_t)) {
+                continue;
+            }
+            if (get_user_u64(val64, optval_addr)) {
+                return -TARGET_EFAULT;
+            }
+            return get_errno(setsockopt(sockfd, level, optname, &val64, sizeof(val64)));
+        default:
+#if HOST_LONG_BITS != TARGET_ABI_BITS || HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
+            gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+                     level, optname);
+            return -TARGET_ENOPROTOOPT;
+#endif
+            break;
+        }
+    }
+
+    /*
+     * When bit size and endian are the same, the structures are the same (we hope).
+     */
+    p = lock_user(VERIFY_READ, optval_addr, optlen, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(setsockopt(sockfd, level, optname, p, optlen));
+    unlock_user(p, optval_addr, 0);
+    return ret;
+}
+
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int val;
+    u_char ch;
+    socklen_t len;
+    uint64_t val64;
+    struct sockopt_entry *e = get_sockopt_entry(level);
+    void *p;
+
+    if (e == NULL) {
+        gemu_log("Unsupported getsockopt level=%d optname=%d\n",
+                 level, optname);
+        return -TARGET_ENOPROTOOPT;
+    }
+
+    while (e->level != SOCK_LEVEL_NONE && e->optname != optname) {
+        e++;
+    }
+
+    if (e->level == SOCK_LEVEL_NONE) {
+        gemu_log("Unsupported getsockopt level=%d optname=%d\n",
+                 level, optname);
+        return -TARGET_ENOPROTOOPT;
+    }
+
+    if (get_user_u32(len, optlen)) {
+        return -TARGET_EFAULT;
+    }
+
+    for (int i = 0; i < ARRAY_SIZE(e->type) && e->type[i] != 0; i++) {
+        switch (e->type[i]) {
+        case SOCKOPT_TYPE_BOOL:
+        case SOCKOPT_TYPE_INT:
+        case SOCKOPT_TYPE_U_INT:
+        case SOCKOPT_TYPE_UINT32_T:
+            if (len != sizeof(int)) {
+                continue;
+            }
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &len));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len == sizeof(int)) {
+                if (put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+                goto done;
+            }
+            continue;
+        case SOCKOPT_TYPE_U_CHAR:
+            if (len != sizeof(u_char)) {
+                continue;
+            }
+            ret = get_errno(getsockopt(sockfd, level, optname, &ch, &len));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len == sizeof(u_char)) {
+                if (put_user_u8(ch, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+                goto done;
+            }
+            continue;
+        case SOCKOPT_TYPE_UINT64_T:
+            if (len != sizeof(uint64_t)) {
+                continue;
+            }
+            ret = get_errno(getsockopt(sockfd, level, optname, &val64, &len));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len == sizeof(uint64_t)) {
+                if (put_user_u64(val64, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+                goto done;
+            }
+            continue;
+        default:
+#if HOST_LONG_BITS != TARGET_ABI_BITS || HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN
+            gemu_log("Unsupported getsockopt level=%d optname=%d\n",
+                     level, optname);
+            return -TARGET_ENOPROTOOPT;
+#endif
+            break;
+        }
+    }
+
+    /*
+     * When bit size and endian are the same, the structures are the same, and
+     * if not that is handled above.
+     */
+    p = lock_user(VERIFY_WRITE, optval_addr, len, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getsockopt(sockfd, level, optname, p, &len));
+    unlock_user(p, optval_addr, ret < 0 ? 0 : len);
+done:
+    if (put_user_u32(len, optlen)) {
+        return -TARGET_EFAULT;
+    }
+    return ret;
+}
+
+
+#endif /* BSD_USER_FREEBSD_OS_SOCKET_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 19/41] bsd-user: Add FreeBSD socket system calls
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (17 preceding siblings ...)
  2026-09-18  4:23 ` [PULL 18/41] bsd-user: Implement both getsockopt and setsockopt Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 20/41] bsd-user: Add os-socket.[ch] sendmsg, recvmsg and cmsg Warner Losh
                   ` (22 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Complete os-socket.h with setfib, bindat, connectat, and accept4.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-socket.h | 83 ++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
index 126e49b282..b0f2498ff7 100644
--- a/bsd-user/freebsd/os-socket.h
+++ b/bsd-user/freebsd/os-socket.h
@@ -336,5 +336,88 @@ done:
     return ret;
 }
 
+/* setfib(2) */
+static inline abi_long do_freebsd_setfib(abi_long fib)
+{
+
+    return get_errno(setfib(fib));
+}
+
+/* bindat(2) */
+static inline abi_long do_freebsd_bindat(int fd, int sockfd,
+        abi_ulong target_addr, socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bindat(fd, sockfd, addr, addrlen));
+}
+
+/* connectat(2) */
+static inline abi_long do_freebsd_connectat(int fd, int sockfd,
+        abi_ulong target_addr, socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen + 1);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connectat(fd, sockfd, addr, addrlen));
+}
+
+/* accept4(2) */
+static inline abi_long do_freebsd_accept4(int fd, abi_ulong target_addr,
+        abi_ulong target_addrlen_addr, int flags)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept4(fd, addr, &addrlen, flags));
+    if (!is_error(ret)) {
+        if (is_error(host_to_target_sockaddr(target_addr, addr, addrlen))) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
 
 #endif /* BSD_USER_FREEBSD_OS_SOCKET_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 20/41] bsd-user: Add os-socket.[ch] sendmsg, recvmsg and cmsg
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (18 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 19/41] bsd-user: Add FreeBSD socket system calls Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 21/41] bsd-user: Add socket system call dispatch Warner Losh
                   ` (21 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Kyle Evans, Michal Meloun, Pierrick Bouvier, Richard Henderson

Add the first part of FreeBSD socket support: do_sendrecvmsg_locked and
do_sendrecvmsg functions. Also add target_msghdr, target_cmsghdr, and
CMSG macros structures to syscall_defs.h.  Add target-to-host and
host-to-target control message conversion functions (t2h_freebsd_cmsg
and h2t_freebsd_cmsg) for sendmsg/recvmsg support, and add os-socket.c
to the FreeBSD build.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Michal Meloun <mmel@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/meson.build  |   3 +-
 bsd-user/freebsd/os-socket.c  | 239 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-socket.h  |  13 +-
 bsd-user/freebsd/os-syscall.c |   3 +
 4 files changed, 253 insertions(+), 5 deletions(-)
 create mode 100644 bsd-user/freebsd/os-socket.c

diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build
index 38f2debf7e..83593a1e20 100644
--- a/bsd-user/freebsd/meson.build
+++ b/bsd-user/freebsd/meson.build
@@ -4,8 +4,9 @@ bsd_syscall_nr = custom_target('bsd-syscall-h',
     command: [sh, meson.current_source_dir() / 'scripts/syscallhdr.sh', '@INPUT@', '@OUTPUT@', 'FREEBSD'])
 
 bsd_user_ss.add(files(
-  'os-stat.c',
   'os-proc.c',
+  'os-socket.c',
+  'os-stat.c',
   'os-sys.c',
   'os-syscall.c'),
   bsd_syscall_nr
diff --git a/bsd-user/freebsd/os-socket.c b/bsd-user/freebsd/os-socket.c
new file mode 100644
index 0000000000..9c723d7608
--- /dev/null
+++ b/bsd-user/freebsd/os-socket.c
@@ -0,0 +1,239 @@
+/*
+ * FreeBSD socket related system call helpers
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh);
+
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    socklen_t msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg, *target_cmsg_start;
+    socklen_t space = 0;
+
+    msg_controllen = tswap32(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+    target_cmsg_start = target_cmsg;
+    if (!target_cmsg) {
+        return -TARGET_EFAULT;
+    }
+
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+        int len = (unsigned char *)(target_cmsg) +
+            tswap32(target_cmsg->cmsg_len) - (unsigned char *)target_data;
+
+        space += CMSG_SPACE(len);
+        if (space > msgh->msg_controllen) {
+            space -= CMSG_SPACE(len);
+            /*
+             * This is a QEMU bug, since we allocated the payload area ourselves
+             * (unlike overflow in host-to-target conversion, which is just the
+             * guest giving us a buffer that's too small). It can't happen for
+             * the payload types we currently support; if it becomes an issue in
+             * future we would need to improve our allocation strategy to
+             * something more intelligent than "twice the size of the target
+             * buffer we're reading from".
+             */
+            gemu_log("Host cmsg overflow\n");
+            break;
+        }
+
+        if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
+            cmsg->cmsg_level = SOL_SOCKET;
+        } else {
+            cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+        }
+        cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
+        cmsg->cmsg_len = CMSG_LEN(len);
+
+        if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+            int *fd = (int *)data;
+            int *target_fd = (int *)target_data;
+            int i, numfds = len / sizeof(int);
+
+            for (i = 0; i < numfds; i++) {
+                __get_user(fd[i], target_fd + i);
+            }
+        } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
+            (cmsg->cmsg_type == SCM_TIMESTAMP) &&
+            (len == sizeof(struct target_freebsd_timeval)))  {
+            /* copy struct timeval to host */
+            struct timeval *tv = (struct timeval *)data;
+            struct target_freebsd_timeval *target_tv =
+                (struct target_freebsd_timeval *)target_data;
+            __get_user(tv->tv_sec, &target_tv->tv_sec);
+            __get_user(tv->tv_usec, &target_tv->tv_usec);
+        } else {
+            gemu_log("Unsupported target ancillary data: %d/%d\n",
+                     cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(data, target_data, len);
+        }
+
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+                                         target_cmsg_start);
+    }
+    unlock_user(target_cmsg_start, target_cmsg_addr, 0);
+the_end:
+    msgh->msg_controllen = space;
+    return 0;
+}
+
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh)
+{
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
+    socklen_t msg_controllen;
+    abi_ulong target_cmsg_addr;
+    struct target_cmsghdr *target_cmsg, *target_cmsg_start;
+    socklen_t space = 0;
+
+    msg_controllen = tswap32(target_msgh->msg_controllen);
+    if (msg_controllen < sizeof(struct target_cmsghdr)) {
+        goto the_end;
+    }
+    target_cmsg_addr = tswapal(target_msgh->msg_control);
+    target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
+    target_cmsg_start = target_cmsg;
+    if (!target_cmsg) {
+        return -TARGET_EFAULT;
+    }
+
+    while (cmsg && target_cmsg) {
+        void *data = CMSG_DATA(cmsg);
+        void *target_data = TARGET_CMSG_DATA(target_cmsg);
+        int len = (unsigned char *)(cmsg) + cmsg->cmsg_len -
+            (unsigned char *)data;
+
+        int tgt_len, tgt_space;
+
+        /*
+         * We never copy a half-header but may copy half-data; this is Linux's
+         * behaviour in put_cmsg(). Note that truncation here is a guest problem
+         * (which we report to the guest via the CTRUNC bit), unlike truncation
+         * in target_to_host_cmsg, which is a QEMU bug.
+         */
+        if (msg_controllen < sizeof(struct target_cmsghdr)) {
+            target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
+            break;
+        }
+
+        if (cmsg->cmsg_level == SOL_SOCKET) {
+            target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
+        } else {
+            target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+        }
+        target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
+
+        /*
+         * Payload types which need a different size of payload on the target
+         * must adjust tgt_len here.
+         */
+        tgt_len = len;
+        switch (cmsg->cmsg_level) {
+        case SOL_SOCKET:
+            switch (cmsg->cmsg_type) {
+            case SCM_TIMESTAMP:
+                tgt_len = sizeof(struct target_freebsd_timeval);
+                break;
+            default:
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+
+        if (msg_controllen < TARGET_CMSG_LEN(tgt_len)) {
+            target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
+            tgt_len = msg_controllen - sizeof(struct target_cmsghdr);
+        }
+
+        /*
+         * We must now copy-and-convert len bytes of payload into tgt_len bytes
+         * of destination space. Bear in mind that in both source and
+         * destination we may be dealing with a truncated value!
+         */
+        switch (cmsg->cmsg_level) {
+        case SOL_SOCKET:
+            switch (cmsg->cmsg_type) {
+            case SCM_RIGHTS:
+            {
+                int *fd = (int *)data;
+                int *target_fd = (int *)target_data;
+                int i, numfds = tgt_len / sizeof(int);
+
+                for (i = 0; i < numfds; i++) {
+                    __put_user(fd[i], target_fd + i);
+                }
+                break;
+            }
+            case SCM_TIMESTAMP:
+            {
+                struct timeval *tv = (struct timeval *)data;
+                struct target_freebsd_timeval *target_tv =
+                    (struct target_freebsd_timeval *)target_data;
+
+                if (len != sizeof(struct timeval) ||
+                    tgt_len != sizeof(struct target_freebsd_timeval)) {
+                    goto unimplemented;
+                }
+
+                /* copy struct timeval to target */
+                __put_user(tv->tv_sec, &target_tv->tv_sec);
+                __put_user(tv->tv_usec, &target_tv->tv_usec);
+                break;
+            }
+            default:
+                goto unimplemented;
+            }
+            break;
+        default:
+        unimplemented:
+            gemu_log("Unsupported host ancillary data: %d/%d\n",
+                     cmsg->cmsg_level, cmsg->cmsg_type);
+            memcpy(target_data, data, MIN(len, tgt_len));
+            if (tgt_len > len) {
+                memset(target_data + len, 0, tgt_len - len);
+            }
+        }
+
+        target_cmsg->cmsg_len = tswap32(TARGET_CMSG_LEN(tgt_len));
+        tgt_space = TARGET_CMSG_SPACE(tgt_len);
+        if (msg_controllen < tgt_space) {
+            tgt_space = msg_controllen;
+        }
+        msg_controllen -= tgt_space;
+        space += tgt_space;
+        cmsg = CMSG_NXTHDR(msgh, cmsg);
+        target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+                                         target_cmsg_start);
+    }
+    unlock_user(target_cmsg_start, target_cmsg_addr, space);
+the_end:
+    target_msgh->msg_controllen = tswap32(space);
+    return 0;
+}
diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
index b0f2498ff7..12e9ec3da8 100644
--- a/bsd-user/freebsd/os-socket.h
+++ b/bsd-user/freebsd/os-socket.h
@@ -19,9 +19,14 @@
 ssize_t safe_recvmsg(int s, struct msghdr *msg, int flags);
 ssize_t safe_sendmsg(int s, const struct msghdr *msg, int flags);
 
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+        struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+        struct msghdr *msgh);
+
 /* do_sendrecvmsg_locked() Must return target values and target errnos. */
-static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
-                                      int flags, int send)
+static inline abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp,
+                                             int flags, int send)
 {
     abi_long ret, len;
     struct msghdr msg;
@@ -122,8 +127,8 @@ out2:
 }
 
 
-static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
-                               int flags, int send)
+static inline abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
+                                      int flags, int send)
 {
     abi_long ret;
     struct target_msghdr *msgp;
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 7bc9fedfb7..46fee46336 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -47,6 +47,7 @@
 #include "os-proc.h"
 #include "os-signal.h"
 #include "os-file.h"
+#include "os-socket.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -85,6 +86,8 @@ safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len, int, flags,
     struct sockaddr *restrict, from, socklen_t *restrict, fromlen);
 safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
     flags, const struct sockaddr *, to, socklen_t, tolen);
+safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
+safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
 
 /* used in os-proc */
 safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 21/41] bsd-user: Add socket system call dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (19 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 20/41] bsd-user: Add os-socket.[ch] sendmsg, recvmsg and cmsg Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 22/41] bsd-user: Add os-time.h with clock and time-of-day functions Warner Losh
                   ` (20 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Wire up socket-related system calls in the FreeBSD syscall dispatcher:
accept, accept4, bind, bindat, connect, connectat, getpeername,
getsockname, getsockopt, setsockopt, listen, recvfrom, recvmsg,
sendmsg, sendto, socket, socketpair, shutdown, and setfib.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 79 +++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 46fee46336..5d3a66e360 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -1073,6 +1073,85 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd_pdkill(arg1, arg2);
         break;
 
+        /*
+         * socket related system calls
+         */
+    case TARGET_FREEBSD_NR_accept: /* accept(2) */
+        ret = do_bsd_accept(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_accept4: /* accept4(2) */
+        ret = do_freebsd_accept4(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_bind: /* bind(2) */
+        ret = do_bsd_bind(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_bindat: /* bindat(2) */
+        ret = do_freebsd_bindat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_connect: /* connect(2) */
+        ret = do_bsd_connect(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_connectat: /* connectat(2) */
+        ret = do_freebsd_connectat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_getpeername: /* getpeername(2) */
+        ret = do_bsd_getpeername(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockname: /* getsockname(2) */
+        ret = do_bsd_getsockname(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getsockopt: /* getsockopt(2) */
+        ret = do_bsd_getsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_setsockopt: /* setsockopt(2) */
+        ret = do_bsd_setsockopt(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_listen: /* listen(2) */
+        ret = get_errno(listen(arg1, arg2));
+        break;
+
+    case TARGET_FREEBSD_NR_recvfrom: /* recvfrom(2) */
+        ret = do_bsd_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_recvmsg: /* recvmsg(2) */
+        ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
+        break;
+
+    case TARGET_FREEBSD_NR_sendmsg: /* sendmsg(2) */
+        ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
+        break;
+
+    case TARGET_FREEBSD_NR_sendto: /* sendto(2) */
+        ret = do_bsd_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_socket: /* socket(2) */
+        ret = do_bsd_socket(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_socketpair: /* socketpair(2) */
+        ret = do_bsd_socketpair(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_shutdown: /* shutdown(2) */
+        ret = do_bsd_shutdown(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_setfib: /* setfib(2) */
+        ret = do_freebsd_setfib(arg1);
+        break;
+
         /*
          * sys{ctl, arch, call}
          */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 22/41] bsd-user: Add os-time.h with clock and time-of-day functions
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (20 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 21/41] bsd-user: Add socket system call dispatch Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 23/41] bsd-user: Add utimes, futimes, and ktimer functions to os-time.h Warner Losh
                   ` (19 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Sean Bruno, Kyle Evans, Pierrick Bouvier, Richard Henderson

Add the first part of FreeBSD time support: nanosleep, clock_nanosleep,
clock_gettime, clock_settime, clock_getres, gettimeofday, settimeofday,
adjtime, ntp_adjtime, and ntp_gettime. Also add safe_syscall wrappers
for nanosleep, clock_nanosleep, and kevent.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Sean Bruno <sbruno@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-time.h | 225 +++++++++++++++++++++++++++++++++++++
 1 file changed, 225 insertions(+)
 create mode 100644 bsd-user/freebsd/os-time.h

diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
new file mode 100644
index 0000000000..e387441d86
--- /dev/null
+++ b/bsd-user/freebsd/os-time.h
@@ -0,0 +1,225 @@
+/*
+ * FreeBSD time related system call shims
+ *
+ * Copyright (c) 2013-2015 Stacey Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef FREEBSD_OS_TIME_H
+#define FREEBSD_OS_TIME_H
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/timex.h>
+#include <poll.h>
+#include <signal.h>
+#include <time.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+#include "bsd-socket.h"
+
+int safe_clock_nanosleep(clockid_t clock_id, int flags,
+     const struct timespec *rqtp, struct timespec *rmtp);
+int safe_nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+int safe_kevent(int, const struct kevent *, int, struct kevent *, int,
+     const struct timespec *);
+
+int __sys_ktimer_create(clockid_t, struct sigevent *restrict,
+     int *restrict);
+int __sys_ktimer_gettime(int, struct itimerspec *);
+int __sys_ktimer_settime(int, int, const struct itimerspec *restrict,
+     struct itimerspec *restrict);
+int __sys_ktimer_delete(int);
+
+/* nanosleep(2) */
+static inline abi_long do_freebsd_nanosleep(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec req, rem;
+
+    ret = t2h_freebsd_timespec(&req, arg1);
+    if (!is_error(ret)) {
+        ret = get_errno(safe_nanosleep(&req, &rem));
+        if (ret == -TARGET_EINTR && arg2) {
+            if (h2t_freebsd_timespec(arg2, &rem) != 0) {
+                ret = -TARGET_EFAULT;
+            }
+        }
+    }
+
+    return ret;
+}
+
+/* clock_nanosleep(2) */
+static inline abi_long do_freebsd_clock_nanosleep(abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4)
+{
+    struct timespec req, rem;
+    abi_long ret;
+    int clkid, flags;
+
+    clkid = arg1;
+    /* XXX Translate? */
+    flags = arg2;
+    ret = t2h_freebsd_timespec(&req, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(safe_clock_nanosleep(clkid, flags, &req, &rem));
+        if (ret == -TARGET_EINTR && arg4) {
+            if (h2t_freebsd_timespec(arg4, &rem) != 0) {
+                ret = -TARGET_EFAULT;
+            }
+        }
+    }
+
+    return ret;
+}
+
+/* clock_gettime(2) */
+static inline abi_long do_freebsd_clock_gettime(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_gettime(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts) != 0) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* clock_settime(2) */
+static inline abi_long do_freebsd_clock_settime(abi_long arg1, abi_long arg2)
+{
+    struct timespec ts;
+
+    if (t2h_freebsd_timespec(&ts, arg2) != 0) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(clock_settime(arg1, &ts));
+}
+
+/* clock_getres(2) */
+static inline abi_long do_freebsd_clock_getres(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    ret = get_errno(clock_getres(arg1, &ts));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timespec(arg2, &ts) != 0) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* gettimeofday(2) */
+static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
+{
+    abi_long ret;
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
+    if (!is_error(ret)) {
+        if (h2t_freebsd_timeval(&tv, arg1)) {
+            return -TARGET_EFAULT;
+        }
+    }
+
+    return ret;
+}
+
+/* settimeofday(2) */
+static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
+{
+    struct timeval tv;
+    struct timezone tz, *target_tz; /* XXX */
+
+    if (arg2 != 0) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+            return -TARGET_EFAULT;
+        }
+        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+        unlock_user_struct(target_tz, arg2, 1);
+    }
+    if (t2h_freebsd_timeval(&tv, arg1)) {
+        return -TARGET_EFAULT;
+    }
+
+    return get_errno(settimeofday(&tv, arg2 != 0 ? &tz : NULL));
+}
+
+/* adjtime(2) */
+static inline abi_long do_freebsd_adjtime(abi_ulong target_delta_addr,
+        abi_ulong target_old_addr)
+{
+    abi_long ret;
+    struct timeval host_delta, host_old;
+
+    ret = t2h_freebsd_timeval(&host_delta, target_delta_addr);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    if (target_old_addr) {
+        ret = get_errno(adjtime(&host_delta, &host_old));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = h2t_freebsd_timeval(&host_old, target_old_addr);
+    } else {
+        ret = get_errno(adjtime(&host_delta, NULL));
+    }
+
+    return ret;
+}
+
+/* ntp_adjtime(2) */
+static inline abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
+{
+    abi_long ret;
+    struct timex host_tx;
+
+    ret = t2h_freebsd_timex(&host_tx, target_tx_addr);
+    if (ret == 0) {
+        ret = get_errno(ntp_adjtime(&host_tx));
+    }
+
+    return ret;
+}
+
+/* ntp_gettime(2) */
+static inline abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
+{
+    abi_long ret;
+    struct ntptimeval host_ntv;
+
+    ret = get_errno(ntp_gettime(&host_ntv));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_ntptimeval(target_ntv_addr, &host_ntv);
+    }
+
+    return ret;
+}
+
+
+
+#endif /* FREEBSD_OS_TIME_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 23/41] bsd-user: Add utimes, futimes, and ktimer functions to os-time.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (21 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 22/41] bsd-user: Add os-time.h with clock and time-of-day functions Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 24/41] bsd-user: Add select, pselect, and ppoll " Warner Losh
                   ` (18 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Kyle Evans, Richard Henderson

Add time-related system call shims: utimes, lutimes, futimes,
futimesat, ktimer_create, ktimer_delete, ktimer_settime, and
ktimer_gettime.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-time.h | 212 +++++++++++++++++++++++++++++++++++++
 1 file changed, 212 insertions(+)

diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
index e387441d86..06104a5b7d 100644
--- a/bsd-user/freebsd/os-time.h
+++ b/bsd-user/freebsd/os-time.h
@@ -221,5 +221,217 @@ static inline abi_long do_freebsd_ntp_gettime(abi_ulong target_ntv_addr)
 }
 
 
+/* utimes(2) */
+static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* lutimes(2) */
+static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(lutimes(p, tvp));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* futimes(2) */
+static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
+{
+    struct timeval *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg2) ||
+                t2h_freebsd_timeval(&tv[1], arg2 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    return get_errno(futimes(arg1, tvp));
+}
+
+/* futimesat(2) */
+static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct timeval *tvp, tv[2];
+
+    if (arg3 != 0) {
+        if (t2h_freebsd_timeval(&tv[0], arg3) ||
+                t2h_freebsd_timeval(&tv[1], arg3 +
+                        sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(arg2);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(futimesat(arg1, p, tvp));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* timer_create(2) */
+static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    /* args: clockid_t clockid, struct sigevent *sevp, int *timerid */
+    abi_long ret;
+
+    struct sigevent host_sevp = { 0 }, *phost_sevp = NULL;
+
+    int clkid = arg1;
+    int timer_index = next_free_host_timer();
+
+    if (timer_index < 0) {
+        ret = -TARGET_EAGAIN;
+    } else {
+        int *phtimer = g_posix_timers  + timer_index;
+
+        if (arg2) {
+            phost_sevp = &host_sevp;
+            ret = target_to_host_sigevent(phost_sevp, arg2);
+            if (ret != 0) {
+                g_posix_timers[timer_index] = 0;
+                return -TARGET_EFAULT;
+            }
+        }
+
+        ret = get_errno(__sys_ktimer_create(clkid, phost_sevp, phtimer));
+        if (ret) {
+            phtimer = NULL;
+        } else {
+            if (put_user(TIMER_MAGIC | timer_index, arg3, int)) {
+                __sys_ktimer_delete(g_posix_timers[timer_index]);
+                g_posix_timers[timer_index] = 0;
+                ret = -TARGET_EFAULT;
+            }
+        }
+    }
+    return ret;
+}
+
+/* timer_delete(2) */
+static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
+{
+    /* args: int timerid */
+    abi_long ret;
+    int timerid = get_timer_id(arg1);
+
+    if (timerid < 0) {
+        ret = timerid;
+    } else {
+        int htimer = g_posix_timers[timerid];
+        ret = get_errno(__sys_ktimer_delete(htimer));
+        g_posix_timers[timerid] = 0;
+    }
+    return ret;
+}
+
+/* timer_settime(2) */
+static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    /*
+     * args: int timerid, int flags, const struct itimerspec *new_value,
+     * struct itimerspec * old_value
+     */
+    abi_long ret;
+    int timerid = get_timer_id(arg1);
+
+    if (timerid < 0) {
+        ret = timerid;
+    } else if (arg3 == 0) {
+        ret = -TARGET_EINVAL;
+    } else {
+        int htimer = g_posix_timers[timerid];
+        struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
+
+        if (target_to_host_itimerspec(&hspec_new, arg3)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(
+            __sys_ktimer_settime(htimer, arg2, &hspec_new, &hspec_old));
+        if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* timer_gettime(2) */
+static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
+{
+    /* args: int timerid, struct itimerspec *curr_value */
+    abi_long ret;
+    int timerid = get_timer_id(arg1);
+
+    if (timerid < 0) {
+        ret = timerid;
+    } else if (!arg2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        int htimer = g_posix_timers[timerid];
+        struct itimerspec hspec;
+        ret = get_errno(__sys_ktimer_gettime(htimer, &hspec));
+        if (!is_error(ret)) {
+            ret = host_to_target_itimerspec(arg2, &hspec);
+        }
+    }
+    return ret;
+}
+
 
 #endif /* FREEBSD_OS_TIME_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 24/41] bsd-user: Add select, pselect, and ppoll to os-time.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (22 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 23/41] bsd-user: Add utimes, futimes, and ktimer functions to os-time.h Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 25/41] bsd-user: Add kqueue and kevent functions " Warner Losh
                   ` (17 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Kyle Evans, Richard Henderson

Add I/O multiplexing system call shims: select, pselect, and ppoll
with proper fd_set, timespec/timeval, and signal mask conversion.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-time.h | 202 +++++++++++++++++++++++++++++++++++++
 1 file changed, 202 insertions(+)

diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
index 06104a5b7d..5f537fac40 100644
--- a/bsd-user/freebsd/os-time.h
+++ b/bsd-user/freebsd/os-time.h
@@ -433,5 +433,207 @@ static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long arg2)
     return ret;
 }
 
+/* select(2) */
+static inline abi_long do_freebsd_select(CPUArchState *env, int n,
+        abi_ulong rfd_addr, abi_ulong wfd_addr, abi_ulong efd_addr,
+        abi_ulong target_tv_addr)
+{
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    struct timeval tv, *tvp;
+    abi_long ret, error;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (ret != 0) {
+        return ret;
+    }
+
+    if (target_tv_addr != 0) {
+        if (t2h_freebsd_timeval(&tv, target_tv_addr)) {
+            return -TARGET_EFAULT;
+        }
+        tvp = &tv;
+    } else {
+        tvp = NULL;
+    }
+
+    ret = get_errno(safe_select(n, rfds_ptr, wfds_ptr, efds_ptr, tvp));
+
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            error = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (wfd_addr != 0) {
+            error = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (efd_addr != 0) {
+            error = copy_to_user_fdset(efd_addr, &efds, n);
+            if (error != 0) {
+                return error;
+            }
+        }
+        if (target_tv_addr != 0) {
+            error = h2t_freebsd_timeval(&tv, target_tv_addr);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+    }
+    return ret;
+}
+
+/* pselect(2) */
+static inline abi_long do_freebsd_pselect(CPUArchState *env, int n,
+        abi_ulong rfd_addr, abi_ulong wfd_addr, abi_ulong efd_addr,
+        abi_ulong ts_addr, abi_ulong set_addr)
+{
+    CPUState *cpu = env_cpu(env);
+    TaskState *tstate = cpu->opaque;
+    fd_set rfds, wfds, efds;
+    fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+    sigset_t *set_ptr;
+    struct timespec ts, *ts_ptr;
+    void *p;
+    abi_long ret, error;
+
+    ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    /* Unlike select(), pselect() uses struct timespec instead of timeval */
+    if (ts_addr) {
+        if (t2h_freebsd_timespec(&ts, ts_addr)) {
+            return -TARGET_EFAULT;
+        }
+        ts_ptr = &ts;
+    } else {
+        ts_ptr = NULL;
+    }
+
+    if (set_addr != 0) {
+        p = lock_user(VERIFY_READ, set_addr, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&tstate->sigsuspend_mask, p);
+        unlock_user(p, set_addr, 0);
+        set_ptr = &tstate->sigsuspend_mask;
+    } else {
+        set_ptr = NULL;
+    }
+
+    ret = get_errno(safe_pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr,
+        set_ptr));
+    if (ret != -TARGET_ERESTART)  {
+        tstate->in_sigsuspend = true;
+    }
+    if (!is_error(ret)) {
+        if (rfd_addr != 0) {
+            error = copy_to_user_fdset(rfd_addr, &rfds, n);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+        if (wfd_addr != 0) {
+            error = copy_to_user_fdset(wfd_addr, &wfds, n);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+        if (efd_addr != 0) {
+            error = copy_to_user_fdset(efd_addr, &efds, n);
+            if (is_error(error)) {
+                return error;
+            }
+        }
+    }
+    return ret;
+}
+
+/* ppoll(2) */
+static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
+        abi_long arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    CPUState *cpu = env_cpu(env);
+    TaskState *tstate = cpu->opaque;
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+    struct timespec ts, *ts_ptr;
+    sigset_t *set_ptr;
+    void *p;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+                           sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    }
+
+    /* Unlike poll(), ppoll() uses struct timespec. */
+    if (arg3) {
+        if (t2h_freebsd_timespec(&ts, arg3)) {
+            return -TARGET_EFAULT;
+        }
+        ts_ptr = &ts;
+    } else {
+        ts_ptr = NULL;
+    }
+
+    if (arg4 != 0) {
+        p = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        target_to_host_sigset(&tstate->sigsuspend_mask, p);
+        unlock_user(p, arg4, 0);
+        set_ptr = &tstate->sigsuspend_mask;
+    } else {
+        set_ptr = NULL;
+    }
+
+    ret = get_errno(ppoll(pfd, nfds, ts_ptr, set_ptr));
+    if (ret != -TARGET_ERESTART) {
+        tstate->in_sigsuspend = true;
+    }
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/* kqueue(2) */
 
 #endif /* FREEBSD_OS_TIME_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 25/41] bsd-user: Add kqueue and kevent functions to os-time.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (23 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 24/41] bsd-user: Add select, pselect, and ppoll " Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 26/41] bsd-user: Add sigtimedwait, itimer, and futimens " Warner Losh
                   ` (16 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Sean Bruno, Kyle Evans, Richard Henderson

Add event notification system call shims: kqueue, freebsd11_kevent
(legacy 32-bit data field), and kevent (with 64-bit ext fields).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Sean Bruno <sbruno@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-time.h | 173 +++++++++++++++++++++++++++++++++++++
 bsd-user/syscall_defs.h    |  22 +++++
 2 files changed, 195 insertions(+)

diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
index 5f537fac40..302872dd8e 100644
--- a/bsd-user/freebsd/os-time.h
+++ b/bsd-user/freebsd/os-time.h
@@ -635,5 +635,178 @@ static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
 }
 
 /* kqueue(2) */
+static inline abi_long do_freebsd_kqueue(void)
+{
+
+    return get_errno(kqueue());
+}
+
+/* kevent(2) */
+/* XXX Maybe some day, consolidate these two... */
+static inline abi_long do_freebsd_freebsd11_kevent(abi_long arg1,
+    abi_ulong arg2, abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    struct kevent *changelist = NULL, *eventlist = NULL;
+    struct target_freebsd11_kevent *target_changelist, *target_eventlist;
+    struct timespec ts;
+    int i;
+
+    if (arg3 != 0) {
+        target_changelist = lock_user(VERIFY_READ, arg2,
+                                      sizeof(*target_changelist) * arg3, 1);
+        if (target_changelist == NULL) {
+            return -TARGET_EFAULT;
+        }
+
+        changelist = alloca(sizeof(struct kevent) * arg3);
+        memset(changelist, '\0', sizeof(struct kevent) * arg3);
+        for (i = 0; i < arg3; i++) {
+            __get_user(changelist[i].ident, &target_changelist[i].ident);
+            __get_user(changelist[i].filter, &target_changelist[i].filter);
+            __get_user(changelist[i].flags, &target_changelist[i].flags);
+            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
+            __get_user(changelist[i].data, &target_changelist[i].data);
+            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
+#if TARGET_ABI_BITS == 32
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap32s((uint32_t *)&changelist[i].udata);
+#else
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap64s((uint64_t *)&changelist[i].udata);
+#endif
+        }
+        unlock_user(target_changelist, arg2, 0);
+    }
+
+    if (arg5 != 0) {
+        eventlist = alloca(sizeof(struct kevent) * arg5);
+    }
+    if (arg6 != 0) {
+        if (t2h_freebsd_timespec(&ts, arg6)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(safe_kevent(arg1, changelist, arg3, eventlist, arg5,
+                                arg6 != 0 ? &ts : NULL));
+
+    if (arg5 == 0) {
+        return ret;
+    }
+
+    if (!is_error(ret)) {
+        target_eventlist = lock_user(VERIFY_WRITE, arg4,
+                                     sizeof(*target_eventlist) * arg5, 0);
+        if (target_eventlist == NULL) {
+            return -TARGET_EFAULT;
+        }
+        for (i = 0; i < ret; i++) {
+            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
+            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
+            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
+            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
+            __put_user(eventlist[i].data, &target_eventlist[i].data);
+            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
+#if TARGET_ABI_BITS == 32
+            tswap32s((uint32_t *)&eventlist[i].udata);
+            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
+#else
+            tswap64s((uint64_t *)&eventlist[i].udata);
+            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
+#endif
+        }
+        unlock_user(target_eventlist, arg4,
+                    sizeof(*target_eventlist) * ret);
+    }
+    return ret;
+}
+
+/* kevent(2) */
+static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
+        abi_long arg3, abi_ulong arg4, abi_long arg5, abi_long arg6)
+{
+    abi_long ret;
+    struct kevent *changelist = NULL, *eventlist = NULL;
+    struct target_freebsd_kevent *target_changelist, *target_eventlist;
+    struct timespec ts;
+    int i;
+
+    if (arg3 != 0) {
+        target_changelist = lock_user(VERIFY_READ, arg2,
+                sizeof(struct target_freebsd_kevent) * arg3, 1);
+        if (target_changelist == NULL) {
+            return -TARGET_EFAULT;
+        }
+
+        changelist = alloca(sizeof(struct kevent) * arg3);
+        for (i = 0; i < arg3; i++) {
+            __get_user(changelist[i].ident, &target_changelist[i].ident);
+            __get_user(changelist[i].filter, &target_changelist[i].filter);
+            __get_user(changelist[i].flags, &target_changelist[i].flags);
+            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
+            __get_user(changelist[i].data, &target_changelist[i].data);
+            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
+#if TARGET_ABI_BITS == 32
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap32s((uint32_t *)&changelist[i].udata);
+#else
+            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
+            tswap64s((uint64_t *)&changelist[i].udata);
+#endif
+            __get_user(changelist[i].ext[0], &target_changelist[i].ext[0]);
+            __get_user(changelist[i].ext[1], &target_changelist[i].ext[1]);
+            __get_user(changelist[i].ext[2], &target_changelist[i].ext[2]);
+            __get_user(changelist[i].ext[3], &target_changelist[i].ext[3]);
+        }
+        unlock_user(target_changelist, arg2, 0);
+    }
+
+    if (arg5 != 0) {
+        eventlist = alloca(sizeof(struct kevent) * arg5);
+    }
+    if (arg6 != 0) {
+        if (t2h_freebsd_timespec(&ts, arg6)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    ret = get_errno(safe_kevent(arg1, changelist, arg3, eventlist, arg5,
+                                arg6 != 0 ? &ts : NULL));
+
+    if (arg5 == 0) {
+        return ret;
+    }
+
+    if (!is_error(ret)) {
+        target_eventlist = lock_user(VERIFY_WRITE, arg4,
+            sizeof(struct target_freebsd_kevent) * arg5, 0);
+        if (target_eventlist == NULL) {
+            return -TARGET_EFAULT;
+        }
+        for (i = 0; i < ret; i++) {
+            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
+            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
+            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
+            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
+            __put_user(eventlist[i].data, &target_eventlist[i].data);
+            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
+#if TARGET_ABI_BITS == 32
+            tswap32s((uint32_t *)&eventlist[i].udata);
+            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
+#else
+            tswap64s((uint64_t *)&eventlist[i].udata);
+            target_eventlist[i].udata = (uintptr_t)eventlist[i].udata;
+#endif
+            __put_user(eventlist[i].ext[0], &target_eventlist[i].ext[0]);
+            __put_user(eventlist[i].ext[1], &target_eventlist[i].ext[1]);
+            __put_user(eventlist[i].ext[2], &target_eventlist[i].ext[2]);
+            __put_user(eventlist[i].ext[3], &target_eventlist[i].ext[3]);
+        }
+        unlock_user(target_eventlist, arg4,
+                sizeof(struct target_freebsd_kevent) * ret);
+    }
+    return ret;
+}
+
+/* sigtimedwait(2) */
 
 #endif /* FREEBSD_OS_TIME_H */
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 0d7002312f..f4bb687388 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -155,6 +155,28 @@ struct target_freebsd_timeval {
 #endif
 };
 
+/*
+ * sys/event.h
+ */
+struct target_freebsd11_kevent {
+    abi_ulong  ident;
+    int16_t    filter;
+    uint16_t   flags;
+    uint32_t   fflags;
+    abi_long   data;
+    abi_ulong  udata;
+};
+
+struct target_freebsd_kevent {
+    abi_ulong  ident;
+    int16_t    filter;
+    uint16_t   flags;
+    uint32_t   fflags;
+    int64_t data;
+    abi_ulong  udata;
+    uint64_t  ext[4];
+};
+
 /*
  *  sys/resource.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 26/41] bsd-user: Add sigtimedwait, itimer, and futimens to os-time.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (24 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 25/41] bsd-user: Add kqueue and kevent functions " Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 27/41] bsd-user: Add os-time.c and time-related type definitions Warner Losh
                   ` (15 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Kyle Evans, Pierrick Bouvier, Richard Henderson

Complete os-time.h with sigtimedwait, setitimer, getitimer,
clock_getcpuclockid2, futimens, and utimensat system call shims.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-time.h | 194 +++++++++++++++++++++++++++++++++++--
 1 file changed, 184 insertions(+), 10 deletions(-)

diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
index 302872dd8e..05cb5db7d1 100644
--- a/bsd-user/freebsd/os-time.h
+++ b/bsd-user/freebsd/os-time.h
@@ -128,19 +128,19 @@ static inline abi_long do_freebsd_gettimeofday(abi_ulong arg1, abi_ulong arg2)
     struct timeval tv;
     struct timezone tz, *target_tz; /* XXX */
 
-    if (arg2 != 0) {
-        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
-            return -TARGET_EFAULT;
-        }
-        __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
-        __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
-        unlock_user_struct(target_tz, arg2, 1);
-    }
     ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
     if (!is_error(ret)) {
         if (h2t_freebsd_timeval(&tv, arg1)) {
             return -TARGET_EFAULT;
         }
+        if (arg2 != 0) {
+            if (!lock_user_struct(VERIFY_WRITE, target_tz, arg2, 0)) {
+                return -TARGET_EFAULT;
+            }
+            __put_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
+            __put_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+            unlock_user_struct(target_tz, arg2, 1);
+        }
     }
 
     return ret;
@@ -153,12 +153,12 @@ static inline abi_long do_freebsd_settimeofday(abi_long arg1, abi_long arg2)
     struct timezone tz, *target_tz; /* XXX */
 
     if (arg2 != 0) {
-        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) {
+        if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 1)) {
             return -TARGET_EFAULT;
         }
         __get_user(tz.tz_minuteswest, &target_tz->tz_minuteswest);
         __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
-        unlock_user_struct(target_tz, arg2, 1);
+        unlock_user_struct(target_tz, arg2, 0);
     }
     if (t2h_freebsd_timeval(&tv, arg1)) {
         return -TARGET_EFAULT;
@@ -601,6 +601,7 @@ static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
     /* Unlike poll(), ppoll() uses struct timespec. */
     if (arg3) {
         if (t2h_freebsd_timespec(&ts, arg3)) {
+            unlock_user(target_pfd, arg1, 0);
             return -TARGET_EFAULT;
         }
         ts_ptr = &ts;
@@ -611,6 +612,7 @@ static inline abi_long do_freebsd_ppoll(CPUArchState *env, abi_long arg1,
     if (arg4 != 0) {
         p = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
         if (p == NULL) {
+            unlock_user(target_pfd, arg1, 0);
             return -TARGET_EFAULT;
         }
         target_to_host_sigset(&tstate->sigsuspend_mask, p);
@@ -808,5 +810,177 @@ static inline abi_long do_freebsd_kevent(abi_long arg1, abi_ulong arg2,
 }
 
 /* sigtimedwait(2) */
+static inline abi_long do_freebsd_sigtimedwait(abi_ulong arg1, abi_ulong arg2,
+        abi_ulong arg3)
+{
+    abi_long ret;
+    void *p;
+    sigset_t set;
+    struct timespec uts, *puts;
+    siginfo_t uinfo;
+
+    p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    target_to_host_sigset(&set, p);
+    unlock_user(p, arg1, 0);
+    if (arg3) {
+        puts = &uts;
+        ret = t2h_freebsd_timespec(puts, arg3);
+        if (ret != 0) {
+            return ret;
+        }
+    } else {
+        puts = NULL;
+    }
+    ret = get_errno(sigtimedwait(&set, &uinfo, puts));
+    if (!is_error(ret) && arg2) {
+        p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0);
+        if (p == NULL) {
+            return -TARGET_EFAULT;
+        }
+        host_to_target_siginfo(p, &uinfo);
+        unlock_user(p, arg2, sizeof(target_siginfo_t));
+    }
+    return ret;
+}
+
+/* setitimer(2) */
+static inline abi_long do_freebsd_setitimer(int arg1, abi_ulong arg2,
+    abi_ulong arg3)
+{
+    abi_long ret = 0;
+    struct itimerval value, ovalue, *pvalue;
+
+    if (arg2) {
+        pvalue = &value;
+        if (t2h_freebsd_timeval(&pvalue->it_interval, arg2) ||
+            t2h_freebsd_timeval(&pvalue->it_value,
+            arg2 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+    } else {
+        pvalue = NULL;
+    }
+    ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+    if (!is_error(ret) && arg3) {
+        if (h2t_freebsd_timeval(&ovalue.it_interval, arg3) ||
+            h2t_freebsd_timeval(&ovalue.it_value,
+            arg3 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getitimer(2) */
+static inline abi_long do_freebsd_getitimer(int arg1, abi_ulong arg2)
+{
+    abi_long ret = 0;
+    struct itimerval value;
+
+    ret = get_errno(getitimer(arg1, &value));
+    if (!is_error(ret) && arg2) {
+        if (h2t_freebsd_timeval(&value.it_interval, arg2) ||
+            h2t_freebsd_timeval(&value.it_value,
+            arg2 + sizeof(struct target_freebsd_timeval))) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* clock_getcpuclockid2(id_t, int, clockid_t *)  Not documented. */
+static inline abi_long do_freebsd_clock_getcpuclockid2(abi_ulong arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret = 0;
+    id_t id;    /* 64-bit value */
+    int which;
+    abi_ulong target_clk_id_addr;
+    clockid_t clk_id;
+
+#if TARGET_ABI_BITS == 32
+    id = (id_t)target_arg64(arg1, arg2);
+    which = (int)arg3;
+    target_clk_id_addr = arg4;
+#else
+    id = (id_t)arg1;
+    which = (int)arg2;
+    target_clk_id_addr = arg3;
+#endif
+
+    if (target_clk_id_addr == 0) {
+        return -TARGET_EINVAL;
+    }
+
+    switch (which) {
+    case TARGET_CPUCLOCK_WHICH_PID:
+        ret = get_errno(clock_getcpuclockid2(id, CPUCLOCK_WHICH_PID, &clk_id));
+        break;
+
+    case TARGET_CPUCLOCK_WHICH_TID:
+        ret = get_errno(clock_getcpuclockid2(id, CPUCLOCK_WHICH_TID, &clk_id));
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    if (!ret && put_user_s32(clk_id, target_clk_id_addr)) {
+        ret = -TARGET_EFAULT;
+    }
+
+    return ret;
+}
+
+static inline abi_long do_freebsd_futimens(abi_ulong arg1,
+        abi_ulong arg2)
+{
+    struct timespec *tvp, tv[2];
+
+    if (arg2 != 0) {
+        if (t2h_freebsd_timespec(&tv[0], arg2) ||
+            t2h_freebsd_timespec(&tv[1], arg2 +
+                sizeof(struct target_freebsd_timespec))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    return get_errno(futimens(arg1, tvp));
+}
+
+static inline abi_long do_freebsd_utimensat(abi_ulong arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4)
+{
+    abi_long ret = 0;
+    void *p;
+    struct timespec *tvp, tv[2];
+
+    if (arg3 != 0) {
+        if (t2h_freebsd_timespec(&tv[0], arg3) ||
+                t2h_freebsd_timespec(&tv[1], arg3 +
+                        sizeof(struct target_freebsd_timespec))) {
+            return -TARGET_EFAULT;
+        }
+        tvp = tv;
+    } else {
+        tvp = NULL;
+    }
+
+    p = lock_user_string(arg2);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(utimensat(arg1, p, tvp,
+        target_to_host_bitmask(arg4, fcntl_flags_tbl)));
+    unlock_user(p, arg2, 0);
+    return ret;
+}
 
 #endif /* FREEBSD_OS_TIME_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 27/41] bsd-user: Add os-time.c and time-related type definitions
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (25 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 26/41] bsd-user: Add sigtimedwait, itimer, and futimens " Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 28/41] bsd-user: Add time system call dispatch Warner Losh
                   ` (14 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Mikaël Urankar,
	Kyle Evans, Richard Henderson

Add os-time.c with time conversion helpers (t2h/h2t functions for
timespec, timeval, timex, ntptimeval, itimerspec) and POSIX timer
helper functions. Also add target_freebsd_timex, target_freebsd_ntptimeval,
target_freebsd_itimerspec, kevent structures, and timer definitions
to syscall_defs.h.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/meson.build  |   3 +-
 bsd-user/freebsd/os-syscall.c |   2 +
 bsd-user/freebsd/os-time.c    | 347 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-time.h    |   3 +
 bsd-user/freebsd/qemu-os.h    |  30 +++
 bsd-user/syscall_defs.h       |  41 ++++
 6 files changed, 425 insertions(+), 1 deletion(-)
 create mode 100644 bsd-user/freebsd/os-time.c

diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build
index 83593a1e20..163d5657db 100644
--- a/bsd-user/freebsd/meson.build
+++ b/bsd-user/freebsd/meson.build
@@ -8,6 +8,7 @@ bsd_user_ss.add(files(
   'os-socket.c',
   'os-stat.c',
   'os-sys.c',
-  'os-syscall.c'),
+  'os-syscall.c',
+  'os-time.c'),
   bsd_syscall_nr
 )
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 5d3a66e360..521660e8c8 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -89,6 +89,8 @@ safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
 safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
 safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
 
+int g_posix_timers[32] = { 0, } ;
+
 /* used in os-proc */
 safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
     struct rusage *, rusage);
diff --git a/bsd-user/freebsd/os-time.c b/bsd-user/freebsd/os-time.c
new file mode 100644
index 0000000000..0dae7dc008
--- /dev/null
+++ b/bsd-user/freebsd/os-time.c
@@ -0,0 +1,347 @@
+/*
+ * FreeBSD time related system call helpers
+ *
+ * Copyright (c) 2013-2015 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#include <errno.h>
+#include <time.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/umtx.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD time conversion functions
+ */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(tv->tv_sec, &target_tv->tv_sec);
+    __get_user(tv->tv_usec, &target_tv->tv_usec);
+    unlock_user_struct(target_tv, target_tv_addr, 0);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+{
+    struct target_freebsd_timeval *target_tv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(tv->tv_sec, &target_tv->tv_sec);
+    __put_user(tv->tv_usec, &target_tv->tv_usec);
+    unlock_user_struct(target_tv, target_tv_addr, 1);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(ts->tv_sec, &target_ts->tv_sec);
+    __get_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 0);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts)
+{
+    struct target_freebsd_timespec *target_ts;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ts->tv_sec, &target_ts->tv_sec);
+    __put_user(ts->tv_nsec, &target_ts->tv_nsec);
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
+}
+
+abi_long t2h_freebsd_umtx_time(abi_ulong target_ut_addr,
+        abi_ulong target_ut_size, void *host_t, size_t *host_tsz)
+{
+    abi_long ret;
+
+    if (target_ut_size <= sizeof(struct target_freebsd_timespec)) {
+        ret = t2h_freebsd_timespec((struct timespec *)host_t, target_ut_addr);
+        if (ret == 0) {
+            *host_tsz = sizeof(struct timespec);
+        }
+        return ret;
+    } else {
+        struct target_freebsd__umtx_time *target_ut;
+        struct _umtx_time *ut = (struct _umtx_time *)host_t;
+
+        if (!lock_user_struct(VERIFY_READ, target_ut, target_ut_addr, 1)) {
+            return -TARGET_EFAULT;
+        }
+        if (t2h_freebsd_timespec(&ut->_timeout, h2g(&target_ut->_timeout))) {
+            unlock_user_struct(target_ut, target_ut_addr, 0);
+            return -TARGET_EFAULT;
+        }
+        __get_user(ut->_flags, &target_ut->_flags);
+        __get_user(ut->_clockid, &target_ut->_clockid);
+        unlock_user_struct(target_ut, target_ut_addr, 0);
+
+        if (target_ut_size > sizeof(struct target_freebsd__umtx_time)) {
+            *host_tsz = sizeof(struct _umtx_time) + sizeof(struct timespec);
+        } else {
+            *host_tsz = sizeof(struct _umtx_time);
+        }
+
+        return 0;
+    }
+}
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr)
+{
+    struct target_freebsd_timex *target_tx;
+
+    if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_tx->modes, &target_tx->modes);
+    __get_user(host_tx->offset, &target_tx->offset);
+    __get_user(host_tx->freq, &target_tx->freq);
+    __get_user(host_tx->maxerror, &target_tx->maxerror);
+    __get_user(host_tx->esterror, &target_tx->esterror);
+    __get_user(host_tx->status, &target_tx->status);
+    __get_user(host_tx->constant, &target_tx->constant);
+    __get_user(host_tx->precision, &target_tx->precision);
+    __get_user(host_tx->tolerance, &target_tx->tolerance);
+    __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
+    __get_user(host_tx->jitter, &target_tx->jitter);
+    __get_user(host_tx->shift, &target_tx->shift);
+    __get_user(host_tx->stabil, &target_tx->stabil);
+    __get_user(host_tx->jitcnt, &target_tx->jitcnt);
+    __get_user(host_tx->calcnt, &target_tx->calcnt);
+    __get_user(host_tx->errcnt, &target_tx->errcnt);
+    __get_user(host_tx->stbcnt, &target_tx->stbcnt);
+    unlock_user_struct(target_tx, target_tx_addr, 0);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_timex(abi_ulong target_tx_addr, struct timex *host_tx)
+{
+    struct target_freebsd_timex *target_tx;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_tx, target_tx_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_tx->modes, &target_tx->modes);
+    __put_user(host_tx->offset, &target_tx->offset);
+    __put_user(host_tx->freq, &target_tx->freq);
+    __put_user(host_tx->maxerror, &target_tx->maxerror);
+    __put_user(host_tx->esterror, &target_tx->esterror);
+    __put_user(host_tx->status, &target_tx->status);
+    __put_user(host_tx->constant, &target_tx->constant);
+    __put_user(host_tx->precision, &target_tx->precision);
+    __put_user(host_tx->tolerance, &target_tx->tolerance);
+    __put_user(host_tx->ppsfreq, &target_tx->ppsfreq);
+    __put_user(host_tx->jitter, &target_tx->jitter);
+    __put_user(host_tx->shift, &target_tx->shift);
+    __put_user(host_tx->stabil, &target_tx->stabil);
+    __put_user(host_tx->jitcnt, &target_tx->jitcnt);
+    __put_user(host_tx->calcnt, &target_tx->calcnt);
+    __put_user(host_tx->errcnt, &target_tx->errcnt);
+    __put_user(host_tx->stbcnt, &target_tx->stbcnt);
+    unlock_user_struct(target_tx, target_tx_addr, 1);
+
+    return 0;
+}
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv)
+{
+    struct target_freebsd_ntptimeval *target_ntv;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
+    __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
+    __put_user(ntv->maxerror, &target_ntv->maxerror);
+    __put_user(ntv->esterror, &target_ntv->esterror);
+    __put_user(ntv->tai, &target_ntv->tai);
+    __put_user(ntv->time_state, &target_ntv->time_state);
+    unlock_user_struct(target_ntv, target_ntv_addr, 1);
+
+    return 0;
+}
+
+/*
+ * select(2) fdset copy functions
+ */
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
+{
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_READ, target_fds_addr,
+            sizeof(abi_ulong) * nw, 1);
+    if (target_fds == NULL) {
+        return -TARGET_EFAULT;
+    }
+    FD_ZERO(fds);
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        /* grab the abi_ulong */
+        __get_user(b, &target_fds[i]);
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            /* check the bit inside the abi_ulong */
+            if ((b >> j) & 1) {
+                FD_SET(k, fds);
+            }
+            k++;
+        }
+    }
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
+}
+
+abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+        abi_ulong target_fds_addr, int n)
+{
+
+    if (target_fds_addr) {
+        if (copy_from_user_fdset(fds, target_fds_addr, n)) {
+            return -TARGET_EFAULT;
+        }
+        *fds_ptr = fds;
+    } else {
+        *fds_ptr = NULL;
+    }
+
+    return 0;
+}
+
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n)
+{
+    int i, nw, j, k;
+    abi_long v;
+    abi_ulong *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    target_fds = lock_user(VERIFY_WRITE, target_fds_addr,
+            sizeof(abi_ulong) * nw, 0);
+    if (target_fds == NULL) {
+        return -TARGET_EFAULT;
+    }
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        v = 0;
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            v |= ((FD_ISSET(k, fds) != 0) << j);
+            k++;
+        }
+        __put_user(v, &target_fds[i]);
+    }
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
+}
+
+abi_int next_free_host_timer(void)
+{
+    int k ;
+    /* FIXME: Does finding the next free slot require a lock? */
+    for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
+        if (g_posix_timers[k] == 0) {
+            g_posix_timers[k] = 1;
+            return k;
+        }
+    }
+    return -1;
+}
+
+int host_to_target_timerid(int timerid)
+{
+    int k;
+
+    for (k = 0; k < ARRAY_SIZE(g_posix_timers); k++) {
+        if (g_posix_timers[k] == timerid) {
+            return TIMER_MAGIC | k;
+        }
+    }
+
+    return -1;
+}
+
+abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
+                                                 abi_ulong target_addr)
+{
+    struct target_freebsd_itimerspec *target_itspec;
+
+    if (!lock_user_struct(VERIFY_READ, target_itspec, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+
+    host_itspec->it_interval.tv_sec =
+                            tswapal(target_itspec->it_interval.tv_sec);
+    host_itspec->it_interval.tv_nsec =
+                            tswapal(target_itspec->it_interval.tv_nsec);
+    host_itspec->it_value.tv_sec = tswapal(target_itspec->it_value.tv_sec);
+    host_itspec->it_value.tv_nsec = tswapal(target_itspec->it_value.tv_nsec);
+
+    unlock_user_struct(target_itspec, target_addr, 0);
+    return 0;
+}
+
+abi_long host_to_target_itimerspec(abi_ulong target_addr,
+                                               struct itimerspec *host_its)
+{
+    struct target_freebsd_itimerspec *target_itspec;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_itspec, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    target_itspec->it_interval.tv_sec = tswapal(host_its->it_interval.tv_sec);
+    target_itspec->it_interval.tv_nsec = tswapal(host_its->it_interval.tv_nsec);
+
+    target_itspec->it_value.tv_sec = tswapal(host_its->it_value.tv_sec);
+    target_itspec->it_value.tv_nsec = tswapal(host_its->it_value.tv_nsec);
+
+    unlock_user_struct(target_itspec, target_addr, 1);
+    return 0;
+}
+
+/* Convert QEMU provided timer ID back to internal 16bit index format */
+int get_timer_id(abi_long arg)
+{
+    int timerid = arg;
+
+    if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
+        return -TARGET_EINVAL;
+    }
+
+    timerid &= 0xffff;
+
+    if (timerid >= ARRAY_SIZE(g_posix_timers)) {
+        return -TARGET_EINVAL;
+    }
+
+    return timerid;
+}
diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
index 05cb5db7d1..213bd16850 100644
--- a/bsd-user/freebsd/os-time.h
+++ b/bsd-user/freebsd/os-time.h
@@ -202,6 +202,9 @@ static inline abi_long do_freebsd_ntp_adjtime(abi_ulong target_tx_addr)
     if (ret == 0) {
         ret = get_errno(ntp_adjtime(&host_tx));
     }
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_timex(target_tx_addr, &host_tx);
+    }
 
     return ret;
 }
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index 12adc50928..ee18b23422 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -32,6 +32,36 @@
 
 struct freebsd11_stat;
 
+/* os-time.c */
+abi_long t2h_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+abi_long h2t_freebsd_timeval(struct timeval *tv, abi_ulong target_tv_addr);
+
+abi_long t2h_freebsd_timespec(struct timespec *ts, abi_ulong target_ts_addr);
+abi_long h2t_freebsd_timespec(abi_ulong target_ts_addr, struct timespec *ts);
+
+abi_long t2h_freebsd_umtx_time(abi_ulong target_ut_addr,
+        abi_ulong target_ut_size, void *host_t, size_t *host_tsz);
+
+abi_long t2h_freebsd_timex(struct timex *host_tx, abi_ulong target_tx_addr);
+abi_long h2t_freebsd_timex(abi_ulong target_tx_addr, struct timex *host_tx);
+
+abi_long h2t_freebsd_ntptimeval(abi_ulong target_ntv_addr,
+        struct ntptimeval *ntv);
+
+abi_ulong copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n);
+abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+        abi_ulong target_fds_addr, int n);
+abi_long copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds,
+        int n);
+
+abi_int next_free_host_timer(void);
+int host_to_target_timerid(int timerid);
+abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
+        abi_ulong target_addr);
+abi_long host_to_target_itimerspec(abi_ulong target_addr,
+        struct itimerspec *host_its);
+int get_timer_id(abi_long arg);
+
 /* os-stat.c */
 abi_long h2t_freebsd11_stat(abi_ulong target_addr,
         struct freebsd11_stat *host_st);
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index f4bb687388..75f2d6fa36 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -155,6 +155,47 @@ struct target_freebsd_timeval {
 #endif
 };
 
+/* compare to sys/timex.h */
+struct target_freebsd_ntptimeval {
+    struct target_freebsd_timespec  time;
+    abi_long    maxerror;
+    abi_long    esterror;
+    abi_long    tai;
+    int32_t     time_state;
+};
+
+struct target_freebsd_itimerspec {
+    struct target_freebsd_timespec it_interval;
+    struct target_freebsd_timespec it_value;
+};
+
+struct target_freebsd_timex {
+    uint32_t    modes;
+    abi_long    offset;
+    abi_long    freq;
+    abi_long    maxerror;
+    abi_long    esterror;
+    int32_t     status;
+    abi_long    constant;
+    abi_long    precision;
+    abi_long    tolerance;
+
+    abi_long    ppsfreq;
+    abi_long    jitter;
+    int32_t     shift;
+    abi_long    stabil;
+    abi_long    jitcnt;
+    abi_long    calcnt;
+    abi_long    errcnt;
+    abi_long    stbcnt;
+};
+
+/* Maxiumum of 32 active POSIX timers allowed at any one time. */
+extern int g_posix_timers[32];
+
+#define TIMER_MAGIC 0x0caf0000
+#define TIMER_MAGIC_MASK 0xffff0000
+
 /*
  * sys/event.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 28/41] bsd-user: Add time system call dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (26 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 27/41] bsd-user: Add os-time.c and time-related type definitions Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 29/41] bsd-user: Add cpu_copy and make init_task_state non-static Warner Losh
                   ` (13 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Wire up time-related system calls in the FreeBSD syscall dispatcher:
nanosleep, clock_nanosleep, clock_gettime, clock_settime, clock_getres,
gettimeofday, settimeofday, adjtime, ntp_adjtime, ntp_gettime,
clock_getcpuclockid2, utimes, lutimes, futimes, futimesat,
ktimer_create, ktimer_delete, ktimer_settime, ktimer_gettime,
select, pselect, ppoll, kqueue, freebsd11_kevent, kevent,
setitimer, getitimer, futimens, utimensat, and sigtimedwait.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 133 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/qemu-os.h    |  18 +++++
 bsd-user/qemu.h               |  41 +++++++++++
 bsd-user/syscall_defs.h       | 121 +++++++++++++++++++++++++++++++
 4 files changed, 313 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 521660e8c8..cc66be3b7c 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -48,6 +48,7 @@
 #include "os-signal.h"
 #include "os-file.h"
 #include "os-socket.h"
+#include "os-time.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -89,6 +90,15 @@ safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
 safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
 safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
 
+/* used in os-time */
+safe_syscall2(int, nanosleep, const struct timespec *, rqtp, struct timespec *,
+    rmtp);
+safe_syscall4(int, clock_nanosleep, clockid_t, clock_id, int, flags,
+    const struct timespec *, rqtp, struct timespec *, rmtp);
+safe_syscall6(int, kevent, int, kq, const struct kevent *, changelist,
+    int, nchanges, struct kevent *, eventlist, int, nevents,
+    const struct timespec *, timeout);
+
 int g_posix_timers[32] = { 0, } ;
 
 /* used in os-proc */
@@ -1028,9 +1038,132 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_getdtablesize();
         break;
 
+        /*
+         * time related system calls.
+         */
+    case TARGET_FREEBSD_NR_nanosleep: /* nanosleep(2) */
+        ret = do_freebsd_nanosleep(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_nanosleep: /* clock_nanosleep(2) */
+        ret = do_freebsd_clock_nanosleep(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_gettime: /* clock_gettime(2) */
+        ret = do_freebsd_clock_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_settime: /* clock_settime(2) */
+        ret = do_freebsd_clock_settime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_getres: /* clock_getres(2) */
+        ret = do_freebsd_clock_getres(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_gettimeofday: /* gettimeofday(2) */
+        ret = do_freebsd_gettimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_settimeofday: /* settimeofday(2) */
+        ret = do_freebsd_settimeofday(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_adjtime: /* adjtime(2) */
+        ret = do_freebsd_adjtime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_adjtime: /* ntp_adjtime(2) */
+        ret = do_freebsd_ntp_adjtime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_clock_getcpuclockid2: /* Not documented. */
+        ret = do_freebsd_clock_getcpuclockid2(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ntp_gettime: /* ntp_gettime(2) */
+        ret = do_freebsd_ntp_gettime(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_utimes: /* utimes(2) */
+        ret = do_freebsd_utimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lutimes: /* lutimes(2) */
+        ret = do_freebsd_lutimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimes: /* futimes(2) */
+        ret = do_freebsd_futimes(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimesat: /* futimesat(2) */
+        ret = do_freebsd_futimesat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_create: /* timer_create(2) */
+        ret = do_freebsd_ktimer_create(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_delete: /* timer_delete(2) */
+        ret = do_freebsd_ktimer_delete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_settime: /* timer_settime(2) */
+        ret = do_freebsd_ktimer_settime(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ktimer_gettime: /* timer_gettime(2) */
+        ret = do_freebsd_ktimer_gettime(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_select: /* select(2) */
+        ret = do_freebsd_select(env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_pselect: /* pselect(2) */
+        ret = do_freebsd_pselect(env, arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_ppoll: /* ppoll(2) */
+        ret = do_freebsd_ppoll(env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */
+        ret = do_freebsd_kqueue();
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_kevent: /* kevent(2) */
+        ret = do_freebsd_freebsd11_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_kevent: /* kevent(2) */
+        ret = do_freebsd_kevent(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_setitimer: /* setitimer(2) */
+        ret = do_freebsd_setitimer(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getitimer: /* getitimer(2) */
+        ret = do_freebsd_getitimer(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_futimens: /* futimens(2) */
+        ret = do_freebsd_futimens(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_utimensat: /* utimensat(2) */
+        ret = do_freebsd_utimensat(arg1, arg2, arg3, arg4);
+        break;
+
         /*
          * signal system calls
          */
+    case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */
+        ret = do_freebsd_sigtimedwait(arg1, arg2, arg3);
+        break;
+
     case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
         ret = do_bsd_sigaction(arg1, arg2, arg3);
         break;
diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h
index ee18b23422..b1ff5c0cd5 100644
--- a/bsd-user/freebsd/qemu-os.h
+++ b/bsd-user/freebsd/qemu-os.h
@@ -62,6 +62,24 @@ abi_long host_to_target_itimerspec(abi_ulong target_addr,
         struct itimerspec *host_its);
 int get_timer_id(abi_long arg);
 
+/* os-socket.c */
+abi_long t2h_freebsd_cmsg(struct msghdr *msgh,
+                struct target_msghdr *target_msgh);
+abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh,
+                struct msghdr *msgh);
+
+/* os-thread.c */
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr);
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp);
+abi_long do_freebsd_thr_new(CPUArchState *env, abi_ulong target_param_addr,
+        int32_t param_size);
+
+/* os-extattr.c */
+struct acl;
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr);
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl);
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type);
+
 /* os-stat.c */
 abi_long h2t_freebsd11_stat(abi_ulong target_addr,
         struct freebsd11_stat *host_st);
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 60d1adf560..069baa7011 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -249,6 +249,47 @@ abi_long do_freebsd_sysctlbyname(CPUArchState *env, abi_ulong namep,
         abi_ulong newlen);
 abi_long do_freebsd_sysarch(CPUArchState *env, abi_long arg1, abi_long arg2);
 
+/* os-thread.c */
+extern pthread_mutex_t *new_freebsd_thread_lock_ptr;
+extern pthread_mutex_t *freebsd_umtx_wait_lck_ptr;
+void *new_freebsd_thread_start(void *arg);
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long tid,
+        size_t tsz, void *t);
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id);
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong id,
+        size_t tsz, void *t);
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake);
+abi_long freebsd_umtx_wake_unsafe(abi_ulong target_addr, uint32_t n_wake);
+abi_long freebsd_umtx_mutex_wake(abi_ulong target_addr, abi_long val);
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t val, size_t tsz,
+        void *t);
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t val,
+        size_t tsz, void *t);
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_nwake_private(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_mutex_wake2(abi_ulong obj, uint32_t val);
+abi_long freebsd_umtx_sem2_wait(abi_ulong obj, size_t tsz, void *t);
+abi_long freebsd_umtx_sem2_wake(abi_ulong obj);
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, size_t tsz, void *t);
+abi_long freebsd_umtx_sem_wake(abi_ulong obj);
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        void *ts, size_t tsz, int mode, abi_ulong val);
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id);
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+        abi_ulong target_umtx_addr, struct timespec *ts, int wflags);
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr);
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr);
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag,
+        size_t tsz, void *t);
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag,
+        size_t tsz, void *t);
+abi_long freebsd_rw_unlock(abi_ulong target_addr);
+abi_long freebsd_umtx_shm(abi_ulong target_addr, long fflag);
+abi_long freebsd_umtx_robust_list(abi_ulong target_addr, size_t rbsize);
+abi_long freebsd_set_ceiling(abi_ulong target_addr, uint32_t ceiling,
+        uint32_t *old_ceiling);
+CPUArchState *cpu_copy(CPUArchState *env);
+
 /* user access */
 
 #define VERIFY_READ  PAGE_READ
diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
index 75f2d6fa36..9fa16e0863 100644
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -639,6 +639,127 @@ struct target_specialfd_eventfd {
     int flags;
 };
 
+/*
+ * FreeBSD thread and user mutex support.
+ */
+
+/* sys/thr.h */
+#define TARGET_THR_SUSPENDED    0x0001
+#define TARGET_THR_SYSTEM_SCOPE 0x0002
+
+struct target_freebsd_thr_param {
+    abi_ulong   start_func; /* thread entry function. */
+    abi_ulong   arg;        /* argument for entry function. */
+    abi_ulong   stack_base; /* stack base address. */
+    abi_ulong   stack_size; /* stack size. */
+    abi_ulong   tls_base;   /* tls base address. */
+    abi_ulong   tls_size;   /* tls size. */
+    abi_ulong   child_tid;  /* address to store new TID. */
+    abi_ulong   parent_tid; /* parent access the new TID here. */
+    int32_t     flags;      /* thread flags. */
+    abi_ulong   rtp;        /* Real-time scheduling priority. */
+    abi_ulong   spare[3];   /* spares. */
+};
+
+/* sys/rtprio.h */
+struct target_freebsd_rtprio {
+    uint16_t    type;
+    uint16_t    prio;
+};
+
+typedef struct {
+    CPUArchState *env;
+    long parent_tid;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    pthread_t thread;
+    sigset_t sigmask;
+    struct target_freebsd_thr_param param;
+} new_freebsd_thread_info_t;
+
+/* sys/utmx.h */
+/* op code for _umtx_op */
+#define TARGET_UMTX_OP_LOCK                 0
+#define TARGET_UMTX_OP_UNLOCK               1
+#define TARGET_UMTX_OP_WAIT                 2
+#define TARGET_UMTX_OP_WAKE                 3
+#define TARGET_UMTX_OP_MUTEX_TRYLOCK        4
+#define TARGET_UMTX_OP_MUTEX_LOCK           5
+#define TARGET_UMTX_OP_MUTEX_UNLOCK         6
+#define TARGET_UMTX_OP_SET_CEILING          7
+#define TARGET_UMTX_OP_CV_WAIT              8
+#define TARGET_UMTX_OP_CV_SIGNAL            9
+#define TARGET_UMTX_OP_CV_BROADCAST         10
+#define TARGET_UMTX_OP_WAIT_UINT            11
+#define TARGET_UMTX_OP_RW_RDLOCK            12
+#define TARGET_UMTX_OP_RW_WRLOCK            13
+#define TARGET_UMTX_OP_RW_UNLOCK            14
+#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE    15
+#define TARGET_UMTX_OP_WAKE_PRIVATE         16
+#define TARGET_UMTX_OP_MUTEX_WAIT           17
+#define TARGET_UMTX_OP_MUTEX_WAKE           18
+#define TARGET_UMTX_OP_SEM_WAIT             19
+#define TARGET_UMTX_OP_SEM_WAKE             20
+#define TARGET_UMTX_OP_NWAKE_PRIVATE        21
+#define TARGET_UMTX_OP_MUTEX_WAKE2          22
+#define TARGET_UMTX_OP_SEM2_WAIT            23
+#define TARGET_UMTX_OP_SEM2_WAKE            24
+#define TARGET_UMTX_OP_SHM                  25
+#define TARGET_UMTX_OP_ROBUST_LISTS         26
+
+/* flags for UMTX_OP_CV_WAIT */
+#define TARGET_CVWAIT_CHECK_UNPARKING       0x01
+#define TARGET_CVWAIT_ABSTIME               0x02
+#define TARGET_CVWAIT_CLOCKID               0x04
+
+#define TARGET_UMTX_UNOWNED                 0x0
+#define TARGET_UMUTEX_UNOWNED               0x0
+#define TARGET_UMTX_CONTESTED               (abi_ulong)(-1)
+#define TARGET_UMUTEX_CONTESTED             0x80000000U
+
+/* flags for umutex */
+#define TARGET_UMUTEX_ERROR_CHECK   0x0002  /* Error-checking mutex */
+#define TARGET_UMUTEX_PRIO_INHERIT  0x0004  /* Priority inherited mutex */
+#define TARGET_UMUTEX_PRIO_PROTECT  0x0008  /* Priority protect mutex */
+
+#define TARGET_UMUTEX_TRY           1
+#define TARGET_UMUTEX_WAIT          2
+
+/* urwlock flags */
+#define TARGET_URWLOCK_PREFER_READER    0x0002
+#define TARGET_URWLOCK_WRITE_OWNER      0x80000000U
+#define TARGET_URWLOCK_WRITE_WAITERS    0x40000000U
+#define TARGET_URWLOCK_READ_WAITERS     0x20000000U
+#define TARGET_URWLOCK_MAX_READERS      0x1fffffffU
+#define TARGET_URWLOCK_READER_COUNT(c)  ((c) & TARGET_URWLOCK_MAX_READERS)
+
+/*
+ * sys/acl.h
+ */
+#define TARGET_FREEBSD_ACL_MAX_ENTRIES          254
+
+/* vaild acl_type_t arguments */
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD      0x00000000
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD     0x00000001
+#define TARGET_FREEBSD_ACL_TYPE_ACCESS          0x00000002
+#define TARGET_FREEBSD_ACL_TYPE_DEFAULT         0x00000003
+#define TARGET_FREEBSD_ACL_TYPE_NFS4            0x00000004
+
+struct target_freebsd_acl_entry {
+    uint32_t    ae_tag;
+    uint32_t    ae_id;
+    uint32_t    ae_perm;
+    uint16_t    ae_entry_type;
+    uint16_t    ae_flags;
+};
+
+struct target_freebsd_acl {
+    uint32_t            acl_maxcnt;
+    uint32_t            acl_cnt;
+    int32_t             acl_spare[4];
+    struct target_freebsd_acl_entry  acl_entry[TARGET_FREEBSD_ACL_MAX_ENTRIES];
+};
+
 /*
  *  sys/uuid.h
  */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 29/41] bsd-user: Add cpu_copy and make init_task_state non-static
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (27 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 28/41] bsd-user: Add time system call dispatch Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 30/41] bsd-user: Add os-thread.h with thr and context functions Warner Losh
                   ` (12 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Pierrick Bouvier,
	Richard Henderson

Add cpu_copy() function for thread creation support and make
init_task_state() non-static so it can be called from os-thread.c.
Move cpu_type to file scope so cpu_copy() can access it.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/main.c | 32 ++++++++++++++++++++++++++++++--
 bsd-user/qemu.h |  1 +
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 694481ae3e..2fbbfc3d86 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -50,6 +50,7 @@
 #include "qemu/guest-random.h"
 #include "gdbstub/user.h"
 #include "exec/page-vary.h"
+#include "exec/watchpoint.h"
 
 #include "host-os.h"
 #include "target_arch_cpu.h"
@@ -215,7 +216,7 @@ bool qemu_cpu_is_self(CPUState *cpu)
 }
 
 /* Assumes contents are already zeroed.  */
-static void init_task_state(TaskState *ts)
+void init_task_state(TaskState *ts)
 {
     ts->sigaltstack_used = (struct target_sigaltstack) {
         .ss_sp = 0,
@@ -224,6 +225,34 @@ static void init_task_state(TaskState *ts)
     };
 }
 
+static const char *cpu_type;
+
+CPUArchState *cpu_copy(CPUArchState *env)
+{
+    CPUState *cpu = env_cpu(env);
+    CPUState *new_cpu = cpu_create(cpu_type);
+    CPUArchState *new_env = cpu_env(new_cpu);
+    CPUBreakpoint *bp;
+
+    /* Reset non arch specific state */
+    cpu_reset(new_cpu);
+
+    new_cpu->tcg_cflags = cpu->tcg_cflags;
+    memcpy(new_env, env, sizeof(CPUArchState));
+
+    /*
+     * Clone all break/watchpoints.
+     * Note: Once we support ptrace with hw-debug register access, make sure
+     * BP_CPU break/watchpoints are handled correctly on clone.
+     */
+    QTAILQ_INIT(&new_cpu->breakpoints);
+    QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
+        cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
+    }
+
+    return new_env;
+}
+
 static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
 
 void gemu_log(const char *fmt, ...)
@@ -256,7 +285,6 @@ int main(int argc, char **argv)
 {
     const char *filename;
     const char *cpu_model;
-    const char *cpu_type;
     const char *log_file = NULL;
     const char *log_mask = NULL;
     const char *seed_optarg = NULL;
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 069baa7011..d2dd8c2ee8 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -122,6 +122,7 @@ struct TaskState {
     struct target_sigaltstack sigaltstack_used;
 } __attribute__((aligned(16)));
 
+void init_task_state(TaskState *ts);
 void stop_all_tasks(void);
 extern const char *interp_prefix;
 extern const char *qemu_uname_release;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 30/41] bsd-user: Add os-thread.h with thr and context functions
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (28 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 29/41] bsd-user: Add cpu_copy and make init_task_state non-static Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 31/41] bsd-user: Add do_freebsd__umtx_op to os-thread.h Warner Losh
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Jessica Clarke,
	Michal Meloun, Richard Henderson

Add thread management system call shims: thr_self, thr_exit, thr_kill,
thr_kill2, thr_suspend, thr_wake, thr_set_name, rtprio_thread,
getcontext, setcontext, and swapcontext.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Signed-off-by: Michal Meloun <mmel@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c |   6 +
 bsd-user/freebsd/os-thread.h  | 244 ++++++++++++++++++++++++++++++++++
 2 files changed, 250 insertions(+)
 create mode 100644 bsd-user/freebsd/os-thread.h

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index cc66be3b7c..f2c3ff25e8 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -49,6 +49,7 @@
 #include "os-file.h"
 #include "os-socket.h"
 #include "os-time.h"
+#include "os-thread.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -90,6 +91,11 @@ safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
 safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
 safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
 
+/* used in os-thread */
+safe_syscall1(int, thr_suspend, struct timespec *, timeout);
+safe_syscall5(int, _umtx_op, void *, obj, int, op, unsigned long, val, void *,
+    uaddr, void *, uaddr2);
+
 /* used in os-time */
 safe_syscall2(int, nanosleep, const struct timespec *, rqtp, struct timespec *,
     rmtp);
diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h
new file mode 100644
index 0000000000..d3f1f01b13
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.h
@@ -0,0 +1,244 @@
+/*
+ * FreeBSD thread and user mutex related system call shims
+ *
+ * Copyright (c) 2013-2015 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef FREEBSD_OS_THREAD_H
+#define FREEBSD_OS_THREAD_H
+
+#include <sys/thr.h>
+#include <sys/rtprio.h>
+#include <sys/umtx.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+int safe_thr_suspend(struct timespec *timeout);
+int safe__umtx_op(void *, int, unsigned long, void *, void *);
+
+#if defined(HOST_BIG_ENDIAN) == defined(TARGET_BIG_ENDIAN) && \
+    (TARGET_ABI_BITS == HOST_LONG_BITS || defined(UMTX_OP__32BIT))
+#define _UMTX_OPTIMIZED
+#if defined(TARGET_ABI32)
+#define QEMU_UMTX_OP(n) (UMTX_OP__32BIT | (n))
+#else
+#define QEMU_UMTX_OP(n) (n)
+#endif /* TARGET_ABI32 */
+#else
+#define QEMU_UMTX_OP(n) (n)
+#endif
+
+static inline abi_long do_freebsd_thr_self(abi_ulong target_id)
+{
+    abi_long ret;
+    long tid;
+
+    ret = get_errno(thr_self(&tid));
+    if (!is_error(ret)) {
+        if (put_user_sal(tid, target_id)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+static inline abi_long do_freebsd_thr_exit(CPUArchState *env,
+        abi_ulong tid_addr)
+{
+    CPUState *cpu = env_cpu(env);
+    TaskState *ts;
+
+    if (block_signals()) {
+        return -TARGET_ERESTART;
+    }
+
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+
+    ts = cpu->opaque;
+
+    if (tid_addr) {
+        /* Signal target userland that it can free the stack. */
+        if (!put_user_sal(1, tid_addr)) {
+            freebsd_umtx_wake_unsafe(tid_addr, INT_MAX);
+        }
+    }
+
+    object_unparent(OBJECT(env_cpu(env)));
+    object_unref(OBJECT(env_cpu(env)));
+    /*
+     * At this point the CPU should be unrealized and removed
+     * from cpu lists. We can clean-up the rest of the thread
+     * data without the lock held.
+     */
+
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    thread_cpu = NULL;
+    g_free(ts);
+    rcu_unregister_thread();
+    pthread_exit(NULL);
+    /* Doesn't return */
+    return 0;
+}
+
+static inline abi_long do_freebsd_thr_kill(long id, int sig)
+{
+
+    return get_errno(thr_kill(id, target_to_host_signal(sig)));
+}
+
+static inline abi_long do_freebsd_thr_kill2(pid_t pid, long id, int sig)
+{
+
+    return get_errno(thr_kill2(pid, id, target_to_host_signal(sig)));
+}
+
+static inline abi_long do_freebsd_thr_suspend(abi_ulong target_ts)
+{
+    abi_long ret;
+    struct timespec ts;
+
+    if (target_ts != 0) {
+        if (t2h_freebsd_timespec(&ts, target_ts)) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(safe_thr_suspend(&ts));
+    } else {
+        ret = get_errno(safe_thr_suspend(NULL));
+    }
+    return ret;
+}
+
+static inline abi_long do_freebsd_thr_wake(long tid)
+{
+
+    return get_errno(thr_wake(tid));
+}
+
+static inline abi_long do_freebsd_thr_set_name(long tid, abi_ulong target_name)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user_string(target_name);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(thr_set_name(tid, p));
+    unlock_user(p, target_name, 0);
+
+    return ret;
+}
+
+static inline abi_long do_freebsd_rtprio_thread(int function, lwpid_t lwpid,
+        abi_ulong target_addr)
+{
+    int ret;
+    struct rtprio rtp;
+
+    ret = t2h_freebsd_rtprio(&rtp, target_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(rtprio_thread(function, lwpid, &rtp));
+    }
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_rtprio(target_addr, &rtp);
+    }
+    return ret;
+}
+
+static inline abi_long do_freebsd_getcontext(CPUArchState *env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ret = do_sigprocmask(0, NULL, &sigmask);
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    return ret;
+}
+
+static inline abi_long do_freebsd_setcontext(CPUArchState *env, abi_ulong arg1)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+    if (arg1 == 0) {
+        return -TARGET_EINVAL;
+    }
+    ucp = lock_user(VERIFY_READ, arg1, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg1, 0);
+    if (!is_error(ret)) {
+        (void)do_sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret == 0 ? -TARGET_EJUSTRETURN : ret;
+}
+
+/* swapcontext(2) */
+static inline abi_long do_freebsd_swapcontext(CPUArchState *env, abi_ulong arg1,
+        abi_ulong arg2)
+{
+    abi_long ret;
+    target_ucontext_t *ucp;
+    sigset_t sigmask;
+
+    if (arg1 == 0 || arg2 == 0) {
+        return -TARGET_EINVAL;
+    }
+    /* Save current context in arg1. */
+    ret = do_sigprocmask(0, NULL, &sigmask);
+    if (!is_error(ret)) {
+        ucp = lock_user(VERIFY_WRITE, arg1, sizeof(target_ucontext_t), 0);
+        if (ucp == 0) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_mcontext(env, &ucp->uc_mcontext, TARGET_MC_GET_CLEAR_RET);
+        host_to_target_sigset(&ucp->uc_sigmask, &sigmask);
+        memset(ucp->__spare__, 0, sizeof(ucp->__spare__));
+        unlock_user(ucp, arg1, sizeof(target_ucontext_t));
+    }
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    /* Restore the context in arg2 to the current context. */
+    ucp = lock_user(VERIFY_READ, arg2, sizeof(target_ucontext_t), 1);
+    if (ucp == 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = set_mcontext(env, &ucp->uc_mcontext, 0);
+    target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
+    unlock_user(ucp, arg2, 0);
+    if (!is_error(ret)) {
+        (void)do_sigprocmask(SIG_SETMASK, &sigmask, NULL);
+    }
+    return ret == 0 ? -TARGET_EJUSTRETURN : ret;
+}
+
+
+#define safe_g2h_untagged(x) ((x) != 0 ? g2h_untagged(x) : NULL)
+
+/*
+ * undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
+ *                           void *target_time);
+ */
+
+#endif /* FREEBSD_OS_THREAD_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 31/41] bsd-user: Add do_freebsd__umtx_op to os-thread.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (29 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 30/41] bsd-user: Add os-thread.h with thr and context functions Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 32/41] bsd-user: Add thread system call dispatch Warner Losh
                   ` (10 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans, Jessica Clarke,
	Sean Bruno, Richard Henderson

Add the _umtx_op system call implementation with support for
UMTX lock/unlock, mutex operations, condition variables, reader-writer
locks, semaphores, shared memory, and robust lists.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Signed-off-by: Sean Bruno <sbruno@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/meson.build |    1 +
 bsd-user/freebsd/os-thread.c | 1682 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-thread.h |  352 +++++++
 3 files changed, 2035 insertions(+)
 create mode 100644 bsd-user/freebsd/os-thread.c

diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build
index 163d5657db..db531604ad 100644
--- a/bsd-user/freebsd/meson.build
+++ b/bsd-user/freebsd/meson.build
@@ -9,6 +9,7 @@ bsd_user_ss.add(files(
   'os-stat.c',
   'os-sys.c',
   'os-syscall.c',
+  'os-thread.c',
   'os-time.c'),
   bsd_syscall_nr
 )
diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c
new file mode 100644
index 0000000000..63c17e10d0
--- /dev/null
+++ b/bsd-user/freebsd/os-thread.c
@@ -0,0 +1,1682 @@
+/*
+ * FreeBSD thr emulation support code
+ *
+ * Copyright (c) 2013-2015 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#include <machine/atomic.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+#include "signal-common.h"
+#include "target_arch_cpu.h"
+#include "target_arch_thread.h"
+#include "tcg/startup.h"
+#include "exec/tb-flush.h"
+
+#include "os-thread.h"
+
+/* #define DEBUG_UMTX(...)   fprintf(stderr, __VA_ARGS__) */
+/* #define DEBUG_UMTX(...) qemu_log(__VA_ARGS__) */
+#define DEBUG_UMTX(...)
+
+#define DETECT_DEADLOCK 0
+#define DEADLOCK_TO     1200
+
+#define NEW_STACK_SIZE  0x40000
+
+/* sys/_umtx.h */
+struct target_umtx {
+    abi_ulong   u_owner;    /* Owner of the mutex. */
+};
+
+struct target_umutex {
+    uint32_t    m_owner;    /* Owner of the mutex */
+    uint32_t    m_flags;    /* Flags of the mutex */
+    uint32_t    m_ceiling[2];   /* Priority protect ceiling */
+    abi_ulong   m_rb_lnk;   /* Robust linkage. */
+#if TARGET_ABI_BITS == 32
+    uint32_t    m_pad;
+#endif
+    uint32_t    m_spare;
+    uint32_t    m_count;    /* QEMU-internal; takes one spare. */
+};
+
+struct target_ucond {
+    uint32_t    c_has_waiters;  /* Has waiters in kernel */
+    uint32_t    c_flags;    /* Flags of the condition variable */
+    uint32_t    c_clockid;  /* Clock id */
+    uint32_t    c_spare[1];
+};
+
+struct target_urwlock {
+    uint32_t    rw_state;
+    uint32_t    rw_flags;
+    uint32_t    rw_blocked_readers;
+    uint32_t    rw_blocked_writers;
+    uint32_t    rw_spare[4];
+};
+
+struct target__usem {
+    uint32_t    _has_waiters;
+    uint32_t    _count;
+    uint32_t    _flags;
+};
+
+struct target__usem2 {
+    uint32_t    _count;
+    uint32_t    _flags;
+};
+
+struct target_umtx_robust_lists_params {
+    abi_ulong   robust_list_offset;
+#if TARGET_ABI_BITS == 32
+    uint32_t    m_pad1;
+#endif
+    abi_ulong   robust_priv_list_offset;
+#if TARGET_ABI_BITS == 32
+    uint32_t    m_pad2;
+#endif
+    abi_ulong   robust_inact_offset;
+#if TARGET_ABI_BITS == 32
+    uint32_t    m_pad3;
+#endif
+};
+
+/*
+ * !!! These mutexes must be reset in fork_end() (in bsd-user/main.c).
+ */
+static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t *new_freebsd_thread_lock_ptr = &new_thread_lock;
+static pthread_mutex_t umtx_wait_lck = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t *freebsd_umtx_wait_lck_ptr = &umtx_wait_lck;
+
+static void rtp_to_schedparam(const struct rtprio *rtp, int *policy,
+        struct sched_param *param)
+{
+
+    switch (rtp->type) {
+    case RTP_PRIO_REALTIME:
+        *policy = SCHED_RR;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    case RTP_PRIO_FIFO:
+        *policy = SCHED_FIFO;
+        param->sched_priority = RTP_PRIO_MAX - rtp->prio;
+        break;
+
+    default:
+        *policy = SCHED_OTHER;
+        param->sched_priority = 0;
+        break;
+    }
+}
+
+void *new_freebsd_thread_start(void *arg)
+{
+    new_freebsd_thread_info_t *info = arg;
+    CPUArchState *env;
+    CPUState *cpu;
+    long tid;
+
+    rcu_register_thread();
+    tcg_register_thread();
+    env = info->env;
+    cpu = env_cpu(env);
+    thread_cpu = cpu;
+    (void)thr_self(&tid);
+
+    /* copy out the child TID to both locations */
+    if (info->param.child_tid) {
+        put_user_ual(tid, info->param.child_tid);
+    }
+    if (info->param.parent_tid) {
+        put_user_ual(tid, info->param.parent_tid);
+    }
+
+    /* Set arch dependent registers to start thread. */
+    target_thread_set_upcall(env, info->param.start_func, info->param.arg,
+        info->param.stack_base, info->param.stack_size);
+    target_cpu_set_tls(env, info->param.tls_base);
+
+    /* Enable signals */
+    sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
+    /* Signal to the parent that we're ready. */
+    pthread_mutex_lock(&info->mutex);
+    pthread_cond_broadcast(&info->cond);
+    pthread_mutex_unlock(&info->mutex);
+    /* Wait until the parent has finished. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    cpu_loop(env);
+    /* never exits */
+
+    return NULL;
+}
+
+/*
+ * FreeBSD user mutex (_umtx) emulation
+ */
+static int tcmpset_al(abi_ulong *addr, abi_ulong a, abi_ulong b)
+{
+    abi_ulong current = tswapal(a);
+    abi_ulong new = tswapal(b);
+
+#ifdef TARGET_ABI32
+    return atomic_cmpset_acq_32(addr, current, new);
+#else
+    return atomic_cmpset_acq_64(addr, current, new);
+#endif
+}
+
+#ifdef _UMTX_OPTIMIZED
+static int optimized_umtx_op(abi_ulong obj, int op, abi_ulong val,
+    void *uaddr1, void *uaddr2)
+{
+
+    return get_errno(safe__umtx_op(g2h_untagged(obj), QEMU_UMTX_OP(op), val,
+                                   uaddr1, uaddr2));
+}
+
+#else /* !_UMTX_OPTIMIZED */
+
+/*
+ * _cv_mutex keeps other threads from doing a signal or broadcast until
+ * the thread is actually asleep and ready.  This is a global mutex for all
+ * condition vars so I am sure performance may be a problem if there are lots
+ * of CVs.
+ *
+ */
+static struct umutex _cv_mutex;
+
+static int tcmpset_32(uint32_t *addr, uint32_t a, uint32_t b)
+{
+    uint32_t current = tswap32(a);
+    uint32_t new = tswap32(b);
+
+    return atomic_cmpset_acq_32(addr, current, new);
+}
+
+#endif /* _UMTX_OPTIMIZED */
+
+static abi_long _umtx_wait_uint(uint32_t *addr, uint32_t target_val,
+        size_t tsz, void *t, const char *where)
+{
+#if DETECT_DEADLOCK
+    abi_long ret;
+    long cnt = 0;
+
+    /* target_val has already been tswap'ed. */
+    if (t == NULL) {
+        struct timespec ts;
+
+        ts.tv_sec = 5;
+        ts.tv_nsec = 0;
+
+        do {
+            if (target_val != *addr) {
+                return 0;
+            }
+
+            ret = get_errno(safe__umtx_op(addr, QEMU_UMTX_OP(UMTX_OP_WAIT_UINT),
+                    target_val, NULL, &ts));
+
+            if (ret != -TARGET_ETIMEDOUT) {
+                return ret;
+            }
+            if (cnt++ > DEADLOCK_TO) {
+                fprintf(stderr, "QEMU: Deadlock in %s from %s\n",
+                        __func__, where);
+                abort();
+            }
+        } while (1);
+    } else
+#endif
+        return get_errno(safe__umtx_op(addr, QEMU_UMTX_OP(UMTX_OP_WAIT_UINT),
+            target_val, (void *)tsz, t));
+}
+
+abi_long freebsd_umtx_wait_uint(abi_ulong obj, uint32_t target_val,
+        size_t tsz, void *t)
+{
+    /* target_val has already been tswap'ed. */
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x, %d, %p)\n", __func__,
+               g2h_untagged(obj), UMTX_OP_WAIT_UINT, target_val, (int)tsz, t);
+
+    return _umtx_wait_uint(g2h_untagged(obj), target_val, tsz, t, __func__);
+}
+
+static abi_long _umtx_wait_uint_private(uint32_t *addr, uint32_t target_val,
+        size_t tsz, void *t, const char *where)
+{
+#if DETECT_DEADLOCK
+    abi_long ret;
+    long cnt = 0;
+
+    /* target_val has already been tswap'ed. */
+    if (t == NULL) {
+        struct timespec ts;
+
+        ts.tv_sec = 5;
+        ts.tv_nsec = 0;
+
+        do {
+            if (target_val != *addr) {
+                return 0;
+            }
+
+            ret = get_errno(safe__umtx_op(addr,
+                QEMU_UMTX_OP(UMTX_OP_WAIT_UINT_PRIVATE), target_val, NULL,
+                &ts));
+
+            if (ret != -TARGET_ETIMEDOUT) {
+                return ret;
+            }
+            if (cnt++ > DEADLOCK_TO) {
+                fprintf(stderr, "QEMU: Deadlock in %s from %s\n", __func__,
+                        where);
+                abort();
+            }
+        } while (1);
+    } else
+#endif /* DETECT_DEADLOCK */
+    {
+        return get_errno(safe__umtx_op(addr,
+            QEMU_UMTX_OP(UMTX_OP_WAIT_UINT_PRIVATE), target_val, (void *)tsz,
+            t));
+    }
+}
+
+abi_long freebsd_umtx_wait_uint_private(abi_ulong obj, uint32_t target_val,
+        size_t tsz, void *t)
+{
+    DEBUG_UMTX("<WAIT_UINT_PRIVATE> %s: _umtx_op(%p (%u), %d, 0x%x, %d, %p)\n",
+        __func__, g2h_untagged(obj), tswap32(*(uint32_t *)g2h_untagged(obj)),
+        UMTX_OP_WAIT_UINT_PRIVATE, target_val, (int)tsz, t);
+
+    return _umtx_wait_uint_private(g2h_untagged(obj), target_val, tsz, t,
+        __func__);
+}
+
+static abi_long _umtx_wait(abi_ulong *addr, abi_ulong target_val, size_t tsz,
+        void *t, const char *where)
+{
+#if DETECT_DEADLOCK
+    abi_long ret;
+    long cnt = 0;
+
+    /* target_val has already been tswap'ed. */
+
+    if (t == NULL) {
+        struct timespec ts;
+
+        ts.tv_sec = 5;
+        ts.tv_nsec = 0;
+
+        do {
+            if (target_val != *addr) {
+                return 0;
+            }
+
+            ret = get_errno(safe__umtx_op(addr, QEMU_UMTX_OP(UMTX_OP_WAIT),
+                        target_val, NULL, &ts));
+            if (ret != -TARGET_ETIMEDOUT) {
+                return ret;
+            }
+
+            if (cnt++ > DEADLOCK_TO) {
+                fprintf(stderr, "QEMU: Deadlock in %s from %s\n", __func__,
+                        where);
+                abort();
+            }
+        } while (1);
+    } else
+#endif /* DETECT_DEADLOCK */
+    {
+        return get_errno(safe__umtx_op(addr, QEMU_UMTX_OP(UMTX_OP_WAIT),
+                target_val, (void *)tsz, t));
+    }
+}
+
+abi_long freebsd_umtx_wait(abi_ulong targ_addr, abi_ulong target_id, size_t tsz,
+        void *t)
+{
+
+    /* target_id has already been tswap'ed. */
+
+    /* We want to check the user memory but not lock it.  We might sleep. */
+    if (!access_ok(VERIFY_READ, targ_addr, sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, %d, %p)\n",
+        __func__, g2h_untagged(targ_addr), UMTX_OP_WAIT, (long long)target_id,
+        (int)tsz, t);
+    return _umtx_wait(g2h_untagged(targ_addr), target_id, tsz, t, __func__);
+}
+
+
+abi_long freebsd_umtx_wake_private(abi_ulong obj, uint32_t val)
+{
+
+    DEBUG_UMTX("<WAKE_PRIVATE> %s: _umtx_op(%p (%d), %d, %u, NULL, NULL)\n",
+        __func__, g2h_untagged(obj), tswap32(*(uint32_t *)g2h_untagged(obj)),
+        UMTX_OP_WAKE_PRIVATE, val);
+    return get_errno(safe__umtx_op(g2h_untagged(obj),
+        QEMU_UMTX_OP(UMTX_OP_WAKE_PRIVATE), val, NULL, NULL));
+}
+
+#if defined(UMTX_OP_NWAKE_PRIVATE)
+#define BATCH_SIZE 128
+abi_long freebsd_umtx_nwake_private(abi_ulong target_array_addr, uint32_t num)
+{
+#ifdef _UMTX_OPTIMIZED
+    abi_ulong *tp;
+    uintptr_t uaddrs[BATCH_SIZE];
+    int count, error, i, j;
+
+    if (!access_ok(VERIFY_READ, target_array_addr, num * sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * If we haven't relocated the guest, there's a 1:1 mapping so we can avoid
+     * having to g2h_untagged() each address and just pass it through as-is.
+     */
+    if (!have_guest_base && !reserved_va) {
+        return optimized_umtx_op(target_array_addr, UMTX_OP_NWAKE_PRIVATE, num,
+            NULL, NULL);
+    }
+
+    tp = (abi_ulong *)g2h_untagged(target_array_addr);
+    for (i = 0, count = num; i < num; i += BATCH_SIZE, count -= BATCH_SIZE) {
+        for (j = i; j < i + MIN(BATCH_SIZE, count); j++) {
+            uaddrs[j % BATCH_SIZE] = (uintptr_t)g2h_untagged(tp[j]);
+        }
+
+        /*
+         * This one should not be passed as compat32 at this point; we've
+         * converted them all to host pointers.
+         */
+        error = get_errno(safe__umtx_op(uaddrs, UMTX_OP_NWAKE_PRIVATE,
+            MIN(BATCH_SIZE, count), NULL, NULL));
+        if (is_error(error)) {
+            return error;
+        }
+    }
+
+    return 0;
+#else
+    int i;
+    abi_ulong *uaddr;
+    abi_long ret = 0;
+
+    DEBUG_UMTX("<NWAKE_PRIVATE> %s: _umtx_op(%p, %d, %d, NULL, NULL) Waking: ",
+        __func__, g2h_untagged(target_array_addr), UMTX_OP_NWAKE_PRIVATE, num);
+
+    if (!access_ok(VERIFY_READ, target_array_addr, num * sizeof(abi_ulong))) {
+        return -TARGET_EFAULT;
+    }
+
+    uaddr = (abi_ulong *)g2h_untagged(target_array_addr);
+    for (i = 0; i < (int32_t)num; i++) {
+        DEBUG_UMTX("%p (%u) ", g2h_untagged(tswapal(uaddr[i])),
+            tswap32(*(uint32_t *)g2h_untagged(tswapal(uaddr[i]))));
+        ret = get_errno(safe__umtx_op(g2h_untagged(tswapal(uaddr[i])),
+            UMTX_OP_WAKE_PRIVATE, INT_MAX, NULL, NULL));
+        if (is_error(ret)) {
+            DEBUG_UMTX("\n");
+            return ret;
+        }
+    }
+    DEBUG_UMTX("\n");
+    return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+#if defined(UMTX_OP_MUTEX_WAKE2)
+abi_long freebsd_umtx_mutex_wake2(abi_ulong target_addr, uint32_t flags)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_umutex))) {
+        return -TARGET_EFAULT;
+    }
+
+    DEBUG_UMTX("<MUTEX WAKE2> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+        __func__, g2h_untagged(target_addr), UMTX_OP_MUTEX_WAKE2, flags);
+    return optimized_umtx_op(target_addr, UMTX_OP_MUTEX_WAKE2, flags, NULL,
+        NULL);
+#else
+    uint32_t count, owner, *addr;
+    struct target_umutex *target_umutex;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    pthread_mutex_lock(&umtx_wait_lck);
+    __get_user(count, &target_umutex->m_count);
+    __get_user(owner, &target_umutex->m_owner);
+    while ((owner & TARGET_UMUTEX_CONTESTED) == 0 && (count > 1 ||
+            (count == 1 && (owner & ~TARGET_UMUTEX_CONTESTED) != 0))) {
+        if (tcmpset_32(&target_umutex->m_owner, owner,
+                    (owner | TARGET_UMUTEX_CONTESTED)))
+            break;
+
+        /* owner has changed */
+        __get_user(owner, &target_umutex->m_owner);
+    }
+    pthread_mutex_unlock(&umtx_wait_lck);
+    addr = &target_umutex->m_owner;
+    /* tcmpset_32 above writes to guest, and addr is just a key below */
+    unlock_user_struct(target_umutex, target_addr, 0);
+
+    return get_errno(safe__umtx_op(addr, UMTX_OP_WAKE_PRIVATE, 1, NULL,
+        NULL));
+#endif /* _UMTX_OPTIMIZED */
+}
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+abi_long freebsd_umtx_sem2_wait(abi_ulong obj, size_t tsz, void *t)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem2))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(obj, UMTX_OP_SEM2_WAIT, 1,
+        (void *)(uintptr_t)tsz, t);
+#else
+    struct target__usem2 *t__usem2;
+    uint32_t count, flags;
+    uint32_t *addr;
+    abi_long ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, t__usem2, obj, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    /*
+     * Make sure the count field has the has USEM_HAS_WAITERS flag set
+     * so userland will always call freebsd_umtx_sem2_wake().
+     */
+    for (;;) {
+        __get_user(count, &t__usem2->_count);
+        if (USEM_COUNT(count) != 0) {
+            unlock_user_struct(t__usem2, obj, 1);
+            return 0;
+        }
+        if ((count & USEM_HAS_WAITERS) != 0) {
+            break;
+        }
+        if (tcmpset_32(&t__usem2->_count, count, (count | USEM_HAS_WAITERS))) {
+            break;
+        }
+    }
+
+    __get_user(flags, &t__usem2->_flags);
+    addr = &t__usem2->_count;
+    unlock_user_struct(t__usem2, obj, 1);
+
+    if ((flags & USYNC_PROCESS_SHARED) == 0) {
+        DEBUG_UMTX("<WAIT SEM2> %s: _umtx_op(%p, %d, %p)\n",
+            __func__, addr, UMTX_OP_WAIT_UINT_PRIVATE, (int)tsz, t);
+
+#if DETECT_DEADLOCK
+        if (t != NULL) {
+            ret = _umtx_wait_uint_private(addr, tswap32(USEM_HAS_WAITERS), tsz,
+                t, __func__);
+        } else {
+            for (;;) {
+                struct timespec ts;
+
+                ts.tv_sec = 120;
+                ts.tv_nsec = 0;
+
+                ret = _umtx_wait_uint_private(addr, tswap32(USEM_HAS_WAITERS),
+                                              0, (void *)&ts, __func__);
+                if (ret == 0) {
+                    break;
+                }
+                if (ret != -ETIMEDOUT) {
+                    break;
+                }
+                if (!lock_user_struct(VERIFY_READ, t__usem2, obj, 1)) {
+                    return -TARGET_EFAULT;
+                }
+                __get_user(count, &t__usem2->_count);
+                unlock_user_struct(t__usem2, obj, 0);
+                if (USEM_COUNT(count) != 0) {
+                    fprintf(stderr, "QEMU:(%s) TIMEOUT (count!=0)\n", __func__);
+                    ret = 0;
+                    break;
+                }
+                if (ret == -ETIMEDOUT) {
+                    fprintf(stderr, "QEMU:(%s) TIMEOUT (exiting)\n", __func__);
+                    exit(-1);
+                }
+            }
+        }
+#else
+        ret = _umtx_wait_uint_private(addr, tswap32(USEM_HAS_WAITERS),
+                                      tsz, t, __func__);
+#endif /* DETECT_DEADLOCK */
+    } else {
+        DEBUG_UMTX("<WAIT SEM2> %s: _umtx_op(%p, %d, %p)\n",
+                   __func__, addr, UMTX_OP_WAIT_UINT, (int)tsz, t);
+#if DETECT_DEADLOCK
+        if (t != NULL) {
+            ret = _umtx_wait_uint(addr, tswap32(USEM_HAS_WAITERS), tsz, t,
+                                  __func__);
+        } else {
+            for (;;) {
+                struct timespec ts;
+
+                ts.tv_sec = 120;
+                ts.tv_nsec = 0;
+
+                ret = _umtx_wait_uint(addr, tswap32(USEM_HAS_WAITERS), 0,
+                                      (void *)&ts, __func__);
+                if (ret == 0) {
+                    break;
+                }
+                if (ret != -ETIMEDOUT) {
+                    break;
+                }
+                if (!lock_user_struct(VERIFY_READ, t__usem2, obj, 1)) {
+                    return -TARGET_EFAULT;
+                }
+                __get_user(count, &t__usem2->_count);
+                unlock_user_struct(t__usem2, obj, 0);
+                if (USEM_COUNT(count) != 0) {
+                    fprintf(stderr, "QEMU:(%s) TIMEOUT (count!=0)\n", __func__);
+                    ret = 0;
+                    break;
+                }
+                if (ret == -ETIMEDOUT) {
+                    fprintf(stderr, "QEMU:(%s) TIMEOUT (exiting)\n", __func__);
+                    exit(-1);
+                }
+            }
+        }
+#else
+        ret = _umtx_wait_uint(addr, tswap32(USEM_HAS_WAITERS), tsz, t,
+                              __func__);
+#endif /* DETECT_DEADLOCK */
+    }
+    return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_umtx_sem2_wake(abi_ulong obj)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_READ, obj, sizeof(struct target__usem2))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(obj, UMTX_OP_SEM2_WAKE, 1, NULL, NULL);
+#else
+    struct target__usem2 *t__usem2;
+    uint32_t *addr, flags;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_READ, t__usem2, obj, 1)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &t__usem2->_flags);
+    addr = &t__usem2->_count;
+    unlock_user_struct(t__usem2, obj, 0);
+
+    if ((flags & USYNC_PROCESS_SHARED) == 0) {
+        DEBUG_UMTX("<WAKE SEM2> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                   __func__,  addr, UMTX_OP_WAKE_PRIVATE, INT_MAX);
+        ret = get_errno(safe__umtx_op(addr, UMTX_OP_WAKE_PRIVATE, INT_MAX, NULL,
+                                      NULL));
+    } else {
+        DEBUG_UMTX("<WAKE SEM2> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                   __func__,  addr, UMTX_OP_WAKE, INT_MAX);
+        ret = get_errno(safe__umtx_op(addr, UMTX_OP_WAKE, INT_MAX, NULL, NULL));
+    }
+
+    return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_umtx_sem_wait(abi_ulong obj, size_t tsz, void *t)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(obj, UMTX_OP_SEM_WAIT, 1,
+        (void *)(uintptr_t)tsz, t);
+#else
+        struct target__usem *t__usem;
+        uint32_t count, flags, *addr;
+        abi_long ret;
+
+        if (!lock_user_struct(VERIFY_WRITE, t__usem, obj, 0)) {
+                return -TARGET_EFAULT;
+        }
+
+        __get_user(count, &t__usem->_count);
+        if (count != 0) {
+                unlock_user_struct(t__usem, obj, 1);
+                return 0;
+        }
+
+        /*
+         * Make sure the _has_waiters field is set so userland will always
+         * call freebsd_umtx_sem_wake().
+         */
+        __put_user(1, &t__usem->_has_waiters);
+
+        __get_user(flags, &t__usem->_flags);
+        addr = &t__usem->_count;
+        unlock_user_struct(t__usem, obj, 1);
+
+        if ((flags &  USYNC_PROCESS_SHARED) == 0) {
+            DEBUG_UMTX("<WAIT SEM> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                       __func__,  &t__usem->_count, UMTX_OP_WAKE_PRIVATE, 0);
+            ret = _umtx_wait_uint_private(addr, 0, tsz, t, __func__);
+        } else {
+            DEBUG_UMTX("<WAIT SEM> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                       __func__,  &t__usem->_count, UMTX_OP_WAKE, 0);
+            ret = _umtx_wait_uint(addr, 0, tsz, t, __func__);
+        }
+
+        return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_umtx_sem_wake(abi_ulong obj)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, obj, sizeof(struct target__usem))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(obj, UMTX_OP_SEM_WAKE, 1, NULL, NULL);
+#else
+    struct target__usem *t__usem;
+        uint32_t flags, *addr;
+        abi_long ret;
+
+        if (!lock_user_struct(VERIFY_READ, t__usem, obj, 1)) {
+                return -TARGET_EFAULT;
+        }
+        __get_user(flags, &t__usem->_flags);
+        addr = &t__usem->_count;
+        unlock_user_struct(t__usem, obj, 0);
+
+        if ((flags & USYNC_PROCESS_SHARED) == 0) {
+            DEBUG_UMTX("<WAKE SEM> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                       __func__,  &t__usem->_count, UMTX_OP_WAKE_PRIVATE, 1);
+            ret = get_errno(safe__umtx_op(addr, UMTX_OP_WAKE_PRIVATE, 1, NULL,
+                                          NULL));
+        } else {
+            DEBUG_UMTX("<WAKE SEM> %s: _umtx_op(%p, %d, %d, NULL, NULL)\n",
+                       __func__,  &t__usem->_count, UMTX_OP_WAKE, 1);
+            ret = get_errno(safe__umtx_op(addr, UMTX_OP_WAKE, 1, NULL, NULL));
+        }
+
+        return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long t2h_freebsd_rtprio(struct rtprio *host_rtp, abi_ulong target_addr)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_READ, target_rtp, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_rtp->type, &target_rtp->type);
+    __get_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_rtprio(abi_ulong target_addr, struct rtprio *host_rtp)
+{
+    struct target_freebsd_rtprio *target_rtp;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_rtp, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __put_user(host_rtp->type, &target_rtp->type);
+    __put_user(host_rtp->prio, &target_rtp->prio);
+    unlock_user_struct(target_rtp, target_addr, 1);
+    return 0;
+}
+
+/* XXX We should never see this? OP_LOCK and OP_UNLOCK are now RESERVED{0,1} */
+abi_long freebsd_lock_umtx(abi_ulong target_addr, abi_long id, size_t tsz,
+        void *t)
+{
+    abi_long ret;
+    abi_long owner;
+
+    gemu_log("This is unreachable.");
+
+    /*
+     * XXX Note that memory at umtx_addr can change and so we need to be
+     * careful and check for faults.
+     */
+    for (;;) {
+        struct target_umtx *target_umtx;
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+        /* Check the simple uncontested case. */
+        if (tcmpset_al(&target_umtx->u_owner,
+                TARGET_UMTX_UNOWNED, id)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+        /* Check to see if the lock is contested but free. */
+        __get_user(owner, &target_umtx->u_owner);
+
+        if (TARGET_UMTX_CONTESTED == owner) {
+            if (tcmpset_al(&target_umtx->u_owner, TARGET_UMTX_CONTESTED,
+                        id | TARGET_UMTX_CONTESTED)) {
+                unlock_user_struct(target_umtx, target_addr, 1);
+                return 0;
+            }
+            /* We failed because it changed on us, restart. */
+            unlock_user_struct(target_umtx, target_addr, 1);
+            continue;
+        }
+
+        /* Set the contested bit and sleep. */
+        do {
+            __get_user(owner, &target_umtx->u_owner);
+            if (owner & TARGET_UMTX_CONTESTED) {
+                break;
+            }
+        } while (!tcmpset_al(&target_umtx->u_owner, owner,
+                    owner | TARGET_UMTX_CONTESTED));
+
+        __get_user(owner, &target_umtx->u_owner);
+        unlock_user_struct(target_umtx, target_addr, 1);
+
+        /* Byte swap, if needed, to match what is stored in user mem. */
+        owner = tswapal(owner);
+        DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h_untagged(target_addr), UMTX_OP_WAIT,
+            (long long)owner);
+        ret = _umtx_wait(g2h_untagged(target_addr), owner, tsz, t, __func__);
+        if (is_error(ret)) {
+            return ret;
+        }
+    }
+}
+
+/* XXX We should never see this? OP_LOCK and OP_UNLOCK are now RESERVED{0,1} */
+abi_long freebsd_unlock_umtx(abi_ulong target_addr, abi_long id)
+{
+    abi_ulong owner;
+    struct target_umtx *target_umtx;
+
+    gemu_log("This is unreachable.");
+    if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(owner, &target_umtx->u_owner);
+    if ((owner & ~TARGET_UMTX_CONTESTED) != id) {
+        unlock_user_struct(target_umtx, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    /* Check the simple uncontested case. */
+    if ((owner & ~TARGET_UMTX_CONTESTED) == 0) {
+        if (tcmpset_al(&target_umtx->u_owner, owner,
+            TARGET_UMTX_UNOWNED)) {
+            unlock_user_struct(target_umtx, target_addr, 1);
+            return 0;
+        }
+    }
+    /* This is a contested lock. Unlock it. */
+    __put_user(TARGET_UMTX_UNOWNED, &target_umtx->u_owner);
+    unlock_user_struct(target_umtx, target_addr, 1);
+
+    /* Wake up all those contesting it. */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h_untagged(target_addr), UMTX_OP_WAKE, 0);
+    return get_errno(safe__umtx_op(g2h_untagged(target_addr),
+        QEMU_UMTX_OP(UMTX_OP_WAKE), 0, 0, 0));
+}
+
+abi_long freebsd_umtx_wake(abi_ulong target_addr, uint32_t n_wake)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h_untagged(target_addr), UMTX_OP_WAKE, n_wake);
+    return get_errno(safe__umtx_op(g2h_untagged(target_addr),
+        QEMU_UMTX_OP(UMTX_OP_WAKE), n_wake, NULL, 0));
+}
+
+abi_long freebsd_umtx_wake_unsafe(abi_ulong target_addr, uint32_t n_wake)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h_untagged(target_addr), UMTX_OP_WAKE, n_wake);
+    return get_errno(_umtx_op(g2h_untagged(target_addr),
+        QEMU_UMTX_OP(UMTX_OP_WAKE), n_wake, NULL, 0));
+}
+
+abi_long freebsd_umtx_mutex_wake(abi_ulong obj, abi_long val)
+{
+
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%llx, NULL, NULL)\n",
+            __func__, g2h_untagged(obj), UMTX_OP_WAKE, (long long)val);
+    return get_errno(safe__umtx_op(g2h_untagged(obj),
+        QEMU_UMTX_OP(UMTX_OP_MUTEX_WAKE), val, NULL, NULL));
+}
+
+abi_long freebsd_lock_umutex(abi_ulong target_addr, uint32_t id,
+        void *ts, size_t tsz, int mode, abi_ulong val)
+{
+#ifdef _UMTX_OPTIMIZED
+    int op;
+
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_umutex))) {
+        return -TARGET_EFAULT;
+    }
+
+    switch (mode) {
+    case TARGET_UMUTEX_WAIT:
+        op = UMTX_OP_MUTEX_WAIT;
+        DEBUG_UMTX("<MUTEX WAIT> %s: _umtx_op(%p, %d, 0x%llx, %p, %p)\n",
+                __func__, g2h_untagged(target_addr), op, (long long)val,
+                (void *)(uintptr_t)tsz, ts);
+        break;
+    case TARGET_UMUTEX_TRY:
+        op = UMTX_OP_MUTEX_TRYLOCK;
+        DEBUG_UMTX("<MUTEX TRYLOCK> %s: _umtx_op(%p, %d, 0x%llx, %p, %p)\n",
+                __func__, g2h_untagged(target_addr), op, (long long)val,
+                (void *)(uintptr_t)tsz, ts);
+        break;
+    default:
+        op = UMTX_OP_MUTEX_LOCK;
+        DEBUG_UMTX("<MUTEX LOCK> %s: _umtx_op(%p, %d, 0x%llx, %p, %p)\n",
+                __func__, g2h_untagged(target_addr), op, (long long)val,
+                (void *)(uintptr_t)tsz, ts);
+        break;
+    }
+
+    return optimized_umtx_op(target_addr, op, val, (void *)(uintptr_t)tsz, ts);
+#else
+    struct target_umutex *target_umutex;
+    uint32_t owner, flags, count, *addr;
+    int ret = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    for (;;) {
+
+        __get_user(owner, &target_umutex->m_owner);
+
+        if ((owner & ~TARGET_UMUTEX_CONTESTED) == 0) {
+            /* Lock is unowned. */
+            if (TARGET_UMUTEX_WAIT == mode) {
+                /* Waiting on an unlocked mutex; bail out. */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                return 0;
+            }
+
+            /* Attempt to acquire it, preserve the contested bit ("owner"). */
+            while ((owner & ~TARGET_UMUTEX_CONTESTED) == 0 &&
+                    !tcmpset_32(&target_umutex->m_owner, owner, owner | id)) {
+                __get_user(owner, &target_umutex->m_owner);
+            }
+
+            if ((owner & ~TARGET_UMUTEX_CONTESTED) == 0) {
+                /*
+                 * The acquire succeeded, because we didn't observe owner with
+                 * a different id.
+                 */
+                unlock_user_struct(target_umutex, target_addr, 1);
+                return 0;
+            }
+
+            /* Otherwise, someone beat us to it; carry on. */
+        }
+
+        __get_user(flags, &target_umutex->m_flags);
+        if ((flags & TARGET_UMUTEX_ERROR_CHECK) != 0 &&
+                (owner & ~TARGET_UMUTEX_CONTESTED) == id) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return -TARGET_EDEADLK;
+        }
+
+        if (TARGET_UMUTEX_TRY == mode) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            return -TARGET_EBUSY;
+        }
+
+        /* Set the contested bit and sleep. */
+        while ((owner & TARGET_UMUTEX_CONTESTED) == 0) {
+            if (tcmpset_32(&target_umutex->m_owner, owner,
+                    owner | TARGET_UMUTEX_CONTESTED)) {
+                /*
+                 * Keep our local view of owner consistent with what we think
+                 * we've set it to.  We're about to sleep on it, and we don't
+                 * really want a spurious return from _umtx_op because of this.
+                 */
+                owner |= TARGET_UMUTEX_CONTESTED;
+
+                break;
+            } else {
+                __get_user(owner, &target_umutex->m_owner);
+            }
+        }
+
+        /*
+         * If it changed during the above loop, we may be able to acquire now.
+         */
+        if ((owner & ~TARGET_UMUTEX_CONTESTED) == 0) {
+            continue;
+        }
+
+        pthread_mutex_lock(&umtx_wait_lck);
+        __get_user(count, &target_umutex->m_count);
+        count++;
+        __put_user(count, &target_umutex->m_count);
+        pthread_mutex_unlock(&umtx_wait_lck);
+
+        addr = &target_umutex->m_owner;
+
+        /* addr used only as key below, not dereferenced */
+        unlock_user_struct(target_umutex, target_addr, 1);
+
+        DEBUG_UMTX("<WAIT UMUTEX> %s: _umtx_op(%p, %d, 0x%x, %d, %jx) "
+            "count = %d\n", __func__, g2h_untagged(target_addr),
+            UMTX_OP_WAIT_PRIVATE, tswap32(target_umutex->m_owner), tsz,
+            (uintmax_t)ts, count);
+        ret = _umtx_wait_uint_private(addr, owner, tsz, (void *)ts, __func__);
+
+        if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+            return -TARGET_EFAULT;
+        }
+
+        pthread_mutex_lock(&umtx_wait_lck);
+        __get_user(count, &target_umutex->m_count);
+        count--;
+        __put_user(count, &target_umutex->m_count);
+        pthread_mutex_unlock(&umtx_wait_lck);
+        if (ret != 0) {
+            unlock_user_struct(target_umutex, target_addr, 1);
+            break;
+        }
+    }
+    return ret;
+#endif  /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_unlock_umutex(abi_ulong target_addr, uint32_t id)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_umutex))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_addr, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+#else
+    struct target_umutex *target_umutex;
+    uint32_t count, owner, *addr, flags;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    /* Make sure we own this mutex. */
+    __get_user(owner, &target_umutex->m_owner);
+    if ((owner & ~TARGET_UMUTEX_CONTESTED) != id) {
+        unlock_user_struct(target_umutex, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+    pthread_mutex_lock(&umtx_wait_lck);
+    __get_user(count, &target_umutex->m_count);
+
+    /* Unlock it; set the contested bit as needed. */
+    flags = TARGET_UMUTEX_UNOWNED;
+    if (count > 1) {
+        flags |= TARGET_UMUTEX_CONTESTED;
+    }
+    __put_user(flags, &target_umutex->m_owner);
+    pthread_mutex_unlock(&umtx_wait_lck);
+
+    addr = &target_umutex->m_owner;
+
+    /* addr is used only as a key, so we can unlock before we use it below */
+    unlock_user_struct(target_umutex, target_addr, 1);
+
+    /*
+     * And wake up any that may be contested it.  We used to only do this if the
+     * lock wasn't contested coming in, but that could have changed in the
+     * interim.  Unconditionally issue the wakeup, in conjunction with the
+     * previous change of owner this should catch all cases.
+     */
+    DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+        __func__, g2h_untagged(target_addr), UMTX_OP_WAKE, 0);
+    return get_errno(safe__umtx_op(addr, UMTX_OP_WAKE_PRIVATE, 1, NULL, NULL));
+#endif  /* _UMTX_OPTIMIZED */
+}
+
+/*
+ * wflags CVWAIT_CHECK_UNPARKING, CVWAIT_ABSTIME, CVWAIT_CLOCKID
+ */
+abi_long freebsd_cv_wait(abi_ulong target_ucond_addr,
+        abi_ulong target_umtx_addr, struct timespec *ts, int wflags)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+        sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_ucond_addr, UMTX_OP_CV_WAIT, wflags,
+        g2h_untagged(target_umtx_addr), ts);
+#else
+    abi_long ret;
+    long tid;
+    struct target_ucond *target_ucond;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_ucond, target_ucond_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Check the clock ID if needed. */
+    if ((wflags & TARGET_CVWAIT_CLOCKID) != 0) {
+        uint32_t clockid;
+
+        __get_user(clockid, &target_ucond->c_clockid);
+        if (clockid >= CLOCK_THREAD_CPUTIME_ID) {
+            /* Only HW clock id will work. */
+            unlock_user_struct(target_ucond, target_ucond_addr, 1);
+            return -TARGET_EINVAL;
+        }
+    }
+
+    thr_self(&tid);
+
+    /* Lock the _cv_mutex so we can safely unlock the user mutex */
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+
+    /* Set c_has_waiters before releasing the user mutex! */
+    __put_user(1, &target_ucond->c_has_waiters);
+
+    /* unlock the user mutex */
+    ret = freebsd_unlock_umutex(target_umtx_addr, tid);
+    if (is_error(ret)) {
+        safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+        unlock_user_struct(target_ucond, target_ucond_addr, 1);
+        return ret;
+    }
+
+    /* UMTX_OP_CV_WAIT unlocks _cv_mutex */
+    DEBUG_UMTX("<CV_WAIT> %s: _umtx_op(%p, %d, 0x%x, %p, NULL)\n",
+        __func__, g2h_untagged(target_ucond_addr), UMTX_OP_CV_WAIT, wflags,
+        &_cv_mutex);
+    ret = safe__umtx_op(g2h_untagged(target_ucond_addr), UMTX_OP_CV_WAIT,
+                        wflags, &_cv_mutex, ts);
+
+    if (is_error(ret)) {
+        safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+        unlock_user_struct(target_ucond, target_ucond_addr, 1);
+        return ret;
+    }
+    ret = freebsd_lock_umutex(target_umtx_addr, tid, NULL, 0, TARGET_UMUTEX_TRY,
+        0);
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+    unlock_user_struct(target_ucond, target_ucond_addr, 1);
+
+    return ret;
+#endif  /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_cv_signal(abi_ulong target_ucond_addr)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+        sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_ucond_addr, UMTX_OP_CV_SIGNAL, 0, NULL,
+        NULL);
+#else
+    abi_long ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<CV_SIGNAL> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+            __func__, g2h_untagged(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0);
+    ret = get_errno(safe__umtx_op(g2h_untagged(target_ucond_addr),
+                                  UMTX_OP_CV_SIGNAL, 0, NULL, NULL));
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_cv_broadcast(abi_ulong target_ucond_addr)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+        sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_ucond_addr, UMTX_OP_CV_BROADCAST, 0, NULL,
+        NULL);
+#else
+    int ret;
+
+    if (!access_ok(VERIFY_WRITE, target_ucond_addr,
+                sizeof(struct target_ucond))) {
+        return -TARGET_EFAULT;
+    }
+
+    /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
+    DEBUG_UMTX("<CV_BROADCAST> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+        __func__, g2h_untagged(target_ucond_addr), UMTX_OP_CV_BROADCAST, 0);
+    ret = get_errno(safe__umtx_op(g2h_untagged(target_ucond_addr),
+                                  UMTX_OP_CV_BROADCAST, 0, NULL, NULL));
+    safe__umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
+
+    return ret;
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_rw_rdlock(abi_ulong target_addr, long fflag, size_t tsz,
+        void *t)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_urwlock))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_addr, UMTX_OP_RW_RDLOCK, fflag,
+        (void *)(uintptr_t)tsz, t);
+#else
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, wrflags;
+    uint32_t state;
+    uint32_t blocked_readers;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    wrflags = TARGET_URWLOCK_WRITE_OWNER;
+    if (!(fflag & TARGET_URWLOCK_PREFER_READER) &&
+            !(flags & TARGET_URWLOCK_PREFER_READER)) {
+        wrflags |= TARGET_URWLOCK_WRITE_WAITERS;
+    }
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        /* try to lock it */
+        while (!(state & wrflags)) {
+            if (TARGET_URWLOCK_READER_COUNT(state) ==
+                TARGET_URWLOCK_MAX_READERS) {
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return -TARGET_EAGAIN;
+            }
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                (state + 1))) {
+                /* The acquired succeeded. */
+                unlock_user_struct(target_urwlock,
+                    target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+        /* set read contention bit */
+        if (!tcmpset_32(&target_urwlock->rw_state, state,
+            state | TARGET_URWLOCK_READ_WAITERS)) {
+            /* The state has changed.  Start over. */
+            continue;
+        }
+
+        /* contention bit is set, increase read waiter count */
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, blocked_readers + 1)) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+
+        ret = 0;
+        while (state & wrflags) {
+            /* sleep/wait */
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x (0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_state,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = _umtx_wait_uint(&target_urwlock->rw_state, tswap32(state),
+                    tsz, t, __func__);
+            if (is_error(ret)) {
+                if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
+                                      target_addr, 0)) {
+                    return ret;
+                }
+                goto rdlock_decrement;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr,
+                        0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease read waiter count */
+rdlock_decrement:
+        __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_readers,
+                    blocked_readers, (blocked_readers - 1))) {
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        }
+        if (blocked_readers == 1) {
+            /* clear read contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_READ_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+        }
+        if (is_error(ret)) {
+            /* tcmpset_32 operates on the target memory, so don't double copy */
+            unlock_user_struct(target_urwlock, target_addr, 0);
+            return ret;
+        }
+    }
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_rw_wrlock(abi_ulong target_addr, long fflag, size_t tsz,
+        void *t)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_urwlock))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_addr, UMTX_OP_RW_WRLOCK, fflag,
+        (void *)(uintptr_t)tsz, t);
+#else
+    struct target_urwlock *target_urwlock;
+    uint32_t blocked_readers, blocked_writers;
+    uint32_t state;
+    abi_long ret;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+    blocked_readers = 0;
+    for (;;) {
+        __get_user(state, &target_urwlock->rw_state);
+        while (!(state & TARGET_URWLOCK_WRITE_OWNER) &&
+            TARGET_URWLOCK_READER_COUNT(state) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_OWNER)) {
+                unlock_user_struct(target_urwlock, target_addr, 1);
+                return 0;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        if (!(state & (TARGET_URWLOCK_WRITE_OWNER |
+                        TARGET_URWLOCK_WRITE_WAITERS)) &&
+                blocked_readers != 0) {
+            DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE,
+                tswap32(state));
+            ret = get_errno(safe__umtx_op(&target_urwlock->rw_state,
+                UMTX_OP_WAKE, INT_MAX, NULL, NULL));
+            unlock_user_struct(target_urwlock, target_addr, ret == 0);
+            return ret;
+        }
+        /* re-read the state */
+        __get_user(state, &target_urwlock->rw_state);
+
+        /* and set TARGET_URWLOCK_WRITE_WAITERS */
+        while (((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                    TARGET_URWLOCK_READER_COUNT(state) != 0) &&
+                (state & TARGET_URWLOCK_WRITE_WAITERS) == 0) {
+            if (tcmpset_32(&target_urwlock->rw_state, state,
+                        state | TARGET_URWLOCK_WRITE_WAITERS)) {
+                break;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* contention bit is set, increase write waiter count */
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, blocked_writers + 1)) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+
+        /* sleep */
+        ret = 0;
+        while ((state & TARGET_URWLOCK_WRITE_OWNER) ||
+                (TARGET_URWLOCK_READER_COUNT(state) != 0)) {
+            unlock_user_struct(target_urwlock, target_addr, 1);
+            DEBUG_UMTX("<WAIT> %s: _umtx_op(%p, %d, 0x%x(0x%x), NULL, NULL)\n",
+                    __func__, &target_urwlock->rw_blocked_writers,
+                    UMTX_OP_WAIT_UINT, tswap32(state),
+                    target_urwlock->rw_state);
+            ret = _umtx_wait_uint(&target_urwlock->rw_state,
+                        tswap32(state), tsz, t, __func__);
+            if (is_error(ret)) {
+                if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
+                                      target_addr, 0)) {
+                    return ret;
+                }
+                goto wrlock_decrement;
+            }
+            if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr,
+                        0)) {
+                return -TARGET_EFAULT;
+            }
+            __get_user(state, &target_urwlock->rw_state);
+        }
+
+        /* decrease the write waiter count */
+wrlock_decrement:
+        __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        while (!tcmpset_32(&target_urwlock->rw_blocked_writers,
+                    blocked_writers, (blocked_writers - 1))) {
+            __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
+        }
+        if (blocked_writers == 1) {
+            /* clear write contention bit */
+            __get_user(state, &target_urwlock->rw_state);
+            while (!tcmpset_32(&target_urwlock->rw_state, state,
+                        state & ~TARGET_URWLOCK_WRITE_WAITERS)) {
+                __get_user(state, &target_urwlock->rw_state);
+            }
+            __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
+        } else {
+            blocked_readers = 0;
+        }
+        if (is_error(ret)) {
+            /* tcmpset_32 operates on the target memory, so don't double copy */
+            unlock_user_struct(target_urwlock, target_addr, 0);
+            return ret;
+        }
+    }
+#endif /* _UMTX_OPTIMIZED */
+}
+
+abi_long freebsd_rw_unlock(abi_ulong target_addr)
+{
+#ifdef _UMTX_OPTIMIZED
+    if (!access_ok(VERIFY_WRITE, target_addr, sizeof(struct target_urwlock))) {
+        return -TARGET_EFAULT;
+    }
+
+    return optimized_umtx_op(target_addr, UMTX_OP_RW_UNLOCK, 0, NULL, NULL);
+#else
+    struct target_urwlock *target_urwlock;
+    uint32_t flags, state, count = 0;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __get_user(flags, &target_urwlock->rw_flags);
+    __get_user(state, &target_urwlock->rw_state);
+
+    if (state & TARGET_URWLOCK_WRITE_OWNER) {
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state,
+                state & ~TARGET_URWLOCK_WRITE_OWNER)) {
+                /*
+                 * Update the state here because we want to make sure that
+                 * another thread didn't unste the flag from underneath us.
+                 * If they did, we throw EPERM as the kernel does.
+                 */
+                __get_user(state, &target_urwlock->rw_state);
+                if (!(state & TARGET_URWLOCK_WRITE_OWNER)) {
+                    unlock_user_struct(target_urwlock, target_addr, 1);
+                    return -TARGET_EPERM;
+                }
+            } else {
+                break;
+            }
+        }
+    } else if (TARGET_URWLOCK_READER_COUNT(state) != 0) {
+        /* decrement reader count */
+        for (;;) {
+            if (!tcmpset_32(&target_urwlock->rw_state, state, (state  - 1))) {
+                /*
+                 * Just as in the branch above; we update the state here because
+                 * we want to make sure the reader count didn't hit 0 while we
+                 * are still trying to decrement this. The kernel also returns
+                 * EPERM here.
+                 */
+                __get_user(state, &target_urwlock->rw_state);
+                if (TARGET_URWLOCK_READER_COUNT(state) == 0) {
+                    unlock_user_struct(target_urwlock, target_addr, 1);
+                    return -TARGET_EPERM;
+                 }
+            } else {
+                break;
+            }
+        }
+    } else {
+        unlock_user_struct(target_urwlock, target_addr, 1);
+        return -TARGET_EPERM;
+    }
+
+    if (!(flags & TARGET_URWLOCK_PREFER_READER)) {
+        if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        } else if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        }
+    } else {
+        if (state & TARGET_URWLOCK_READ_WAITERS) {
+            count = INT_MAX;
+        } else if (state & TARGET_URWLOCK_WRITE_WAITERS) {
+            count = 1;
+        }
+    }
+
+    /* rw_state used below as key only */
+    unlock_user_struct(target_urwlock, target_addr, 1);
+    if (count != 0) {
+        DEBUG_UMTX("<WAKE> %s: _umtx_op(%p, %d, 0x%x, NULL, NULL)\n",
+                __func__, &target_urwlock->rw_state, UMTX_OP_WAKE, count);
+        return get_errno(safe__umtx_op(&target_urwlock->rw_state, UMTX_OP_WAKE,
+                    count, NULL, NULL));
+    } else {
+        return 0;
+    }
+#endif  /* _UMTX_OPTIMIZED */
+}
+
+abi_long
+freebsd_umtx_shm(abi_ulong target_addr, long fflag)
+{
+
+    return get_errno(safe__umtx_op(NULL, QEMU_UMTX_OP(UMTX_OP_SHM), fflag,
+        g2h_untagged(target_addr), NULL));
+}
+
+abi_long
+freebsd_umtx_robust_list(abi_ulong target_addr, size_t rbsize)
+{
+#ifdef _UMTX_OPTIMIZED
+    struct target_umtx_robust_lists_params *tparams;
+    struct umtx_robust_lists_params hparams;
+    abi_long error;
+
+    if (rbsize < sizeof(*tparams)) {
+        return -TARGET_EINVAL;
+    }
+
+    if (!lock_user_struct(VERIFY_READ, tparams, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+
+    hparams.robust_list_offset =
+        (uintptr_t)g2h_untagged(tparams->robust_list_offset);
+    hparams.robust_priv_list_offset =
+        (uintptr_t)g2h_untagged(tparams->robust_priv_list_offset);
+    hparams.robust_inact_offset =
+        (uintptr_t)g2h_untagged(tparams->robust_inact_offset);
+
+    error = optimized_umtx_op(0, UMTX_OP_ROBUST_LISTS, sizeof(hparams),
+        &hparams, NULL);
+    unlock_user_struct(tparams, target_addr, 0);
+    return error;
+#else
+    gemu_log("safe__umtx_op(..., UMTX_OP_ROBUST_LISTS. ...)  not supported\n");
+    return -TARGET_EOPNOTSUPP;
+#endif
+}
+
+abi_long do_freebsd_thr_new(CPUArchState *env,
+        abi_ulong target_param_addr, int32_t param_size)
+{
+    new_freebsd_thread_info_t info;
+    pthread_attr_t attr;
+    TaskState *ts;
+    CPUArchState *new_env;
+    CPUState *new_cpu;
+    struct target_freebsd_thr_param *target_param;
+    abi_ulong target_rtp_addr;
+    struct target_freebsd_rtprio *target_rtp;
+    struct rtprio *rtp_ptr, rtp;
+    CPUState *cpu = env_cpu(env);
+    TaskState *parent_ts = (TaskState *)cpu->opaque;
+    sigset_t sigmask;
+    struct sched_param sched_param;
+    int sched_policy;
+    int ret = 0;
+
+    memset(&info, 0, sizeof(info));
+
+    if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    info.param.start_func = tswapal(target_param->start_func);
+    info.param.arg = tswapal(target_param->arg);
+    info.param.stack_base = tswapal(target_param->stack_base);
+    info.param.stack_size = tswapal(target_param->stack_size);
+    info.param.tls_base = tswapal(target_param->tls_base);
+    info.param.tls_size = tswapal(target_param->tls_size);
+    info.param.child_tid = tswapal(target_param->child_tid);
+    info.param.parent_tid = tswapal(target_param->parent_tid);
+    info.param.flags = tswap32(target_param->flags);
+    target_rtp_addr = info.param.rtp = tswapal(target_param->rtp);
+    unlock_user_struct(target_param, target_param_addr, 0);
+
+    thr_self(&info.parent_tid);
+
+    if (target_rtp_addr) {
+        if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr, 1)) {
+            return -TARGET_EFAULT;
+        }
+        rtp.type = tswap16(target_rtp->type);
+        rtp.prio = tswap16(target_rtp->prio);
+        unlock_user_struct(target_rtp, target_rtp_addr, 0);
+        rtp_ptr = &rtp;
+    } else {
+        rtp_ptr = NULL;
+    }
+
+    /* Create a new CPU instance. */
+    ts = g_malloc0(sizeof(TaskState));
+    init_task_state(ts);
+
+    /* Grab a mutex so that thread setup appears atomic. */
+    pthread_mutex_lock(new_freebsd_thread_lock_ptr);
+
+    /*
+     * If this is our first additional thread, we need to ensure we
+     * generate code for parallel execution and flush old translations.
+     * Do this now so that the copy gets CF_PARALLEL too.
+     */
+    if (!(cpu->tcg_cflags & CF_PARALLEL)) {
+        cpu->tcg_cflags |= CF_PARALLEL;
+        tb_flush__exclusive_or_serial();
+    }
+
+    new_env = cpu_copy(env);
+
+    new_cpu = env_cpu(new_env);
+    new_cpu->opaque = ts;
+    ts->bprm = parent_ts->bprm;
+    ts->info = parent_ts->info;
+    ts->signal_mask = parent_ts->signal_mask;
+    ts->ts_tid = qemu_get_thread_id();
+
+    pthread_mutex_init(&info.mutex, NULL);
+    pthread_mutex_lock(&info.mutex);
+    pthread_cond_init(&info.cond, NULL);
+    info.env = new_env;
+
+    /* XXX check return values... */
+    pthread_attr_init(&attr);
+    pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    if (rtp_ptr) {
+        rtp_to_schedparam(&rtp, &sched_policy, &sched_param);
+        pthread_attr_setschedpolicy(&attr, sched_policy);
+        pthread_attr_setschedparam(&attr, &sched_param);
+    }
+
+    /*
+     * It is not safe to deliver signals until the child has finished
+     * initializing, so temporarily block all signals.
+     */
+    sigfillset(&sigmask);
+    sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
+
+    ret = pthread_create(&info.thread, &attr, new_freebsd_thread_start, &info);
+
+    sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
+    pthread_attr_destroy(&attr);
+    if (ret == 0) {
+        /* Wait for the child to initialize. */
+        pthread_cond_wait(&info.cond, &info.mutex);
+    } else {
+        /* Creation of new thread failed. */
+        object_unparent(OBJECT(new_cpu));
+        object_unref(OBJECT(new_cpu));
+        g_free(ts);
+        ret = -host_to_target_errno(ret);
+    }
+
+    pthread_mutex_unlock(&info.mutex);
+    pthread_cond_destroy(&info.cond);
+    pthread_mutex_destroy(&info.mutex);
+    pthread_mutex_unlock(new_freebsd_thread_lock_ptr);
+
+    return ret;
+}
diff --git a/bsd-user/freebsd/os-thread.h b/bsd-user/freebsd/os-thread.h
index d3f1f01b13..4258b24095 100644
--- a/bsd-user/freebsd/os-thread.h
+++ b/bsd-user/freebsd/os-thread.h
@@ -240,5 +240,357 @@ static inline abi_long do_freebsd_swapcontext(CPUArchState *env, abi_ulong arg1,
  * undocumented _umtx_op(void *obj, int op, u_long val, void *uaddr,
  *                           void *target_time);
  */
+static inline abi_long do_freebsd__umtx_op(abi_ulong obj, int op, abi_ulong val,
+        abi_ulong uaddr, abi_ulong target_time)
+{
+    abi_long ret;
+#ifndef _UMTX_OPTIMIZED
+    struct _umtx_time ut[2];
+    struct timespec ts;
+    size_t utsz;
+    long tid;
+#endif
+
+    switch (op) {
+    case TARGET_UMTX_OP_WAIT:
+        /* args: obj *, val, (void *)sizeof(ut), ut * */
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_umtx_wait(obj, val, uaddr,
+                                safe_g2h_untagged(target_time));
+#else
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_umtx_wait(obj, tswapal(val), utsz, &ut);
+        } else {
+            ret = freebsd_umtx_wait(obj, tswapal(val), 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_WAKE:
+        /* args: obj *, nr_wakeup */
+        ret = freebsd_umtx_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_LOCK:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_lock_umutex(obj, 0, safe_g2h_untagged(target_time), uaddr,
+                                  0, val);
+#else
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_lock_umutex(obj, tid, ut, utsz, 0, tswapal(val));
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, 0, 0, tswapal(val));
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_UNLOCK:
+#ifdef _UMTX_OPTIMIZED
+        ret = freebsd_unlock_umutex(obj, 0);
+#else
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_unlock_umutex(obj, tid);
+#endif
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_TRYLOCK:
+#ifdef _UMTX_OPTIMIZED
+        ret = freebsd_lock_umutex(obj, 0, NULL, 0, TARGET_UMUTEX_TRY, val);
+#else
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        ret = freebsd_lock_umutex(obj, tid, NULL, 0, TARGET_UMUTEX_TRY,
+            tswapal(val));
+#endif
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAIT:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_lock_umutex(obj, 0, safe_g2h_untagged(target_time), uaddr,
+            TARGET_UMUTEX_WAIT, val);
+#else
+        ret = get_errno(thr_self(&tid));
+        if (is_error(ret)) {
+            return ret;
+        }
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_lock_umutex(obj, tid, ut, utsz, TARGET_UMUTEX_WAIT,
+                tswapal(val));
+        } else {
+            ret = freebsd_lock_umutex(obj, tid, NULL, 0, TARGET_UMUTEX_WAIT,
+                tswapal(val));
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_MUTEX_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_mutex_wake(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_SET_CEILING:
+        ret = 0; /* XXX quietly ignore these things for now */
+        break;
+
+    case TARGET_UMTX_OP_CV_WAIT:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_cv_wait(obj, uaddr, safe_g2h_untagged(target_time), val);
+#else
+        /*
+         * Initialization of the struct conv is done by
+         * bzero'ing everything in userland.
+         */
+        if (target_time != 0) {
+            if (t2h_freebsd_timespec(&ts, target_time)) {
+                return -TARGET_EFAULT;
+            }
+            ret = freebsd_cv_wait(obj, uaddr, &ts, val);
+        } else {
+            ret = freebsd_cv_wait(obj, uaddr, NULL, val);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_CV_SIGNAL:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_signal(obj);
+        break;
+
+    case TARGET_UMTX_OP_CV_BROADCAST:
+        /*
+         * XXX
+         * User code may check if c_has_waiters is zero.  Other
+         * than that it is assume that user code doesn't do
+         * much with the struct conv fields and is pretty
+         * much opauque to userland.
+         */
+        ret = freebsd_cv_broadcast(obj);
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_umtx_wait_uint(obj, val, uaddr,
+                                     safe_g2h_untagged(target_time));
+#else
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        /* args: obj *, val, (void *)sizeof(ut), ut * */
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val),
+                                         utsz, &ut);
+        } else {
+            ret = freebsd_umtx_wait_uint(obj, tswap32((uint32_t)val), 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_umtx_wait_uint_private(obj, val, uaddr,
+            safe_g2h_untagged(target_time));
+#else
+        if (!access_ok(VERIFY_READ, obj, sizeof(abi_ulong))) {
+            return -TARGET_EFAULT;
+        }
+        /* args: obj *, val, (void *)sizeof(ut), ut * */
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    utsz, &ut);
+        } else {
+            ret = freebsd_umtx_wait_uint_private(obj, tswap32((uint32_t)val),
+                    0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_WAKE_PRIVATE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_wake_private(obj, val);
+        break;
+
+    case TARGET_UMTX_OP_RW_RDLOCK:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_rw_rdlock(obj, val, uaddr,
+                                safe_g2h_untagged(target_time));
+#else
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_rw_rdlock(obj, val, utsz, &ut);
+        } else {
+            ret = freebsd_rw_rdlock(obj, val, 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_RW_WRLOCK:
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_rw_wrlock(obj, val, uaddr,
+                                safe_g2h_untagged(target_time));
+#else
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_rw_wrlock(obj, val, utsz, &ut);
+        } else {
+            ret = freebsd_rw_wrlock(obj, val, 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_RW_UNLOCK:
+        ret = freebsd_rw_unlock(obj);
+        break;
+
+#ifdef UMTX_OP_MUTEX_WAKE2
+    case TARGET_UMTX_OP_MUTEX_WAKE2:
+        ret = freebsd_umtx_mutex_wake2(obj, val);
+        break;
+#endif /* UMTX_OP_MUTEX_WAKE2 */
+
+#ifdef UMTX_OP_NWAKE_PRIVATE
+    case TARGET_UMTX_OP_NWAKE_PRIVATE:
+        ret = freebsd_umtx_nwake_private(obj, val);
+        break;
+#endif /* UMTX_OP_NWAKE_PRIVATE */
+
+    case TARGET_UMTX_OP_SEM2_WAIT:
+        /* args: obj *, val, (void *)sizeof(ut), ut * */
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(
+            (uaddr > sizeof(struct target_freebsd__umtx_time) ? VERIFY_WRITE :
+             VERIFY_READ), target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_umtx_sem2_wait(obj, uaddr,
+                                     safe_g2h_untagged(target_time));
+#else
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            /* Kernel writes out the ut[1] if utsz >= _umtx_time + timespec. */
+            ret = freebsd_umtx_sem2_wait(obj, utsz, ut);
+            if (ret == -TARGET_EINTR && (ut[0]._flags & UMTX_ABSTIME) == 0 &&
+                utsz >= sizeof(struct target_freebsd__umtx_time) +
+                sizeof(struct target_freebsd_timespec)) {
+                abi_ulong cret;
+
+                cret = h2t_freebsd_timespec(target_time +
+                    sizeof(struct target_freebsd__umtx_time), &ut[1]._timeout);
+                if (is_error(cret)) {
+                    ret = cret;
+                }
+            }
+        } else {
+            ret = freebsd_umtx_sem2_wait(obj, 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_SEM2_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_sem2_wake(obj);
+        break;
+    case TARGET_UMTX_OP_SEM_WAIT:
+        /* args: obj *, val, (void *)sizeof(ut), ut * */
+#ifdef _UMTX_OPTIMIZED
+        if (target_time != 0 && !access_ok(VERIFY_READ, target_time, uaddr)) {
+            return -TARGET_EFAULT;
+        }
+        ret = freebsd_umtx_sem_wait(obj, uaddr, safe_g2h_untagged(target_time));
+#else
+        if (target_time != 0) {
+            ret = t2h_freebsd_umtx_time(target_time, uaddr, ut, &utsz);
+            if (is_error(ret)) {
+                return ret;
+            }
+            ret = freebsd_umtx_sem_wait(obj, utsz, ut);
+        } else {
+            ret = freebsd_umtx_sem_wait(obj, 0, NULL);
+        }
+#endif
+        break;
+
+    case TARGET_UMTX_OP_SEM_WAKE:
+        /* Don't need to do access_ok(). */
+        ret = freebsd_umtx_sem_wake(obj);
+        break;
+    case TARGET_UMTX_OP_SHM:
+        ret = freebsd_umtx_shm(uaddr, val);
+        break;
+    case TARGET_UMTX_OP_ROBUST_LISTS:
+        ret = freebsd_umtx_robust_list(uaddr, val);
+        break;
+    default:
+        return -TARGET_EINVAL;
+    }
+    return ret;
+}
 
 #endif /* FREEBSD_OS_THREAD_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 32/41] bsd-user: Add thread system call dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (30 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 31/41] bsd-user: Add do_freebsd__umtx_op to os-thread.h Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 33/41] bsd-user: Add os-extattr.h with file and fd extattr functions Warner Losh
                   ` (9 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans,
	Richard Henderson

Wire up thread-related system calls: thr_new, thr_set_name, thr_self,
thr_suspend, thr_wake, thr_kill, thr_kill2, thr_exit, rtprio_thread,
getcontext, setcontext, swapcontext, and _umtx_op.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 55 +++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index f2c3ff25e8..0c729da0ab 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -1293,6 +1293,61 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd_setfib(arg1);
         break;
 
+        /*
+         * thread system calls
+         */
+    case TARGET_FREEBSD_NR_thr_new: /* thr_new(2) */
+        ret = do_freebsd_thr_new(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_set_name: /* thr_set_name(2) */
+        ret = do_freebsd_thr_set_name(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_self: /* thr_self(2) */
+        ret = do_freebsd_thr_self(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_suspend: /* thr_suspend(2) */
+        ret = do_freebsd_thr_suspend(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_wake: /* thr_wake(2) */
+        ret = do_freebsd_thr_wake(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill: /* thr_kill(2) */
+        ret = do_freebsd_thr_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_kill2: /* thr_kill2(2) */
+        ret = do_freebsd_thr_kill2(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_thr_exit: /* thr_exit(2) */
+        ret = do_freebsd_thr_exit(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rtprio_thread: /* rtprio_thread(2) */
+        ret = do_freebsd_rtprio_thread(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getcontext: /* getcontext(2) */
+        ret = do_freebsd_getcontext(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_setcontext: /* setcontext(2) */
+        ret = do_freebsd_setcontext(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapcontext: /* swapcontext(2) */
+        ret = do_freebsd_swapcontext(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR__umtx_op: /* undocumented */
+        ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5);
+        break;
+
         /*
          * sys{ctl, arch, call}
          */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 33/41] bsd-user: Add os-extattr.h with file and fd extattr functions
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (31 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 32/41] bsd-user: Add thread system call dispatch Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 34/41] bsd-user: Add link and list extattr functions to os-extattr.h Warner Losh
                   ` (8 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Stacey Son, Richard Henderson

Add the first part of extended attribute support: extattrctl,
extattr_set_file, extattr_get_file, extattr_delete_file,
extattr_set_fd, extattr_get_fd, and extattr_delete_fd.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-extattr.h | 208 ++++++++++++++++++++++++++++++++++
 1 file changed, 208 insertions(+)
 create mode 100644 bsd-user/freebsd/os-extattr.h

diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
new file mode 100644
index 0000000000..fb3ef27346
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.h
@@ -0,0 +1,208 @@
+/*
+ * FreeBSD extended attributes and ACL system call support
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <sys/extattr.h>
+#include <sys/acl.h>
+
+/* extattrctl() */
+static inline abi_long do_freebsd_extattrctl(abi_ulong arg1, abi_ulong arg2,
+                                             abi_ulong arg3, abi_ulong arg4,
+                                             abi_ulong arg5)
+{
+    abi_long ret;
+    void *p, *a, *f;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    f = lock_user_string(arg3);
+    if (f == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg5);
+    if (a == NULL) {
+        unlock_user(f, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattrctl(path(p), arg2, f, arg4, a));
+    unlock_user(a, arg5, 0);
+    unlock_user(f, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_file(2) */
+static inline abi_long do_freebsd_extattr_set_file(abi_long arg1,
+                                                   abi_long arg2,
+                                                   abi_long arg3,
+                                                   abi_long arg4,
+                                                   abi_long arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_get_file(2) */
+static inline abi_long do_freebsd_extattr_get_file(abi_long arg1,
+                                                   abi_long arg2,
+                                                   abi_long arg3,
+                                                   abi_long arg4,
+                                                   abi_long arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_file(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_file(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_file(2) */
+static inline abi_long do_freebsd_extattr_delete_file(abi_long arg1,
+                                                      abi_long arg2,
+                                                      abi_long arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_file(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_fd(2) */
+static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1, abi_long arg2,
+                                                 abi_long arg3, abi_long arg4,
+                                                 abi_long arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_get_fd(2) */
+static inline abi_long do_freebsd_extattr_get_fd(abi_long arg1, abi_long arg2,
+                                                 abi_long arg3, abi_long arg4,
+                                                 abi_long arg5)
+{
+    abi_long ret;
+    void *a, *d;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_fd(arg1, arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+/* extattr_delete_fd(2) */
+static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
+                                                    abi_long arg2,
+                                                    abi_long arg3)
+{
+    abi_long ret;
+    void *a;
+
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_fd(arg1, arg2, a));
+    unlock_user(a, arg3, 0);
+
+    return ret;
+}
+
+
+#endif /* FREEBSD_OS_EXTATTR_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 34/41] bsd-user: Add link and list extattr functions to os-extattr.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (32 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 33/41] bsd-user: Add os-extattr.h with file and fd extattr functions Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 35/41] bsd-user: Add ACL system call shims " Warner Losh
                   ` (7 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Stacey Son, Richard Henderson

Add extattr_get_link, extattr_set_link, extattr_delete_link,
extattr_list_fd, extattr_list_file, and extattr_list_link.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-extattr.h | 172 ++++++++++++++++++++++++++++++++++
 1 file changed, 172 insertions(+)

diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
index fb3ef27346..90f0c64c93 100644
--- a/bsd-user/freebsd/os-extattr.h
+++ b/bsd-user/freebsd/os-extattr.h
@@ -204,5 +204,177 @@ static inline abi_long do_freebsd_extattr_delete_fd(abi_long arg1,
     return ret;
 }
 
+/* extattr_get_link(2) */
+static inline abi_long do_freebsd_extattr_get_link(abi_long arg1,
+                                                   abi_long arg2,
+                                                   abi_long arg3,
+                                                   abi_long arg4,
+                                                   abi_long arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    if (arg4 && arg5 > 0) {
+        d = lock_user(VERIFY_WRITE, arg4, arg5, 0);
+        if (d == NULL) {
+            unlock_user(a, arg3, 0);
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_get_link(path(p), arg2, a, d, arg5));
+        unlock_user(d, arg4, arg5);
+    } else {
+        ret = get_errno(extattr_get_link(path(p), arg2, a, NULL, arg5));
+    }
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_set_link(2) */
+static inline abi_long do_freebsd_extattr_set_link(abi_long arg1,
+                                                   abi_long arg2,
+                                                   abi_long arg3,
+                                                   abi_long arg4,
+                                                   abi_long arg5)
+{
+    abi_long ret;
+    void *p, *a, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    d = lock_user(VERIFY_READ, arg4, arg5, 1);
+    if (d == NULL) {
+        unlock_user(a, arg3, 0);
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
+    unlock_user(d, arg4, arg5);
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_delete_link(2) */
+static inline abi_long do_freebsd_extattr_delete_link(abi_long arg1,
+                                                      abi_long arg2,
+                                                      abi_long arg3)
+{
+    abi_long ret;
+    void *p, *a;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    a = lock_user_string(arg3);
+    if (a == NULL) {
+        unlock_user(p, arg1, 0);
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(extattr_delete_link(path(p), arg2, a));
+    unlock_user(a, arg3, 0);
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_fd(2) */
+static inline abi_long do_freebsd_extattr_list_fd(
+    abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *d;
+
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_fd(arg1, arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_fd(arg1, arg2, NULL, arg4));
+    }
+    return ret;
+}
+
+/* extattr_list_file(2) */
+static inline abi_long do_freebsd_extattr_list_file(
+    abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_file(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_file(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* extattr_list_link(2) */
+static inline abi_long do_freebsd_extattr_list_link(
+    abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p, *d;
+
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (arg3 && arg4 > 0) {
+        d = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+        if (d == NULL) {
+            unlock_user(p, arg1, 0);
+            return -TARGET_EFAULT;
+        }
+        ret = get_errno(extattr_list_link(path(p), arg2, d, arg4));
+        unlock_user(d, arg3, arg4);
+    } else {
+        ret = get_errno(extattr_list_link(path(p), arg2, NULL, arg4));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/*
+ *  Access Control Lists
+ */
+
 
 #endif /* FREEBSD_OS_EXTATTR_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 35/41] bsd-user: Add ACL system call shims to os-extattr.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (33 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 34/41] bsd-user: Add link and list extattr functions to os-extattr.h Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 36/41] bsd-user: Add os-extattr.c with ACL conversion functions Warner Losh
                   ` (6 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Stacey Son, Richard Henderson

Complete os-extattr.h with ACL operations: __acl_aclcheck_fd,
__acl_aclcheck_file, __acl_aclcheck_link, __acl_delete_fd,
__acl_delete_file, __acl_delete_link, __acl_get_fd, __acl_get_file,
__acl_get_link, __acl_set_fd, __acl_set_file, and __acl_set_link.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-extattr.h | 289 +++++++++++++++++++++++++++++++++-
 1 file changed, 285 insertions(+), 4 deletions(-)

diff --git a/bsd-user/freebsd/os-extattr.h b/bsd-user/freebsd/os-extattr.h
index 90f0c64c93..b6fe9051f1 100644
--- a/bsd-user/freebsd/os-extattr.h
+++ b/bsd-user/freebsd/os-extattr.h
@@ -65,7 +65,7 @@ static inline abi_long do_freebsd_extattr_set_file(abi_long arg1,
         return -TARGET_EFAULT;
     }
     ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5));
-    unlock_user(d, arg4, arg5);
+    unlock_user(d, arg4, 0);
     unlock_user(a, arg3, 0);
     unlock_user(p, arg1, 0);
 
@@ -151,7 +151,7 @@ static inline abi_long do_freebsd_extattr_set_fd(abi_long arg1, abi_long arg2,
         return -TARGET_EFAULT;
     }
     ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5));
-    unlock_user(d, arg4, arg5);
+    unlock_user(d, arg4, 0);
     unlock_user(a, arg3, 0);
 
     return ret;
@@ -267,7 +267,7 @@ static inline abi_long do_freebsd_extattr_set_link(abi_long arg1,
         return -TARGET_EFAULT;
     }
     ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5));
-    unlock_user(d, arg4, arg5);
+    unlock_user(d, arg4, 0);
     unlock_user(a, arg3, 0);
     unlock_user(p, arg1, 0);
 
@@ -376,5 +376,286 @@ static inline abi_long do_freebsd_extattr_list_link(
  *  Access Control Lists
  */
 
+/* __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_fd(abi_long arg1, abi_long arg2,
+                                                   abi_long arg3)
+{
+    abi_long ret;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_file(abi_long arg1,
+                                                     abi_long arg2,
+                                                     abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_file(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_aclcheck_link(abi_long arg1,
+                                                     abi_long arg2,
+                                                     abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    struct acl host_acl;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_aclcheck_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_fd(int filedes, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_fd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    return get_errno(__acl_delete_fd(arg1, type));
+}
+
+/* int __acl_delete_file(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_file(abi_long arg1,
+                                                   abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_file(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_delete_link(const char *path, acl_type_t type); */
+static inline abi_long do_freebsd__acl_delete_link(abi_long arg1,
+                                                   abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_delete_link(path(p), type));
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_fd(abi_long arg1, abi_long arg2,
+                                              abi_long arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    memset(&host_acl, 0, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
 
-#endif /* FREEBSD_OS_EXTATTR_H */
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = get_errno(__acl_get_fd(arg1, type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+
+    return ret;
+}
+
+/* __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_file(abi_long arg1, abi_long arg2,
+                                                abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    memset(&host_acl, 0, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_file(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_get_link(abi_long arg1, abi_long arg2,
+                                                abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    memset(&host_acl, 0, sizeof(struct acl));
+    host_acl.acl_maxcnt = ACL_MAX_ENTRIES;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__acl_get_link(path(p), type, &host_acl));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_acl(arg3, &host_acl);
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_fd(abi_long arg1, abi_long arg2,
+                                              abi_long arg3)
+{
+    abi_long ret;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_fd(arg1, type, &host_acl));
+    }
+
+    return ret;
+}
+
+/* int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_file(abi_long arg1, abi_long arg2,
+                                                abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_file(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
+
+/* int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); */
+static inline abi_long do_freebsd__acl_set_link(abi_long arg1, abi_long arg2,
+                                                abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+    acl_type_t type;
+    struct acl host_acl;
+
+    ret = t2h_freebsd_acl_type(&type, arg2);
+    if (is_error(ret)) {
+        return ret;
+    }
+    p = lock_user_string(arg1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = t2h_freebsd_acl(&host_acl, arg3);
+    if (!is_error(ret)) {
+        ret = get_errno(__acl_set_link(path(p), type, &host_acl));
+    }
+    unlock_user(p, arg1, 0);
+
+    return ret;
+}
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 36/41] bsd-user: Add os-extattr.c with ACL conversion functions
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (34 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 35/41] bsd-user: Add ACL system call shims " Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 37/41] bsd-user: Add extended attribute and ACL system call dispatch Warner Losh
                   ` (5 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Stacey Son, Richard Henderson

Add os-extattr.c with t2h_freebsd_acl, h2t_freebsd_acl, and
t2h_freebsd_acl_type helper functions for ACL operations. Add
os-extattr.c to the build and include os-extattr.h in the
syscall dispatcher.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/meson.build  |   1 +
 bsd-user/freebsd/os-extattr.c | 118 ++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-syscall.c |   2 +
 3 files changed, 121 insertions(+)
 create mode 100644 bsd-user/freebsd/os-extattr.c

diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build
index db531604ad..0fc779749d 100644
--- a/bsd-user/freebsd/meson.build
+++ b/bsd-user/freebsd/meson.build
@@ -4,6 +4,7 @@ bsd_syscall_nr = custom_target('bsd-syscall-h',
     command: [sh, meson.current_source_dir() / 'scripts/syscallhdr.sh', '@INPUT@', '@OUTPUT@', 'FREEBSD'])
 
 bsd_user_ss.add(files(
+  'os-extattr.c',
   'os-proc.c',
   'os-socket.c',
   'os-stat.c',
diff --git a/bsd-user/freebsd/os-extattr.c b/bsd-user/freebsd/os-extattr.c
new file mode 100644
index 0000000000..3456157b4d
--- /dev/null
+++ b/bsd-user/freebsd/os-extattr.c
@@ -0,0 +1,118 @@
+/*
+ * FreeBSD extend attributes and ACL conversions
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#ifndef _ACL_PRIVATE
+#define _ACL_PRIVATE
+#endif
+#include <sys/acl.h>
+
+#include "qemu.h"
+#include "qemu-os.h"
+
+/*
+ * FreeBSD ACL conversion.
+ */
+abi_long t2h_freebsd_acl(struct acl *host_acl, abi_ulong target_addr)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) {
+        return -TARGET_EFAULT;
+    }
+    __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __get_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    if (host_acl->acl_maxcnt > ACL_MAX_ENTRIES ||
+        host_acl->acl_cnt > ACL_MAX_ENTRIES) {
+        unlock_user_struct(target_acl, target_addr, 0);
+        return -TARGET_EINVAL;
+    }
+
+    for (i = 0; i < host_acl->acl_cnt; i++) {
+        __get_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __get_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __get_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __get_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __get_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 0);
+    return 0;
+}
+
+abi_long h2t_freebsd_acl(abi_ulong target_addr, struct acl *host_acl)
+{
+    uint32_t i;
+    struct target_freebsd_acl *target_acl;
+
+    if (host_acl->acl_maxcnt > ACL_MAX_ENTRIES ||
+        host_acl->acl_cnt > ACL_MAX_ENTRIES) {
+        return -TARGET_EINVAL;
+    }
+
+    if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) {
+        return -TARGET_EFAULT;
+    }
+
+    __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt);
+    __put_user(host_acl->acl_cnt, &target_acl->acl_cnt);
+
+    for (i = 0; i < host_acl->acl_cnt; i++) {
+        __put_user(host_acl->acl_entry[i].ae_tag,
+            &target_acl->acl_entry[i].ae_tag);
+        __put_user(host_acl->acl_entry[i].ae_id,
+            &target_acl->acl_entry[i].ae_id);
+        __put_user(host_acl->acl_entry[i].ae_perm,
+            &target_acl->acl_entry[i].ae_perm);
+        __put_user(host_acl->acl_entry[i].ae_entry_type,
+            &target_acl->acl_entry[i].ae_entry_type);
+        __put_user(host_acl->acl_entry[i].ae_flags,
+            &target_acl->acl_entry[i].ae_flags);
+    }
+
+    unlock_user_struct(target_acl, target_addr, 1);
+    return 0;
+}
+
+abi_long t2h_freebsd_acl_type(acl_type_t *host_type, abi_long target_type)
+{
+
+    switch (target_type) {
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS_OLD:
+        *host_type = ACL_TYPE_ACCESS_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT_OLD:
+        *host_type = ACL_TYPE_DEFAULT_OLD;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_ACCESS:
+        *host_type = ACL_TYPE_ACCESS;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_DEFAULT:
+        *host_type = ACL_TYPE_DEFAULT;
+        break;
+
+    case TARGET_FREEBSD_ACL_TYPE_NFS4:
+        *host_type = ACL_TYPE_NFS4;
+        break;
+
+    default:
+        return -TARGET_EINVAL;
+    }
+    return 0;
+}
+
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 0c729da0ab..f385034a53 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -17,6 +17,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+#define _ACL_PRIVATE
 #include "qemu/osdep.h"
 #include "qemu/cutils.h"
 #include "qemu/path.h"
@@ -43,6 +44,7 @@
 #include "bsd-socket.h"
 
 /* BSD dependent syscall shims */
+#include "os-extattr.h"
 #include "os-stat.h"
 #include "os-proc.h"
 #include "os-signal.h"
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 37/41] bsd-user: Add extended attribute and ACL system call dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (35 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 36/41] bsd-user: Add os-extattr.c with ACL conversion functions Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 38/41] bsd-user: Add scheduler and cpuset functions to os-misc.h Warner Losh
                   ` (4 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Stacey Son, Richard Henderson

Wire up extended attribute and ACL system calls: extattrctl,
extattr_set/get/delete for file, fd, and link variants,
extattr_list for fd, file, and link, and all __acl_* operations
(aclcheck, delete, get, set for fd, file, and link).

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 103 ++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index f385034a53..a14efd3fd4 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -1365,6 +1365,109 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd_sysarch(env, arg1, arg2);
         break;
 
+        /*
+         * extended attributes and ACL system calls
+         */
+    case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */
+        ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_file: /* extattr_set_file(2) */
+        ret = do_freebsd_extattr_set_file(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_file: /* extattr_get_file(2) */
+        ret = do_freebsd_extattr_get_file(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_file: /* extattr_delete_file(2) */
+        ret = do_freebsd_extattr_delete_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_fd: /* extattr_set_fd(2) */
+        ret = do_freebsd_extattr_set_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_fd: /* extattr_get_fd(2) */
+        ret = do_freebsd_extattr_get_fd(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_fd: /* extattr_delete_fd(2) */
+        ret = do_freebsd_extattr_delete_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_get_link: /* extattr_get_link(2) */
+        ret = do_freebsd_extattr_get_link(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_set_link: /* extattr_set_link(2) */
+        ret = do_freebsd_extattr_set_link(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_delete_link: /* extattr_delete_link(2) */
+        ret = do_freebsd_extattr_delete_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_fd: /* extattr_list_fd(2) */
+        ret = do_freebsd_extattr_list_fd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_file: /* extattr_list_file(2) */
+        ret = do_freebsd_extattr_list_file(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_extattr_list_link: /* extattr_list_link(2) */
+        ret = do_freebsd_extattr_list_link(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_fd: /* __acl_aclcheck_fd() */
+        ret = do_freebsd__acl_aclcheck_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_file: /* __acl_aclcheck_file() */
+        ret = do_freebsd__acl_aclcheck_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_aclcheck_link: /* __acl_aclcheck_link() */
+        ret = do_freebsd__acl_aclcheck_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_fd: /* __acl_delete_fd() */
+        ret = do_freebsd__acl_delete_fd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_file: /* __acl_delete_file() */
+        ret = do_freebsd__acl_delete_file(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_delete_link: /* __acl_delete_link() */
+        ret = do_freebsd__acl_delete_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_fd: /* __acl_get_fd() */
+        ret = do_freebsd__acl_get_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_file: /* __acl_get_file() */
+        ret = do_freebsd__acl_get_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_get_link: /* __acl_get_link() */
+        ret = do_freebsd__acl_get_link(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_fd: /* __acl_set_fd() */
+        ret = do_freebsd__acl_set_fd(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_file: /* __acl_set_file() */
+        ret = do_freebsd__acl_set_file(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___acl_set_link: /* __acl_set_link() */
+        ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
+        break;
+
     default:
         qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
         ret = -TARGET_ENOSYS;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 38/41] bsd-user: Add scheduler and cpuset functions to os-misc.h
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (36 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 37/41] bsd-user: Add extended attribute and ACL system call dispatch Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 39/41] bsd-user: Add scheduler, cpuset, kmod, and misc syscall dispatch Warner Losh
                   ` (3 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Sean Bruno,
	Mikaël Urankar, Richard Henderson

Expand os-misc.h with scheduler functions (sched_setparam,
sched_getparam, sched_setscheduler, sched_getscheduler,
sched_rr_get_interval) and CPU affinity functions (cpuset,
cpuset_setid, cpuset_getid, cpuset_getaffinity, cpuset_setaffinity).
Also add sched_yield, sched_get_priority_min, and
sched_get_priority_max to bsd-proc.h.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Sean Bruno <sbruno@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/bsd-proc.h        |  18 ++
 bsd-user/freebsd/os-misc.h | 466 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 480 insertions(+), 4 deletions(-)

diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
index 7efc5b4c92..b9973dbedf 100644
--- a/bsd-user/bsd-proc.h
+++ b/bsd-user/bsd-proc.h
@@ -400,4 +400,22 @@ static inline abi_long do_bsd_setpriority(abi_long which, abi_long who,
     return get_errno(setpriority(which, who, prio));
 }
 
+/* sched_yield(2) */
+static inline abi_long do_bsd_sched_yield(void)
+{
+    return get_errno(sched_yield());
+}
+
+/* sched_get_priority_min(2) */
+static inline abi_long do_bsd_sched_get_priority_min(int policy)
+{
+    return get_errno(sched_get_priority_min(policy));
+}
+
+/* sched_get_priority_max(2) */
+static inline abi_long do_bsd_sched_get_priority_max(int policy)
+{
+    return get_errno(sched_get_priority_max(policy));
+}
+
 #endif /* !BSD_PROC_H */
diff --git a/bsd-user/freebsd/os-misc.h b/bsd-user/freebsd/os-misc.h
index d9979b2a8b..0f87b21cc8 100644
--- a/bsd-user/freebsd/os-misc.h
+++ b/bsd-user/freebsd/os-misc.h
@@ -11,6 +11,363 @@
 #include <sys/cpuset.h>
 #include <sys/random.h>
 #include <sched.h>
+#include <kenv.h>
+
+/* sched_setparam(2) */
+static inline abi_long do_freebsd_sched_setparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setparam(pid, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_get_param(2) */
+static inline abi_long do_freebsd_sched_getparam(pid_t pid,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_errno(sched_getparam(pid, &host_sp));
+    if (!is_error(ret)) {
+        ret = put_user_s32(host_sp.sched_priority, target_sp_addr);
+    }
+    return ret;
+}
+
+/* sched_setscheduler(2) */
+static inline abi_long do_freebsd_sched_setscheduler(pid_t pid, int policy,
+        abi_ulong target_sp_addr)
+{
+    abi_long ret;
+    struct sched_param host_sp;
+
+    ret = get_user_s32(host_sp.sched_priority, target_sp_addr);
+    if (!is_error(ret)) {
+        ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
+    }
+    return ret;
+}
+
+/* sched_getscheduler(2) */
+static inline abi_long do_freebsd_sched_getscheduler(pid_t pid)
+{
+
+    return get_errno(sched_getscheduler(pid));
+}
+
+/* sched_rr_get_interval(2) */
+static inline abi_long do_freebsd_sched_rr_get_interval(pid_t pid,
+        abi_ulong target_ts_addr)
+{
+    abi_long ret;
+    struct timespec host_ts;
+
+    ret = get_errno(sched_rr_get_interval(pid, &host_ts));
+    if (!is_error(ret)) {
+        ret = h2t_freebsd_timespec(target_ts_addr, &host_ts);
+    }
+    return ret;
+}
+
+/* cpuset(2) */
+static inline abi_long do_freebsd_cpuset(abi_ulong target_cpuid)
+{
+    abi_long ret;
+    cpusetid_t setid;
+
+    ret = get_errno(cpuset(&setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_cpuid);
+}
+
+#define target_to_host_cpuset_which(hp, t) do { \
+    (*hp) = t;                               \
+} while (0)
+
+#define target_to_host_cpuset_level(hp, t) do { \
+    (*hp) = t;                               \
+} while (0)
+
+/* cpuset_setid(2) */
+static inline abi_long do_freebsd_cpuset_setid(CPUArchState *env, abi_long arg1,
+        abi_ulong arg2, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+
+    target_to_host_cpuset_which(&which, arg1);
+#if TARGET_ABI_BITS == 32
+    /* See if we need to align the register pairs */
+    if (regpairs_aligned(env)) {
+        id = target_arg64(arg3, arg4);
+        setid = arg5;
+    } else {
+        id = target_arg64(arg2, arg3);
+        setid = arg4;
+    }
+#else
+    id = arg2;
+    setid = arg3;
+#endif
+    return get_errno(cpuset_setid(which, id, setid));
+}
+
+/* cpuset_getid(2) */
+static inline abi_long do_freebsd_cpuset_getid(abi_long arg1, abi_ulong arg2,
+        abi_ulong arg3, abi_ulong arg4, abi_ulong arg5)
+{
+    abi_long ret;
+    id_t id;    /* 64-bit value */
+    cpusetid_t setid;
+    cpuwhich_t which;
+    cpulevel_t level;
+    abi_ulong target_setid;
+
+    target_to_host_cpuset_which(&which, arg1);
+    target_to_host_cpuset_level(&level, arg2);
+#if TARGET_ABI_BITS == 32
+    id = target_arg64(arg3, arg4);
+    target_setid = arg5;
+#else
+    id = arg3;
+    target_setid = arg4;
+#endif
+    ret = get_errno(cpuset_getid(level, which, id, &setid));
+    if (is_error(ret)) {
+        return ret;
+    }
+    return put_user_s32(setid, target_setid);
+}
+
+static abi_long copy_from_user_cpuset_mask(cpuset_t *mask,
+                                           abi_ulong target_mask_addr)
+{
+    int i, j, k;
+    abi_ulong b, *target_mask;
+
+    target_mask = lock_user(VERIFY_READ, target_mask_addr,
+                            CPU_SETSIZE / 8, 1);
+    if (target_mask == NULL) {
+        return -TARGET_EFAULT;
+    }
+    CPU_ZERO(mask);
+    k = 0;
+    for (i = 0; i < ((CPU_SETSIZE / 8) / sizeof(abi_ulong)); i++) {
+        __get_user(b, &target_mask[i]);
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            if ((b >> j) & 1) {
+                CPU_SET(k, mask);
+            }
+            k++;
+        }
+    }
+    unlock_user(target_mask, target_mask_addr, 0);
+
+    return 0;
+}
+
+static abi_long copy_to_user_cpuset_mask(abi_ulong target_mask_addr,
+        cpuset_t *mask)
+{
+    int i, j, k;
+    abi_ulong b, *target_mask;
+
+    target_mask = lock_user(VERIFY_WRITE, target_mask_addr,
+                            CPU_SETSIZE / 8, 0);
+    if (target_mask == NULL) {
+        return -TARGET_EFAULT;
+    }
+    k = 0;
+    for (i = 0; i < ((CPU_SETSIZE / 8) / sizeof(abi_ulong)); i++) {
+        b = 0;
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            b |= ((CPU_ISSET(k, mask) != 0) << j);
+            k++;
+        }
+        __put_user(b, &target_mask[i]);
+    }
+    unlock_user(target_mask, target_mask_addr, (CPU_SETSIZE / 8));
+
+    return 0;
+}
+
+/* cpuset_getaffinity(2) */
+/* cpuset_getaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, cpuset_t *); */
+static inline abi_long do_freebsd_cpuset_getaffinity(cpulevel_t level,
+        cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+    cpuset_t mask;
+    abi_long ret;
+    id_t id;    /* 64-bit */
+    abi_ulong setsize, target_mask;
+
+#if TARGET_ABI_BITS == 32
+    id = (id_t)target_arg64(arg3, arg4);
+    setsize = arg5;
+    target_mask = arg6;
+#else
+    id = (id_t)arg3;
+    setsize = arg4;
+    target_mask = arg5;
+#endif
+
+    ret = get_errno(cpuset_getaffinity(level, which, id, setsize, &mask));
+    if (ret == 0) {
+        ret = copy_to_user_cpuset_mask(target_mask, &mask);
+    }
+
+    return ret;
+}
+
+/* cpuset_setaffinity(2) */
+/* cpuset_setaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, const cpuset_t *);*/
+static inline abi_long do_freebsd_cpuset_setaffinity(cpulevel_t level,
+        cpuwhich_t which, abi_ulong arg3, abi_ulong arg4, abi_ulong arg5,
+        abi_ulong arg6)
+{
+    cpuset_t mask;
+    abi_long ret;
+    id_t id; /* 64-bit */
+    abi_ulong setsize, target_mask;
+
+#if TARGET_ABI_BITS == 32
+    id = (id_t)target_arg64(arg3, arg4);
+    setsize = arg5;
+    target_mask = arg6;
+#else
+    id = (id_t)arg3;
+    setsize = arg4;
+    target_mask = arg5;
+#endif
+
+    ret = copy_from_user_cpuset_mask(&mask, target_mask);
+    if (ret == 0) {
+        ret = get_errno(cpuset_setaffinity(level, which, id, setsize,
+                                           &mask));
+    }
+
+    return ret;
+}
+
+/*
+ * Pretend there are no modules loaded into the kernel. Don't allow loading or
+ * unloading of modules. This works well for tests, and little else seems to
+ * care. Will reevaluate if examples are found that do matter.
+ */
+
+/* modfnext(2) */
+static inline abi_long do_freebsd_modfnext(abi_long modid)
+{
+    return -TARGET_ENOENT;
+}
+
+/* modfind(2) */
+static inline abi_long do_freebsd_modfind(abi_ulong target_name)
+{
+    return -TARGET_ENOENT;
+}
+
+/* kldload(2) */
+static inline abi_long do_freebsd_kldload(abi_ulong target_name)
+{
+    return -TARGET_EPERM;
+}
+
+/* kldunload(2) */
+static inline abi_long do_freebsd_kldunload(abi_long fileid)
+{
+    return -TARGET_EPERM;
+}
+
+/* kldunloadf(2) */
+static inline abi_long do_freebsd_kldunloadf(abi_long fileid, abi_long flags)
+{
+    return -TARGET_EPERM;
+}
+
+/* kldfind(2) */
+static inline abi_long do_freebsd_kldfind(abi_ulong target_name)
+{
+    return -TARGET_ENOENT;
+}
+
+/* kldnext(2) */
+static inline abi_long do_freebsd_kldnext(abi_long fileid)
+{
+    return -TARGET_ENOENT;
+}
+
+
+/* kldstat(2) */
+static inline abi_long do_freebsd_kldstat(abi_long fileid,
+        abi_ulong target_stat)
+{
+    return -TARGET_ENOENT;
+}
+
+/* kldfirstmod(2) */
+static inline abi_long do_freebsd_kldfirstmod(abi_long fileid)
+{
+    return -TARGET_ENOENT;
+}
+
+/* kldsym(2) */
+static inline abi_long do_freebsd_kldsym(abi_long fileid, abi_long cmd,
+        abi_ulong target_data)
+{
+    return -TARGET_ENOENT;
+}
+
+/*
+ * New posix calls
+ */
+
+#if TARGET_ABI_BITS == 32
+static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_BIG_ENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS == 32 */
+static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+/* posix_fallocate(2) */
+static inline abi_long do_freebsd_posix_fallocate(abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+#if TARGET_ABI_BITS == 32
+    return get_errno(posix_fallocate(arg1, target_offset64(arg3, arg4),
+        target_offset64(arg5, arg6)));
+#else
+    return get_errno(posix_fallocate(arg1, arg2, arg3));
+#endif
+}
+
+/* posix_openpt(2) */
+static inline abi_long do_freebsd_posix_openpt(abi_long flags)
+{
+
+    return get_errno(posix_openpt(flags));
+}
 
 /*
  * shm_open2 isn't exported, but the __sys_ alias is. We can use either for the
@@ -19,7 +376,6 @@
 int __sys_shm_open2(const char *path, int flags, mode_t mode, int shmflags,
     const char *);
 
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048
 /* shm_open2(2) */
 static inline abi_long do_freebsd_shm_open2(abi_ulong pathptr, abi_ulong flags,
     abi_long mode, abi_ulong shmflags, abi_ulong nameptr)
@@ -56,9 +412,7 @@ static inline abi_long do_freebsd_shm_open2(abi_ulong pathptr, abi_ulong flags,
     }
     return ret;
 }
-#endif /* __FreeBSD_version >= 1300048 */
 
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049
 /* shm_rename(2) */
 static inline abi_long do_freebsd_shm_rename(abi_ulong fromptr, abi_ulong toptr,
         abi_ulong flags)
@@ -81,6 +435,110 @@ static inline abi_long do_freebsd_shm_rename(abi_ulong fromptr, abi_ulong toptr,
 
     return ret;
 }
-#endif /* __FreeBSD_version >= 1300049 */
+
+#if defined(CONFIG_GETRANDOM)
+static inline abi_long do_freebsd_getrandom(abi_ulong buf, abi_ulong buflen,
+        abi_ulong flags)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, buf, buflen, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(getrandom(p, buflen, flags));
+    unlock_user(p, buf, ret);
+
+    return ret;
+}
+#endif
+
+static inline abi_long do_freebsd_kenv(abi_long action, abi_ulong name,
+    abi_ulong value, abi_long len)
+{
+    abi_long ret;
+    void *gname = NULL;         /* unlocked in cases where set */
+    void *gvalue = NULL;        /* unlocked in cases where set */
+
+    ret = -TARGET_EINVAL;
+    switch (action) {
+    case KENV_GET:
+        gname = lock_user_string(name);
+        if (gname == NULL) {
+            ret = -TARGET_EFAULT;
+            break;
+        }
+        gvalue = lock_user(VERIFY_WRITE, value, len, 0);
+        if (gvalue == NULL) {
+            ret = -TARGET_EFAULT;
+            break;
+        }
+        ret = get_errno(kenv(action, gname, gvalue, len));
+        if (ret > 0) {
+            len = ret;
+        } else {
+            len = 0;
+        }
+        break;
+    case KENV_SET:
+        gname = lock_user_string(name);
+        if (gname == NULL) {
+            ret = -TARGET_EFAULT;
+            break;
+        }
+        gvalue = lock_user(VERIFY_READ, value, len, 1);
+        if (gvalue == NULL) {
+            ret = -TARGET_EFAULT;
+            break;
+        }
+        ret = get_errno(kenv(action, gname, gvalue, len));
+        unlock_user(gvalue, value, 0);
+        gvalue = NULL;
+        break;
+    case KENV_UNSET:
+        gname = lock_user_string(name);
+        if (gname == NULL) {
+            ret = -TARGET_EFAULT;
+            break;
+        }
+        /* value and name ignored, per kenv(2) */
+        ret = get_errno(kenv(action, gname, NULL, 0));
+        break;
+    /* All three treated the same */
+    case KENV_DUMP:
+    case KENV_DUMP_LOADER:
+    case KENV_DUMP_STATIC:
+        /* value == NULL -> just return length */
+        if (value != 0) {
+            gvalue = lock_user(VERIFY_WRITE, value, len, 0);
+            if (gvalue == NULL) {
+                ret = -TARGET_EFAULT;
+                break;
+            }
+        }
+        /* name is ignored, per kenv(2) */
+        ret = get_errno(kenv(action, NULL, gvalue, len));
+        if (ret > 0) {
+            len = ret;
+        } else {
+            len = 0;
+        }
+        break;
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    /* Unmap everything mapped */
+    if (gvalue != NULL) {
+        unlock_user(gvalue, value, len);
+    }
+    if (gname != NULL) {
+        unlock_user(gname, name, 0);
+    }
+
+    return ret;
+}
 
 #endif /* OS_MISC_H */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 39/41] bsd-user: Add scheduler, cpuset, kmod, and misc syscall dispatch
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (37 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 38/41] bsd-user: Add scheduler and cpuset functions to os-misc.h Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 40/41] bsd-user: Move qemu_guest_random_seed_main to same as linux-user Warner Losh
                   ` (2 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Stacey Son, Kyle Evans,
	Richard Henderson

Wire up remaining system calls: sched_setparam, sched_getparam,
sched_setscheduler, sched_getscheduler, sched_get_priority_max,
sched_get_priority_min, sched_rr_get_interval, sched_yield,
cpuset, cpuset_setid, cpuset_getid, cpuset_getaffinity,
cpuset_setaffinity, modfnext, modfind, kldload, kldunload,
kldunloadf, kldfind, kldnext, kldstat, kldfirstmod, kldsym,
posix_fallocate, posix_openpt, getrandom, kenv, cap_rights_limit,
cap_ioctls_limit, cap_fcntls_limit, cap_enter, syscall, and
__syscall.

We also reshuffle a few system calls here to match the blitz branch
which adds some churn, but is the least bad way to deal with the issues.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 512 +++++++++++++++++++++-------------
 1 file changed, 323 insertions(+), 189 deletions(-)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index a14efd3fd4..7e400c89bc 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -532,6 +532,10 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_closefrom(arg1);
         break;
 
+    case TARGET_FREEBSD_NR_close_range: /* close_range(2) */
+        ret = do_freebsd_close_range(arg1, arg2, arg3);
+        break;
+
     case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
         ret = do_bsd_revoke(arg1);
         break;
@@ -696,6 +700,10 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_chflags(arg1, arg2);
         break;
 
+    case TARGET_FREEBSD_NR_chflagsat: /* chflagsat(2) */
+        ret = do_bsd_chflagsat(arg1, arg2, arg3, arg4);
+        break;
+
     case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
         ret = do_bsd_lchflags(arg1, arg2);
         break;
@@ -740,6 +748,10 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_poll(arg1, arg2, arg3);
         break;
 
+    case TARGET_FREEBSD_NR_ppoll: /* ppoll(2) */
+        ret = do_freebsd_ppoll(env, arg1, arg2, arg3, arg4);
+        break;
+
     case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
         ret = do_bsd_lseek(env, arg1, arg2, arg3, arg4, arg5);
         break;
@@ -766,14 +778,6 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_swapoff(arg1, arg2);
         break;
 
-    case TARGET_FREEBSD_NR_chflagsat: /* chflagsat(2) */
-        ret = do_bsd_chflagsat(arg1, arg2, arg3, arg4);
-        break;
-
-    case TARGET_FREEBSD_NR_close_range: /* close_range(2) */
-        ret = do_freebsd_close_range(arg1, arg2, arg3);
-        break;
-
     case TARGET_FREEBSD_NR___realpathat:
         /* __realpathat(2) (XXX no realpathat()) */
         ret = do_freebsd_realpathat(arg1, arg2, arg3, arg4, arg5);
@@ -787,125 +791,12 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd___specialfd(arg1, arg2, arg3);
         break;
 
-        /*
-         * ioctl(2)
-         */
-    case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */
-        ret = do_bsd_ioctl(arg1, arg2, arg3);
-        break;
-
-        /*
-         * stat system calls
-         */
-    case TARGET_FREEBSD_NR_freebsd11_stat: /* stat(2) */
-        ret = do_freebsd11_stat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_lstat: /* lstat(2) */
-        ret = do_freebsd11_lstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_fstat: /* fstat(2) */
-        ret = do_freebsd11_fstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_fstat: /* fstat(2) */
-        ret = do_freebsd_fstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_fstatat: /* fstatat(2) */
-        ret = do_freebsd11_fstatat(arg1, arg2, arg3, arg4);
-        break;
-
-    case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */
-        ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_nstat: /* undocumented */
-        ret = do_freebsd11_nstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_nfstat: /* undocumented */
-        ret = do_freebsd11_nfstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_nlstat: /* undocumented */
-        ret = do_freebsd11_nlstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_getfh: /* getfh(2) */
-        ret = do_freebsd_getfh(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */
-        ret = do_freebsd_lgetfh(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */
-        ret = do_freebsd_fhopen(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_fhstat: /* fhstat(2) */
-        ret = do_freebsd11_fhstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */
-        ret = do_freebsd_fhstat(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_fhstatfs: /* fhstatfs(2) */
-        ret = do_freebsd11_fhstatfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */
-        ret = do_freebsd_fhstatfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_statfs: /* statfs(2) */
-        ret = do_freebsd11_statfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_statfs: /* statfs(2) */
-        ret = do_freebsd_statfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_fstatfs: /* fstatfs(2) */
-        ret = do_freebsd11_fstatfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */
-        ret = do_freebsd_fstatfs(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_getfsstat: /* getfsstat(2) */
-        ret = do_freebsd11_getfsstat(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */
-        ret = do_freebsd_getfsstat(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_getdents: /* getdents(2) */
-        ret = do_freebsd11_getdents(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */
-        ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4);
-        break;
-
-    case TARGET_FREEBSD_NR_freebsd11_getdirentries: /* getdirentries(2) */
-        ret = do_freebsd11_getdirentries(arg1, arg2, arg3, arg4);
-        break;
-    case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */
-        ret = do_freebsd_fcntl(arg1, arg2, arg3);
-        break;
-
         /*
          * Memory management system calls.
          */
     case TARGET_FREEBSD_NR_mmap: /* mmap(2) */
         ret = do_bsd_mmap(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
-                          arg8);
+           arg8);
         break;
 
     case TARGET_FREEBSD_NR_munmap: /* munmap(2) */
@@ -952,17 +843,13 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_shm_open(arg1, arg2, arg3);
         break;
 
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048
     case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */
         ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5);
         break;
-#endif
 
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049
     case TARGET_FREEBSD_NR_shm_rename: /* shm_rename(2) */
         ret = do_freebsd_shm_rename(arg1, arg2, arg3);
         break;
-#endif
 
     case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */
         ret = do_bsd_shm_unlink(arg1);
@@ -984,68 +871,10 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_shmdt(arg1);
         break;
 
-        /*
-         * System V Semaphores
-         */
-    case TARGET_FREEBSD_NR_semget: /* semget(2) */
-        ret = do_bsd_semget(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_semop: /* semop(2) */
-        ret = do_bsd_semop(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR___semctl: { /* __semctl() undocumented */
-        ret = do_bsd___semctl(arg1, arg2, arg3, arg4);
-        break;
-    }
-
-        /*
-         * System V Messages
-         */
-    case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */
-        ret = do_bsd_msgctl(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_msgget: /* msgget(2) */
-        ret = do_bsd_msgget(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */
-        ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4);
-        break;
-
-    case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */
-        ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5);
-        break;
-
     case TARGET_FREEBSD_NR_freebsd11_vadvise:
         ret = do_bsd_vadvise();
         break;
 
-        /*
-         * Misc
-         */
-    case TARGET_FREEBSD_NR_break:
-        ret = do_obreak(arg1);
-        break;
-
-    case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */
-        ret = do_bsd_quotactl(arg1, arg2, arg3);
-        break;
-
-    case TARGET_FREEBSD_NR_reboot: /* reboot(2) */
-        ret = do_bsd_reboot(arg1);
-        break;
-
-    case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */
-        ret = do_bsd_uuidgen(arg1, arg2);
-        break;
-
-    case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */
-        ret = do_bsd_getdtablesize();
-        break;
-
         /*
          * time related system calls.
          */
@@ -1133,10 +962,6 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd_pselect(env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 
-    case TARGET_FREEBSD_NR_ppoll: /* ppoll(2) */
-        ret = do_freebsd_ppoll(env, arg1, arg2, arg3, arg4);
-        break;
-
     case TARGET_FREEBSD_NR_kqueue: /* kqueue(2) */
         ret = do_freebsd_kqueue();
         break;
@@ -1350,6 +1175,119 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd__umtx_op(arg1, arg2, arg3, arg4, arg5);
         break;
 
+        /*
+         * ioctl(2)
+         */
+    case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */
+        ret = do_bsd_ioctl(arg1, arg2, arg3);
+        break;
+
+        /*
+         * stat system calls
+         */
+    case TARGET_FREEBSD_NR_freebsd11_stat: /* stat(2) */
+        ret = do_freebsd11_stat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_lstat: /* lstat(2) */
+        ret = do_freebsd11_lstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_fstat: /* fstat(2) */
+        ret = do_freebsd11_fstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstat: /* fstat(2) */
+        ret = do_freebsd_fstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_fstatat: /* fstatat(2) */
+        ret = do_freebsd11_fstatat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */
+        ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_nstat: /* undocumented */
+        ret = do_freebsd11_nstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_nfstat: /* undocumented */
+        ret = do_freebsd11_nfstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_nlstat: /* undocumented */
+        ret = do_freebsd11_nlstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getfh: /* getfh(2) */
+        ret = do_freebsd_getfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */
+        ret = do_freebsd_lgetfh(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */
+        ret = do_freebsd_fhopen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_fhstat: /* fhstat(2) */
+        ret = do_freebsd11_fhstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */
+        ret = do_freebsd_fhstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_fhstatfs: /* fhstatfs(2) */
+        ret = do_freebsd11_fhstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */
+        ret = do_freebsd_fhstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_statfs: /* statfs(2) */
+        ret = do_freebsd11_statfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_statfs: /* statfs(2) */
+        ret = do_freebsd_statfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_fstatfs: /* fstatfs(2) */
+        ret = do_freebsd11_fstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */
+        ret = do_freebsd_fstatfs(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_getfsstat: /* getfsstat(2) */
+        ret = do_freebsd11_getfsstat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */
+        ret = do_freebsd_getfsstat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_getdents: /* getdents(2) */
+        ret = do_freebsd11_getdents(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */
+        ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd11_getdirentries: /* getdirentries(2) */
+        ret = do_freebsd11_getdirentries(arg1, arg2, arg3, arg4);
+        break;
+    case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */
+        ret = do_freebsd_fcntl(arg1, arg2, arg3);
+        break;
+
         /*
          * sys{ctl, arch, call}
          */
@@ -1365,8 +1303,14 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd_sysarch(env, arg1, arg2);
         break;
 
+    case TARGET_FREEBSD_NR_syscall: /* syscall(2) */
+    case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */
+        ret = do_freebsd_syscall(env, arg1 & 0xffff, arg2, arg3, arg4,
+                arg5, arg6, arg7, arg8, 0);
+        break;
+
         /*
-         * extended attributes and ACL system calls
+         * extended attributes system calls
          */
     case TARGET_FREEBSD_NR_extattrctl: /* extattrctl() */
         ret = do_freebsd_extattrctl(arg1, arg2, arg3, arg4, arg5);
@@ -1468,6 +1412,196 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_freebsd__acl_set_link(arg1, arg2, arg3);
         break;
 
+        /*
+         * System V Semaphores
+         */
+    case TARGET_FREEBSD_NR_semget: /* semget(2) */
+        ret = do_bsd_semget(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_semop: /* semop(2) */
+        ret = do_bsd_semop(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR___semctl: { /* __semctl() undocumented */
+        ret = do_bsd___semctl(arg1, arg2, arg3, arg4);
+        break;
+    }
+
+        /*
+         * System V Messages
+         */
+    case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */
+        ret = do_bsd_msgctl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_msgget: /* msgget(2) */
+        ret = do_bsd_msgget(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */
+        ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */
+        ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+        /*
+         * FreeBSD scheduler control
+         */
+    case TARGET_FREEBSD_NR_sched_setparam: /* sched_setparam(2) */
+        ret = do_freebsd_sched_setparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getparam: /* sched_getparam(2) */
+        ret = do_freebsd_sched_getparam(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_setscheduler: /* sched_setscheduler(2) */
+        ret = do_freebsd_sched_setscheduler(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_getscheduler: /* sched_getscheduler(2) */
+        ret = do_freebsd_sched_getscheduler(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_get_priority_max: /* sched_get_priority_max(2)*/
+        ret = do_bsd_sched_get_priority_max(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_get_priority_min: /* sched_get_priority_min(2)*/
+        ret = do_bsd_sched_get_priority_min(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_rr_get_interval: /* sched_rr_get_interval(2) */
+        ret = do_freebsd_sched_rr_get_interval(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sched_yield: /* sched_yield(2)*/
+        ret = do_bsd_sched_yield();
+        break;
+
+
+        /*
+         * FreeBSD CPU affinity sets management
+         */
+    case TARGET_FREEBSD_NR_cpuset: /* cpuset(2) */
+        ret = do_freebsd_cpuset(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setid: /* cpuset_setid(2) */
+        ret = do_freebsd_cpuset_setid(env, arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getid: /* cpuset_getid(2) */
+        ret = do_freebsd_cpuset_getid(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_getaffinity: /* cpuset_getaffinity(2) */
+        ret = do_freebsd_cpuset_getaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_cpuset_setaffinity: /* cpuset_setaffinity(2) */
+        ret = do_freebsd_cpuset_setaffinity(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+        /*
+         * FreeBSD kernel module
+         */
+    case TARGET_FREEBSD_NR_modfnext: /* modfnext(2) */
+        ret = do_freebsd_modfnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_modfind: /* modfind(2) */
+        ret = do_freebsd_modfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldload: /* kldload(2) */
+        ret = do_freebsd_kldload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunload: /* kldunload(2) */
+        ret = do_freebsd_kldunload(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldunloadf: /* kldunloadf(2) */
+        ret = do_freebsd_kldunloadf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfind: /* kldfind(2) */
+        ret = do_freebsd_kldfind(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldnext: /* kldnext(2) */
+        ret = do_freebsd_kldnext(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldstat: /* kldstat(2) */
+        ret = do_freebsd_kldstat(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kldfirstmod: /* kldfirstmod(2) */
+        ret = do_freebsd_kldfirstmod(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_kldsym: /* kldsym(2) */
+        ret = do_freebsd_kldsym(arg1, arg2, arg3);
+        break;
+
+        /*
+         * FreeBSD additional posix support
+         */
+    case TARGET_FREEBSD_NR_posix_fallocate: /* posix_fallocate(2) */
+        ret = do_freebsd_posix_fallocate(arg1, arg2, arg3, arg4, arg5, arg6);
+        break;
+
+    case TARGET_FREEBSD_NR_posix_openpt: /* posix_openpt(2) */
+        ret = do_freebsd_posix_openpt(arg1);
+        break;
+
+        /*
+         * Misc
+         */
+    case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */
+        ret = do_bsd_quotactl(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_reboot: /* reboot(2) */
+        ret = do_bsd_reboot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */
+        ret = do_bsd_uuidgen(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */
+        ret = do_bsd_getdtablesize();
+        break;
+
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
+        break;
+
+#if defined(CONFIG_GETRANDOM)
+    case TARGET_FREEBSD_NR_getrandom:
+        ret = do_freebsd_getrandom(arg1, arg2, arg3);
+        break;
+#endif
+    case TARGET_FREEBSD_NR_kenv:
+        ret = do_freebsd_kenv(arg1, arg2, arg3, arg4);
+        break;
+
+    /* XXX */
+    case TARGET_FREEBSD_NR_cap_rights_limit:
+    case TARGET_FREEBSD_NR_cap_ioctls_limit:
+    case TARGET_FREEBSD_NR_cap_fcntls_limit:
+        ret = -TARGET_EINVAL;
+        break;
+    case TARGET_FREEBSD_NR_cap_enter:
+        ret = 0;
+        break;
+
     default:
         qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
         ret = -TARGET_ENOSYS;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 40/41] bsd-user: Move qemu_guest_random_seed_main to same as linux-user
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (38 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 39/41] bsd-user: Add scheduler, cpuset, kmod, and misc syscall dispatch Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18  4:24 ` [PULL 41/41] bsd-user Update random_seed on thread creation Warner Losh
  2026-09-18 19:19 ` [PULL 00/41] Misc 2026q2 v4 patches Richard Henderson
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kyle Evans, Warner Losh, Richard Henderson

Linux-user initializes this before doing the environment stuff. Go ahead
and move it there for consistency, though it doesn't matter since we
don't use it until later.

Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/main.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 2fbbfc3d86..13cd752b99 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -541,9 +541,6 @@ int main(int argc, char **argv)
         do_strace = 1;
     }
 
-    target_environ = envlist_to_environ(envlist, NULL);
-    envlist_free(envlist);
-
     {
         Error *err = NULL;
         if (seed_optarg != NULL) {
@@ -557,6 +554,9 @@ int main(int argc, char **argv)
         }
     }
 
+    target_environ = envlist_to_environ(envlist, NULL);
+    envlist_free(envlist);
+
     /*
      * Now that page sizes are configured we can do
      * proper page alignment for guest_base.
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PULL 41/41] bsd-user Update random_seed on thread creation
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (39 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 40/41] bsd-user: Move qemu_guest_random_seed_main to same as linux-user Warner Losh
@ 2026-09-18  4:24 ` Warner Losh
  2026-09-18 19:19 ` [PULL 00/41] Misc 2026q2 v4 patches Richard Henderson
  41 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-18  4:24 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Warner Losh, Philippe Mathieu-Daudé,
	Richard Henderson

Initialize / update cpu->random_seed in similar locations to the
linux-user code. Set it just before we create the thread, and update it
in the thread startup code.

Reported-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-thread.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/bsd-user/freebsd/os-thread.c b/bsd-user/freebsd/os-thread.c
index 63c17e10d0..15872f03fd 100644
--- a/bsd-user/freebsd/os-thread.c
+++ b/bsd-user/freebsd/os-thread.c
@@ -14,6 +14,7 @@
 #include "signal-common.h"
 #include "target_arch_cpu.h"
 #include "target_arch_thread.h"
+#include "qemu/guest-random.h"
 #include "tcg/startup.h"
 #include "exec/tb-flush.h"
 
@@ -142,7 +143,7 @@ void *new_freebsd_thread_start(void *arg)
     target_thread_set_upcall(env, info->param.start_func, info->param.arg,
         info->param.stack_base, info->param.stack_size);
     target_cpu_set_tls(env, info->param.tls_base);
-
+    qemu_guest_random_seed_thread_part2(cpu->random_seed);
     /* Enable signals */
     sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
     /* Signal to the parent that we're ready. */
@@ -1657,6 +1658,7 @@ abi_long do_freebsd_thr_new(CPUArchState *env,
      */
     sigfillset(&sigmask);
     sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
+    cpu->random_seed = qemu_guest_random_seed_thread_part1();
 
     ret = pthread_create(&info.thread, &attr, new_freebsd_thread_start, &info);
 
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PULL 00/41] Misc 2026q2 v4 patches
  2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
                   ` (40 preceding siblings ...)
  2026-09-18  4:24 ` [PULL 41/41] bsd-user Update random_seed on thread creation Warner Losh
@ 2026-09-18 19:19 ` Richard Henderson
  2026-09-19 16:49   ` Warner Losh
  41 siblings, 1 reply; 45+ messages in thread
From: Richard Henderson @ 2026-09-18 19:19 UTC (permalink / raw)
  To: Warner Losh, qemu-devel
  Cc: Kyle Evans, Pierrick Bouvier, Philippe Mathieu-Daudé

On 9/17/26 18:23, Warner Losh wrote:
> The following changes since commit 3b5d71cc3652fa7f5ecc449f05dae3ead2b718d7:
> 
>    Merge tag 'pull-ufs-20260918' ofhttps://gitlab.com/jeuk20.kim/qemu into staging (2026-09-17 15:18:09 -1000)
> 
> are available in the Git repository at:
> 
>    git@gitlab.com:bsdimp/qemu-from-official.git tags/misc-2026q2-v4-pull-request
> 
> for you to fetch changes up to 1f71ada86d7ad43c7241a6ae96912139ec3a6a7e:
> 
>    bsd-user Update random_seed on thread creation (2026-09-17 22:07:42 -0600)
> 
> ----------------------------------------------------------------
> bsd-user: Upstream most of the remaining system calls

Applied, thanks.

r~


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PULL 06/41] bsd-user: Add signal system call dispatch
  2026-09-19 16:47 Warner Losh
@ 2026-09-19 16:47 ` Warner Losh
  0 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-19 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Warner Losh, Kyle Evans, Stacey Son, Kyle Evans, Pierrick Bouvier,
	Richard Henderson

Wire up the signal-related system calls in the FreeBSD syscall
dispatcher: sigaction, sigprocmask, sigpending, sigsuspend, sigreturn,
sigwait, sigwaitinfo, sigqueue, sigaltstack, kill, and pdkill.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Assisted-by: Claude Opus 4.6 (1M context)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/freebsd/os-syscall.c | 48 +++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 7fefdb569f..06148fe3ce 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -43,6 +43,7 @@
 /* BSD dependent syscall shims */
 #include "os-stat.h"
 #include "os-proc.h"
+#include "os-signal.h"
 #include "os-misc.h"
 
 /* I/O */
@@ -950,6 +951,53 @@ static abi_long freebsd_syscall(CPUArchState *env, int num, abi_long arg1,
         ret = do_bsd_getdtablesize();
         break;
 
+        /*
+         * signal system calls
+         */
+    case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */
+        ret = do_bsd_sigaction(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */
+        ret = do_bsd_sigprocmask(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */
+        ret = do_bsd_sigpending(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */
+        ret = do_bsd_sigsuspend(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */
+        ret = do_bsd_sigreturn(env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */
+        ret = do_bsd_sigwait(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */
+        ret = do_bsd_sigwaitinfo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */
+        ret = do_bsd_sigqueue(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */
+        ret = do_bsd_sigaltstack(env, arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_kill: /* kill(2) */
+        ret = do_bsd_kill(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */
+        ret = do_freebsd_pdkill(arg1, arg2);
+        break;
+
         /*
          * sys{ctl, arch, call}
          */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PULL 00/41] Misc 2026q2 v4 patches
  2026-09-18 19:19 ` [PULL 00/41] Misc 2026q2 v4 patches Richard Henderson
@ 2026-09-19 16:49   ` Warner Losh
  0 siblings, 0 replies; 45+ messages in thread
From: Warner Losh @ 2026-09-19 16:49 UTC (permalink / raw)
  To: Richard Henderson
  Cc: qemu-devel, Kyle Evans, Pierrick Bouvier,
	Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 1047 bytes --]

On Fri, Sep 18, 2026 at 1:19 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 9/17/26 18:23, Warner Losh wrote:
> > The following changes since commit
> 3b5d71cc3652fa7f5ecc449f05dae3ead2b718d7:
> >
> >    Merge tag 'pull-ufs-20260918' ofhttps://gitlab.com/jeuk20.kim/qemu
> into staging (2026-09-17 15:18:09 -1000)
> >
> > are available in the Git repository at:
> >
> >    git@gitlab.com:bsdimp/qemu-from-official.git
> tags/misc-2026q2-v4-pull-request
> >
> > for you to fetch changes up to 1f71ada86d7ad43c7241a6ae96912139ec3a6a7e:
> >
> >    bsd-user Update random_seed on thread creation (2026-09-17 22:07:42
> -0600)
> >
> > ----------------------------------------------------------------
> > bsd-user: Upstream most of the remaining system calls
>
> Applied, thanks.


I missed this and just resent it with a tiny tweak. Ignore it. I'll include
the tiny tweak in my next pull request which should be quicker now... My
apologies for the extra email. No need to revert or anything.

Warner

[-- Attachment #2: Type: text/html, Size: 1586 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2026-09-19 16:53 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-18  4:23 [PULL 00/41] Misc 2026q2 v4 patches Warner Losh
2026-09-18  4:23 ` [PULL 01/41] bsd-user: Upstream most of the remaining system calls Warner Losh
2026-09-18  4:23 ` [PULL 02/41] bsd-user: Rename cpu_env to env throughout bsd-user Warner Losh
2026-09-18  4:23 ` [PULL 03/41] bsd-user: Fix copy direciton in preadv Warner Losh
2026-09-18  4:23 ` [PULL 04/41] bsd-user: Add bsd-signal.h with sigaction through sigreturn Warner Losh
2026-09-18  4:23 ` [PULL 05/41] bsd-user: Add signal shims sigwait through kill and os-signal.h Warner Losh
2026-09-18  4:23 ` [PULL 06/41] bsd-user: Add signal system call dispatch Warner Losh
2026-09-18  4:23 ` [PULL 07/41] bsd-user: move sys/shm.h lines Warner Losh
2026-09-18  4:23 ` [PULL 08/41] bsd-user: Remove mmap defines Warner Losh
2026-09-18  4:23 ` [PULL 09/41] bsd-user: Use target_suseconds_t Warner Losh
2026-09-18  4:23 ` [PULL 10/41] bsd-user: Move sys/uuid.h defines Warner Losh
2026-09-18  4:23 ` [PULL 11/41] bsd-user: Fix realpathat for FreeBSD 15.0 and newer Warner Losh
2026-09-18  4:23 ` [PULL 12/41] bsd-user: Add os-file.h with chflagsat, close_range, and more Warner Losh
2026-09-18  4:23 ` [PULL 13/41] bsd-user: Add poll, poll2, lseek, pipe, and swap system call shims Warner Losh
2026-09-18  4:23 ` [PULL 14/41] bsd-user: Add FreeBSD socket helpers and sockaddr conversion Warner Losh
2026-09-18  4:23 ` [PULL 15/41] bsd-user: Add bsd-socket.h with bind through getsockname Warner Losh
2026-09-18  4:23 ` [PULL 16/41] bsd-user: Add socket shims socketpair through shutdown Warner Losh
2026-09-18  4:23 ` [PULL 17/41] bsd-user: Commit the generated os-sockopt.h files Warner Losh
2026-09-18  4:23 ` [PULL 18/41] bsd-user: Implement both getsockopt and setsockopt Warner Losh
2026-09-18  4:24 ` [PULL 19/41] bsd-user: Add FreeBSD socket system calls Warner Losh
2026-09-18  4:24 ` [PULL 20/41] bsd-user: Add os-socket.[ch] sendmsg, recvmsg and cmsg Warner Losh
2026-09-18  4:24 ` [PULL 21/41] bsd-user: Add socket system call dispatch Warner Losh
2026-09-18  4:24 ` [PULL 22/41] bsd-user: Add os-time.h with clock and time-of-day functions Warner Losh
2026-09-18  4:24 ` [PULL 23/41] bsd-user: Add utimes, futimes, and ktimer functions to os-time.h Warner Losh
2026-09-18  4:24 ` [PULL 24/41] bsd-user: Add select, pselect, and ppoll " Warner Losh
2026-09-18  4:24 ` [PULL 25/41] bsd-user: Add kqueue and kevent functions " Warner Losh
2026-09-18  4:24 ` [PULL 26/41] bsd-user: Add sigtimedwait, itimer, and futimens " Warner Losh
2026-09-18  4:24 ` [PULL 27/41] bsd-user: Add os-time.c and time-related type definitions Warner Losh
2026-09-18  4:24 ` [PULL 28/41] bsd-user: Add time system call dispatch Warner Losh
2026-09-18  4:24 ` [PULL 29/41] bsd-user: Add cpu_copy and make init_task_state non-static Warner Losh
2026-09-18  4:24 ` [PULL 30/41] bsd-user: Add os-thread.h with thr and context functions Warner Losh
2026-09-18  4:24 ` [PULL 31/41] bsd-user: Add do_freebsd__umtx_op to os-thread.h Warner Losh
2026-09-18  4:24 ` [PULL 32/41] bsd-user: Add thread system call dispatch Warner Losh
2026-09-18  4:24 ` [PULL 33/41] bsd-user: Add os-extattr.h with file and fd extattr functions Warner Losh
2026-09-18  4:24 ` [PULL 34/41] bsd-user: Add link and list extattr functions to os-extattr.h Warner Losh
2026-09-18  4:24 ` [PULL 35/41] bsd-user: Add ACL system call shims " Warner Losh
2026-09-18  4:24 ` [PULL 36/41] bsd-user: Add os-extattr.c with ACL conversion functions Warner Losh
2026-09-18  4:24 ` [PULL 37/41] bsd-user: Add extended attribute and ACL system call dispatch Warner Losh
2026-09-18  4:24 ` [PULL 38/41] bsd-user: Add scheduler and cpuset functions to os-misc.h Warner Losh
2026-09-18  4:24 ` [PULL 39/41] bsd-user: Add scheduler, cpuset, kmod, and misc syscall dispatch Warner Losh
2026-09-18  4:24 ` [PULL 40/41] bsd-user: Move qemu_guest_random_seed_main to same as linux-user Warner Losh
2026-09-18  4:24 ` [PULL 41/41] bsd-user Update random_seed on thread creation Warner Losh
2026-09-18 19:19 ` [PULL 00/41] Misc 2026q2 v4 patches Richard Henderson
2026-09-19 16:49   ` Warner Losh
  -- strict thread matches above, loose matches on Subject: below --
2026-09-19 16:47 Warner Losh
2026-09-19 16:47 ` [PULL 06/41] bsd-user: Add signal system call dispatch Warner Losh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.